From a7349af9344ccbd6eabd64df156b3ea2e12d6f87 Mon Sep 17 00:00:00 2001 From: "renovate-sh-app[bot]" <219655108+renovate-sh-app[bot]@users.noreply.github.com> Date: Fri, 24 Oct 2025 17:34:24 +0100 Subject: [PATCH 001/378] chore(deps): update dependency @openfeature/web-sdk to v1.6.2 (#112923) | datasource | package | from | to | | ---------- | -------------------- | ----- | ----- | | npm | @openfeature/web-sdk | 1.6.1 | 1.6.2 | Signed-off-by: renovate-sh-app[bot] <219655108+renovate-sh-app[bot]@users.noreply.github.com> Co-authored-by: renovate-sh-app[bot] <219655108+renovate-sh-app[bot]@users.noreply.github.com> --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 389f77fd789..456bf083bed 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5847,11 +5847,11 @@ __metadata: linkType: hard "@openfeature/web-sdk@npm:^1.6.1": - version: 1.6.1 - resolution: "@openfeature/web-sdk@npm:1.6.1" + version: 1.7.0 + resolution: "@openfeature/web-sdk@npm:1.7.0" peerDependencies: "@openfeature/core": ^1.9.0 - checksum: 10/8bd7d1ea386e21cdd7492cab2fd1d2b138b4e6a376a4c0a40244633e5955f6452039bc2633fc5230bd7b494506a4137ba7210d40850634f9618f77a0ee435f9d + checksum: 10/8b9f5ec5bb0e618b439b2e18b73d5c1aecdeea98da28588dc949da2fa0bd8258d27a8329f2371b527410bbeb858af4a8b01254fda59df9d10b26fb23e9217c22 languageName: node linkType: hard From 9b7c68c9940f1fb600500cae764deab8274a8697 Mon Sep 17 00:00:00 2001 From: Leon Sorokin Date: Fri, 24 Oct 2025 11:35:52 -0500 Subject: [PATCH 002/378] TimeSeries: Allow custom time units on x-axis (#112913) * more panels * fix --- .../src/components/uPlot/config/UPlotAxisBuilder.ts | 4 ++-- public/app/core/components/TimeSeries/utils.ts | 3 +++ public/app/core/components/TimelineChart/utils.ts | 7 ++++++- public/app/plugins/panel/heatmap/module.tsx | 7 ++++++- public/app/plugins/panel/heatmap/utils.ts | 12 ++++++++++++ 5 files changed, 29 insertions(+), 4 deletions(-) diff --git a/packages/grafana-ui/src/components/uPlot/config/UPlotAxisBuilder.ts b/packages/grafana-ui/src/components/uPlot/config/UPlotAxisBuilder.ts index 3d8d5972fe1..675d6536184 100644 --- a/packages/grafana-ui/src/components/uPlot/config/UPlotAxisBuilder.ts +++ b/packages/grafana-ui/src/components/uPlot/config/UPlotAxisBuilder.ts @@ -163,8 +163,6 @@ export class UPlotAxisBuilder extends PlotConfigBuilder { if (values) { config.values = values; - } else if (isTime) { - config.values = formatTime; } else if (formatValue) { config.values = (u: uPlot, splits, axisIdx, tickSpace, tickIncr) => { let decimals = guessDecimals(roundDecimals(tickIncr, 6)); @@ -176,6 +174,8 @@ export class UPlotAxisBuilder extends PlotConfigBuilder { } }); }; + } else if (isTime) { + config.values = formatTime; } // store timezone diff --git a/public/app/core/components/TimeSeries/utils.ts b/public/app/core/components/TimeSeries/utils.ts index 1bf0c5a18c0..f029388e602 100644 --- a/public/app/core/components/TimeSeries/utils.ts +++ b/public/app/core/components/TimeSeries/utils.ts @@ -156,6 +156,9 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn = ({ theme, grid: { show: i === 0 && xField.config.custom?.axisGridShow }, filter: filterTicks, + formatValue: xField.config.unit?.startsWith('time:') + ? (v, decimals) => xField.display!(v, decimals).text + : undefined, }); } diff --git a/public/app/core/components/TimelineChart/utils.ts b/public/app/core/components/TimelineChart/utils.ts index 1b233d4a3ad..78f7cd4ef69 100644 --- a/public/app/core/components/TimelineChart/utils.ts +++ b/public/app/core/components/TimelineChart/utils.ts @@ -166,7 +166,9 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn = ( range: coreConfig.yRange, }); - const xAxisHidden = frame.fields[0].config.custom.axisPlacement === AxisPlacement.Hidden; + const xField = frame.fields[0]; + + const xAxisHidden = xField.config.custom.axisPlacement === AxisPlacement.Hidden; builder.addAxis({ show: !xAxisHidden, @@ -176,6 +178,9 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn = ( placement: AxisPlacement.Bottom, timeZone: timeZones[0], theme, + formatValue: xField.config.unit?.startsWith('time:') + ? (v, decimals) => xField.display!(v, decimals).text + : undefined, }); const yCustomConfig = frame.fields[1].config.custom; diff --git a/public/app/plugins/panel/heatmap/module.tsx b/public/app/plugins/panel/heatmap/module.tsx index 6375f7e012b..897fdbda461 100644 --- a/public/app/plugins/panel/heatmap/module.tsx +++ b/public/app/plugins/panel/heatmap/module.tsx @@ -23,13 +23,18 @@ import { Options, defaultOptions, HeatmapColorMode, HeatmapColorScale } from './ export const plugin = new PanelPlugin(HeatmapPanel) .useFieldConfig({ - disableStandardOptions: Object.values(FieldConfigProperty).filter((v) => v !== FieldConfigProperty.Links), + disableStandardOptions: Object.values(FieldConfigProperty).filter( + (v) => v !== FieldConfigProperty.Links && v !== FieldConfigProperty.Unit + ), standardOptions: { [FieldConfigProperty.Links]: { settings: { showOneClick: true, }, }, + [FieldConfigProperty.Unit]: { + hideFromDefaults: true, + }, }, useCustomConfig: (builder) => { const category = [t('heatmap.category-heatmap', 'Heatmap')]; diff --git a/public/app/plugins/panel/heatmap/utils.ts b/public/app/plugins/panel/heatmap/utils.ts index 3618dcdef2d..11a1c03b7c7 100644 --- a/public/app/plugins/panel/heatmap/utils.ts +++ b/public/app/plugins/panel/heatmap/utils.ts @@ -10,6 +10,7 @@ import { incrRoundUp, TimeRange, FieldType, + getDisplayProcessor, } from '@grafana/data'; import { AxisPlacement, ScaleDirection, ScaleDistribution, ScaleOrientation, HeatmapCellLayout } from '@grafana/schema'; import { UPlotConfigBuilder } from '@grafana/ui'; @@ -163,6 +164,13 @@ export function prepConfig(opts: PrepConfigOpts) { } } + let xField = dataRef.current?.heatmap?.fields[0]!; + xField.display ??= getDisplayProcessor({ + field: xField, + theme, + timeZone, + }); + builder.addAxis({ scaleKey: xScaleKey, placement: AxisPlacement.Bottom, @@ -170,6 +178,10 @@ export function prepConfig(opts: PrepConfigOpts) { isTime, theme: theme, timeZone, + formatValue: + isTime && xField.config.unit?.startsWith('time:') + ? (v, decimals) => xField.display!(v, decimals).text + : undefined, }); const yField = dataRef.current?.heatmap?.fields[1]!; From 59bfb44a508a9af31e9d171155d6b87c0cb0b71e Mon Sep 17 00:00:00 2001 From: Josh Hunt Date: Fri, 24 Oct 2025 17:42:42 +0100 Subject: [PATCH 003/378] FS: Apply versionString in help menu in frontend (#112958) Set version in help menu in the frontend instead --- pkg/api/index.go | 1 - pkg/services/navtree/models.go | 8 --- .../AppChrome/MegaMenu/utils.test.ts | 49 ++++++++++++++----- .../components/AppChrome/MegaMenu/utils.ts | 26 ++++++---- .../AppChrome/TopBar/useHelpNode.tsx | 15 ++++-- .../commandPalette/actions/staticActions.ts | 4 +- 6 files changed, 66 insertions(+), 37 deletions(-) diff --git a/pkg/api/index.go b/pkg/api/index.go index 765a40c4688..1effea38164 100644 --- a/pkg/api/index.go +++ b/pkg/api/index.go @@ -216,7 +216,6 @@ func (hs *HTTPServer) setIndexViewData(c *contextmodel.ReqContext) (*dtos.IndexV hs.HooksService.RunIndexDataHooks(&data, c) data.NavTree.ApplyCostManagementIA() - data.NavTree.ApplyHelpVersion(data.Settings.BuildInfo.VersionString) // RunIndexDataHooks can modify the version string data.NavTree.Sort() return &data, nil diff --git a/pkg/services/navtree/models.go b/pkg/services/navtree/models.go index 51bbdf261b1..15418e04b59 100644 --- a/pkg/services/navtree/models.go +++ b/pkg/services/navtree/models.go @@ -158,14 +158,6 @@ func Sort(nodes []*NavLink) { } } -func (root *NavTreeRoot) ApplyHelpVersion(version string) { - helpNode := root.FindById("help") - - if helpNode != nil { - helpNode.SubTitle = version - } -} - func (root *NavTreeRoot) ApplyCostManagementIA() { orgAdminNode := root.FindById(NavIDCfg) var costManagementApp *NavLink diff --git a/public/app/core/components/AppChrome/MegaMenu/utils.test.ts b/public/app/core/components/AppChrome/MegaMenu/utils.test.ts index ea5a289bd95..e66c7c923c8 100644 --- a/public/app/core/components/AppChrome/MegaMenu/utils.test.ts +++ b/public/app/core/components/AppChrome/MegaMenu/utils.test.ts @@ -1,7 +1,10 @@ +import { cloneDeep } from 'lodash'; + import { NavModelItem } from '@grafana/data'; +import { config } from '@grafana/runtime'; import { ContextSrv, setContextSrv } from 'app/core/services/context_srv'; -import { enrichHelpItem, getActiveItem, findByUrl } from './utils'; +import { getEnrichedHelpItem, getActiveItem, findByUrl } from './utils'; const starredDashboardUid = 'foo'; const mockNavTree: NavModelItem[] = [ @@ -67,40 +70,62 @@ jest.mock('../../../app_events', () => ({ })); describe('enrichConfigItems', () => { - let mockHelpNode: NavModelItem; + let mockHelpNode: NavModelItem = { + id: 'help', + text: 'Help', + }; + let originalBuildInfo = { ...config.buildInfo }; - beforeEach(() => { - mockHelpNode = { - id: 'help', - text: 'Help', - }; + beforeAll(() => { + config.buildInfo.versionString = '9.0.0-test'; + }); + + afterAll(() => { + config.buildInfo = originalBuildInfo; }); it('enhances the help node with extra child links', () => { const contextSrv = new ContextSrv(); setContextSrv(contextSrv); - const helpNode = enrichHelpItem(mockHelpNode); - expect(helpNode!.children).toContainEqual( + const helpNode = getEnrichedHelpItem(mockHelpNode); + expect(helpNode.children).toContainEqual( expect.objectContaining({ text: 'Documentation', }) ); - expect(helpNode!.children).toContainEqual( + expect(helpNode.children).toContainEqual( expect.objectContaining({ text: 'Support', }) ); - expect(helpNode!.children).toContainEqual( + expect(helpNode.children).toContainEqual( expect.objectContaining({ text: 'Community', }) ); - expect(helpNode!.children).toContainEqual( + expect(helpNode.children).toContainEqual( expect.objectContaining({ text: 'Keyboard shortcuts', }) ); }); + + it('adds the version string as subtitle', () => { + const helpNode = getEnrichedHelpItem(mockHelpNode); + expect(helpNode.subTitle).toBe(config.buildInfo.versionString); + }); + + it("doesn't mutate the original help node", () => { + const originalHelpNode = cloneDeep(mockHelpNode); + const newHelpNode = getEnrichedHelpItem(mockHelpNode); + + // The mockHelpNode should remain deeply equal to the clone we made of it + expect(mockHelpNode).toEqual(originalHelpNode); + + // The new node should have a different identity than the original + expect(newHelpNode).not.toBe(mockHelpNode); + expect(newHelpNode.children).not.toBe(mockHelpNode.children); + }); }); describe('getActiveItem', () => { diff --git a/public/app/core/components/AppChrome/MegaMenu/utils.ts b/public/app/core/components/AppChrome/MegaMenu/utils.ts index 9996db02879..473e76ec834 100644 --- a/public/app/core/components/AppChrome/MegaMenu/utils.ts +++ b/public/app/core/components/AppChrome/MegaMenu/utils.ts @@ -13,14 +13,21 @@ import { HelpModal } from '../../help/HelpModal'; import { DOCK_MENU_BUTTON_ID, MEGA_MENU_HEADER_TOGGLE_ID } from './MegaMenuHeader'; -export const enrichHelpItem = (helpItem: NavModelItem) => { +const emitOpenShortcutsModal = () => { + appEvents.publish(new ShowModalReactEvent({ component: HelpModal })); +}; + +export const getEnrichedHelpItem = (helpItem: NavModelItem): NavModelItem => { let menuItems = helpItem.children || []; - if (helpItem.id === 'help') { - const onOpenShortcuts = () => { - appEvents.publish(new ShowModalReactEvent({ component: HelpModal })); - }; - helpItem.children = [ + if (helpItem.id !== 'help') { + return helpItem; + } + + return { + ...helpItem, + subTitle: config.buildInfo.versionString, + children: [ ...menuItems, ...getFooterLinks(), ...getEditionAndUpdateLinks(), @@ -28,11 +35,10 @@ export const enrichHelpItem = (helpItem: NavModelItem) => { id: 'keyboard-shortcuts', text: t('nav.help/keyboard-shortcuts', 'Keyboard shortcuts'), icon: 'keyboard', - onClick: onOpenShortcuts, + onClick: emitOpenShortcutsModal, }, - ]; - } - return helpItem; + ], + }; }; export const enrichWithInteractionTracking = ( diff --git a/public/app/core/components/AppChrome/TopBar/useHelpNode.tsx b/public/app/core/components/AppChrome/TopBar/useHelpNode.tsx index 52beedffb56..fe9490520c2 100644 --- a/public/app/core/components/AppChrome/TopBar/useHelpNode.tsx +++ b/public/app/core/components/AppChrome/TopBar/useHelpNode.tsx @@ -1,11 +1,18 @@ import { cloneDeep } from 'lodash'; +import { useMemo } from 'react'; +import { NavModelItem } from '@grafana/data'; import { useSelector } from 'app/types/store'; -import { enrichHelpItem } from '../MegaMenu/utils'; +import { getEnrichedHelpItem } from '../MegaMenu/utils'; -export function useHelpNode() { +export function useHelpNode(): NavModelItem | undefined { const navIndex = useSelector((state) => state.navIndex); - const helpNode = cloneDeep(navIndex['help']); - return helpNode ? enrichHelpItem(helpNode) : undefined; + + const helpNode = useMemo(() => { + const helpNode = cloneDeep(navIndex['help']); + return helpNode ? getEnrichedHelpItem(helpNode) : undefined; + }, [navIndex]); + + return helpNode; } diff --git a/public/app/features/commandPalette/actions/staticActions.ts b/public/app/features/commandPalette/actions/staticActions.ts index b70c5ee4f1c..597e749a6cc 100644 --- a/public/app/features/commandPalette/actions/staticActions.ts +++ b/public/app/features/commandPalette/actions/staticActions.ts @@ -2,7 +2,7 @@ import { useMemo } from 'react'; import { NavModelItem } from '@grafana/data'; import { t } from '@grafana/i18n'; -import { enrichHelpItem } from 'app/core/components/AppChrome/MegaMenu/utils'; +import { getEnrichedHelpItem } from 'app/core/components/AppChrome/MegaMenu/utils'; import { shouldRenderInviteUserButton, performInviteUserClick, @@ -25,7 +25,7 @@ function navTreeToActions(navTree: NavModelItem[], parents: NavModelItem[] = []) for (let navItem of navTree) { // help node needs enriching with the frontend links if (navItem.id === 'help') { - navItem = enrichHelpItem({ ...navItem }); + navItem = getEnrichedHelpItem({ ...navItem }); delete navItem.url; } const { url, target, text, isCreateAction, children, onClick, keywords } = navItem; From e23ba8aa6c1e2b42bb22e1da8e9dd720e6948295 Mon Sep 17 00:00:00 2001 From: Jacob Valdez Date: Fri, 24 Oct 2025 11:45:49 -0500 Subject: [PATCH 004/378] docs: Fix broken refs in single stack access doc (#112903) From d2dbb816b2d8635a27c4638eac2647f371ee8094 Mon Sep 17 00:00:00 2001 From: Andreas Christou Date: Fri, 24 Oct 2025 19:28:04 +0200 Subject: [PATCH 005/378] Graphite: Fix legacy response unmarshalling (#112968) Fix legacy response unmarshalling --- pkg/tsdb/graphite/query.go | 10 ++++-- pkg/tsdb/graphite/query_test.go | 64 +++++++++++++++++++++++++++++++++ pkg/tsdb/graphite/types.go | 6 ++++ 3 files changed, 78 insertions(+), 2 deletions(-) diff --git a/pkg/tsdb/graphite/query.go b/pkg/tsdb/graphite/query.go index 6f4d2bca083..2ab60b21592 100644 --- a/pkg/tsdb/graphite/query.go +++ b/pkg/tsdb/graphite/query.go @@ -256,8 +256,14 @@ func (s *Service) parseResponse(res *http.Response) ([]TargetResponseDTO, error) var data []TargetResponseDTO err = json.Unmarshal(body, &data) if err != nil { - s.logger.Info("Failed to unmarshal graphite response", "error", err, "status", res.Status, "body", string(body)) - return nil, backend.DownstreamError(err) + s.logger.Warn("Failed to unamrshal to newer graphite response, attempting legacy") + var legacyData LegacyTargetResponseDTO + err = json.Unmarshal(body, &legacyData) + if err != nil { + s.logger.Info("Failed to unmarshal legacy graphite response", "error", err, "status", res.Status, "body", string(body)) + return nil, backend.PluginError(err) + } + return legacyData.Series, nil } return data, nil diff --git a/pkg/tsdb/graphite/query_test.go b/pkg/tsdb/graphite/query_test.go index 8af55a156a5..036f5401194 100644 --- a/pkg/tsdb/graphite/query_test.go +++ b/pkg/tsdb/graphite/query_test.go @@ -225,6 +225,70 @@ func TestConvertResponses(t *testing.T) { t.Errorf("Data frames should have been equal but was, expected:\n%s\nactual:\n%s", expectedFramesJSON, dataFramesJSON) } }) + + t.Run("Converts legacy response with no series", func(*testing.T) { + body := ` + { + "version": "v0.1", + "meta": { + "stats": {} + }, + "series": [] + }` + refId := "A" + expectedFrames := data.Frames{} + + httpResponse := &http.Response{StatusCode: 200, Body: io.NopCloser(strings.NewReader(body))} + dataFrames, err := service.toDataFrames(httpResponse, refId) + + require.NoError(t, err) + if !reflect.DeepEqual(expectedFrames, dataFrames) { + expectedFramesJSON, _ := json.Marshal(expectedFrames) + dataFramesJSON, _ := json.Marshal(dataFrames) + t.Errorf("Data frames should have been equal but was, expected:\n%s\nactual:\n%s", expectedFramesJSON, dataFramesJSON) + } + }) + + t.Run("Converts legacy response with series", func(*testing.T) { + body := ` + { + "version": "v0.1", + "meta": { + "stats": { + } + }, + "series": [ + { + "target": "target", + "tags": { "fooTag": "fooValue", "barTag": "barValue", "int": 100, "float": 3.14 }, + "datapoints": [[50, 1], [null, 2], [100, 3]] + } + ] + }` + refId := "A" + a := 50.0 + b := 100.0 + expectedFrame := data.NewFrame("A", + data.NewField("time", nil, []time.Time{time.Unix(1, 0).UTC(), time.Unix(2, 0).UTC(), time.Unix(3, 0).UTC()}), + data.NewField("value", data.Labels{ + "fooTag": "fooValue", + "barTag": "barValue", + "int": "100", + "float": "3.14", + }, []*float64{&a, nil, &b}).SetConfig(&data.FieldConfig{DisplayNameFromDS: "target"}), + ).SetMeta(&data.FrameMeta{Type: data.FrameTypeTimeSeriesMulti}) + expectedFrames := data.Frames{expectedFrame} + + httpResponse := &http.Response{StatusCode: 200, Body: io.NopCloser(strings.NewReader(body))} + dataFrames, err := service.toDataFrames(httpResponse, refId) + + require.NoError(t, err) + if !reflect.DeepEqual(expectedFrames, dataFrames) { + expectedFramesJSON, _ := json.Marshal(expectedFrames) + dataFramesJSON, _ := json.Marshal(dataFrames) + t.Errorf("Data frames should have been equal but was, expected:\n%s\nactual:\n%s", expectedFramesJSON, dataFramesJSON) + } + }) } func TestFixIntervalFormat(t *testing.T) { diff --git a/pkg/tsdb/graphite/types.go b/pkg/tsdb/graphite/types.go index 11c184b13de..7f836961b54 100644 --- a/pkg/tsdb/graphite/types.go +++ b/pkg/tsdb/graphite/types.go @@ -9,6 +9,12 @@ type TargetResponseDTO struct { Tags map[string]any `json:"tags"` } +type LegacyTargetResponseDTO struct { + Version string `json:"version"` + Meta map[string]any `json:"meta"` + Series []TargetResponseDTO `json:"series"` +} + type DataTimePoint [2]Float type DataTimeSeriesPoints []DataTimePoint From f019d58a99a572f7d272c28f2ecbbe7cf5fea09e Mon Sep 17 00:00:00 2001 From: Mihai Turdean <6640685+mihai-turdean@users.noreply.github.com> Date: Fri, 24 Oct 2025 11:45:24 -0600 Subject: [PATCH 006/378] [grafana-iam] Add `resourcePermissions` hooks to sync write to Zanzana on UPDATE and DELETE (#112767) --- pkg/registry/apis/iam/hooks.go | 278 +++++++++++++++++++++++++++- pkg/registry/apis/iam/hooks_test.go | 257 +++++++++++++++++++++++++ pkg/registry/apis/iam/metrics.go | 42 ++++- pkg/registry/apis/iam/register.go | 4 +- 4 files changed, 573 insertions(+), 8 deletions(-) diff --git a/pkg/registry/apis/iam/hooks.go b/pkg/registry/apis/iam/hooks.go index aac644dcfc3..42b2ffe604b 100644 --- a/pkg/registry/apis/iam/hooks.go +++ b/pkg/registry/apis/iam/hooks.go @@ -10,6 +10,7 @@ import ( "google.golang.org/protobuf/types/known/structpb" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apiserver/pkg/registry/generic/registry" iamv0 "github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1" "github.com/grafana/grafana/pkg/services/accesscontrol" @@ -96,6 +97,26 @@ func NewResourceTuple(object string, resource iamv0.ResourcePermissionspecResour return key, nil } +// tupleToTupleKeyWithoutCondition converts a TupleKey to TupleKeyWithoutCondition +// This is needed for delete operations which don't support conditions +func tupleToTupleKeyWithoutCondition(tuple *v1.TupleKey) *v1.TupleKeyWithoutCondition { + return &v1.TupleKeyWithoutCondition{ + User: tuple.User, + Relation: tuple.Relation, + Object: tuple.Object, + } +} + +// toTupleKeysWithoutCondition converts v1.TupleKey to v1.TupleKeyWithoutCondition +// by stripping the condition field, which is required for delete operations +func toTupleKeysWithoutCondition(tuples []*v1.TupleKey) []*v1.TupleKeyWithoutCondition { + result := make([]*v1.TupleKeyWithoutCondition, len(tuples)) + for i, t := range tuples { + result[i] = tupleToTupleKeyWithoutCondition(t) + } + return result +} + // AfterResourcePermissionCreate is a post-create hook that writes the resource permission to Zanzana (openFGA) func (b *IdentityAccessManagementAPIBuilder) AfterResourcePermissionCreate(obj runtime.Object, _ *metav1.CreateOptions) { if b.zClient == nil { @@ -104,19 +125,29 @@ func (b *IdentityAccessManagementAPIBuilder) AfterResourcePermissionCreate(obj r rp, ok := obj.(*iamv0.ResourcePermission) if !ok { + b.logger.Error("failed to convert object to resourcePermission type", "object", obj) return } + resourceType := "resourcepermission" + operation := "create" + // Grab a ticket to write to Zanzana - // This limits the amount of concurrent writes to Zanzana + // This limits the amount of concurrent connections to Zanzana wait := time.Now() b.zTickets <- true - hooksWaitHistogram.Observe(time.Since(wait).Seconds()) // Record wait time + hooksWaitHistogram.WithLabelValues(resourceType, operation).Observe(time.Since(wait).Seconds()) // Record wait time go func(rp *iamv0.ResourcePermission) { + start := time.Now() + status := "success" + defer func() { // Release the ticket after write is done <-b.zTickets + // Record operation duration and count + hooksDurationHistogram.WithLabelValues(resourceType, operation, status).Observe(time.Since(start).Seconds()) + hooksOperationCounter.WithLabelValues(resourceType, operation, status).Inc() }() resource := rp.Spec.Resource @@ -142,6 +173,7 @@ func (b *IdentityAccessManagementAPIBuilder) AfterResourcePermissionCreate(obj r // Avoid writing if there are no valid tuples if len(tuples) == 0 { b.logger.Warn("no valid tuples to write", "namespace", rp.Namespace, "resource", object) + status = "failure" return } @@ -161,12 +193,252 @@ func (b *IdentityAccessManagementAPIBuilder) AfterResourcePermissionCreate(obj r }, }) if err != nil { + status = "failure" b.logger.Error("failed to write resource permission to zanzana", "err", err, "namespace", rp.Namespace, "object", object, "tuplesCnt", len(tuples), ) + } else { + // Record successful tuple writes + hooksTuplesCounter.WithLabelValues(resourceType, operation, "write").Add(float64(len(tuples))) + } + }(rp.DeepCopy()) // Pass a copy of the object +} + +// BeginResourcePermissionUpdate is a pre-update hook that prepares zanzana updates +// It converts old and new permissions to tuples and performs the zanzana write after K8s update succeeds +func (b *IdentityAccessManagementAPIBuilder) BeginResourcePermissionUpdate(ctx context.Context, obj, oldObj runtime.Object, options *metav1.UpdateOptions) (registry.FinishFunc, error) { + if b.zClient == nil { + return nil, nil + } + + // Extract permissions from both old and new objects + oldRP, ok := oldObj.(*iamv0.ResourcePermission) + if !ok { + return nil, nil + } + + newRP, ok := obj.(*iamv0.ResourcePermission) + if !ok { + return nil, nil + } + + // Convert old permissions to tuples for deletion + var oldTuples []*v1.TupleKey + if len(oldRP.Spec.Permissions) > 0 { + oldResource := oldRP.Spec.Resource + oldObject := zanzana.NewObjectEntry(toZanzanaType(oldResource.ApiGroup), oldResource.ApiGroup, oldResource.Resource, "", oldResource.Name) + + oldTuples = make([]*v1.TupleKey, 0, len(oldRP.Spec.Permissions)) + for _, p := range oldRP.Spec.Permissions { + tuple, err := NewResourceTuple(oldObject, oldResource, p) + if err != nil { + b.logger.Error("failed to create old resource permission tuple", + "namespace", oldRP.Namespace, + "object", oldObject, + "err", err, + ) + continue + } + oldTuples = append(oldTuples, tuple) + } + } + + // Convert new permissions to tuples for writing + var newTuples []*v1.TupleKey + if len(newRP.Spec.Permissions) > 0 { + newResource := newRP.Spec.Resource + newObject := zanzana.NewObjectEntry(toZanzanaType(newResource.ApiGroup), newResource.ApiGroup, newResource.Resource, "", newResource.Name) + + newTuples = make([]*v1.TupleKey, 0, len(newRP.Spec.Permissions)) + for _, p := range newRP.Spec.Permissions { + tuple, err := NewResourceTuple(newObject, newResource, p) + if err != nil { + b.logger.Error("failed to create new resource permission tuple", + "namespace", newRP.Namespace, + "object", newObject, + "err", err, + ) + continue + } + newTuples = append(newTuples, tuple) + } + } + + // Return a finish function that performs the zanzana write only on success + return func(ctx context.Context, success bool) { + if !success { + // Update failed, don't write to zanzana + return + } + + // Grab a ticket to write to Zanzana + // This limits the amount of concurrent connections to Zanzana + wait := time.Now() + b.zTickets <- true + hooksWaitHistogram.WithLabelValues("resourcepermission", "update").Observe(time.Since(wait).Seconds()) + + go func() { + start := time.Now() + status := "success" + + defer func() { + <-b.zTickets + // Record operation duration and count + hooksDurationHistogram.WithLabelValues("resourcepermission", "update", status).Observe(time.Since(start).Seconds()) + hooksOperationCounter.WithLabelValues("resourcepermission", "update", status).Inc() + }() + + b.logger.Debug("updating resource permission in zanzana", + "namespace", newRP.Namespace, + "oldPermissionsCnt", len(oldRP.Spec.Permissions), + "newPermissionsCnt", len(newRP.Spec.Permissions), + ) + + ctx, cancel := context.WithTimeout(context.Background(), defaultWriteTimeout) + defer cancel() + + // Prepare write request + req := &v1.WriteRequest{ + Namespace: newRP.Namespace, + } + + // Add deletes for old tuples + if len(oldTuples) > 0 { + deleteTuples := toTupleKeysWithoutCondition(oldTuples) + req.Deletes = &v1.WriteRequestDeletes{ + TupleKeys: deleteTuples, + } + b.logger.Debug("deleting existing resource permissions from zanzana", + "namespace", newRP.Namespace, + "tuplesCnt", len(deleteTuples), + ) + } + + // Add writes for new tuples + if len(newTuples) > 0 { + req.Writes = &v1.WriteRequestWrites{ + TupleKeys: newTuples, + } + b.logger.Debug("writing new resource permissions to zanzana", + "namespace", newRP.Namespace, + "tuplesCnt", len(newTuples), + ) + } + + // Only make the request if there are deletes or writes + if (req.Deletes != nil && len(req.Deletes.TupleKeys) > 0) || (req.Writes != nil && len(req.Writes.TupleKeys) > 0) { + err := b.zClient.Write(ctx, req) + if err != nil { + status = "failure" + b.logger.Error("failed to update resource permission in zanzana", + "err", err, + "namespace", newRP.Namespace, + ) + } else { + // Record successful tuple operations + if len(oldTuples) > 0 { + hooksTuplesCounter.WithLabelValues("resourcepermission", "update", "delete").Add(float64(len(oldTuples))) + } + if len(newTuples) > 0 { + hooksTuplesCounter.WithLabelValues("resourcepermission", "update", "write").Add(float64(len(newTuples))) + } + } + } else { + b.logger.Debug("no tuples to update in zanzana", "namespace", newRP.Namespace) + } + }() + }, nil +} + +// AfterResourcePermissionDelete is a post-delete hook that removes the resource permission from Zanzana (openFGA) +func (b *IdentityAccessManagementAPIBuilder) AfterResourcePermissionDelete(obj runtime.Object, _ *metav1.DeleteOptions) { + if b.zClient == nil { + return + } + + rp, ok := obj.(*iamv0.ResourcePermission) + if !ok { + b.logger.Error("failed to convert object to resourcePermission type", "object", obj) + return + } + + resourceType := "resourcepermission" + operation := "delete" + + // Grab a ticket to write to Zanzana + // This limits the amount of concurrent connections to Zanzana + wait := time.Now() + b.zTickets <- true + hooksWaitHistogram.WithLabelValues(resourceType, operation).Observe(time.Since(wait).Seconds()) // Record wait time + + go func(rp *iamv0.ResourcePermission) { + start := time.Now() + status := "success" + + defer func() { + // Release the ticket after write is done + <-b.zTickets + // Record operation duration and count + hooksDurationHistogram.WithLabelValues(resourceType, operation, status).Observe(time.Since(start).Seconds()) + hooksOperationCounter.WithLabelValues(resourceType, operation, status).Inc() + }() + + resource := rp.Spec.Resource + permissions := rp.Spec.Permissions + + object := zanzana.NewObjectEntry(toZanzanaType(resource.ApiGroup), resource.ApiGroup, resource.Resource, "", resource.Name) + + // Generate delete tuples from the permissions + deleteTuples := make([]*v1.TupleKeyWithoutCondition, 0, len(permissions)) + for _, p := range permissions { + tuple, err := NewResourceTuple(object, resource, p) + if err != nil { + b.logger.Error("failed to create resource permission tuple for deletion", + "namespace", rp.Namespace, + "object", object, + "err", err, + ) + continue + } + deleteTuples = append(deleteTuples, tupleToTupleKeyWithoutCondition(tuple)) + } + + // Avoid writing if there are no valid tuples + if len(deleteTuples) == 0 { + b.logger.Warn("no valid tuples to delete", "namespace", rp.Namespace, "resource", object) + status = "failure" + return + } + + b.logger.Debug("deleting resource permission from zanzana", + "namespace", rp.Namespace, + "object", object, + "tuplesCnt", len(deleteTuples), + ) + + ctx, cancel := context.WithTimeout(context.Background(), defaultWriteTimeout) + defer cancel() + + err := b.zClient.Write(ctx, &v1.WriteRequest{ + Namespace: rp.Namespace, + Deletes: &v1.WriteRequestDeletes{ + TupleKeys: deleteTuples, + }, + }) + if err != nil { + status = "failure" + b.logger.Error("failed to delete resource permission from zanzana", + "err", err, + "namespace", rp.Namespace, + "object", object, + "tuplesCnt", len(deleteTuples), + ) + } else { + // Record successful tuple deletions + hooksTuplesCounter.WithLabelValues(resourceType, operation, "delete").Add(float64(len(deleteTuples))) } }(rp.DeepCopy()) // Pass a copy of the object } @@ -236,7 +508,7 @@ func (b *IdentityAccessManagementAPIBuilder) AfterRoleCreate(obj runtime.Object, wait := time.Now() b.zTickets <- true - hooksWaitHistogram.Observe(time.Since(wait).Seconds()) + hooksWaitHistogram.WithLabelValues("role", "create").Observe(time.Since(wait).Seconds()) go func() { defer func() { diff --git a/pkg/registry/apis/iam/hooks_test.go b/pkg/registry/apis/iam/hooks_test.go index 9c783171560..c19e45ce0d9 100644 --- a/pkg/registry/apis/iam/hooks_test.go +++ b/pkg/registry/apis/iam/hooks_test.go @@ -16,6 +16,7 @@ import ( type FakeZanzanaClient struct { zanzana.Client writeCallback func(context.Context, *v1.WriteRequest) error + readCallback func(context.Context, *v1.ReadRequest) (*v1.ReadResponse, error) } // Write implements zanzana.Client. @@ -23,6 +24,14 @@ func (f *FakeZanzanaClient) Write(ctx context.Context, req *v1.WriteRequest) err return f.writeCallback(ctx, req) } +// Read implements zanzana.Client. +func (f *FakeZanzanaClient) Read(ctx context.Context, req *v1.ReadRequest) (*v1.ReadResponse, error) { + if f.readCallback != nil { + return f.readCallback(ctx, req) + } + return &v1.ReadResponse{}, nil +} + func requireTuplesMatch(t *testing.T, actual []*v1.TupleKey, expected []*v1.TupleKey, msgAndArgs ...interface{}) { t.Helper() for _, exp := range expected { @@ -137,6 +146,254 @@ func TestAfterResourcePermissionCreate(t *testing.T) { }) } +func TestBeginResourcePermissionUpdate(t *testing.T) { + b := &IdentityAccessManagementAPIBuilder{ + logger: log.NewNopLogger(), + zTickets: make(chan bool, 1), + } + + t.Run("should update zanzana entries for folder resource permissions", func(t *testing.T) { + oldFolderPerm := iamv0.ResourcePermission{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "org-2", + }, + Spec: iamv0.ResourcePermissionSpec{ + Resource: iamv0.ResourcePermissionspecResource{ + ApiGroup: "folder.grafana.app", Resource: "folders", Name: "fold1", + }, + Permissions: []iamv0.ResourcePermissionspecPermission{ + {Kind: iamv0.ResourcePermissionSpecPermissionKindUser, Name: "u1", Verb: "View"}, + }, + }, + } + + newFolderPerm := iamv0.ResourcePermission{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "org-2", + }, + Spec: iamv0.ResourcePermissionSpec{ + Resource: iamv0.ResourcePermissionspecResource{ + ApiGroup: "folder.grafana.app", Resource: "folders", Name: "fold1", + }, + Permissions: []iamv0.ResourcePermissionspecPermission{ + {Kind: iamv0.ResourcePermissionSpecPermissionKindUser, Name: "u2", Verb: "Edit"}, + {Kind: iamv0.ResourcePermissionSpecPermissionKindTeam, Name: "team1", Verb: "View"}, + }, + }, + } + + testFolderWrite := func(ctx context.Context, req *v1.WriteRequest) error { + require.NotNil(t, req) + require.Equal(t, "org-2", req.Namespace) + + // Should delete old permission + require.NotNil(t, req.Deletes) + require.Len(t, req.Deletes.TupleKeys, 1) + require.Equal( + t, + req.Deletes.TupleKeys[0], + &v1.TupleKeyWithoutCondition{User: "user:u1", Relation: "view", Object: "folder:fold1"}, + ) + + // Should write new permissions + require.NotNil(t, req.Writes) + require.Len(t, req.Writes.TupleKeys, 2) + + expectedWrites := []*v1.TupleKey{ + {User: "user:u2", Relation: "edit", Object: "folder:fold1"}, + {User: "team:team1#member", Relation: "view", Object: "folder:fold1"}, + } + requireTuplesMatch(t, req.Writes.TupleKeys, expectedWrites) + return nil + } + + b.zClient = &FakeZanzanaClient{writeCallback: testFolderWrite} + + // Call BeginUpdate which does all the work + finishFunc, err := b.BeginResourcePermissionUpdate(context.Background(), &newFolderPerm, &oldFolderPerm, nil) + require.NoError(t, err) + require.NotNil(t, finishFunc) + + // Call the finish function with success=true to trigger the zanzana write + finishFunc(context.Background(), true) + }) + + // Wait for the ticket to be released + <-b.zTickets + + t.Run("should update zanzana entries for dashboard resource permissions", func(t *testing.T) { + oldDashPerm := iamv0.ResourcePermission{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + }, + Spec: iamv0.ResourcePermissionSpec{ + Resource: iamv0.ResourcePermissionspecResource{ + ApiGroup: "dashboard.grafana.app", Resource: "dashboards", Name: "dash1", + }, + Permissions: []iamv0.ResourcePermissionspecPermission{ + {Kind: iamv0.ResourcePermissionSpecPermissionKindUser, Name: "u1", Verb: "View"}, + }, + }, + } + + newDashPerm := iamv0.ResourcePermission{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + }, + Spec: iamv0.ResourcePermissionSpec{ + Resource: iamv0.ResourcePermissionspecResource{ + ApiGroup: "dashboard.grafana.app", Resource: "dashboards", Name: "dash1", + }, + Permissions: []iamv0.ResourcePermissionspecPermission{ + {Kind: iamv0.ResourcePermissionSpecPermissionKindServiceAccount, Name: "sa1", Verb: "Edit"}, + }, + }, + } + + object := "resource:dashboard.grafana.app/dashboards/dash1" + + testDashWrite := func(ctx context.Context, req *v1.WriteRequest) error { + require.NotNil(t, req) + require.Equal(t, "default", req.Namespace) + + // Should delete old permission + require.NotNil(t, req.Deletes) + require.Len(t, req.Deletes.TupleKeys, 1) + require.Equal( + t, + req.Deletes.TupleKeys[0], + &v1.TupleKeyWithoutCondition{User: "user:u1", Relation: "view", Object: object}, + ) + + // Should write new permission + require.NotNil(t, req.Writes) + require.Len(t, req.Writes.TupleKeys, 1) + + tuple := req.Writes.TupleKeys[0] + require.NotNil(t, tuple.Condition) + require.Equal(t, "group_filter", tuple.Condition.Name) + tuple.Condition = nil + require.Equal( + t, + tuple, + &v1.TupleKey{User: "service-account:sa1", Relation: "edit", Object: object}, + ) + + return nil + } + + b.zClient = &FakeZanzanaClient{writeCallback: testDashWrite} + + // Call BeginUpdate which does all the work + finishFunc, err := b.BeginResourcePermissionUpdate(context.Background(), &newDashPerm, &oldDashPerm, nil) + require.NoError(t, err) + require.NotNil(t, finishFunc) + + // Call the finish function with success=true to trigger the zanzana write + finishFunc(context.Background(), true) + }) +} + +func TestAfterResourcePermissionDelete(t *testing.T) { + b := &IdentityAccessManagementAPIBuilder{ + logger: log.NewNopLogger(), + zTickets: make(chan bool, 1), + } + + t.Run("should delete zanzana entries for folder resource permissions", func(t *testing.T) { + folderPerm := iamv0.ResourcePermission{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "org-2", + }, + Spec: iamv0.ResourcePermissionSpec{ + Resource: iamv0.ResourcePermissionspecResource{ + ApiGroup: "folder.grafana.app", Resource: "folders", Name: "fold1", + }, + Permissions: []iamv0.ResourcePermissionspecPermission{ + {Kind: iamv0.ResourcePermissionSpecPermissionKindUser, Name: "u1", Verb: "View"}, + {Kind: iamv0.ResourcePermissionSpecPermissionKindBasicRole, Name: "Editor", Verb: "Edit"}, + }, + }, + } + + testFolderDelete := func(ctx context.Context, req *v1.WriteRequest) error { + require.NotNil(t, req) + require.Equal(t, "org-2", req.Namespace) + + // Should have deletes but no writes + require.NotNil(t, req.Deletes) + require.Len(t, req.Deletes.TupleKeys, 2) + require.Nil(t, req.Writes) + + require.Equal( + t, + req.Deletes.TupleKeys[0], + &v1.TupleKeyWithoutCondition{User: "user:u1", Relation: "view", Object: "folder:fold1"}, + ) + require.Equal( + t, + req.Deletes.TupleKeys[1], + &v1.TupleKeyWithoutCondition{User: "role:basic_editor#assignee", Relation: "edit", Object: "folder:fold1"}, + ) + return nil + } + + b.zClient = &FakeZanzanaClient{writeCallback: testFolderDelete} + b.AfterResourcePermissionDelete(&folderPerm, nil) + }) + + // Wait for the ticket to be released + <-b.zTickets + + t.Run("should delete zanzana entries for dashboard resource permissions", func(t *testing.T) { + dashPerm := iamv0.ResourcePermission{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + }, + Spec: iamv0.ResourcePermissionSpec{ + Resource: iamv0.ResourcePermissionspecResource{ + ApiGroup: "dashboard.grafana.app", Resource: "dashboards", Name: "dash1", + }, + Permissions: []iamv0.ResourcePermissionspecPermission{ + {Kind: iamv0.ResourcePermissionSpecPermissionKindServiceAccount, Name: "sa1", Verb: "View"}, + {Kind: iamv0.ResourcePermissionSpecPermissionKindTeam, Name: "team1", Verb: "Edit"}, + }, + }, + } + + testDashDelete := func(ctx context.Context, req *v1.WriteRequest) error { + object := "resource:dashboard.grafana.app/dashboards/dash1" + + require.NotNil(t, req) + require.Equal(t, "default", req.Namespace) + + // Should have deletes but no writes + require.NotNil(t, req.Deletes) + require.Len(t, req.Deletes.TupleKeys, 2) + require.Nil(t, req.Writes) + + require.Equal( + t, + req.Deletes.TupleKeys[0], + &v1.TupleKeyWithoutCondition{User: "service-account:sa1", Relation: "view", Object: object}, + ) + require.Equal( + t, + req.Deletes.TupleKeys[1], + &v1.TupleKeyWithoutCondition{User: "team:team1#member", Relation: "edit", Object: object}, + ) + + return nil + } + + b.zClient = &FakeZanzanaClient{writeCallback: testDashDelete} + b.AfterResourcePermissionDelete(&dashPerm, nil) + }) + + // Wait for the ticket to be released + <-b.zTickets +} + func TestAfterCoreRoleCreate(t *testing.T) { t.Run("should create zanzana entries for core role with folder permissions", func(t *testing.T) { b := &IdentityAccessManagementAPIBuilder{ diff --git a/pkg/registry/apis/iam/metrics.go b/pkg/registry/apis/iam/metrics.go index 6c25a8746f7..aa918732843 100644 --- a/pkg/registry/apis/iam/metrics.go +++ b/pkg/registry/apis/iam/metrics.go @@ -14,19 +14,53 @@ const ( var ( registerOnce sync.Once - hooksWaitHistogram = prometheus.NewHistogram(prometheus.HistogramOpts{ + hooksWaitHistogram = prometheus.NewHistogramVec(prometheus.HistogramOpts{ Namespace: metricsNamespace, Subsystem: metricsSubSystem, Name: "hooks_wait_duration_seconds", Help: "Time spent in the hooks waiting for a ticket to start processing", Buckets: prometheus.ExponentialBuckets(0.001, 2, 5), // 1ms to ~16s - }) + }, []string{"resource_type", "operation"}) + + // hooksDurationHistogram tracks the total duration of hook operations + hooksDurationHistogram = prometheus.NewHistogramVec(prometheus.HistogramOpts{ + Namespace: metricsNamespace, + Subsystem: metricsSubSystem, + Name: "hooks_operation_duration_seconds", + Help: "Time spent executing hook operations (create, update, delete)", + Buckets: prometheus.ExponentialBuckets(0.001, 2, 10), // 1ms to ~1s + }, []string{"resource_type", "operation", "status"}) + + // hooksOperationCounter tracks the number of hook operations + hooksOperationCounter = prometheus.NewCounterVec(prometheus.CounterOpts{ + Namespace: metricsNamespace, + Subsystem: metricsSubSystem, + Name: "hooks_operations_total", + Help: "Total number of hook operations by resource type, operation, and status", + }, []string{"resource_type", "operation", "status"}) + + // hooksTuplesCounter tracks the number of tuples written/deleted + hooksTuplesCounter = prometheus.NewCounterVec(prometheus.CounterOpts{ + Namespace: metricsNamespace, + Subsystem: metricsSubSystem, + Name: "hooks_tuples_total", + Help: "Total number of tuples written or deleted by resource type and operation type", + }, []string{"resource_type", "operation", "action"}) ) func registerMetrics(reg prometheus.Registerer) { registerOnce.Do(func() { - if err := reg.Register(hooksWaitHistogram); err != nil { - log.New("iam.apis").Warn("failed to register iam apiserver metrics", "error", err) + metrics := []prometheus.Collector{ + hooksWaitHistogram, + hooksDurationHistogram, + hooksOperationCounter, + hooksTuplesCounter, + } + + for _, metric := range metrics { + if err := reg.Register(metric); err != nil { + log.New("iam.apis").Warn("failed to register iam apiserver metrics", "error", err) + } } }) } diff --git a/pkg/registry/apis/iam/register.go b/pkg/registry/apis/iam/register.go index c852515f75c..1d1e74730f4 100644 --- a/pkg/registry/apis/iam/register.go +++ b/pkg/registry/apis/iam/register.go @@ -305,8 +305,10 @@ func (b *IdentityAccessManagementAPIBuilder) UpdateAPIGroupInfo(apiGroupInfo *ge return err } if enableZanzanaSync { - b.logger.Info("Enabling AfterCreate hook for ResourcePermission to sync to Zanzana") + b.logger.Info("Enabling AfterCreate, BeginUpdate, and AfterDelete hooks for ResourcePermission to sync to Zanzana") resourcePermissionStore.AfterCreate = b.AfterResourcePermissionCreate + resourcePermissionStore.BeginUpdate = b.BeginResourcePermissionUpdate + resourcePermissionStore.AfterDelete = b.AfterResourcePermissionDelete } storage[iamv0.ResourcePermissionInfo.StoragePath()] = resourcePermissionStore } From eabb34815288e4ffa99e289a9984d6ec0bd71a2d Mon Sep 17 00:00:00 2001 From: Paul Marbach Date: Fri, 24 Oct 2025 15:04:33 -0400 Subject: [PATCH 007/378] StateTimeline: Comment and metadata cleanup (#112960) --- eslint.config.js | 19 +++++++++++++++++++ .../state-timeline/StateTimelinePanel.tsx | 3 --- .../plugins/panel/state-timeline/hooks.tsx | 7 +++++++ 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/eslint.config.js b/eslint.config.js index f01463559aa..b88a4231fd3 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -485,6 +485,25 @@ module.exports = [ }, }, + // dataviz prefers to use `clsx` over `cx` to compose classes as a rule for performance reasons + { + files: ['public/app/plugins/panel/state-timeline/**/*.{ts,tsx}'], + rules: { + 'no-restricted-imports': [ + 'error', + withBaseRestrictedImportsConfig({ + patterns: [ + { + group: ['@emotion/css'], + importNames: ['cx'], + message: 'Do not use "cx" from @emotion/css. Instead, use `clsx` and compose together only strings.', + }, + ], + }), + ], + }, + }, + // Old betterer rules config: { files: ['**/*.{js,jsx,ts,tsx}'], diff --git a/public/app/plugins/panel/state-timeline/StateTimelinePanel.tsx b/public/app/plugins/panel/state-timeline/StateTimelinePanel.tsx index 8dffba2ad0d..59883b946c4 100644 --- a/public/app/plugins/panel/state-timeline/StateTimelinePanel.tsx +++ b/public/app/plugins/panel/state-timeline/StateTimelinePanel.tsx @@ -29,9 +29,6 @@ import { containerStyles } from './styles'; interface TimelinePanelProps extends PanelProps {} -/** - * @alpha - */ export const StateTimelinePanel = ({ data, timeRange, diff --git a/public/app/plugins/panel/state-timeline/hooks.tsx b/public/app/plugins/panel/state-timeline/hooks.tsx index 9d23d2cf21e..c52c6adbf87 100644 --- a/public/app/plugins/panel/state-timeline/hooks.tsx +++ b/public/app/plugins/panel/state-timeline/hooks.tsx @@ -17,6 +17,13 @@ const paginationStyles = { }), }; +/** + * a React hook used to encapsulate the rendering and state for pagination in StateTimeline. + * @param frames DataFrames to paginate + * @param perPage number of series per page + * @returns the current frames rendered, the pagination element to render, the height of the pagination element, + * and a paginationRev which GraphNG uses to trigger re-renders. + */ export function usePagination(frames?: DataFrame[], perPage?: number) { const [currentPage, setCurrentPage] = useState(1); From 5656f62cf41dc37e5beec201c41140bb8c883161 Mon Sep 17 00:00:00 2001 From: Paul Marbach Date: Fri, 24 Oct 2025 15:04:49 -0400 Subject: [PATCH 008/378] Gauge: Update codeownership for RadialGauge grafana/ui component (#112972) --- .github/CODEOWNERS | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 70815f59d7b..006bf6f476f 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -720,6 +720,7 @@ /packages/grafana-ui/src/components/BarGauge/ @grafana/dataviz-squad /packages/grafana-ui/src/components/DataLinks/ @grafana/dataviz-squad /packages/grafana-ui/src/components/Gauge/ @grafana/dataviz-squad +/packages/grafana-ui/src/components/RadialGauge/ @grafana/dataviz-squad /packages/grafana-ui/src/components/PluginSignatureBadge/ @grafana/plugins-platform-frontend /packages/grafana-ui/src/components/Sparkline/ @grafana/grafana-frontend-platform @grafana/app-o11y-visualizations /packages/grafana-ui/src/components/Table/ @grafana/dataviz-squad From 1bf0861738a12979ddfc9dd6a4646c4f768329ca Mon Sep 17 00:00:00 2001 From: Paul Marbach Date: Fri, 24 Oct 2025 15:05:13 -0400 Subject: [PATCH 009/378] TimeSeries: Tests for x-axis units (#112956) * more panels * fix * TimeSeries: Tests for x-axis units --------- Co-authored-by: Leon Sorokin --- .../core/components/TimeSeries/utils.test.ts | 105 +++++++++++++++++- 1 file changed, 104 insertions(+), 1 deletion(-) diff --git a/public/app/core/components/TimeSeries/utils.test.ts b/public/app/core/components/TimeSeries/utils.test.ts index 583358c7c4c..c57d96c2213 100644 --- a/public/app/core/components/TimeSeries/utils.test.ts +++ b/public/app/core/components/TimeSeries/utils.test.ts @@ -1,4 +1,4 @@ -import { EventBus, FieldType } from '@grafana/data'; +import { createDataFrame, dateTime, DateTimeInput, EventBus, FieldType } from '@grafana/data'; import { getTheme } from '@grafana/ui'; import { preparePlotConfigBuilder } from './utils'; @@ -272,3 +272,106 @@ describe('when fill below to option is used', () => { } }); }); + +describe('time axis units', () => { + it('should use default time unit formatting if no custom unit provided ', () => { + const frame = createDataFrame({ + fields: [ + { + config: {}, + values: [1667406900000, 1667407170000, 1667407185000], + name: 'Time', + type: FieldType.time, + }, + { + config: {}, + values: [1, 2, 3], + name: 'Value', + type: FieldType.number, + }, + { + config: {}, + values: [4, 5, 6], + name: 'Value', + type: FieldType.number, + }, + ], + }); + const eventBus = { + publish: jest.fn(), + getStream: jest.fn(), + subscribe: jest.fn(), + removeAllListeners: jest.fn(), + newScopedBus: jest.fn(), + }; + const builder = preparePlotConfigBuilder({ + frame, + //@ts-ignore + theme: getTheme(), + timeZones: ['browser'], + getTimeRange: jest.fn(), + eventBus, + sync: jest.fn(), + allFrames: [frame], + renderers: [], + }); + const config = builder.getConfig(); + expect(config.axes![0]!.values).toEqual(expect.any(Function)); + // @ts-ignore + expect(config.axes![0]!.values(config, [1667406900000, 1761316576114], 0, 100, 1000)).toEqual([ + '11:35:00', + '09:36:16', + ]); + }); + + it('should use custom time unit if provided ', () => { + const frame = createDataFrame({ + fields: [ + { + config: { unit: 'time: MM-DD' }, + values: [1667406900000, 1667407170000, 1667407185000], + name: 'Time', + state: { multipleFrames: true, displayName: 'Time', origin: { fieldIndex: 0, frameIndex: 0 } }, + type: FieldType.time, + display: jest.fn((v) => ({ text: dateTime(v as DateTimeInput).format('MM-DD'), numeric: Number(v) })), + }, + { + config: {}, + values: [1, 2, 3], + name: 'Value', + state: { multipleFrames: true, displayName: 'Test1', origin: { fieldIndex: 1, frameIndex: 0 } }, + type: FieldType.number, + }, + { + config: {}, + values: [4, 5, 6], + name: 'Value', + state: { multipleFrames: true, displayName: 'Test2', origin: { fieldIndex: 1, frameIndex: 1 } }, + type: FieldType.number, + }, + ], + }); + const eventBus = { + publish: jest.fn(), + getStream: jest.fn(), + subscribe: jest.fn(), + removeAllListeners: jest.fn(), + newScopedBus: jest.fn(), + }; + const builder = preparePlotConfigBuilder({ + frame, + //@ts-ignore + theme: getTheme(), + timeZones: ['browser'], + getTimeRange: jest.fn(), + eventBus, + sync: jest.fn(), + allFrames: [frame], + renderers: [], + }); + const config = builder.getConfig(); + expect(config.axes![0]!.values).toEqual(expect.any(Function)); + // @ts-ignore + expect(config.axes![0]!.values(config, [1667406900000, 1761316576114], 0, 100, 1000)).toEqual(['11-02', '10-24']); + }); +}); From 815ced0f70f376f986057b2237004d2134a0380b Mon Sep 17 00:00:00 2001 From: Isabel Matwawana <76437239+imatwawana@users.noreply.github.com> Date: Fri, 24 Oct 2025 15:13:47 -0400 Subject: [PATCH 010/378] Docs: Update saved queries permissions for Viewer role (#112978) --- .../panels-visualizations/query-transform-data/_index.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/sources/visualizations/panels-visualizations/query-transform-data/_index.md b/docs/sources/visualizations/panels-visualizations/query-transform-data/_index.md index 42dcf1338b7..0c7e80fc41b 100644 --- a/docs/sources/visualizations/panels-visualizations/query-transform-data/_index.md +++ b/docs/sources/visualizations/panels-visualizations/query-transform-data/_index.md @@ -178,7 +178,6 @@ To save a query you've created: - No validation is performed when you save a query, so it's possible to save an invalid query. You should confirm the query is working properly before you save it. - Saved queries are currently accessible from the query editors in Dashboards and Explore. - You can save a maximum of 1000 queries. -- Users with the Viewer role who have access to Explore can use saved queries, but can't write them. - If you have multiple queries open in Explore and you edit one of them by way of the **Edit in Explore** function in the **Saved queries** drawer, the edited query replaces your open queries in Explore. ### Special data sources From b9b0ff1219a22ca0a3b09ea42c06a2526e878f40 Mon Sep 17 00:00:00 2001 From: "grafana-pr-automation[bot]" <140550294+grafana-pr-automation[bot]@users.noreply.github.com> Date: Sat, 25 Oct 2025 00:39:21 +0000 Subject: [PATCH 011/378] I18n: Download translations from Crowdin (#113012) New Crowdin translations by GitHub Action Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- public/locales/cs-CZ/grafana.json | 16 ++++++++++++---- public/locales/de-DE/grafana.json | 16 ++++++++++++---- public/locales/es-ES/grafana.json | 16 ++++++++++++---- public/locales/fr-FR/grafana.json | 16 ++++++++++++---- public/locales/hu-HU/grafana.json | 16 ++++++++++++---- public/locales/id-ID/grafana.json | 16 ++++++++++++---- public/locales/it-IT/grafana.json | 16 ++++++++++++---- public/locales/ja-JP/grafana.json | 16 ++++++++++++---- public/locales/ko-KR/grafana.json | 16 ++++++++++++---- public/locales/nl-NL/grafana.json | 16 ++++++++++++---- public/locales/pl-PL/grafana.json | 16 ++++++++++++---- public/locales/pt-BR/grafana.json | 16 ++++++++++++---- public/locales/pt-PT/grafana.json | 16 ++++++++++++---- public/locales/ru-RU/grafana.json | 16 ++++++++++++---- public/locales/sv-SE/grafana.json | 16 ++++++++++++---- public/locales/tr-TR/grafana.json | 14 +++++++++++--- public/locales/zh-Hans/grafana.json | 16 ++++++++++++---- public/locales/zh-Hant/grafana.json | 16 ++++++++++++---- 18 files changed, 215 insertions(+), 71 deletions(-) diff --git a/public/locales/cs-CZ/grafana.json b/public/locales/cs-CZ/grafana.json index 2b9c3df9988..670906c1906 100644 --- a/public/locales/cs-CZ/grafana.json +++ b/public/locales/cs-CZ/grafana.json @@ -4642,7 +4642,8 @@ }, "editor": { "info": "", - "not-supported-for-custom-grid": "Podmíněné vykreslení není pro vlastní rozvržení mřížky podporováno. Chcete-li použít podmíněné vykreslení, přepněte na automatickou mřížku.", + "learn-more": "", + "not-supported-for-custom-grid": "", "unsupported-object-type": "" }, "overlay": { @@ -6030,6 +6031,13 @@ "usage-count_many": "Použito na {{count}} nástěnkách", "usage-count_other": "Použito na {{count}} nástěnkách" }, + "managed-badge": { + "kubectl": "", + "plugin": "", + "provisioned": "", + "repository": "", + "terraform": "" + }, "move-provisioned-dashboard-form": { "api-error": "Nástěnku se nepodařilo přesunout", "cancel-action": "Zrušit", @@ -7677,7 +7685,6 @@ } }, "folder-filter": { - "clear-folder-button": "Vymazat složky", "noOptionsMessage-no-folders-found": "Nebyly nalezeny žádné složky", "select-aria-label": "Filtr složky", "select-placeholder": "Filtrovat podle složky" @@ -12780,6 +12787,7 @@ "theme-label": "Motiv rozhraní", "week-start-label": "Začátek týdne" }, + "save": "", "theme": { "default-label": "Výchozí", "experimental": "Experimentální" @@ -13183,13 +13191,13 @@ "placeholder-search-teams": "Hledat týmy" }, "team-settings": { - "description-email": "Toto je volitelné a používá se především k nastavení avatara profilu týmu (prostřednictvím služby Gravatar)", + "description-email": "", "label-email": "E-mail", "label-name": "Název", "label-numerical-identifier": "Číselný identifikátor", "label-role": "Role", "label-team-details": "Podrobnosti o týmu", - "save": "Uložit" + "save": "" }, "team-sync-upgrade-content": { "description": "Synchronizace týmu usnadňuje správu přístupu uživatelů v Grafaně tím, že okamžitě aktualizuje týmy a oprávnění každého uživatele Grafany na základě členství ve skupině jednotného přihlášení místo jednotlivého přihlášení uživatele" diff --git a/public/locales/de-DE/grafana.json b/public/locales/de-DE/grafana.json index cdcc5e5a0c8..38bb7627cff 100644 --- a/public/locales/de-DE/grafana.json +++ b/public/locales/de-DE/grafana.json @@ -4602,7 +4602,8 @@ }, "editor": { "info": "", - "not-supported-for-custom-grid": "Bedingtes Rendering wird für das benutzerdefinierte Rasterlayout nicht unterstützt. Wechseln Sie zum automatischen Raster, um bedingtes Rendering zu nutzen.", + "learn-more": "", + "not-supported-for-custom-grid": "", "unsupported-object-type": "" }, "overlay": { @@ -5986,6 +5987,13 @@ "usage-count_one": "Verwendet bei {{count}} Dashboards", "usage-count_other": "Verwendet bei {{count}} Dashboards" }, + "managed-badge": { + "kubectl": "", + "plugin": "", + "provisioned": "", + "repository": "", + "terraform": "" + }, "move-provisioned-dashboard-form": { "api-error": "Dashboard konnte nicht verschoben werden", "cancel-action": "Abbrechen", @@ -7631,7 +7639,6 @@ } }, "folder-filter": { - "clear-folder-button": "Ordner löschen", "noOptionsMessage-no-folders-found": "Keine Ordner gefunden", "select-aria-label": "Ordnerfilter", "select-placeholder": "Nach Ordner filtern" @@ -12672,6 +12679,7 @@ "theme-label": "UI-Design", "week-start-label": "Wochenbeginn" }, + "save": "", "theme": { "default-label": "Standard", "experimental": "Experimentell" @@ -13073,13 +13081,13 @@ "placeholder-search-teams": "Teams suchen" }, "team-settings": { - "description-email": "Dies ist optional und wird hauptsächlich zum Festlegen eines Teamprofil-Avatars genutzt (über den Gravatar-Dienst)", + "description-email": "", "label-email": "E-Mail-Adresse", "label-name": "Name", "label-numerical-identifier": "Numerischer Identifikator", "label-role": "Rolle", "label-team-details": "Angaben zum Team", - "save": "Speichern" + "save": "" }, "team-sync-upgrade-content": { "description": "Team Sync erleichtert Ihnen die Verwaltung des Nutzerzugriffs in Grafana, da die Grafana-Teams und die Berechtigungen jedes Nutzers sofort auf der Grundlage seiner Single-Sign-On-Gruppenmitgliedschaft aktualisiert werden, und nicht, wenn sich die Nutzer anmelden" diff --git a/public/locales/es-ES/grafana.json b/public/locales/es-ES/grafana.json index d1723b676a3..acd1c36de4b 100644 --- a/public/locales/es-ES/grafana.json +++ b/public/locales/es-ES/grafana.json @@ -4602,7 +4602,8 @@ }, "editor": { "info": "", - "not-supported-for-custom-grid": "La representación condicional no es compatible con el diseño de cuadrícula personalizado. Emplea la cuadrícula automática para poder usarla.", + "learn-more": "", + "not-supported-for-custom-grid": "", "unsupported-object-type": "" }, "overlay": { @@ -5986,6 +5987,13 @@ "usage-count_one": "Utilizado en {{count}} dashboards", "usage-count_other": "Utilizado en {{count}} dashboards" }, + "managed-badge": { + "kubectl": "", + "plugin": "", + "provisioned": "", + "repository": "", + "terraform": "" + }, "move-provisioned-dashboard-form": { "api-error": "No se ha podido mover el dashboard", "cancel-action": "Cancelar", @@ -7631,7 +7639,6 @@ } }, "folder-filter": { - "clear-folder-button": "Borrar carpetas", "noOptionsMessage-no-folders-found": "No se han encontrado carpetas", "select-aria-label": "Filtro de carpeta", "select-placeholder": "Filtrar por carpeta" @@ -12672,6 +12679,7 @@ "theme-label": "Tema de interfaz de usuario", "week-start-label": "Inicio de la semana" }, + "save": "", "theme": { "default-label": "Por defecto", "experimental": "Experimental" @@ -13073,13 +13081,13 @@ "placeholder-search-teams": "Buscar equipos" }, "team-settings": { - "description-email": "Esto es opcional y se utiliza principalmente para establecer el avatar del perfil del equipo (a través del servicio gravatar)", + "description-email": "", "label-email": "Correo electrónico", "label-name": "Nombre", "label-numerical-identifier": "Identificador numérico", "label-role": "Rol", "label-team-details": "Detalles del equipo", - "save": "Guardar" + "save": "" }, "team-sync-upgrade-content": { "description": "La sincronización de equipos facilita la gestión del acceso de los usuarios en Grafana, ya que actualiza inmediatamente los equipos y los permisos de Grafana de cada usuario en función de su pertenencia a un grupo de inicio de sesión único, en lugar de hacerlo cuando los usuarios inician sesión" diff --git a/public/locales/fr-FR/grafana.json b/public/locales/fr-FR/grafana.json index 8f21bf03463..c22cc0025e3 100644 --- a/public/locales/fr-FR/grafana.json +++ b/public/locales/fr-FR/grafana.json @@ -4602,7 +4602,8 @@ }, "editor": { "info": "", - "not-supported-for-custom-grid": "Le rendu conditionnel n’est pas pris en charge pour la grille personnalisée. Basculez vers la grille automatique pour l’utiliser.", + "learn-more": "", + "not-supported-for-custom-grid": "", "unsupported-object-type": "" }, "overlay": { @@ -5986,6 +5987,13 @@ "usage-count_one": "Utilisé sur {{count}} tableaux de bord", "usage-count_other": "Utilisé sur {{count}} tableaux de bord" }, + "managed-badge": { + "kubectl": "", + "plugin": "", + "provisioned": "", + "repository": "", + "terraform": "" + }, "move-provisioned-dashboard-form": { "api-error": "Échec du déplacement du tableau de bord", "cancel-action": "Annuler", @@ -7631,7 +7639,6 @@ } }, "folder-filter": { - "clear-folder-button": "Effacer les dossiers", "noOptionsMessage-no-folders-found": "Aucun dossier trouvé", "select-aria-label": "Filtre de dossier", "select-placeholder": "Filtrer par dossier" @@ -12672,6 +12679,7 @@ "theme-label": "Thème de l'interface utilisateur", "week-start-label": "Début de la semaine" }, + "save": "", "theme": { "default-label": "Par défaut", "experimental": "Expérimental" @@ -13073,13 +13081,13 @@ "placeholder-search-teams": "Rechercher les équipes" }, "team-settings": { - "description-email": "Ceci est facultatif et est principalement utilisé pour définir l’avatar du profil d’équipe (via le service gravatar)", + "description-email": "", "label-email": "Adresse e-mail", "label-name": "Nom", "label-numerical-identifier": "Identificateur numérique", "label-role": "Rôle", "label-team-details": "Détails de l’équipe", - "save": "Enregistrer" + "save": "" }, "team-sync-upgrade-content": { "description": "La synchronisation d’équipe vous permet de gérer plus facilement l’accès des utilisateurs à Grafana, en mettant immédiatement à jour les équipes et les autorisations Grafana de chaque utilisateur en fonction de leur appartenance à un groupe d’authentification unique, plutôt que lorsque les utilisateurs se connectent" diff --git a/public/locales/hu-HU/grafana.json b/public/locales/hu-HU/grafana.json index 12950e7f078..967656853b4 100644 --- a/public/locales/hu-HU/grafana.json +++ b/public/locales/hu-HU/grafana.json @@ -4602,7 +4602,8 @@ }, "editor": { "info": "", - "not-supported-for-custom-grid": "A feltételes ábrázolás nem támogatott az egyéni rácselrendezésnél. A feltételes ábrázolás használatához váltson automatikus rácsra.", + "learn-more": "", + "not-supported-for-custom-grid": "", "unsupported-object-type": "" }, "overlay": { @@ -5986,6 +5987,13 @@ "usage-count_one": "{{count}} irányítópulton használatos", "usage-count_other": "{{count}} irányítópulton használatos" }, + "managed-badge": { + "kubectl": "", + "plugin": "", + "provisioned": "", + "repository": "", + "terraform": "" + }, "move-provisioned-dashboard-form": { "api-error": "Nem sikerült áthelyezni az irányítópultot", "cancel-action": "Mégse", @@ -7631,7 +7639,6 @@ } }, "folder-filter": { - "clear-folder-button": "Mappák törlése", "noOptionsMessage-no-folders-found": "Nem található mappa", "select-aria-label": "Mappaszűrő", "select-placeholder": "Szűrés mappa alapján" @@ -12672,6 +12679,7 @@ "theme-label": "Felület témája", "week-start-label": "Hét kezdete" }, + "save": "", "theme": { "default-label": "Alapértelmezett", "experimental": "Kísérleti" @@ -13073,13 +13081,13 @@ "placeholder-search-teams": "Csapatok keresése" }, "team-settings": { - "description-email": "Ez nem kötelező, és elsősorban a csapatprofil avatárjának beállítására szolgál (a gravatar szolgáltatáson keresztül)", + "description-email": "", "label-email": "E-mail-cím", "label-name": "Név", "label-numerical-identifier": "Numerikus azonosító", "label-role": "Szerepkör", "label-team-details": "Csapat adatai", - "save": "Mentés" + "save": "" }, "team-sync-upgrade-content": { "description": "A csapatszinkronizálás megkönnyíti a felhasználói hozzáférés kezelését a Grafanában azáltal, hogy azonnal frissíti az egyes felhasználók Grafana-csapatait és engedélyeit az egyszeri bejelentkezési csoporttagságuk alapján, ahelyett, hogy a felhasználók bejelentkezésekor kerülne erre sor" diff --git a/public/locales/id-ID/grafana.json b/public/locales/id-ID/grafana.json index 2c2c84fcb5b..70e14895802 100644 --- a/public/locales/id-ID/grafana.json +++ b/public/locales/id-ID/grafana.json @@ -4582,7 +4582,8 @@ }, "editor": { "info": "", - "not-supported-for-custom-grid": "Rendering bersyarat tidak didukung untuk tata letak kisi khusus. Beralih ke kisi otomatis untuk menggunakan perenderan bersyarat.", + "learn-more": "", + "not-supported-for-custom-grid": "", "unsupported-object-type": "" }, "overlay": { @@ -5964,6 +5965,13 @@ "last-edited": "{{timeAgo}} oleh", "usage-count_other": "Digunakan pada {{count}} dasbor" }, + "managed-badge": { + "kubectl": "", + "plugin": "", + "provisioned": "", + "repository": "", + "terraform": "" + }, "move-provisioned-dashboard-form": { "api-error": "Gagal memindahkan dasbor", "cancel-action": "Batal", @@ -7608,7 +7616,6 @@ } }, "folder-filter": { - "clear-folder-button": "Hapus folder", "noOptionsMessage-no-folders-found": "Folder tidak ditemukan", "select-aria-label": "Filter folder", "select-placeholder": "Filter berdasarkan folder" @@ -12618,6 +12625,7 @@ "theme-label": "Tema antarmuka", "week-start-label": "Minggu mulai" }, + "save": "", "theme": { "default-label": "Default", "experimental": "Eksperimental" @@ -13018,13 +13026,13 @@ "placeholder-search-teams": "Cari tim" }, "team-settings": { - "description-email": "Hal ini opsional dan secara spesifik digunakan untuk mengatur avatar profil tim (melalui layanan gravatar)", + "description-email": "", "label-email": "Email", "label-name": "Nama", "label-numerical-identifier": "Pengidentifikasi numerik", "label-role": "Peran", "label-team-details": "Detail tim", - "save": "Simpan" + "save": "" }, "team-sync-upgrade-content": { "description": "Sinkronisasi Tim lebih memudahkan Anda mengelola akses pengguna di Grafana, dengan segera memperbarui tim dan izin Grafana setiap pengguna berdasarkan keanggotaan grup single sign-on mereka, alih-alih saat pengguna masuk" diff --git a/public/locales/it-IT/grafana.json b/public/locales/it-IT/grafana.json index 8b04d94a23c..ae7ad603e9e 100644 --- a/public/locales/it-IT/grafana.json +++ b/public/locales/it-IT/grafana.json @@ -4602,7 +4602,8 @@ }, "editor": { "info": "", - "not-supported-for-custom-grid": "Il rendering condizionale non è supportato per il layout della griglia personalizzata. Passa alla griglia automatica per utilizzare il rendering condizionale.", + "learn-more": "", + "not-supported-for-custom-grid": "", "unsupported-object-type": "" }, "overlay": { @@ -5986,6 +5987,13 @@ "usage-count_one": "Utilizzato su {{count}} dashboard", "usage-count_other": "Utilizzato su {{count}} dashboard" }, + "managed-badge": { + "kubectl": "", + "plugin": "", + "provisioned": "", + "repository": "", + "terraform": "" + }, "move-provisioned-dashboard-form": { "api-error": "Impossibile spostare la dashboard", "cancel-action": "Annulla", @@ -7631,7 +7639,6 @@ } }, "folder-filter": { - "clear-folder-button": "Cancella cartelle", "noOptionsMessage-no-folders-found": "Nessuna cartella trovata", "select-aria-label": "Filtro cartelle", "select-placeholder": "Filtra per cartella" @@ -12672,6 +12679,7 @@ "theme-label": "Tema dell'interfaccia", "week-start-label": "Inizio settimana" }, + "save": "", "theme": { "default-label": "Predefinito", "experimental": "Sperimentale" @@ -13073,13 +13081,13 @@ "placeholder-search-teams": "Cerca team" }, "team-settings": { - "description-email": "Questo è facoltativo e viene utilizzato principalmente per impostare l'avatar del profilo del team (tramite il servizio gravatar)", + "description-email": "", "label-email": "E-mail", "label-name": "Nome", "label-numerical-identifier": "Identificatore numerico", "label-role": "Ruolo", "label-team-details": "Dettagli team", - "save": "Salva" + "save": "" }, "team-sync-upgrade-content": { "description": "La sincronizzazione dei team semplifica la gestione degli accessi degli utenti in Grafana, aggiornando immediatamente i team e le autorizzazioni di ciascun utente in base alla sua appartenenza al gruppo Single Sign-On, anziché al momento dell'accesso" diff --git a/public/locales/ja-JP/grafana.json b/public/locales/ja-JP/grafana.json index 936c3627ac4..242dde381fc 100644 --- a/public/locales/ja-JP/grafana.json +++ b/public/locales/ja-JP/grafana.json @@ -4582,7 +4582,8 @@ }, "editor": { "info": "", - "not-supported-for-custom-grid": "カスタムグリッドレイアウトでは、条件付きレンダリングはサポートされていません。条件付きレンダリングを使用するには、自動グリッドに切り替えてください。", + "learn-more": "", + "not-supported-for-custom-grid": "", "unsupported-object-type": "" }, "overlay": { @@ -5964,6 +5965,13 @@ "last-edited": "が{{timeAgo}}に実施", "usage-count_other": "{{count}}件のダッシュボードで使用中" }, + "managed-badge": { + "kubectl": "", + "plugin": "", + "provisioned": "", + "repository": "", + "terraform": "" + }, "move-provisioned-dashboard-form": { "api-error": "ダッシュボードの移動に失敗しました", "cancel-action": "キャンセル", @@ -7608,7 +7616,6 @@ } }, "folder-filter": { - "clear-folder-button": "フォルダをクリア", "noOptionsMessage-no-folders-found": "フォルダが見つかりません", "select-aria-label": "フォルダフィルター", "select-placeholder": "フォルダでフィルタリング" @@ -12618,6 +12625,7 @@ "theme-label": "インターフェースのテーマ", "week-start-label": "週のはじまり" }, + "save": "", "theme": { "default-label": "初期設定", "experimental": "試験運用" @@ -13018,13 +13026,13 @@ "placeholder-search-teams": "チームを検索" }, "team-settings": { - "description-email": "これは任意であり、主にチームプロフィールのアバター設定(gravatar経由)に使用されます", + "description-email": "", "label-email": "メールアドレス", "label-name": "名前", "label-numerical-identifier": "数値ID", "label-role": "ロール", "label-team-details": "チーム詳細", - "save": "保存" + "save": "" }, "team-sync-upgrade-content": { "description": "チーム同期を使用すると、ユーザーがサインインした際ではなく、シングルサインオングループのメンバーシップに基づいて各ユーザーのGrafanaチームと権限がすぐに更新されるため、Grafanaでのユーザーアクセス管理が容易になります" diff --git a/public/locales/ko-KR/grafana.json b/public/locales/ko-KR/grafana.json index 35db45b924c..1818ac731f6 100644 --- a/public/locales/ko-KR/grafana.json +++ b/public/locales/ko-KR/grafana.json @@ -4582,7 +4582,8 @@ }, "editor": { "info": "", - "not-supported-for-custom-grid": "맞춤형 그리드 레이아웃에서는 조건부 렌더링이 지원되지 않습니다. 조건부 렌더링을 사용하려면 자동 그리드로 전환하세요.", + "learn-more": "", + "not-supported-for-custom-grid": "", "unsupported-object-type": "" }, "overlay": { @@ -5964,6 +5965,13 @@ "last-edited": " 님({{timeAgo}}에)", "usage-count_other": "{{count}}개의 대시보드에서 사용됨" }, + "managed-badge": { + "kubectl": "", + "plugin": "", + "provisioned": "", + "repository": "", + "terraform": "" + }, "move-provisioned-dashboard-form": { "api-error": "대시보드를 이동하지 못했습니다", "cancel-action": "취소", @@ -7608,7 +7616,6 @@ } }, "folder-filter": { - "clear-folder-button": "폴더 비우기", "noOptionsMessage-no-folders-found": "폴더를 찾을 수 없습니다", "select-aria-label": "폴더 필터", "select-placeholder": "폴더별로 필터링" @@ -12618,6 +12625,7 @@ "theme-label": "인터페이스 테마", "week-start-label": "주 시작 요일" }, + "save": "", "theme": { "default-label": "기본값", "experimental": "실험적 기능" @@ -13018,13 +13026,13 @@ "placeholder-search-teams": "팀 검색" }, "team-settings": { - "description-email": "이 항목은 선택 사항이며 주로 (gravatar 서비스를 통해) 팀 프로필 아바타를 설정하는 데 사용됩니다", + "description-email": "", "label-email": "이메일", "label-name": "이름", "label-numerical-identifier": "숫자 식별자", "label-role": "역할", "label-team-details": "팀 세부 정보", - "save": "저장" + "save": "" }, "team-sync-upgrade-content": { "description": "팀 동기화를 사용하면 사용자가 로그인할 때가 아니라 싱글 사인온 그룹에 속한 사용자인지 여부를 토대로 각 사용자의 Grafana 팀 및 권한을 즉시 업데이트하여 Grafana에서 사용자의 액세스를 보다 쉽게 관리할 수 있습니다" diff --git a/public/locales/nl-NL/grafana.json b/public/locales/nl-NL/grafana.json index b2c06f6e235..b1072873e9e 100644 --- a/public/locales/nl-NL/grafana.json +++ b/public/locales/nl-NL/grafana.json @@ -4602,7 +4602,8 @@ }, "editor": { "info": "", - "not-supported-for-custom-grid": "Voorwaardelijke weergave wordt niet ondersteund in de aangepaste rasterindeling. Schakel over naar auto grid om dit te gebruiken.", + "learn-more": "", + "not-supported-for-custom-grid": "", "unsupported-object-type": "" }, "overlay": { @@ -5986,6 +5987,13 @@ "usage-count_one": "Gebruikt op {{count}} dashboards", "usage-count_other": "Gebruikt op {{count}} dashboards" }, + "managed-badge": { + "kubectl": "", + "plugin": "", + "provisioned": "", + "repository": "", + "terraform": "" + }, "move-provisioned-dashboard-form": { "api-error": "Kan dashboard niet verplaatsen", "cancel-action": "Annuleren", @@ -7631,7 +7639,6 @@ } }, "folder-filter": { - "clear-folder-button": "Mappen wissen", "noOptionsMessage-no-folders-found": "Geen mappen gevonden", "select-aria-label": "Mapfilter", "select-placeholder": "Filteren op map" @@ -12672,6 +12679,7 @@ "theme-label": "Interfacethema", "week-start-label": "Begin van de week" }, + "save": "", "theme": { "default-label": "Standaard", "experimental": "Experimenteel" @@ -13073,13 +13081,13 @@ "placeholder-search-teams": "Teams zoeken" }, "team-settings": { - "description-email": "Dit is optioneel en wordt voornamelijk gebruikt voor het instellen van de teamprofielavatar (via gravatar-service)", + "description-email": "", "label-email": "E-mailadres", "label-name": "Naam", "label-numerical-identifier": "Numerieke id", "label-role": "Rol", "label-team-details": "Teamgegevens", - "save": "Opslaan" + "save": "" }, "team-sync-upgrade-content": { "description": "Teamsynchronisatie maakt het makkelijker voor je om de toegang van gebruikers in Grafana te beheren door onmiddellijk de Grafana-teams en toestemmingen van elke gebruiker bij te werken op basis van hun lidmaatschap van een single sign-on-groep, in plaats van wanneer gebruikers zich aanmelden" diff --git a/public/locales/pl-PL/grafana.json b/public/locales/pl-PL/grafana.json index e75ed6eab23..def81eec364 100644 --- a/public/locales/pl-PL/grafana.json +++ b/public/locales/pl-PL/grafana.json @@ -4642,7 +4642,8 @@ }, "editor": { "info": "", - "not-supported-for-custom-grid": "Renderowanie warunkowe nie jest obsługiwane w przypadku niestandardowego układu siatki. Przełącz na automatyczną siatkę, aby użyć renderowania warunkowego.", + "learn-more": "", + "not-supported-for-custom-grid": "", "unsupported-object-type": "" }, "overlay": { @@ -6030,6 +6031,13 @@ "usage-count_many": "Używane na {{count}} pulpitach", "usage-count_other": "Używane na {{count}} pulpitach" }, + "managed-badge": { + "kubectl": "", + "plugin": "", + "provisioned": "", + "repository": "", + "terraform": "" + }, "move-provisioned-dashboard-form": { "api-error": "Nie udało się przenieść pulpitu", "cancel-action": "Anuluj", @@ -7677,7 +7685,6 @@ } }, "folder-filter": { - "clear-folder-button": "Wyczyść foldery", "noOptionsMessage-no-folders-found": "Nie znaleziono folderów", "select-aria-label": "Filtr folderów", "select-placeholder": "Filtruj wg folderu" @@ -12780,6 +12787,7 @@ "theme-label": "Motyw interfejsu", "week-start-label": "Początek tygodnia" }, + "save": "", "theme": { "default-label": "Domyślny", "experimental": "Eksperymentalna" @@ -13183,13 +13191,13 @@ "placeholder-search-teams": "Szukaj zespołów" }, "team-settings": { - "description-email": "Jest to opcjonalne i służy przede wszystkim do ustawiania awatara profilu zespołu (za pośrednictwem usługi Gravatar)", + "description-email": "", "label-email": "E-mail", "label-name": "Nazwa", "label-numerical-identifier": "Identyfikator numeryczny", "label-role": "Rola", "label-team-details": "Szczegóły zespołu", - "save": "Zapisz" + "save": "" }, "team-sync-upgrade-content": { "description": "Synchronizacja zespołów ułatwia zarządzanie dostępem użytkowników w usłudze Grafana, natychmiast aktualizując zespoły i uprawnienia każdego użytkownika Grafany na podstawie członkostwa w grupie jednokrotnego logowania, a nie podczas logowania się użytkowników" diff --git a/public/locales/pt-BR/grafana.json b/public/locales/pt-BR/grafana.json index 9547a7095ec..2d8973c2893 100644 --- a/public/locales/pt-BR/grafana.json +++ b/public/locales/pt-BR/grafana.json @@ -4602,7 +4602,8 @@ }, "editor": { "info": "", - "not-supported-for-custom-grid": "A renderização condicional não é compatível com o layout de grade personalizado. Mude para a grade automática para poder usá-la.", + "learn-more": "", + "not-supported-for-custom-grid": "", "unsupported-object-type": "" }, "overlay": { @@ -5986,6 +5987,13 @@ "usage-count_one": "Usado em {{count}} painéis", "usage-count_other": "Usado em {{count}} painéis" }, + "managed-badge": { + "kubectl": "", + "plugin": "", + "provisioned": "", + "repository": "", + "terraform": "" + }, "move-provisioned-dashboard-form": { "api-error": "Falha ao mover o painel de controle", "cancel-action": "Cancelar", @@ -7631,7 +7639,6 @@ } }, "folder-filter": { - "clear-folder-button": "Limpar pastas", "noOptionsMessage-no-folders-found": "Nenhuma pasta encontrada", "select-aria-label": "Filtro de pasta", "select-placeholder": "Filtrar por pasta" @@ -12672,6 +12679,7 @@ "theme-label": "Tema da interface", "week-start-label": "Início da semana" }, + "save": "", "theme": { "default-label": "Padrão", "experimental": "Em testes" @@ -13073,13 +13081,13 @@ "placeholder-search-teams": "Pesquisar equipes" }, "team-settings": { - "description-email": "Isso é opcional e é usado principalmente para definir o avatar do perfil da equipe (através do serviço gravatar)", + "description-email": "", "label-email": "E-mail", "label-name": "Nome", "label-numerical-identifier": "Identificador numérico", "label-role": "Função", "label-team-details": "Detalhes da equipe", - "save": "Salvar" + "save": "" }, "team-sync-upgrade-content": { "description": "A sincronização de equipes facilita o gerenciamento do acesso dos usuários na Grafana, pois atualiza imediatamente as equipes e permissões da Grafana de cada usuário, considerando a associação do usuário ao grupo de autenticação única, em vez de considerar o momento em que os usuários iniciaram sessão" diff --git a/public/locales/pt-PT/grafana.json b/public/locales/pt-PT/grafana.json index b032052150b..e3a8efaaa5f 100644 --- a/public/locales/pt-PT/grafana.json +++ b/public/locales/pt-PT/grafana.json @@ -4602,7 +4602,8 @@ }, "editor": { "info": "", - "not-supported-for-custom-grid": "A renderização condicional não é suportada para o layout de grelha personalizado. Mude para a grelha automática para utilizar a renderização condicional.", + "learn-more": "", + "not-supported-for-custom-grid": "", "unsupported-object-type": "" }, "overlay": { @@ -5986,6 +5987,13 @@ "usage-count_one": "Utilizado em {{count}} painéis de controlo", "usage-count_other": "Utilizado em {{count}} painéis de controlo" }, + "managed-badge": { + "kubectl": "", + "plugin": "", + "provisioned": "", + "repository": "", + "terraform": "" + }, "move-provisioned-dashboard-form": { "api-error": "Não foi possível mover o painel de controlo", "cancel-action": "Cancelar", @@ -7631,7 +7639,6 @@ } }, "folder-filter": { - "clear-folder-button": "Limpar pastas", "noOptionsMessage-no-folders-found": "Nenhuma pasta encontrada", "select-aria-label": "Filtro de pastas", "select-placeholder": "Filtrar por pasta" @@ -12672,6 +12679,7 @@ "theme-label": "Tema da interface", "week-start-label": "Início da semana" }, + "save": "", "theme": { "default-label": "Predefinição", "experimental": "Experimental" @@ -13073,13 +13081,13 @@ "placeholder-search-teams": "Pesquisar equipas" }, "team-settings": { - "description-email": "Isto é opcional e é utilizado principalmente para definir o avatar do perfil da equipa (através do serviço gravatar)", + "description-email": "", "label-email": "E-mail", "label-name": "Nome", "label-numerical-identifier": "Identificador numérico", "label-role": "Função", "label-team-details": "Detalhes da equipa", - "save": "Guardar" + "save": "" }, "team-sync-upgrade-content": { "description": "A sincronização de equipas facilita a gestão do acesso dos utilizadores na Grafana, atualizando imediatamente as equipas e permissões Grafana de cada utilizador com base na sua afiliação de grupo de início de sessão único, em vez de quando os utilizadores iniciam sessão" diff --git a/public/locales/ru-RU/grafana.json b/public/locales/ru-RU/grafana.json index 92369c7c519..ded982bf9ca 100644 --- a/public/locales/ru-RU/grafana.json +++ b/public/locales/ru-RU/grafana.json @@ -4642,7 +4642,8 @@ }, "editor": { "info": "", - "not-supported-for-custom-grid": "При выборе пользовательского размещения сетки не поддерживается условный рендеринг. Чтобы воспользоваться функцией, переключитесь на автоматическую сетку.", + "learn-more": "", + "not-supported-for-custom-grid": "", "unsupported-object-type": "" }, "overlay": { @@ -6030,6 +6031,13 @@ "usage-count_many": "Используется на {{count}} дашбордах", "usage-count_other": "Используется на {{count}} дашбордах" }, + "managed-badge": { + "kubectl": "", + "plugin": "", + "provisioned": "", + "repository": "", + "terraform": "" + }, "move-provisioned-dashboard-form": { "api-error": "Не удалось переместить дашборд", "cancel-action": "Отмена", @@ -7677,7 +7685,6 @@ } }, "folder-filter": { - "clear-folder-button": "Очистить папки", "noOptionsMessage-no-folders-found": "Папки не найдены", "select-aria-label": "Фильтр папок", "select-placeholder": "Фильтровать по папкам" @@ -12780,6 +12787,7 @@ "theme-label": "Тема интерфейса", "week-start-label": "Начало недели" }, + "save": "", "theme": { "default-label": "По умолчанию", "experimental": "Экспериментальный" @@ -13183,13 +13191,13 @@ "placeholder-search-teams": "Поиск команд" }, "team-settings": { - "description-email": "Это необязательное действие, которое используется в основном для установки аватара профиля команды (с помощью сервиса Gravatar).", + "description-email": "", "label-email": "Адрес электронной почты", "label-name": "Имя", "label-numerical-identifier": "Числовой идентификатор", "label-role": "Роль", "label-team-details": "Сведения о команде", - "save": "Сохранить" + "save": "" }, "team-sync-upgrade-content": { "description": "Синхронизация команд упрощает управление доступом пользователей в Grafana, сразу обновляя команды Grafana и разрешения каждого пользователя на основе их участия в группе с единым входом, а не при входе пользователя в систему." diff --git a/public/locales/sv-SE/grafana.json b/public/locales/sv-SE/grafana.json index c8ac186753d..db4a9953f36 100644 --- a/public/locales/sv-SE/grafana.json +++ b/public/locales/sv-SE/grafana.json @@ -4602,7 +4602,8 @@ }, "editor": { "info": "", - "not-supported-for-custom-grid": "Villkorsstyrd rendering stöds inte för den anpassade rutnätslayouten. Byt till automatiskt rutnät om du vill använda villkorsstyrd rendering.", + "learn-more": "", + "not-supported-for-custom-grid": "", "unsupported-object-type": "" }, "overlay": { @@ -5986,6 +5987,13 @@ "usage-count_one": "Används på {{count}} instrumentpaneler", "usage-count_other": "Används på {{count}} instrumentpaneler" }, + "managed-badge": { + "kubectl": "", + "plugin": "", + "provisioned": "", + "repository": "", + "terraform": "" + }, "move-provisioned-dashboard-form": { "api-error": "Det gick inte att flytta kontrollpanelen", "cancel-action": "Avbryt", @@ -7631,7 +7639,6 @@ } }, "folder-filter": { - "clear-folder-button": "Rensa mappar", "noOptionsMessage-no-folders-found": "Inga mappar hittades", "select-aria-label": "Mappfilter", "select-placeholder": "Filtrera efter mapp" @@ -12672,6 +12679,7 @@ "theme-label": "Gränssnittstema", "week-start-label": "Veckostart" }, + "save": "", "theme": { "default-label": "Standard", "experimental": "Experimentellt" @@ -13073,13 +13081,13 @@ "placeholder-search-teams": "Sök team" }, "team-settings": { - "description-email": "Detta är valfritt och används främst för att ställa in teamprofilens avatar (via gravatartjänsten)", + "description-email": "", "label-email": "E-post", "label-name": "Namn", "label-numerical-identifier": "Numerisk identifierare", "label-role": "Roll", "label-team-details": "Teamdetaljer", - "save": "Spara" + "save": "" }, "team-sync-upgrade-content": { "description": "Team Sync gör det enklare att hantera användarnas åtkomst i Grafana genom att omedelbart uppdatera varje användares Grafana-team och behörigheter baserat på deras gruppmedlemskap med enkel inloggning, istället för när användare loggar in" diff --git a/public/locales/tr-TR/grafana.json b/public/locales/tr-TR/grafana.json index 77afeef9bfb..3aa30fa95c6 100644 --- a/public/locales/tr-TR/grafana.json +++ b/public/locales/tr-TR/grafana.json @@ -4602,6 +4602,7 @@ }, "editor": { "info": "", + "learn-more": "", "not-supported-for-custom-grid": "", "unsupported-object-type": "" }, @@ -5986,6 +5987,13 @@ "usage-count_one": "{{count}} panoda kullanılıyor", "usage-count_other": "{{count}} panoda kullanılıyor" }, + "managed-badge": { + "kubectl": "", + "plugin": "", + "provisioned": "", + "repository": "", + "terraform": "" + }, "move-provisioned-dashboard-form": { "api-error": "Pano taşınamadı", "cancel-action": "İptal et", @@ -7631,7 +7639,6 @@ } }, "folder-filter": { - "clear-folder-button": "Klasörleri temizle", "noOptionsMessage-no-folders-found": "Klasör bulunamadı", "select-aria-label": "Klasör filtresi", "select-placeholder": "Klasöre göre filtrele" @@ -12672,6 +12679,7 @@ "theme-label": "Arayüz teması", "week-start-label": "Hafta başlangıcı" }, + "save": "", "theme": { "default-label": "Varsayılan", "experimental": "Deneysel" @@ -13073,13 +13081,13 @@ "placeholder-search-teams": "Ekip ara" }, "team-settings": { - "description-email": "Bu isteğe bağlıdır ve öncelikle ekip profil avatarını (gravatar servisi aracılığıyla) ayarlamak için kullanılır", + "description-email": "", "label-email": "E-posta", "label-name": "Ad", "label-numerical-identifier": "Sayısal tanımlayıcı", "label-role": "Rol", "label-team-details": "Ekip bilgileri", - "save": "Kaydet" + "save": "" }, "team-sync-upgrade-content": { "description": "Ekip Senkronizasyonu, kullanıcıların Grafana üzerindeki erişimlerini yönetmeyi kolaylaştırır; kullanıcılar oturum açtığında değil, doğrudan SSO grup üyeliklerine göre Grafana ekipleri ve izinleri güncellenir" diff --git a/public/locales/zh-Hans/grafana.json b/public/locales/zh-Hans/grafana.json index d0973e0378b..b5f5f4a2e26 100644 --- a/public/locales/zh-Hans/grafana.json +++ b/public/locales/zh-Hans/grafana.json @@ -4582,7 +4582,8 @@ }, "editor": { "info": "", - "not-supported-for-custom-grid": "自定义网格布局不支持条件渲染。请切换到自动网格以使用条件渲染。", + "learn-more": "", + "not-supported-for-custom-grid": "", "unsupported-object-type": "" }, "overlay": { @@ -5964,6 +5965,13 @@ "last-edited": "{{timeAgo}}由 ", "usage-count_other": "用于 {{count}} 个数据面板" }, + "managed-badge": { + "kubectl": "", + "plugin": "", + "provisioned": "", + "repository": "", + "terraform": "" + }, "move-provisioned-dashboard-form": { "api-error": "移动数据面板失败", "cancel-action": "取消", @@ -7608,7 +7616,6 @@ } }, "folder-filter": { - "clear-folder-button": "清除文件夹", "noOptionsMessage-no-folders-found": "未找到文件夹", "select-aria-label": "文件夹筛选", "select-placeholder": "按文件夹筛选" @@ -12618,6 +12625,7 @@ "theme-label": "UI 主题", "week-start-label": "每周开始日" }, + "save": "", "theme": { "default-label": "默认", "experimental": "实验性" @@ -13018,13 +13026,13 @@ "placeholder-search-teams": "搜索团队" }, "team-settings": { - "description-email": "这是可选项,主要用于设置团队资料头像(通过 gravatar 服务)", + "description-email": "", "label-email": "电子邮箱", "label-name": "名称", "label-numerical-identifier": "数字标识符", "label-role": "角色", "label-team-details": "团队详情", - "save": "保存" + "save": "" }, "team-sync-upgrade-content": { "description": "团队同步可根据每个用户的单点登录组成员身份立即更新其 Grafana 团队和权限,而不是在用户登录时更新,从而让您更轻松地管理用户在 Grafana 中的访问权限" diff --git a/public/locales/zh-Hant/grafana.json b/public/locales/zh-Hant/grafana.json index 416ebc99cc5..37893071b08 100644 --- a/public/locales/zh-Hant/grafana.json +++ b/public/locales/zh-Hant/grafana.json @@ -4582,7 +4582,8 @@ }, "editor": { "info": "", - "not-supported-for-custom-grid": "自訂網格版面配置不支援條件轉譯。切換至自動網格以使用條件轉譯。", + "learn-more": "", + "not-supported-for-custom-grid": "", "unsupported-object-type": "" }, "overlay": { @@ -5964,6 +5965,13 @@ "last-edited": "在 {{timeAgo}}前", "usage-count_other": "用於 {{count}} 個儀表板" }, + "managed-badge": { + "kubectl": "", + "plugin": "", + "provisioned": "", + "repository": "", + "terraform": "" + }, "move-provisioned-dashboard-form": { "api-error": "無法移動儀表板", "cancel-action": "取消", @@ -7608,7 +7616,6 @@ } }, "folder-filter": { - "clear-folder-button": "清除資料夾", "noOptionsMessage-no-folders-found": "未找到資料夾", "select-aria-label": "資料夾篩選條件", "select-placeholder": "按資料夾篩選" @@ -12618,6 +12625,7 @@ "theme-label": "介面主題", "week-start-label": "一週哪一天開始" }, + "save": "", "theme": { "default-label": "預設值", "experimental": "實驗性" @@ -13018,13 +13026,13 @@ "placeholder-search-teams": "搜尋團隊" }, "team-settings": { - "description-email": "這是可選項目,主要用於設定團隊個人資料頭像(透過 gravatar 服務)", + "description-email": "", "label-email": "電子郵件", "label-name": "名稱", "label-numerical-identifier": "數字識別碼", "label-role": "角色", "label-team-details": "團隊詳細資料", - "save": "儲存" + "save": "" }, "team-sync-upgrade-content": { "description": "團隊同步可讓您更輕鬆地管理 Grafana 中的使用者存取權限,它可以根據每個使用者的單一登入群組成員資格,立即更新其 Grafana 團隊和權限,而不是在使用者登入時更新" From cc4a6cff6408f82f0ef649050f057688b4ae142a Mon Sep 17 00:00:00 2001 From: Kevin Minehart <5140827+kminehart@users.noreply.github.com> Date: Sat, 25 Oct 2025 16:50:04 +0200 Subject: [PATCH 012/378] CI: End process if e2e tests fail in daggerbuild (#113013) --- pkg/build/daggerbuild/e2e/validate_package.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/build/daggerbuild/e2e/validate_package.go b/pkg/build/daggerbuild/e2e/validate_package.go index 3bcc1c5f936..ce8f1e97026 100644 --- a/pkg/build/daggerbuild/e2e/validate_package.go +++ b/pkg/build/daggerbuild/e2e/validate_package.go @@ -15,5 +15,6 @@ func ValidatePackage(ctx context.Context, d *dagger.Client, service *dagger.Serv return c.WithServiceBinding("grafana", service). WithEnvVariable("GRAFANA_URL", "http://grafana:3000"). + WithEnvVariable("PW_TEST_HTML_REPORT_OPEN", "never"). WithExec([]string{"yarn", "e2e:acceptance"}), nil } From 6a15f40a855f006e3a8ec0b8d3be05673024c9ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=A4ggmark?= Date: Mon, 27 Oct 2025 05:48:31 +0100 Subject: [PATCH 013/378] Plugins: Remove plugin load failure logging for unauth users (#112940) --- .../features/plugins/pluginPreloader.test.ts | 81 ++++++++++++++++--- .../app/features/plugins/pluginPreloader.ts | 13 +-- .../features/plugins/pluginSettings.test.ts | 39 ++++++--- public/app/features/plugins/pluginSettings.ts | 2 +- 4 files changed, 110 insertions(+), 25 deletions(-) diff --git a/public/app/features/plugins/pluginPreloader.test.ts b/public/app/features/plugins/pluginPreloader.test.ts index 29aef9d46cc..9dc6d55fd4c 100644 --- a/public/app/features/plugins/pluginPreloader.test.ts +++ b/public/app/features/plugins/pluginPreloader.test.ts @@ -1,27 +1,21 @@ import { PluginLoadingStrategy, PluginType, + type AppPluginConfig, type PluginMeta, type PluginMetaInfo, type AngularMeta, type PluginDependencies, type PluginExtensions, AppPlugin, + OrgRole, } from '@grafana/data'; -import type { AppPluginConfig } from '@grafana/runtime'; +import { ContextSrv, setContextSrv } from 'app/core/services/context_srv'; import { getPluginSettings } from 'app/features/plugins/pluginSettings'; import { pluginImporter } from './importer/pluginImporter'; import { clearPreloadedPluginsCache, preloadPlugins } from './pluginPreloader'; -jest.mock('app/core/services/context_srv', () => ({ - contextSrv: { - user: { - orgRole: 'Admin', - }, - }, -})); - jest.mock('app/features/plugins/pluginSettings', () => ({ getPluginSettings: jest.fn(), })); @@ -81,6 +75,9 @@ const createMockPluginMeta = (overrides: Partial = {}): PluginMeta = describe('pluginPreloader', () => { beforeEach(() => { + const contextSrv = new ContextSrv(); + contextSrv.user.orgRole = OrgRole.Admin; + setContextSrv(contextSrv); jest.clearAllMocks(); jest.resetModules(); clearPreloadedPluginsCache(); @@ -272,5 +269,71 @@ describe('pluginPreloader', () => { expect(getPluginSettingsMock).toHaveBeenCalledTimes(2); expect(importAppPluginMock).toHaveBeenCalledTimes(2); }); + + it('should have showErrorAlert set to false for user with no role', async () => { + const contextSrv = new ContextSrv(); + contextSrv.user.orgRole = ''; + setContextSrv(contextSrv); + + const appConfig = createMockAppPluginConfig({ + id: 'test-plugin', + path: '/path/to/plugin', + version: '1.0.0', + }); + + const mockPluginMeta = createMockPluginMeta({ + id: 'test-plugin', + name: 'Test Plugin', + type: PluginType.app, + }); + + getPluginSettingsMock.mockResolvedValue(mockPluginMeta); + importAppPluginMock.mockResolvedValue(new AppPlugin()); + + await preloadPlugins([appConfig]); + + expect(getPluginSettingsMock).toHaveBeenCalledWith('test-plugin', { + showErrorAlert: false, + }); + expect(importAppPluginMock).toHaveBeenCalledWith(mockPluginMeta); + }); + + it('should log all errors for user with role', async () => { + const consoleSpy = jest.spyOn(console, 'error').mockImplementation(() => {}); + const appConfig = createMockAppPluginConfig({ + id: 'test-plugin', + path: '/path/to/plugin', + version: '1.0.0', + }); + const error = { status: 401, message: 'Unauthorized' }; + + getPluginSettingsMock.mockRejectedValue(error); + + await preloadPlugins([appConfig]); + + expect(consoleSpy).toHaveBeenCalledWith( + `[Plugins] Failed to preload plugin: /path/to/plugin (version: 1.0.0)`, + error + ); + }); + + it('should not log any errors for user without role', async () => { + const contextSrv = new ContextSrv(); + contextSrv.user.orgRole = ''; + setContextSrv(contextSrv); + const consoleSpy = jest.spyOn(console, 'error').mockImplementation(() => {}); + const appConfig = createMockAppPluginConfig({ + id: 'test-plugin', + path: '/path/to/plugin', + version: '1.0.0', + }); + const error = { status: 401, message: 'Unauthorized' }; + + getPluginSettingsMock.mockRejectedValue(error); + + await preloadPlugins([appConfig]); + + expect(consoleSpy).not.toHaveBeenCalled(); + }); }); }); diff --git a/public/app/features/plugins/pluginPreloader.ts b/public/app/features/plugins/pluginPreloader.ts index 938d42458dc..85b7d262a9e 100644 --- a/public/app/features/plugins/pluginPreloader.ts +++ b/public/app/features/plugins/pluginPreloader.ts @@ -1,9 +1,9 @@ import type { + AppPluginConfig, PluginExtensionAddedLinkConfig, PluginExtensionExposedComponentConfig, PluginExtensionAddedComponentConfig, } from '@grafana/data'; -import type { AppPluginConfig } from '@grafana/runtime'; import { contextSrv } from 'app/core/services/context_srv'; import { getPluginSettings } from 'app/features/plugins/pluginSettings'; @@ -36,13 +36,16 @@ export async function preloadPlugins(apps: AppPluginConfig[] = []) { } async function preload(config: AppPluginConfig): Promise { - try { - const meta = await getPluginSettings(config.id, { - showErrorAlert: contextSrv.user.orgRole !== '', - }); + const showErrorAlert = contextSrv.user.orgRole !== ''; + try { + const meta = await getPluginSettings(config.id, { showErrorAlert }); await pluginImporter.importApp(meta); } catch (error) { + if (!showErrorAlert) { + return; + } + console.error(`[Plugins] Failed to preload plugin: ${config.path} (version: ${config.version})`, error); } } diff --git a/public/app/features/plugins/pluginSettings.test.ts b/public/app/features/plugins/pluginSettings.test.ts index 02c16af039b..86e09a5d10a 100644 --- a/public/app/features/plugins/pluginSettings.test.ts +++ b/public/app/features/plugins/pluginSettings.test.ts @@ -22,8 +22,8 @@ describe('PluginSettings', () => { id: 'test-plugin', enabled: true, }; - getBackendSrv().get = jest.fn().mockResolvedValue(testPluginResponse); - const getRequestSpy = jest.spyOn(getBackendSrv(), 'get'); + + const getRequestSpy = jest.spyOn(getBackendSrv(), 'get').mockResolvedValue(testPluginResponse); // act const response = await getPluginSettings('test'); // assert @@ -42,8 +42,7 @@ describe('PluginSettings', () => { id: 'test-plugin', enabled: true, }; - getBackendSrv().get = jest.fn().mockResolvedValue(testPluginResponse); - const getRequestSpy = jest.spyOn(getBackendSrv(), 'get'); + const getRequestSpy = jest.spyOn(getBackendSrv(), 'get').mockResolvedValue(testPluginResponse); // act const response1 = await getPluginSettings('test'); const response2 = await getPluginSettings('test'); @@ -62,8 +61,8 @@ describe('PluginSettings', () => { id: 'test-plugin', enabled: true, }; - getBackendSrv().get = jest.fn().mockResolvedValue(testPluginResponse); - const getRequestSpy = jest.spyOn(getBackendSrv(), 'get'); + + const getRequestSpy = jest.spyOn(getBackendSrv(), 'get').mockResolvedValue(testPluginResponse); // act const response1 = await getPluginSettings('test'); @@ -83,8 +82,7 @@ describe('PluginSettings', () => { id: 'test-plugin', enabled: true, }; - getBackendSrv().get = jest.fn().mockResolvedValue(testPluginResponse); - const getRequestSpy = jest.spyOn(getBackendSrv(), 'get'); + const getRequestSpy = jest.spyOn(getBackendSrv(), 'get').mockResolvedValue(testPluginResponse); // act const response1 = await getPluginSettings('test'); await clearPluginSettingsCache('another-test'); @@ -103,8 +101,8 @@ describe('PluginSettings', () => { id: 'test-plugin', enabled: true, }; - getBackendSrv().get = jest.fn().mockResolvedValue(testPluginResponse); - const getRequestSpy = jest.spyOn(getBackendSrv(), 'get'); + + const getRequestSpy = jest.spyOn(getBackendSrv(), 'get').mockResolvedValue(testPluginResponse); // act const response1 = await getPluginSettings('test'); @@ -116,4 +114,25 @@ describe('PluginSettings', () => { expect(response2).toEqual(testPluginResponse); expect(getRequestSpy).toHaveBeenCalledTimes(2); }); + + it('should reject with Unknown Plugin message if error status is not 403 or 401', async () => { + const error = { status: 404, message: 'Not found' }; + jest.spyOn(getBackendSrv(), 'get').mockRejectedValue(error); + + await expect(getPluginSettings('test')).rejects.toEqual(new Error('Unknown Plugin')); + }); + + it('should reject thrown error if error status is 403', async () => { + const error = { status: 403, message: 'Forbidden' }; + jest.spyOn(getBackendSrv(), 'get').mockRejectedValue(error); + + await expect(getPluginSettings('test')).rejects.toEqual({ ...error, isHandled: true }); + }); + + it('should reject thrown error if error status is 401', async () => { + const error = { status: 401, message: 'Unauthorized' }; + jest.spyOn(getBackendSrv(), 'get').mockRejectedValue(error); + + await expect(getPluginSettings('test')).rejects.toEqual({ ...error, isHandled: true }); + }); }); diff --git a/public/app/features/plugins/pluginSettings.ts b/public/app/features/plugins/pluginSettings.ts index 1865df5b914..9bc9d4c9606 100644 --- a/public/app/features/plugins/pluginSettings.ts +++ b/public/app/features/plugins/pluginSettings.ts @@ -20,7 +20,7 @@ export function getPluginSettings(pluginId: string, options?: Partial { // User does not have access to plugin - if (typeof e === 'object' && e !== null && 'status' in e && e.status === 403) { + if (typeof e === 'object' && e !== null && 'status' in e && (e.status === 403 || e.status === 401)) { e.isHandled = true; return Promise.reject(e); } From 5df4a3b9a39f41ef913ec098f2f32318a629ac94 Mon Sep 17 00:00:00 2001 From: Ryan McKinley Date: Mon, 27 Oct 2025 09:34:26 +0300 Subject: [PATCH 014/378] Chore: Update app-sdk to v0.48.1 (#113023) --- apps/alerting/alertenrichment/go.mod | 4 +-- apps/alerting/alertenrichment/go.sum | 8 ++--- apps/alerting/notifications/go.mod | 10 +++--- apps/alerting/notifications/go.sum | 28 +++++++-------- apps/alerting/rules/go.mod | 10 +++--- apps/alerting/rules/go.sum | 24 ++++++------- apps/correlations/go.mod | 10 +++--- apps/correlations/go.sum | 24 ++++++------- apps/dashboard/go.mod | 18 +++++----- apps/dashboard/go.sum | 36 +++++++++---------- .../dashboard/v2alpha1/dashboard_spec_gen.go | 8 +++-- .../dashboard/v2beta1/dashboard_spec_gen.go | 8 +++-- apps/folder/go.mod | 10 +++--- apps/folder/go.sum | 20 +++++------ apps/iam/go.mod | 18 +++++----- apps/iam/go.sum | 36 +++++++++---------- apps/investigations/go.mod | 10 +++--- apps/investigations/go.sum | 24 ++++++------- apps/logsdrilldown/go.mod | 10 +++--- apps/logsdrilldown/go.sum | 24 ++++++------- apps/playlist/go.mod | 10 +++--- apps/playlist/go.sum | 24 ++++++------- apps/plugins/go.mod | 12 +++---- apps/plugins/go.sum | 28 +++++++-------- apps/preferences/go.mod | 10 +++--- apps/preferences/go.sum | 20 +++++------ apps/provisioning/go.mod | 12 +++---- apps/provisioning/go.sum | 28 +++++++-------- apps/scope/go.mod | 2 +- apps/scope/go.sum | 4 +-- apps/sdk.mk | 2 +- apps/secret/go.mod | 10 +++--- apps/secret/go.sum | 20 +++++------ apps/shorturl/go.mod | 12 +++---- apps/shorturl/go.sum | 28 +++++++-------- go.mod | 18 +++++----- go.sum | 36 +++++++++---------- go.work.sum | 10 ++++++ pkg/aggregator/go.mod | 14 ++++---- pkg/aggregator/go.sum | 28 +++++++-------- pkg/apimachinery/go.mod | 4 +-- pkg/apimachinery/go.sum | 8 ++--- pkg/apiserver/go.mod | 11 +++--- pkg/apiserver/go.sum | 24 ++++++------- pkg/build/go.mod | 2 +- pkg/build/go.sum | 4 +-- pkg/build/wire/go.mod | 4 +-- pkg/build/wire/go.sum | 8 ++--- pkg/codegen/go.mod | 8 ++--- pkg/codegen/go.sum | 16 ++++----- pkg/kinds/dashboard/dashboard_spec_gen.go | 3 +- pkg/plugins/codegen/go.mod | 8 ++--- pkg/plugins/codegen/go.sum | 20 +++++------ pkg/promlib/go.mod | 10 +++--- pkg/promlib/go.sum | 24 ++++++------- 55 files changed, 419 insertions(+), 403 deletions(-) diff --git a/apps/alerting/alertenrichment/go.mod b/apps/alerting/alertenrichment/go.mod index 008fa603189..efab71e825e 100644 --- a/apps/alerting/alertenrichment/go.mod +++ b/apps/alerting/alertenrichment/go.mod @@ -3,7 +3,7 @@ module github.com/grafana/grafana/apps/alerting/alertenrichment go 1.25.3 require ( - github.com/grafana/grafana-app-sdk v0.47.0 + github.com/grafana/grafana-app-sdk v0.48.1 github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250901080157-a0280d701b28 k8s.io/apimachinery v0.34.1 k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 @@ -27,7 +27,7 @@ require ( github.com/x448/float16 v0.8.4 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/net v0.45.0 // indirect + golang.org/x/net v0.46.0 // indirect golang.org/x/text v0.30.0 // indirect google.golang.org/protobuf v1.36.10 // indirect gopkg.in/inf.v0 v0.9.1 // indirect diff --git a/apps/alerting/alertenrichment/go.sum b/apps/alerting/alertenrichment/go.sum index 16227da2710..2d95fb4b1a2 100644 --- a/apps/alerting/alertenrichment/go.sum +++ b/apps/alerting/alertenrichment/go.sum @@ -23,8 +23,8 @@ github.com/google/gnostic-models v0.7.0/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7O github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/grafana/grafana-app-sdk v0.47.0 h1:zTKV+p6zM9y+In+dAcaHczbJJsQj9WKglSBcQXMOA+8= -github.com/grafana/grafana-app-sdk v0.47.0/go.mod h1:kywXmkppq0oReUMzkjTW8Fq2EBzyN7v914jttTWnWxA= +github.com/grafana/grafana-app-sdk v0.48.1 h1:bKJadWH18WCpJ+Zk8AezRFXCcZgGredRv+fRS+8zkek= +github.com/grafana/grafana-app-sdk v0.48.1/go.mod h1:5LljCz+wvmGfkQ8ZKTOfserhtXNEF0cSFthoWShvN6c= github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250901080157-a0280d701b28 h1:PgMfX4OPENz/iXmtDDIW9+poZY4UD0hhmXm7flVclDo= github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250901080157-a0280d701b28/go.mod h1:av5N0Naq+8VV9MLF7zAkihy/mVq5UbS2EvRSJukDHlY= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= @@ -73,8 +73,8 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.45.0 h1:RLBg5JKixCy82FtLJpeNlVM0nrSqpCRYzVU1n8kj0tM= -golang.org/x/net v0.45.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY= +golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4= +golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= diff --git a/apps/alerting/notifications/go.mod b/apps/alerting/notifications/go.mod index 91c7b67b93b..b4dfcef1c01 100644 --- a/apps/alerting/notifications/go.mod +++ b/apps/alerting/notifications/go.mod @@ -3,8 +3,8 @@ module github.com/grafana/grafana/apps/alerting/notifications go 1.25.3 require ( - github.com/grafana/grafana-app-sdk v0.47.0 - github.com/grafana/grafana-app-sdk/logging v0.46.0 + github.com/grafana/grafana-app-sdk v0.48.1 + github.com/grafana/grafana-app-sdk/logging v0.48.1 k8s.io/apimachinery v0.34.1 k8s.io/apiserver v0.34.1 k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 @@ -84,13 +84,13 @@ require ( go.uber.org/zap v1.27.0 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/net v0.45.0 // indirect + golang.org/x/net v0.46.0 // indirect golang.org/x/oauth2 v0.32.0 // indirect golang.org/x/sync v0.17.0 // indirect golang.org/x/sys v0.37.0 // indirect - golang.org/x/term v0.35.0 // indirect + golang.org/x/term v0.36.0 // indirect golang.org/x/text v0.30.0 // indirect - golang.org/x/time v0.13.0 // indirect + golang.org/x/time v0.14.0 // indirect gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250908214217-97024824d090 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20251002232023-7c0ddcbb5797 // indirect diff --git a/apps/alerting/notifications/go.sum b/apps/alerting/notifications/go.sum index 620e474799c..c8c9f53e5ef 100644 --- a/apps/alerting/notifications/go.sum +++ b/apps/alerting/notifications/go.sum @@ -71,10 +71,10 @@ 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.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo= github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA= -github.com/grafana/grafana-app-sdk v0.47.0 h1:zTKV+p6zM9y+In+dAcaHczbJJsQj9WKglSBcQXMOA+8= -github.com/grafana/grafana-app-sdk v0.47.0/go.mod h1:kywXmkppq0oReUMzkjTW8Fq2EBzyN7v914jttTWnWxA= -github.com/grafana/grafana-app-sdk/logging v0.46.0 h1:JhQ+ZK5orcmM+dZ3YZdT9uCizJEFU2I6JBNUSFWvCC8= -github.com/grafana/grafana-app-sdk/logging v0.46.0/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA= +github.com/grafana/grafana-app-sdk v0.48.1 h1:bKJadWH18WCpJ+Zk8AezRFXCcZgGredRv+fRS+8zkek= +github.com/grafana/grafana-app-sdk v0.48.1/go.mod h1:5LljCz+wvmGfkQ8ZKTOfserhtXNEF0cSFthoWShvN6c= +github.com/grafana/grafana-app-sdk/logging v0.48.1 h1:veM0X5LAPyN3KsDLglWjIofndbGuf7MqnrDuDN+F/Ng= +github.com/grafana/grafana-app-sdk/logging v0.48.1/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA= github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0 h1:QGLs/O40yoNK9vmy4rhUGBVyMf1lISBGtXRpsu/Qu/o= github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0/go.mod h1:hM2alZsMUni80N33RBe6J0e423LB+odMj7d3EMP9l20= github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.2 h1:sGm2vDRFUrQJO/Veii4h4zG2vvqG6uWNkBHSTqXOZk0= @@ -224,8 +224,8 @@ go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= 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/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI= -golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8= +golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04= +golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= @@ -236,8 +236,8 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.45.0 h1:RLBg5JKixCy82FtLJpeNlVM0nrSqpCRYzVU1n8kj0tM= -golang.org/x/net v0.45.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY= +golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4= +golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.32.0 h1:jsCblLleRMDrxMN29H3z/k1KliIvpLgCkE6R8FXXNgY= golang.org/x/oauth2 v0.32.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= @@ -254,21 +254,21 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/term v0.35.0 h1:bZBVKBudEyhRcajGcNc3jIfWPqV4y/Kt2XcoigOWtDQ= -golang.org/x/term v0.35.0/go.mod h1:TPGtkTLesOwf2DE8CgVYiZinHAOuy5AYUYT1lENIZnA= +golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q= +golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k= golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= -golang.org/x/time v0.13.0 h1:eUlYslOIt32DgYD6utsuUeHs4d7AsEYLuIAdg7FlYgI= -golang.org/x/time v0.13.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= +golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= +golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 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.37.0 h1:DVSRzp7FwePZW356yEAChSdNcQo6Nsp+fex1SUW09lE= -golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w= +golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ= +golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs= 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= diff --git a/apps/alerting/rules/go.mod b/apps/alerting/rules/go.mod index d148f4a9c87..f10d66be03f 100644 --- a/apps/alerting/rules/go.mod +++ b/apps/alerting/rules/go.mod @@ -3,8 +3,8 @@ module github.com/grafana/grafana/apps/alerting/rules go 1.25.3 require ( - github.com/grafana/grafana-app-sdk v0.47.0 - github.com/grafana/grafana-app-sdk/logging v0.46.0 + github.com/grafana/grafana-app-sdk v0.48.1 + github.com/grafana/grafana-app-sdk/logging v0.48.1 k8s.io/apimachinery v0.34.1 k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 ) @@ -67,13 +67,13 @@ require ( go.opentelemetry.io/proto/otlp v1.7.1 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/net v0.45.0 // indirect + golang.org/x/net v0.46.0 // indirect golang.org/x/oauth2 v0.32.0 // indirect golang.org/x/sync v0.17.0 // indirect golang.org/x/sys v0.37.0 // indirect - golang.org/x/term v0.35.0 // indirect + golang.org/x/term v0.36.0 // indirect golang.org/x/text v0.30.0 // indirect - golang.org/x/time v0.13.0 // indirect + golang.org/x/time v0.14.0 // indirect gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250908214217-97024824d090 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20251002232023-7c0ddcbb5797 // indirect diff --git a/apps/alerting/rules/go.sum b/apps/alerting/rules/go.sum index fe5ba699151..a0e59cd5731 100644 --- a/apps/alerting/rules/go.sum +++ b/apps/alerting/rules/go.sum @@ -48,10 +48,10 @@ github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 h1:BHT72Gu3keYf3ZEu2J github.com/google/pprof v0.0.0-20250403155104-27863c87afa6/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= 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/grafana/grafana-app-sdk v0.47.0 h1:zTKV+p6zM9y+In+dAcaHczbJJsQj9WKglSBcQXMOA+8= -github.com/grafana/grafana-app-sdk v0.47.0/go.mod h1:kywXmkppq0oReUMzkjTW8Fq2EBzyN7v914jttTWnWxA= -github.com/grafana/grafana-app-sdk/logging v0.46.0 h1:JhQ+ZK5orcmM+dZ3YZdT9uCizJEFU2I6JBNUSFWvCC8= -github.com/grafana/grafana-app-sdk/logging v0.46.0/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA= +github.com/grafana/grafana-app-sdk v0.48.1 h1:bKJadWH18WCpJ+Zk8AezRFXCcZgGredRv+fRS+8zkek= +github.com/grafana/grafana-app-sdk v0.48.1/go.mod h1:5LljCz+wvmGfkQ8ZKTOfserhtXNEF0cSFthoWShvN6c= +github.com/grafana/grafana-app-sdk/logging v0.48.1 h1:veM0X5LAPyN3KsDLglWjIofndbGuf7MqnrDuDN+F/Ng= +github.com/grafana/grafana-app-sdk/logging v0.48.1/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 h1:8Tjv8EJ+pM1xP8mK6egEbD1OgnVTyacbefKhmbLhIhU= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2/go.mod h1:pkJQ2tZHJ0aFOVEEot6oZmaVEZcRme73eIFmhiVuRWs= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -163,8 +163,8 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.45.0 h1:RLBg5JKixCy82FtLJpeNlVM0nrSqpCRYzVU1n8kj0tM= -golang.org/x/net v0.45.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY= +golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4= +golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= golang.org/x/oauth2 v0.32.0 h1:jsCblLleRMDrxMN29H3z/k1KliIvpLgCkE6R8FXXNgY= golang.org/x/oauth2 v0.32.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -177,20 +177,20 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/term v0.35.0 h1:bZBVKBudEyhRcajGcNc3jIfWPqV4y/Kt2XcoigOWtDQ= -golang.org/x/term v0.35.0/go.mod h1:TPGtkTLesOwf2DE8CgVYiZinHAOuy5AYUYT1lENIZnA= +golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q= +golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k= golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= -golang.org/x/time v0.13.0 h1:eUlYslOIt32DgYD6utsuUeHs4d7AsEYLuIAdg7FlYgI= -golang.org/x/time v0.13.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= +golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= +golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 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.37.0 h1:DVSRzp7FwePZW356yEAChSdNcQo6Nsp+fex1SUW09lE= -golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w= +golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ= +golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs= 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= diff --git a/apps/correlations/go.mod b/apps/correlations/go.mod index a8dc35dec8f..c9c1e623da6 100644 --- a/apps/correlations/go.mod +++ b/apps/correlations/go.mod @@ -3,8 +3,8 @@ module github.com/grafana/grafana/apps/correlations go 1.25.3 require ( - github.com/grafana/grafana-app-sdk v0.47.0 - github.com/grafana/grafana-app-sdk/logging v0.46.0 + github.com/grafana/grafana-app-sdk v0.48.1 + github.com/grafana/grafana-app-sdk/logging v0.48.1 k8s.io/apimachinery v0.34.1 k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 ) @@ -67,13 +67,13 @@ require ( go.opentelemetry.io/proto/otlp v1.7.1 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/net v0.45.0 // indirect + golang.org/x/net v0.46.0 // indirect golang.org/x/oauth2 v0.32.0 // indirect golang.org/x/sync v0.17.0 // indirect golang.org/x/sys v0.37.0 // indirect - golang.org/x/term v0.35.0 // indirect + golang.org/x/term v0.36.0 // indirect golang.org/x/text v0.30.0 // indirect - golang.org/x/time v0.13.0 // indirect + golang.org/x/time v0.14.0 // indirect gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250908214217-97024824d090 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20251002232023-7c0ddcbb5797 // indirect diff --git a/apps/correlations/go.sum b/apps/correlations/go.sum index fe5ba699151..a0e59cd5731 100644 --- a/apps/correlations/go.sum +++ b/apps/correlations/go.sum @@ -48,10 +48,10 @@ github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 h1:BHT72Gu3keYf3ZEu2J github.com/google/pprof v0.0.0-20250403155104-27863c87afa6/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= 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/grafana/grafana-app-sdk v0.47.0 h1:zTKV+p6zM9y+In+dAcaHczbJJsQj9WKglSBcQXMOA+8= -github.com/grafana/grafana-app-sdk v0.47.0/go.mod h1:kywXmkppq0oReUMzkjTW8Fq2EBzyN7v914jttTWnWxA= -github.com/grafana/grafana-app-sdk/logging v0.46.0 h1:JhQ+ZK5orcmM+dZ3YZdT9uCizJEFU2I6JBNUSFWvCC8= -github.com/grafana/grafana-app-sdk/logging v0.46.0/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA= +github.com/grafana/grafana-app-sdk v0.48.1 h1:bKJadWH18WCpJ+Zk8AezRFXCcZgGredRv+fRS+8zkek= +github.com/grafana/grafana-app-sdk v0.48.1/go.mod h1:5LljCz+wvmGfkQ8ZKTOfserhtXNEF0cSFthoWShvN6c= +github.com/grafana/grafana-app-sdk/logging v0.48.1 h1:veM0X5LAPyN3KsDLglWjIofndbGuf7MqnrDuDN+F/Ng= +github.com/grafana/grafana-app-sdk/logging v0.48.1/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 h1:8Tjv8EJ+pM1xP8mK6egEbD1OgnVTyacbefKhmbLhIhU= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2/go.mod h1:pkJQ2tZHJ0aFOVEEot6oZmaVEZcRme73eIFmhiVuRWs= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -163,8 +163,8 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.45.0 h1:RLBg5JKixCy82FtLJpeNlVM0nrSqpCRYzVU1n8kj0tM= -golang.org/x/net v0.45.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY= +golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4= +golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= golang.org/x/oauth2 v0.32.0 h1:jsCblLleRMDrxMN29H3z/k1KliIvpLgCkE6R8FXXNgY= golang.org/x/oauth2 v0.32.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -177,20 +177,20 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/term v0.35.0 h1:bZBVKBudEyhRcajGcNc3jIfWPqV4y/Kt2XcoigOWtDQ= -golang.org/x/term v0.35.0/go.mod h1:TPGtkTLesOwf2DE8CgVYiZinHAOuy5AYUYT1lENIZnA= +golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q= +golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k= golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= -golang.org/x/time v0.13.0 h1:eUlYslOIt32DgYD6utsuUeHs4d7AsEYLuIAdg7FlYgI= -golang.org/x/time v0.13.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= +golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= +golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 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.37.0 h1:DVSRzp7FwePZW356yEAChSdNcQo6Nsp+fex1SUW09lE= -golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w= +golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ= +golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs= 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= diff --git a/apps/dashboard/go.mod b/apps/dashboard/go.mod index a1025296b08..de0bc8b4614 100644 --- a/apps/dashboard/go.mod +++ b/apps/dashboard/go.mod @@ -5,13 +5,13 @@ go 1.25.3 require ( cuelang.org/go v0.11.1 github.com/grafana/authlib/types v0.0.0-20250926065801-df98203cff37 - github.com/grafana/grafana-app-sdk v0.47.0 - github.com/grafana/grafana-app-sdk/logging v0.46.0 + github.com/grafana/grafana-app-sdk v0.48.1 + github.com/grafana/grafana-app-sdk/logging v0.48.1 github.com/grafana/grafana-plugin-sdk-go v0.281.0 github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250514132646-acbc7b54ed9e github.com/prometheus/client_golang v1.23.2 github.com/stretchr/testify v1.11.1 - golang.org/x/net v0.45.0 + golang.org/x/net v0.46.0 k8s.io/apimachinery v0.34.1 k8s.io/apiserver v0.34.1 k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 @@ -107,17 +107,17 @@ require ( go.opentelemetry.io/proto/otlp v1.7.1 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/crypto v0.42.0 // indirect + golang.org/x/crypto v0.43.0 // indirect golang.org/x/exp v0.0.0-20251002181428-27f1f14c8bb9 // indirect - golang.org/x/mod v0.28.0 // indirect + golang.org/x/mod v0.29.0 // indirect golang.org/x/oauth2 v0.32.0 // indirect golang.org/x/sync v0.17.0 // indirect golang.org/x/sys v0.37.0 // indirect - golang.org/x/telemetry v0.0.0-20250908211612-aef8a434d053 // indirect - golang.org/x/term v0.35.0 // indirect + golang.org/x/telemetry v0.0.0-20251008203120-078029d740a8 // indirect + golang.org/x/term v0.36.0 // indirect golang.org/x/text v0.30.0 // indirect - golang.org/x/time v0.13.0 // indirect - golang.org/x/tools v0.37.0 // indirect + golang.org/x/time v0.14.0 // indirect + golang.org/x/tools v0.38.0 // indirect golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250908214217-97024824d090 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20251002232023-7c0ddcbb5797 // indirect diff --git a/apps/dashboard/go.sum b/apps/dashboard/go.sum index 35aadacf8f9..7a46e1764bb 100644 --- a/apps/dashboard/go.sum +++ b/apps/dashboard/go.sum @@ -85,10 +85,10 @@ github.com/grafana/authlib/types v0.0.0-20250926065801-df98203cff37 h1:qEwZ+7MbP github.com/grafana/authlib/types v0.0.0-20250926065801-df98203cff37/go.mod h1:qeWYbnWzaYGl88JlL9+DsP1GT2Cudm58rLtx13fKZdw= github.com/grafana/dskit v0.0.0-20250908063411-6b6da59b5cc4 h1:jSojuc7njleS3UOz223WDlXOinmuLAIPI0z2vtq8EgI= github.com/grafana/dskit v0.0.0-20250908063411-6b6da59b5cc4/go.mod h1:VahT+GtfQIM+o8ht2StR6J9g+Ef+C2Vokh5uuSmOD/4= -github.com/grafana/grafana-app-sdk v0.47.0 h1:zTKV+p6zM9y+In+dAcaHczbJJsQj9WKglSBcQXMOA+8= -github.com/grafana/grafana-app-sdk v0.47.0/go.mod h1:kywXmkppq0oReUMzkjTW8Fq2EBzyN7v914jttTWnWxA= -github.com/grafana/grafana-app-sdk/logging v0.46.0 h1:JhQ+ZK5orcmM+dZ3YZdT9uCizJEFU2I6JBNUSFWvCC8= -github.com/grafana/grafana-app-sdk/logging v0.46.0/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA= +github.com/grafana/grafana-app-sdk v0.48.1 h1:bKJadWH18WCpJ+Zk8AezRFXCcZgGredRv+fRS+8zkek= +github.com/grafana/grafana-app-sdk v0.48.1/go.mod h1:5LljCz+wvmGfkQ8ZKTOfserhtXNEF0cSFthoWShvN6c= +github.com/grafana/grafana-app-sdk/logging v0.48.1 h1:veM0X5LAPyN3KsDLglWjIofndbGuf7MqnrDuDN+F/Ng= +github.com/grafana/grafana-app-sdk/logging v0.48.1/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA= github.com/grafana/grafana-plugin-sdk-go v0.281.0 h1:V8dGyatzcOLQeivFhBV2JWMwTSZH/clDnpfKG9p3dTA= github.com/grafana/grafana-plugin-sdk-go v0.281.0/go.mod h1:3I0g+v6jAwVmrt6BEjDUP4V6pkhGP5QKY5NkXY4Ayr4= github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250514132646-acbc7b54ed9e h1:BTKk7LHuG1kmAkucwTA7DuMbKpKvJTKrGdBmUNO4dfQ= @@ -280,20 +280,20 @@ go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= 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/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI= -golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8= +golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04= +golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0= golang.org/x/exp v0.0.0-20251002181428-27f1f14c8bb9 h1:TQwNpfvNkxAVlItJf6Cr5JTsVZoC/Sj7K3OZv2Pc14A= golang.org/x/exp v0.0.0-20251002181428-27f1f14c8bb9/go.mod h1:TwQYMMnGpvZyc+JpB/UAuTNIsVJifOlSkrZkhcvpVUk= 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.28.0 h1:gQBtGhjxykdjY9YhZpSlZIsbnaE2+PgjfLWUQTnoZ1U= -golang.org/x/mod v0.28.0/go.mod h1:yfB/L0NOf/kmEbXjzCPOx1iK1fRutOydrCMsqRhEBxI= +golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA= +golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w= 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= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.45.0 h1:RLBg5JKixCy82FtLJpeNlVM0nrSqpCRYzVU1n8kj0tM= -golang.org/x/net v0.45.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY= +golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4= +golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= golang.org/x/oauth2 v0.32.0 h1:jsCblLleRMDrxMN29H3z/k1KliIvpLgCkE6R8FXXNgY= golang.org/x/oauth2 v0.32.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -313,22 +313,22 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/telemetry v0.0.0-20250908211612-aef8a434d053 h1:dHQOQddU4YHS5gY33/6klKjq7Gp3WwMyOXGNp5nzRj8= -golang.org/x/telemetry v0.0.0-20250908211612-aef8a434d053/go.mod h1:+nZKN+XVh4LCiA9DV3ywrzN4gumyCnKjau3NGb9SGoE= -golang.org/x/term v0.35.0 h1:bZBVKBudEyhRcajGcNc3jIfWPqV4y/Kt2XcoigOWtDQ= -golang.org/x/term v0.35.0/go.mod h1:TPGtkTLesOwf2DE8CgVYiZinHAOuy5AYUYT1lENIZnA= +golang.org/x/telemetry v0.0.0-20251008203120-078029d740a8 h1:LvzTn0GQhWuvKH/kVRS3R3bVAsdQWI7hvfLHGgh9+lU= +golang.org/x/telemetry v0.0.0-20251008203120-078029d740a8/go.mod h1:Pi4ztBfryZoJEkyFTI5/Ocsu2jXyDr6iSdgJiYE/uwE= +golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q= +golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k= golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= -golang.org/x/time v0.13.0 h1:eUlYslOIt32DgYD6utsuUeHs4d7AsEYLuIAdg7FlYgI= -golang.org/x/time v0.13.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= +golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= +golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 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.37.0 h1:DVSRzp7FwePZW356yEAChSdNcQo6Nsp+fex1SUW09lE= -golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w= +golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ= +golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs= 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= diff --git a/apps/dashboard/pkg/apis/dashboard/v2alpha1/dashboard_spec_gen.go b/apps/dashboard/pkg/apis/dashboard/v2alpha1/dashboard_spec_gen.go index bb737fb8ac3..5562379e68b 100644 --- a/apps/dashboard/pkg/apis/dashboard/v2alpha1/dashboard_spec_gen.go +++ b/apps/dashboard/pkg/apis/dashboard/v2alpha1/dashboard_spec_gen.go @@ -1064,9 +1064,11 @@ type DashboardAutoGridLayoutSpec struct { // NewDashboardAutoGridLayoutSpec creates a new DashboardAutoGridLayoutSpec object. func NewDashboardAutoGridLayoutSpec() *DashboardAutoGridLayoutSpec { return &DashboardAutoGridLayoutSpec{ - MaxColumnCount: (func(input float64) *float64 { return &input })(3), - FillScreen: (func(input bool) *bool { return &input })(false), - Items: []DashboardAutoGridLayoutItemKind{}, + MaxColumnCount: (func(input float64) *float64 { return &input })(3), + ColumnWidthMode: DashboardAutoGridLayoutSpecColumnWidthModeStandard, + RowHeightMode: DashboardAutoGridLayoutSpecRowHeightModeStandard, + FillScreen: (func(input bool) *bool { return &input })(false), + Items: []DashboardAutoGridLayoutItemKind{}, } } diff --git a/apps/dashboard/pkg/apis/dashboard/v2beta1/dashboard_spec_gen.go b/apps/dashboard/pkg/apis/dashboard/v2beta1/dashboard_spec_gen.go index 2ac53a7600c..35674997511 100644 --- a/apps/dashboard/pkg/apis/dashboard/v2beta1/dashboard_spec_gen.go +++ b/apps/dashboard/pkg/apis/dashboard/v2beta1/dashboard_spec_gen.go @@ -1058,9 +1058,11 @@ type DashboardAutoGridLayoutSpec struct { // NewDashboardAutoGridLayoutSpec creates a new DashboardAutoGridLayoutSpec object. func NewDashboardAutoGridLayoutSpec() *DashboardAutoGridLayoutSpec { return &DashboardAutoGridLayoutSpec{ - MaxColumnCount: (func(input float64) *float64 { return &input })(3), - FillScreen: (func(input bool) *bool { return &input })(false), - Items: []DashboardAutoGridLayoutItemKind{}, + MaxColumnCount: (func(input float64) *float64 { return &input })(3), + ColumnWidthMode: DashboardAutoGridLayoutSpecColumnWidthModeStandard, + RowHeightMode: DashboardAutoGridLayoutSpecRowHeightModeStandard, + FillScreen: (func(input bool) *bool { return &input })(false), + Items: []DashboardAutoGridLayoutItemKind{}, } } diff --git a/apps/folder/go.mod b/apps/folder/go.mod index 89d24838284..f87baeab415 100644 --- a/apps/folder/go.mod +++ b/apps/folder/go.mod @@ -3,7 +3,7 @@ module github.com/grafana/grafana/apps/folder go 1.25.3 require ( - github.com/grafana/grafana-app-sdk v0.47.0 + github.com/grafana/grafana-app-sdk v0.48.1 github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250514132646-acbc7b54ed9e k8s.io/apimachinery v0.34.1 k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 @@ -24,7 +24,7 @@ require ( github.com/go-test/deep v1.1.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/google/gnostic-models v0.7.0 // indirect - github.com/grafana/grafana-app-sdk/logging v0.46.0 // indirect + github.com/grafana/grafana-app-sdk/logging v0.48.1 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/josharian/intern v1.0.0 // indirect @@ -50,12 +50,12 @@ require ( go.opentelemetry.io/otel/trace v1.38.0 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/net v0.45.0 // indirect + golang.org/x/net v0.46.0 // indirect golang.org/x/oauth2 v0.32.0 // indirect golang.org/x/sys v0.37.0 // indirect - golang.org/x/term v0.35.0 // indirect + golang.org/x/term v0.36.0 // indirect golang.org/x/text v0.30.0 // indirect - golang.org/x/time v0.13.0 // indirect + golang.org/x/time v0.14.0 // indirect google.golang.org/protobuf v1.36.10 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/apps/folder/go.sum b/apps/folder/go.sum index 3cb21ccfd3e..9b1b0735938 100644 --- a/apps/folder/go.sum +++ b/apps/folder/go.sum @@ -33,10 +33,10 @@ github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 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/grafana/grafana-app-sdk v0.47.0 h1:zTKV+p6zM9y+In+dAcaHczbJJsQj9WKglSBcQXMOA+8= -github.com/grafana/grafana-app-sdk v0.47.0/go.mod h1:kywXmkppq0oReUMzkjTW8Fq2EBzyN7v914jttTWnWxA= -github.com/grafana/grafana-app-sdk/logging v0.46.0 h1:JhQ+ZK5orcmM+dZ3YZdT9uCizJEFU2I6JBNUSFWvCC8= -github.com/grafana/grafana-app-sdk/logging v0.46.0/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA= +github.com/grafana/grafana-app-sdk v0.48.1 h1:bKJadWH18WCpJ+Zk8AezRFXCcZgGredRv+fRS+8zkek= +github.com/grafana/grafana-app-sdk v0.48.1/go.mod h1:5LljCz+wvmGfkQ8ZKTOfserhtXNEF0cSFthoWShvN6c= +github.com/grafana/grafana-app-sdk/logging v0.48.1 h1:veM0X5LAPyN3KsDLglWjIofndbGuf7MqnrDuDN+F/Ng= +github.com/grafana/grafana-app-sdk/logging v0.48.1/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA= github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250514132646-acbc7b54ed9e h1:BTKk7LHuG1kmAkucwTA7DuMbKpKvJTKrGdBmUNO4dfQ= github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250514132646-acbc7b54ed9e/go.mod h1:IA4SOwun8QyST9c5UNs/fN37XL6boXXDvRYFcFwbipg= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -126,8 +126,8 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.45.0 h1:RLBg5JKixCy82FtLJpeNlVM0nrSqpCRYzVU1n8kj0tM= -golang.org/x/net v0.45.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY= +golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4= +golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= golang.org/x/oauth2 v0.32.0 h1:jsCblLleRMDrxMN29H3z/k1KliIvpLgCkE6R8FXXNgY= golang.org/x/oauth2 v0.32.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -138,14 +138,14 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/term v0.35.0 h1:bZBVKBudEyhRcajGcNc3jIfWPqV4y/Kt2XcoigOWtDQ= -golang.org/x/term v0.35.0/go.mod h1:TPGtkTLesOwf2DE8CgVYiZinHAOuy5AYUYT1lENIZnA= +golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q= +golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k= golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= -golang.org/x/time v0.13.0 h1:eUlYslOIt32DgYD6utsuUeHs4d7AsEYLuIAdg7FlYgI= -golang.org/x/time v0.13.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= +golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= +golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 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= diff --git a/apps/iam/go.mod b/apps/iam/go.mod index d0934bdf950..63dae42947a 100644 --- a/apps/iam/go.mod +++ b/apps/iam/go.mod @@ -46,8 +46,8 @@ replace github.com/prometheus/alertmanager => github.com/grafana/prometheus-aler require ( github.com/grafana/grafana v0.0.0-00010101000000-000000000000 - github.com/grafana/grafana-app-sdk v0.47.0 - github.com/grafana/grafana-app-sdk/logging v0.46.0 + github.com/grafana/grafana-app-sdk v0.48.1 + github.com/grafana/grafana-app-sdk/logging v0.48.1 github.com/grafana/grafana/apps/folder v0.0.0 github.com/grafana/grafana/pkg/apimachinery v0.0.0 github.com/prometheus/client_golang v1.23.2 @@ -434,18 +434,18 @@ require ( go.yaml.in/yaml/v2 v2.4.3 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect gocloud.dev v0.42.0 // indirect - golang.org/x/crypto v0.42.0 // indirect + golang.org/x/crypto v0.43.0 // indirect golang.org/x/exp v0.0.0-20251002181428-27f1f14c8bb9 // indirect - golang.org/x/mod v0.28.0 // indirect - golang.org/x/net v0.45.0 // indirect + golang.org/x/mod v0.29.0 // indirect + golang.org/x/net v0.46.0 // indirect golang.org/x/oauth2 v0.32.0 // indirect golang.org/x/sync v0.17.0 // indirect golang.org/x/sys v0.37.0 // indirect - golang.org/x/telemetry v0.0.0-20250908211612-aef8a434d053 // indirect - golang.org/x/term v0.35.0 // indirect + golang.org/x/telemetry v0.0.0-20251008203120-078029d740a8 // indirect + golang.org/x/term v0.36.0 // indirect golang.org/x/text v0.30.0 // indirect - golang.org/x/time v0.13.0 // indirect - golang.org/x/tools v0.37.0 // indirect + golang.org/x/time v0.14.0 // indirect + golang.org/x/tools v0.38.0 // indirect golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect gonum.org/v1/gonum v0.16.0 // indirect diff --git a/apps/iam/go.sum b/apps/iam/go.sum index c8e63a53524..9aaebddce10 100644 --- a/apps/iam/go.sum +++ b/apps/iam/go.sum @@ -844,10 +844,10 @@ github.com/grafana/gofpdf v0.0.0-20250307124105-3b9c5d35577f h1:5xkjl5Y/j2QefJKO github.com/grafana/gofpdf v0.0.0-20250307124105-3b9c5d35577f/go.mod h1:+O5QxOwwgP10jedZHapzXY+IPKTnzHBtIs5UUb9G+kI= github.com/grafana/gomemcache v0.0.0-20250828162811-a96f6acee2fe h1:q+QaVANzNZxvTovycpQvDTfsNZ2rHh4XIIaccMnrIR4= github.com/grafana/gomemcache v0.0.0-20250828162811-a96f6acee2fe/go.mod h1:j/s0jkda4UXTemDs7Pgw/vMT06alWc42CHisvYac0qw= -github.com/grafana/grafana-app-sdk v0.47.0 h1:zTKV+p6zM9y+In+dAcaHczbJJsQj9WKglSBcQXMOA+8= -github.com/grafana/grafana-app-sdk v0.47.0/go.mod h1:kywXmkppq0oReUMzkjTW8Fq2EBzyN7v914jttTWnWxA= -github.com/grafana/grafana-app-sdk/logging v0.46.0 h1:JhQ+ZK5orcmM+dZ3YZdT9uCizJEFU2I6JBNUSFWvCC8= -github.com/grafana/grafana-app-sdk/logging v0.46.0/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA= +github.com/grafana/grafana-app-sdk v0.48.1 h1:bKJadWH18WCpJ+Zk8AezRFXCcZgGredRv+fRS+8zkek= +github.com/grafana/grafana-app-sdk v0.48.1/go.mod h1:5LljCz+wvmGfkQ8ZKTOfserhtXNEF0cSFthoWShvN6c= +github.com/grafana/grafana-app-sdk/logging v0.48.1 h1:veM0X5LAPyN3KsDLglWjIofndbGuf7MqnrDuDN+F/Ng= +github.com/grafana/grafana-app-sdk/logging v0.48.1/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA= github.com/grafana/grafana-aws-sdk v1.2.0 h1:LLR4/g91WBuCRwm2cbWfCREq565+GxIFe08nqqIcIuw= github.com/grafana/grafana-aws-sdk v1.2.0/go.mod h1:bBo7qOmM3f61vO+2JxTolNUph1l2TmtzmWcU9/Im+8A= github.com/grafana/grafana-azure-sdk-go/v2 v2.3.1 h1:FFcEA01tW+SmuJIuDbHOdgUBL+d7DPrZ2N4zwzPhfGk= @@ -1710,8 +1710,8 @@ golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI= -golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8= +golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04= +golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1753,8 +1753,8 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.28.0 h1:gQBtGhjxykdjY9YhZpSlZIsbnaE2+PgjfLWUQTnoZ1U= -golang.org/x/mod v0.28.0/go.mod h1:yfB/L0NOf/kmEbXjzCPOx1iK1fRutOydrCMsqRhEBxI= +golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA= +golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w= 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-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1809,8 +1809,8 @@ golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.45.0 h1:RLBg5JKixCy82FtLJpeNlVM0nrSqpCRYzVU1n8kj0tM= -golang.org/x/net v0.45.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY= +golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4= +golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1944,12 +1944,12 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/telemetry v0.0.0-20250908211612-aef8a434d053 h1:dHQOQddU4YHS5gY33/6klKjq7Gp3WwMyOXGNp5nzRj8= -golang.org/x/telemetry v0.0.0-20250908211612-aef8a434d053/go.mod h1:+nZKN+XVh4LCiA9DV3ywrzN4gumyCnKjau3NGb9SGoE= +golang.org/x/telemetry v0.0.0-20251008203120-078029d740a8 h1:LvzTn0GQhWuvKH/kVRS3R3bVAsdQWI7hvfLHGgh9+lU= +golang.org/x/telemetry v0.0.0-20251008203120-078029d740a8/go.mod h1:Pi4ztBfryZoJEkyFTI5/Ocsu2jXyDr6iSdgJiYE/uwE= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.35.0 h1:bZBVKBudEyhRcajGcNc3jIfWPqV4y/Kt2XcoigOWtDQ= -golang.org/x/term v0.35.0/go.mod h1:TPGtkTLesOwf2DE8CgVYiZinHAOuy5AYUYT1lENIZnA= +golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q= +golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1964,8 +1964,8 @@ golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.13.0 h1:eUlYslOIt32DgYD6utsuUeHs4d7AsEYLuIAdg7FlYgI= -golang.org/x/time v0.13.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= +golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= +golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -2027,8 +2027,8 @@ golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.37.0 h1:DVSRzp7FwePZW356yEAChSdNcQo6Nsp+fex1SUW09lE= -golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w= +golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ= +golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs= golang.org/x/tools/godoc v0.1.0-deprecated h1:o+aZ1BOj6Hsx/GBdJO/s815sqftjSnrZZwyYTHODvtk= golang.org/x/tools/godoc v0.1.0-deprecated/go.mod h1:qM63CriJ961IHWmnWa9CjZnBndniPt4a3CK0PVB9bIg= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/apps/investigations/go.mod b/apps/investigations/go.mod index 11e545fb631..fdf11d0b25a 100644 --- a/apps/investigations/go.mod +++ b/apps/investigations/go.mod @@ -3,7 +3,7 @@ module github.com/grafana/grafana/apps/investigations go 1.25.3 require ( - github.com/grafana/grafana-app-sdk v0.47.0 + github.com/grafana/grafana-app-sdk v0.48.1 k8s.io/apimachinery v0.34.1 k8s.io/klog/v2 v2.130.1 k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 @@ -31,7 +31,7 @@ require ( github.com/google/go-cmp v0.7.0 // indirect github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 // indirect github.com/google/uuid v1.6.0 // indirect - github.com/grafana/grafana-app-sdk/logging v0.46.0 // indirect + github.com/grafana/grafana-app-sdk/logging v0.48.1 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect @@ -68,13 +68,13 @@ require ( go.opentelemetry.io/proto/otlp v1.7.1 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/net v0.45.0 // indirect + golang.org/x/net v0.46.0 // indirect golang.org/x/oauth2 v0.32.0 // indirect golang.org/x/sync v0.17.0 // indirect golang.org/x/sys v0.37.0 // indirect - golang.org/x/term v0.35.0 // indirect + golang.org/x/term v0.36.0 // indirect golang.org/x/text v0.30.0 // indirect - golang.org/x/time v0.13.0 // indirect + golang.org/x/time v0.14.0 // indirect gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250908214217-97024824d090 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20251002232023-7c0ddcbb5797 // indirect diff --git a/apps/investigations/go.sum b/apps/investigations/go.sum index fe5ba699151..a0e59cd5731 100644 --- a/apps/investigations/go.sum +++ b/apps/investigations/go.sum @@ -48,10 +48,10 @@ github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 h1:BHT72Gu3keYf3ZEu2J github.com/google/pprof v0.0.0-20250403155104-27863c87afa6/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= 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/grafana/grafana-app-sdk v0.47.0 h1:zTKV+p6zM9y+In+dAcaHczbJJsQj9WKglSBcQXMOA+8= -github.com/grafana/grafana-app-sdk v0.47.0/go.mod h1:kywXmkppq0oReUMzkjTW8Fq2EBzyN7v914jttTWnWxA= -github.com/grafana/grafana-app-sdk/logging v0.46.0 h1:JhQ+ZK5orcmM+dZ3YZdT9uCizJEFU2I6JBNUSFWvCC8= -github.com/grafana/grafana-app-sdk/logging v0.46.0/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA= +github.com/grafana/grafana-app-sdk v0.48.1 h1:bKJadWH18WCpJ+Zk8AezRFXCcZgGredRv+fRS+8zkek= +github.com/grafana/grafana-app-sdk v0.48.1/go.mod h1:5LljCz+wvmGfkQ8ZKTOfserhtXNEF0cSFthoWShvN6c= +github.com/grafana/grafana-app-sdk/logging v0.48.1 h1:veM0X5LAPyN3KsDLglWjIofndbGuf7MqnrDuDN+F/Ng= +github.com/grafana/grafana-app-sdk/logging v0.48.1/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 h1:8Tjv8EJ+pM1xP8mK6egEbD1OgnVTyacbefKhmbLhIhU= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2/go.mod h1:pkJQ2tZHJ0aFOVEEot6oZmaVEZcRme73eIFmhiVuRWs= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -163,8 +163,8 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.45.0 h1:RLBg5JKixCy82FtLJpeNlVM0nrSqpCRYzVU1n8kj0tM= -golang.org/x/net v0.45.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY= +golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4= +golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= golang.org/x/oauth2 v0.32.0 h1:jsCblLleRMDrxMN29H3z/k1KliIvpLgCkE6R8FXXNgY= golang.org/x/oauth2 v0.32.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -177,20 +177,20 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/term v0.35.0 h1:bZBVKBudEyhRcajGcNc3jIfWPqV4y/Kt2XcoigOWtDQ= -golang.org/x/term v0.35.0/go.mod h1:TPGtkTLesOwf2DE8CgVYiZinHAOuy5AYUYT1lENIZnA= +golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q= +golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k= golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= -golang.org/x/time v0.13.0 h1:eUlYslOIt32DgYD6utsuUeHs4d7AsEYLuIAdg7FlYgI= -golang.org/x/time v0.13.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= +golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= +golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 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.37.0 h1:DVSRzp7FwePZW356yEAChSdNcQo6Nsp+fex1SUW09lE= -golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w= +golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ= +golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs= 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= diff --git a/apps/logsdrilldown/go.mod b/apps/logsdrilldown/go.mod index 4d034b73343..6d2c5654233 100644 --- a/apps/logsdrilldown/go.mod +++ b/apps/logsdrilldown/go.mod @@ -5,8 +5,8 @@ go 1.24.0 toolchain go1.24.6 require ( - github.com/grafana/grafana-app-sdk v0.47.0 - github.com/grafana/grafana-app-sdk/logging v0.46.0 + github.com/grafana/grafana-app-sdk v0.48.1 + github.com/grafana/grafana-app-sdk/logging v0.48.1 k8s.io/apimachinery v0.34.1 k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 ) @@ -69,13 +69,13 @@ require ( go.opentelemetry.io/proto/otlp v1.7.1 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/net v0.45.0 // indirect + golang.org/x/net v0.46.0 // indirect golang.org/x/oauth2 v0.32.0 // indirect golang.org/x/sync v0.17.0 // indirect golang.org/x/sys v0.37.0 // indirect - golang.org/x/term v0.35.0 // indirect + golang.org/x/term v0.36.0 // indirect golang.org/x/text v0.30.0 // indirect - golang.org/x/time v0.13.0 // indirect + golang.org/x/time v0.14.0 // indirect gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250908214217-97024824d090 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20251002232023-7c0ddcbb5797 // indirect diff --git a/apps/logsdrilldown/go.sum b/apps/logsdrilldown/go.sum index fe5ba699151..a0e59cd5731 100644 --- a/apps/logsdrilldown/go.sum +++ b/apps/logsdrilldown/go.sum @@ -48,10 +48,10 @@ github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 h1:BHT72Gu3keYf3ZEu2J github.com/google/pprof v0.0.0-20250403155104-27863c87afa6/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= 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/grafana/grafana-app-sdk v0.47.0 h1:zTKV+p6zM9y+In+dAcaHczbJJsQj9WKglSBcQXMOA+8= -github.com/grafana/grafana-app-sdk v0.47.0/go.mod h1:kywXmkppq0oReUMzkjTW8Fq2EBzyN7v914jttTWnWxA= -github.com/grafana/grafana-app-sdk/logging v0.46.0 h1:JhQ+ZK5orcmM+dZ3YZdT9uCizJEFU2I6JBNUSFWvCC8= -github.com/grafana/grafana-app-sdk/logging v0.46.0/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA= +github.com/grafana/grafana-app-sdk v0.48.1 h1:bKJadWH18WCpJ+Zk8AezRFXCcZgGredRv+fRS+8zkek= +github.com/grafana/grafana-app-sdk v0.48.1/go.mod h1:5LljCz+wvmGfkQ8ZKTOfserhtXNEF0cSFthoWShvN6c= +github.com/grafana/grafana-app-sdk/logging v0.48.1 h1:veM0X5LAPyN3KsDLglWjIofndbGuf7MqnrDuDN+F/Ng= +github.com/grafana/grafana-app-sdk/logging v0.48.1/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 h1:8Tjv8EJ+pM1xP8mK6egEbD1OgnVTyacbefKhmbLhIhU= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2/go.mod h1:pkJQ2tZHJ0aFOVEEot6oZmaVEZcRme73eIFmhiVuRWs= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -163,8 +163,8 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.45.0 h1:RLBg5JKixCy82FtLJpeNlVM0nrSqpCRYzVU1n8kj0tM= -golang.org/x/net v0.45.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY= +golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4= +golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= golang.org/x/oauth2 v0.32.0 h1:jsCblLleRMDrxMN29H3z/k1KliIvpLgCkE6R8FXXNgY= golang.org/x/oauth2 v0.32.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -177,20 +177,20 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/term v0.35.0 h1:bZBVKBudEyhRcajGcNc3jIfWPqV4y/Kt2XcoigOWtDQ= -golang.org/x/term v0.35.0/go.mod h1:TPGtkTLesOwf2DE8CgVYiZinHAOuy5AYUYT1lENIZnA= +golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q= +golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k= golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= -golang.org/x/time v0.13.0 h1:eUlYslOIt32DgYD6utsuUeHs4d7AsEYLuIAdg7FlYgI= -golang.org/x/time v0.13.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= +golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= +golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 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.37.0 h1:DVSRzp7FwePZW356yEAChSdNcQo6Nsp+fex1SUW09lE= -golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w= +golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ= +golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs= 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= diff --git a/apps/playlist/go.mod b/apps/playlist/go.mod index eb2d0319990..387d8ccd445 100644 --- a/apps/playlist/go.mod +++ b/apps/playlist/go.mod @@ -3,7 +3,7 @@ module github.com/grafana/grafana/apps/playlist go 1.25.3 require ( - github.com/grafana/grafana-app-sdk v0.47.0 + github.com/grafana/grafana-app-sdk v0.48.1 k8s.io/apimachinery v0.34.1 k8s.io/client-go v0.34.1 k8s.io/klog/v2 v2.130.1 @@ -32,7 +32,7 @@ require ( github.com/google/go-cmp v0.7.0 // indirect github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 // indirect github.com/google/uuid v1.6.0 // indirect - github.com/grafana/grafana-app-sdk/logging v0.46.0 // indirect + github.com/grafana/grafana-app-sdk/logging v0.48.1 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect @@ -69,13 +69,13 @@ require ( go.opentelemetry.io/proto/otlp v1.7.1 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/net v0.45.0 // indirect + golang.org/x/net v0.46.0 // indirect golang.org/x/oauth2 v0.32.0 // indirect golang.org/x/sync v0.17.0 // indirect golang.org/x/sys v0.37.0 // indirect - golang.org/x/term v0.35.0 // indirect + golang.org/x/term v0.36.0 // indirect golang.org/x/text v0.30.0 // indirect - golang.org/x/time v0.13.0 // indirect + golang.org/x/time v0.14.0 // indirect gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250908214217-97024824d090 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20251002232023-7c0ddcbb5797 // indirect diff --git a/apps/playlist/go.sum b/apps/playlist/go.sum index fe5ba699151..a0e59cd5731 100644 --- a/apps/playlist/go.sum +++ b/apps/playlist/go.sum @@ -48,10 +48,10 @@ github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 h1:BHT72Gu3keYf3ZEu2J github.com/google/pprof v0.0.0-20250403155104-27863c87afa6/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= 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/grafana/grafana-app-sdk v0.47.0 h1:zTKV+p6zM9y+In+dAcaHczbJJsQj9WKglSBcQXMOA+8= -github.com/grafana/grafana-app-sdk v0.47.0/go.mod h1:kywXmkppq0oReUMzkjTW8Fq2EBzyN7v914jttTWnWxA= -github.com/grafana/grafana-app-sdk/logging v0.46.0 h1:JhQ+ZK5orcmM+dZ3YZdT9uCizJEFU2I6JBNUSFWvCC8= -github.com/grafana/grafana-app-sdk/logging v0.46.0/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA= +github.com/grafana/grafana-app-sdk v0.48.1 h1:bKJadWH18WCpJ+Zk8AezRFXCcZgGredRv+fRS+8zkek= +github.com/grafana/grafana-app-sdk v0.48.1/go.mod h1:5LljCz+wvmGfkQ8ZKTOfserhtXNEF0cSFthoWShvN6c= +github.com/grafana/grafana-app-sdk/logging v0.48.1 h1:veM0X5LAPyN3KsDLglWjIofndbGuf7MqnrDuDN+F/Ng= +github.com/grafana/grafana-app-sdk/logging v0.48.1/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 h1:8Tjv8EJ+pM1xP8mK6egEbD1OgnVTyacbefKhmbLhIhU= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2/go.mod h1:pkJQ2tZHJ0aFOVEEot6oZmaVEZcRme73eIFmhiVuRWs= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -163,8 +163,8 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.45.0 h1:RLBg5JKixCy82FtLJpeNlVM0nrSqpCRYzVU1n8kj0tM= -golang.org/x/net v0.45.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY= +golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4= +golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= golang.org/x/oauth2 v0.32.0 h1:jsCblLleRMDrxMN29H3z/k1KliIvpLgCkE6R8FXXNgY= golang.org/x/oauth2 v0.32.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -177,20 +177,20 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/term v0.35.0 h1:bZBVKBudEyhRcajGcNc3jIfWPqV4y/Kt2XcoigOWtDQ= -golang.org/x/term v0.35.0/go.mod h1:TPGtkTLesOwf2DE8CgVYiZinHAOuy5AYUYT1lENIZnA= +golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q= +golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k= golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= -golang.org/x/time v0.13.0 h1:eUlYslOIt32DgYD6utsuUeHs4d7AsEYLuIAdg7FlYgI= -golang.org/x/time v0.13.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= +golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= +golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 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.37.0 h1:DVSRzp7FwePZW356yEAChSdNcQo6Nsp+fex1SUW09lE= -golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w= +golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ= +golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs= 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= diff --git a/apps/plugins/go.mod b/apps/plugins/go.mod index 4bb9b755dca..ab1de1b4186 100644 --- a/apps/plugins/go.mod +++ b/apps/plugins/go.mod @@ -4,7 +4,7 @@ go 1.25.3 require ( github.com/grafana/authlib/types v0.0.0-20250926065801-df98203cff37 - github.com/grafana/grafana-app-sdk v0.47.0 + github.com/grafana/grafana-app-sdk v0.48.1 github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250428110029-a8ea72012bde k8s.io/apimachinery v0.34.1 k8s.io/apiserver v0.34.1 @@ -38,7 +38,7 @@ require ( github.com/google/uuid v1.6.0 // indirect github.com/grafana/authlib v0.0.0-20250930082137-a40e2c2b094f // indirect github.com/grafana/dskit v0.0.0-20250908063411-6b6da59b5cc4 // indirect - github.com/grafana/grafana-app-sdk/logging v0.46.0 // indirect + github.com/grafana/grafana-app-sdk/logging v0.48.1 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect @@ -75,14 +75,14 @@ require ( go.opentelemetry.io/proto/otlp v1.7.1 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/crypto v0.42.0 // indirect - golang.org/x/net v0.45.0 // indirect + golang.org/x/crypto v0.43.0 // indirect + golang.org/x/net v0.46.0 // indirect golang.org/x/oauth2 v0.32.0 // indirect golang.org/x/sync v0.17.0 // indirect golang.org/x/sys v0.37.0 // indirect - golang.org/x/term v0.35.0 // indirect + golang.org/x/term v0.36.0 // indirect golang.org/x/text v0.30.0 // indirect - golang.org/x/time v0.13.0 // indirect + golang.org/x/time v0.14.0 // indirect gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250908214217-97024824d090 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20251002232023-7c0ddcbb5797 // indirect diff --git a/apps/plugins/go.sum b/apps/plugins/go.sum index caf9fddb9b7..07264ead5aa 100644 --- a/apps/plugins/go.sum +++ b/apps/plugins/go.sum @@ -58,10 +58,10 @@ github.com/grafana/authlib/types v0.0.0-20250926065801-df98203cff37 h1:qEwZ+7MbP github.com/grafana/authlib/types v0.0.0-20250926065801-df98203cff37/go.mod h1:qeWYbnWzaYGl88JlL9+DsP1GT2Cudm58rLtx13fKZdw= github.com/grafana/dskit v0.0.0-20250908063411-6b6da59b5cc4 h1:jSojuc7njleS3UOz223WDlXOinmuLAIPI0z2vtq8EgI= github.com/grafana/dskit v0.0.0-20250908063411-6b6da59b5cc4/go.mod h1:VahT+GtfQIM+o8ht2StR6J9g+Ef+C2Vokh5uuSmOD/4= -github.com/grafana/grafana-app-sdk v0.47.0 h1:zTKV+p6zM9y+In+dAcaHczbJJsQj9WKglSBcQXMOA+8= -github.com/grafana/grafana-app-sdk v0.47.0/go.mod h1:kywXmkppq0oReUMzkjTW8Fq2EBzyN7v914jttTWnWxA= -github.com/grafana/grafana-app-sdk/logging v0.46.0 h1:JhQ+ZK5orcmM+dZ3YZdT9uCizJEFU2I6JBNUSFWvCC8= -github.com/grafana/grafana-app-sdk/logging v0.46.0/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA= +github.com/grafana/grafana-app-sdk v0.48.1 h1:bKJadWH18WCpJ+Zk8AezRFXCcZgGredRv+fRS+8zkek= +github.com/grafana/grafana-app-sdk v0.48.1/go.mod h1:5LljCz+wvmGfkQ8ZKTOfserhtXNEF0cSFthoWShvN6c= +github.com/grafana/grafana-app-sdk/logging v0.48.1 h1:veM0X5LAPyN3KsDLglWjIofndbGuf7MqnrDuDN+F/Ng= +github.com/grafana/grafana-app-sdk/logging v0.48.1/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA= github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250428110029-a8ea72012bde h1:ydSrBIOCxJQ84+JU+cyYsOLL40QeXrB7rYfsY/ezU4w= github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250428110029-a8ea72012bde/go.mod h1:3MwgP0ISxGviTy3ZUJZsNz/56NNtHztMlH+gcxDt6Tw= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 h1:8Tjv8EJ+pM1xP8mK6egEbD1OgnVTyacbefKhmbLhIhU= @@ -171,16 +171,16 @@ go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= 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/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI= -golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8= +golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04= +golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0= 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/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= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.45.0 h1:RLBg5JKixCy82FtLJpeNlVM0nrSqpCRYzVU1n8kj0tM= -golang.org/x/net v0.45.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY= +golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4= +golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= golang.org/x/oauth2 v0.32.0 h1:jsCblLleRMDrxMN29H3z/k1KliIvpLgCkE6R8FXXNgY= golang.org/x/oauth2 v0.32.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -193,20 +193,20 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/term v0.35.0 h1:bZBVKBudEyhRcajGcNc3jIfWPqV4y/Kt2XcoigOWtDQ= -golang.org/x/term v0.35.0/go.mod h1:TPGtkTLesOwf2DE8CgVYiZinHAOuy5AYUYT1lENIZnA= +golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q= +golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k= golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= -golang.org/x/time v0.13.0 h1:eUlYslOIt32DgYD6utsuUeHs4d7AsEYLuIAdg7FlYgI= -golang.org/x/time v0.13.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= +golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= +golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 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.37.0 h1:DVSRzp7FwePZW356yEAChSdNcQo6Nsp+fex1SUW09lE= -golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w= +golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ= +golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs= 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= diff --git a/apps/preferences/go.mod b/apps/preferences/go.mod index 3e5cac7119c..abd2a1ad561 100644 --- a/apps/preferences/go.mod +++ b/apps/preferences/go.mod @@ -3,7 +3,7 @@ module github.com/grafana/grafana/apps/preferences go 1.25.3 require ( - github.com/grafana/grafana-app-sdk v0.47.0 + github.com/grafana/grafana-app-sdk v0.48.1 github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250804150913-990f1c69ecc2 github.com/stretchr/testify v1.11.1 k8s.io/apimachinery v0.34.1 @@ -25,7 +25,7 @@ require ( github.com/go-test/deep v1.1.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/google/gnostic-models v0.7.0 // indirect - github.com/grafana/grafana-app-sdk/logging v0.46.0 // indirect + github.com/grafana/grafana-app-sdk/logging v0.48.1 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/josharian/intern v1.0.0 // indirect @@ -50,12 +50,12 @@ require ( go.opentelemetry.io/otel/trace v1.38.0 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/net v0.45.0 // indirect + golang.org/x/net v0.46.0 // indirect golang.org/x/oauth2 v0.32.0 // indirect golang.org/x/sys v0.37.0 // indirect - golang.org/x/term v0.35.0 // indirect + golang.org/x/term v0.36.0 // indirect golang.org/x/text v0.30.0 // indirect - golang.org/x/time v0.13.0 // indirect + golang.org/x/time v0.14.0 // indirect google.golang.org/protobuf v1.36.10 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/apps/preferences/go.sum b/apps/preferences/go.sum index 9ec1464aa8e..0af48867382 100644 --- a/apps/preferences/go.sum +++ b/apps/preferences/go.sum @@ -33,10 +33,10 @@ github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 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/grafana/grafana-app-sdk v0.47.0 h1:zTKV+p6zM9y+In+dAcaHczbJJsQj9WKglSBcQXMOA+8= -github.com/grafana/grafana-app-sdk v0.47.0/go.mod h1:kywXmkppq0oReUMzkjTW8Fq2EBzyN7v914jttTWnWxA= -github.com/grafana/grafana-app-sdk/logging v0.46.0 h1:JhQ+ZK5orcmM+dZ3YZdT9uCizJEFU2I6JBNUSFWvCC8= -github.com/grafana/grafana-app-sdk/logging v0.46.0/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA= +github.com/grafana/grafana-app-sdk v0.48.1 h1:bKJadWH18WCpJ+Zk8AezRFXCcZgGredRv+fRS+8zkek= +github.com/grafana/grafana-app-sdk v0.48.1/go.mod h1:5LljCz+wvmGfkQ8ZKTOfserhtXNEF0cSFthoWShvN6c= +github.com/grafana/grafana-app-sdk/logging v0.48.1 h1:veM0X5LAPyN3KsDLglWjIofndbGuf7MqnrDuDN+F/Ng= +github.com/grafana/grafana-app-sdk/logging v0.48.1/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA= github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250804150913-990f1c69ecc2 h1:X0cnaFdR+iz+sDSuoZmkryFSjOirchHe2MdKSRwBWgM= github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250804150913-990f1c69ecc2/go.mod h1:RRvSjHH12/PnQaXraMO65jUhVu8n59mzvhfIMBETnV4= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -126,8 +126,8 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.45.0 h1:RLBg5JKixCy82FtLJpeNlVM0nrSqpCRYzVU1n8kj0tM= -golang.org/x/net v0.45.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY= +golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4= +golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= golang.org/x/oauth2 v0.32.0 h1:jsCblLleRMDrxMN29H3z/k1KliIvpLgCkE6R8FXXNgY= golang.org/x/oauth2 v0.32.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -138,14 +138,14 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/term v0.35.0 h1:bZBVKBudEyhRcajGcNc3jIfWPqV4y/Kt2XcoigOWtDQ= -golang.org/x/term v0.35.0/go.mod h1:TPGtkTLesOwf2DE8CgVYiZinHAOuy5AYUYT1lENIZnA= +golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q= +golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k= golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= -golang.org/x/time v0.13.0 h1:eUlYslOIt32DgYD6utsuUeHs4d7AsEYLuIAdg7FlYgI= -golang.org/x/time v0.13.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= +golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= +golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 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= diff --git a/apps/provisioning/go.mod b/apps/provisioning/go.mod index 78aed88b2da..ad4bf7e3143 100644 --- a/apps/provisioning/go.mod +++ b/apps/provisioning/go.mod @@ -7,7 +7,7 @@ require ( github.com/google/go-github/v70 v70.0.0 github.com/google/uuid v1.6.0 github.com/grafana/authlib v0.0.0-20250930082137-a40e2c2b094f - github.com/grafana/grafana-app-sdk/logging v0.46.0 + github.com/grafana/grafana-app-sdk/logging v0.48.1 github.com/grafana/grafana/apps/secret v0.0.0-20250902093454-b56b7add012f github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250804150913-990f1c69ecc2 github.com/grafana/nanogit v0.0.0-20250723104447-68f58f5ecec0 @@ -44,7 +44,7 @@ require ( github.com/gorilla/mux v1.8.1 // indirect github.com/grafana/authlib/types v0.0.0-20250926065801-df98203cff37 // indirect github.com/grafana/dskit v0.0.0-20250908063411-6b6da59b5cc4 // indirect - github.com/grafana/grafana-app-sdk v0.47.0 // indirect + github.com/grafana/grafana-app-sdk v0.48.1 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.18.0 // indirect @@ -68,13 +68,13 @@ require ( go.opentelemetry.io/otel/trace v1.38.0 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/crypto v0.42.0 // indirect - golang.org/x/net v0.45.0 // indirect + golang.org/x/crypto v0.43.0 // indirect + golang.org/x/net v0.46.0 // indirect golang.org/x/sync v0.17.0 // indirect golang.org/x/sys v0.37.0 // indirect - golang.org/x/term v0.35.0 // indirect + golang.org/x/term v0.36.0 // indirect golang.org/x/text v0.30.0 // indirect - golang.org/x/time v0.13.0 // indirect + golang.org/x/time v0.14.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20251002232023-7c0ddcbb5797 // indirect google.golang.org/grpc v1.76.0 // indirect google.golang.org/protobuf v1.36.10 // indirect diff --git a/apps/provisioning/go.sum b/apps/provisioning/go.sum index 4f5d177e3d5..a51e063c607 100644 --- a/apps/provisioning/go.sum +++ b/apps/provisioning/go.sum @@ -62,10 +62,10 @@ github.com/grafana/authlib/types v0.0.0-20250926065801-df98203cff37 h1:qEwZ+7MbP github.com/grafana/authlib/types v0.0.0-20250926065801-df98203cff37/go.mod h1:qeWYbnWzaYGl88JlL9+DsP1GT2Cudm58rLtx13fKZdw= github.com/grafana/dskit v0.0.0-20250908063411-6b6da59b5cc4 h1:jSojuc7njleS3UOz223WDlXOinmuLAIPI0z2vtq8EgI= github.com/grafana/dskit v0.0.0-20250908063411-6b6da59b5cc4/go.mod h1:VahT+GtfQIM+o8ht2StR6J9g+Ef+C2Vokh5uuSmOD/4= -github.com/grafana/grafana-app-sdk v0.47.0 h1:zTKV+p6zM9y+In+dAcaHczbJJsQj9WKglSBcQXMOA+8= -github.com/grafana/grafana-app-sdk v0.47.0/go.mod h1:kywXmkppq0oReUMzkjTW8Fq2EBzyN7v914jttTWnWxA= -github.com/grafana/grafana-app-sdk/logging v0.46.0 h1:JhQ+ZK5orcmM+dZ3YZdT9uCizJEFU2I6JBNUSFWvCC8= -github.com/grafana/grafana-app-sdk/logging v0.46.0/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA= +github.com/grafana/grafana-app-sdk v0.48.1 h1:bKJadWH18WCpJ+Zk8AezRFXCcZgGredRv+fRS+8zkek= +github.com/grafana/grafana-app-sdk v0.48.1/go.mod h1:5LljCz+wvmGfkQ8ZKTOfserhtXNEF0cSFthoWShvN6c= +github.com/grafana/grafana-app-sdk/logging v0.48.1 h1:veM0X5LAPyN3KsDLglWjIofndbGuf7MqnrDuDN+F/Ng= +github.com/grafana/grafana-app-sdk/logging v0.48.1/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA= github.com/grafana/grafana/apps/secret v0.0.0-20250902093454-b56b7add012f h1:f+Z5Xpfp1WNYjUe23ginerWsHWUsRgOWrr3WGu3SlWs= github.com/grafana/grafana/apps/secret v0.0.0-20250902093454-b56b7add012f/go.mod h1:RA8mP8KVIwKXBx3Ssqa/uEBABib5LvUWYPVMxrNvnP0= github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250804150913-990f1c69ecc2 h1:X0cnaFdR+iz+sDSuoZmkryFSjOirchHe2MdKSRwBWgM= @@ -156,8 +156,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= -golang.org/x/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI= -golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8= +golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04= +golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0= 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.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= @@ -170,8 +170,8 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/net v0.45.0 h1:RLBg5JKixCy82FtLJpeNlVM0nrSqpCRYzVU1n8kj0tM= -golang.org/x/net v0.45.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY= +golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4= +golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= golang.org/x/oauth2 v0.32.0 h1:jsCblLleRMDrxMN29H3z/k1KliIvpLgCkE6R8FXXNgY= golang.org/x/oauth2 v0.32.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -198,8 +198,8 @@ golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuX golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= -golang.org/x/term v0.35.0 h1:bZBVKBudEyhRcajGcNc3jIfWPqV4y/Kt2XcoigOWtDQ= -golang.org/x/term v0.35.0/go.mod h1:TPGtkTLesOwf2DE8CgVYiZinHAOuy5AYUYT1lENIZnA= +golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q= +golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= @@ -208,16 +208,16 @@ golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k= golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= -golang.org/x/time v0.13.0 h1:eUlYslOIt32DgYD6utsuUeHs4d7AsEYLuIAdg7FlYgI= -golang.org/x/time v0.13.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= +golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= +golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 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.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.37.0 h1:DVSRzp7FwePZW356yEAChSdNcQo6Nsp+fex1SUW09lE= -golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w= +golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ= +golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs= 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= diff --git a/apps/scope/go.mod b/apps/scope/go.mod index e769828a09d..c2efa6601d8 100644 --- a/apps/scope/go.mod +++ b/apps/scope/go.mod @@ -30,7 +30,7 @@ require ( github.com/x448/float16 v0.8.4 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/net v0.45.0 // indirect + golang.org/x/net v0.46.0 // indirect golang.org/x/text v0.30.0 // indirect google.golang.org/protobuf v1.36.10 // indirect gopkg.in/inf.v0 v0.9.1 // indirect diff --git a/apps/scope/go.sum b/apps/scope/go.sum index 80edbe531d4..f720929510d 100644 --- a/apps/scope/go.sum +++ b/apps/scope/go.sum @@ -73,8 +73,8 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.45.0 h1:RLBg5JKixCy82FtLJpeNlVM0nrSqpCRYzVU1n8kj0tM= -golang.org/x/net v0.45.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY= +golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4= +golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= diff --git a/apps/sdk.mk b/apps/sdk.mk index 04e8f4ade70..01d88064558 100644 --- a/apps/sdk.mk +++ b/apps/sdk.mk @@ -1,4 +1,4 @@ -APP_SDK_VERSION = v0.47.0 +APP_SDK_VERSION = v0.48.1 APP_SDK_DIR = $(shell go env GOPATH)/bin/app-sdk-$(APP_SDK_VERSION) APP_SDK_BIN = $(APP_SDK_DIR)/grafana-app-sdk diff --git a/apps/secret/go.mod b/apps/secret/go.mod index 4d9d57f91b2..35e7485e080 100644 --- a/apps/secret/go.mod +++ b/apps/secret/go.mod @@ -3,7 +3,7 @@ module github.com/grafana/grafana/apps/secret go 1.25.3 require ( - github.com/grafana/grafana-app-sdk v0.47.0 + github.com/grafana/grafana-app-sdk v0.48.1 github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250710134100-1f3dc0533caf github.com/stretchr/testify v1.11.1 google.golang.org/grpc v1.76.0 @@ -29,7 +29,7 @@ require ( github.com/go-test/deep v1.1.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/google/gnostic-models v0.7.0 // indirect - github.com/grafana/grafana-app-sdk/logging v0.46.0 // indirect + github.com/grafana/grafana-app-sdk/logging v0.48.1 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/josharian/intern v1.0.0 // indirect @@ -55,12 +55,12 @@ require ( go.opentelemetry.io/otel/trace v1.38.0 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/net v0.45.0 // indirect + golang.org/x/net v0.46.0 // indirect golang.org/x/oauth2 v0.32.0 // indirect golang.org/x/sys v0.37.0 // indirect - golang.org/x/term v0.35.0 // indirect + golang.org/x/term v0.36.0 // indirect golang.org/x/text v0.30.0 // indirect - golang.org/x/time v0.13.0 // indirect + golang.org/x/time v0.14.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20251002232023-7c0ddcbb5797 // indirect gopkg.in/inf.v0 v0.9.1 // indirect k8s.io/client-go v0.34.1 // indirect diff --git a/apps/secret/go.sum b/apps/secret/go.sum index a4efed39b82..fcbebea1537 100644 --- a/apps/secret/go.sum +++ b/apps/secret/go.sum @@ -37,10 +37,10 @@ github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 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/grafana/grafana-app-sdk v0.47.0 h1:zTKV+p6zM9y+In+dAcaHczbJJsQj9WKglSBcQXMOA+8= -github.com/grafana/grafana-app-sdk v0.47.0/go.mod h1:kywXmkppq0oReUMzkjTW8Fq2EBzyN7v914jttTWnWxA= -github.com/grafana/grafana-app-sdk/logging v0.46.0 h1:JhQ+ZK5orcmM+dZ3YZdT9uCizJEFU2I6JBNUSFWvCC8= -github.com/grafana/grafana-app-sdk/logging v0.46.0/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA= +github.com/grafana/grafana-app-sdk v0.48.1 h1:bKJadWH18WCpJ+Zk8AezRFXCcZgGredRv+fRS+8zkek= +github.com/grafana/grafana-app-sdk v0.48.1/go.mod h1:5LljCz+wvmGfkQ8ZKTOfserhtXNEF0cSFthoWShvN6c= +github.com/grafana/grafana-app-sdk/logging v0.48.1 h1:veM0X5LAPyN3KsDLglWjIofndbGuf7MqnrDuDN+F/Ng= +github.com/grafana/grafana-app-sdk/logging v0.48.1/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA= github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250710134100-1f3dc0533caf h1:BBGDHffvVNLoYQlXEpbXcxE0vbpq7pm/8OWF5I+UDZg= github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250710134100-1f3dc0533caf/go.mod h1:eAlOam2uWhrsEZlOoAr7XZ9hbBP7SyYGYn31/aQAPs8= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -138,8 +138,8 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.45.0 h1:RLBg5JKixCy82FtLJpeNlVM0nrSqpCRYzVU1n8kj0tM= -golang.org/x/net v0.45.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY= +golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4= +golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= golang.org/x/oauth2 v0.32.0 h1:jsCblLleRMDrxMN29H3z/k1KliIvpLgCkE6R8FXXNgY= golang.org/x/oauth2 v0.32.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -150,14 +150,14 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/term v0.35.0 h1:bZBVKBudEyhRcajGcNc3jIfWPqV4y/Kt2XcoigOWtDQ= -golang.org/x/term v0.35.0/go.mod h1:TPGtkTLesOwf2DE8CgVYiZinHAOuy5AYUYT1lENIZnA= +golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q= +golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k= golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= -golang.org/x/time v0.13.0 h1:eUlYslOIt32DgYD6utsuUeHs4d7AsEYLuIAdg7FlYgI= -golang.org/x/time v0.13.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= +golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= +golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 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= diff --git a/apps/shorturl/go.mod b/apps/shorturl/go.mod index 19d4fdc9306..e17faafae16 100644 --- a/apps/shorturl/go.mod +++ b/apps/shorturl/go.mod @@ -3,8 +3,8 @@ module github.com/grafana/grafana/apps/shorturl go 1.25.3 require ( - github.com/grafana/grafana-app-sdk v0.47.0 - github.com/grafana/grafana-app-sdk/logging v0.46.0 + github.com/grafana/grafana-app-sdk v0.48.1 + github.com/grafana/grafana-app-sdk/logging v0.48.1 github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250915132226-585b53bc7dba k8s.io/apimachinery v0.34.1 k8s.io/klog/v2 v2.130.1 @@ -73,14 +73,14 @@ require ( go.opentelemetry.io/proto/otlp v1.7.1 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/crypto v0.42.0 // indirect - golang.org/x/net v0.45.0 // indirect + golang.org/x/crypto v0.43.0 // indirect + golang.org/x/net v0.46.0 // indirect golang.org/x/oauth2 v0.32.0 // indirect golang.org/x/sync v0.17.0 // indirect golang.org/x/sys v0.37.0 // indirect - golang.org/x/term v0.35.0 // indirect + golang.org/x/term v0.36.0 // indirect golang.org/x/text v0.30.0 // indirect - golang.org/x/time v0.13.0 // indirect + golang.org/x/time v0.14.0 // indirect gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250908214217-97024824d090 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20251002232023-7c0ddcbb5797 // indirect diff --git a/apps/shorturl/go.sum b/apps/shorturl/go.sum index 77009d338af..9fda293a4b4 100644 --- a/apps/shorturl/go.sum +++ b/apps/shorturl/go.sum @@ -56,10 +56,10 @@ github.com/grafana/authlib/types v0.0.0-20250926065801-df98203cff37 h1:qEwZ+7MbP github.com/grafana/authlib/types v0.0.0-20250926065801-df98203cff37/go.mod h1:qeWYbnWzaYGl88JlL9+DsP1GT2Cudm58rLtx13fKZdw= github.com/grafana/dskit v0.0.0-20250908063411-6b6da59b5cc4 h1:jSojuc7njleS3UOz223WDlXOinmuLAIPI0z2vtq8EgI= github.com/grafana/dskit v0.0.0-20250908063411-6b6da59b5cc4/go.mod h1:VahT+GtfQIM+o8ht2StR6J9g+Ef+C2Vokh5uuSmOD/4= -github.com/grafana/grafana-app-sdk v0.47.0 h1:zTKV+p6zM9y+In+dAcaHczbJJsQj9WKglSBcQXMOA+8= -github.com/grafana/grafana-app-sdk v0.47.0/go.mod h1:kywXmkppq0oReUMzkjTW8Fq2EBzyN7v914jttTWnWxA= -github.com/grafana/grafana-app-sdk/logging v0.46.0 h1:JhQ+ZK5orcmM+dZ3YZdT9uCizJEFU2I6JBNUSFWvCC8= -github.com/grafana/grafana-app-sdk/logging v0.46.0/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA= +github.com/grafana/grafana-app-sdk v0.48.1 h1:bKJadWH18WCpJ+Zk8AezRFXCcZgGredRv+fRS+8zkek= +github.com/grafana/grafana-app-sdk v0.48.1/go.mod h1:5LljCz+wvmGfkQ8ZKTOfserhtXNEF0cSFthoWShvN6c= +github.com/grafana/grafana-app-sdk/logging v0.48.1 h1:veM0X5LAPyN3KsDLglWjIofndbGuf7MqnrDuDN+F/Ng= +github.com/grafana/grafana-app-sdk/logging v0.48.1/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA= github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250915132226-585b53bc7dba h1:Qam8QzVRsyZN39zgZ9Vj6e8PEfswvv2McnqCZ/v5NcI= github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250915132226-585b53bc7dba/go.mod h1:rlJ/mmE0RQolOB2+HV3+bw+ZifHyPDQurBwZEus+Wm0= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 h1:8Tjv8EJ+pM1xP8mK6egEbD1OgnVTyacbefKhmbLhIhU= @@ -169,16 +169,16 @@ go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= 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/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI= -golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8= +golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04= +golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0= 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/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= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.45.0 h1:RLBg5JKixCy82FtLJpeNlVM0nrSqpCRYzVU1n8kj0tM= -golang.org/x/net v0.45.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY= +golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4= +golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= golang.org/x/oauth2 v0.32.0 h1:jsCblLleRMDrxMN29H3z/k1KliIvpLgCkE6R8FXXNgY= golang.org/x/oauth2 v0.32.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -191,20 +191,20 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/term v0.35.0 h1:bZBVKBudEyhRcajGcNc3jIfWPqV4y/Kt2XcoigOWtDQ= -golang.org/x/term v0.35.0/go.mod h1:TPGtkTLesOwf2DE8CgVYiZinHAOuy5AYUYT1lENIZnA= +golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q= +golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k= golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= -golang.org/x/time v0.13.0 h1:eUlYslOIt32DgYD6utsuUeHs4d7AsEYLuIAdg7FlYgI= -golang.org/x/time v0.13.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= +golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= +golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 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.37.0 h1:DVSRzp7FwePZW356yEAChSdNcQo6Nsp+fex1SUW09lE= -golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w= +golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ= +golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs= 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= diff --git a/go.mod b/go.mod index 70244a7d8af..8c587d67a29 100644 --- a/go.mod +++ b/go.mod @@ -96,8 +96,8 @@ require ( github.com/grafana/gofpdf v0.0.0-20250307124105-3b9c5d35577f // @grafana/sharing-squad github.com/grafana/gomemcache v0.0.0-20250318131618-74242eea118d // @grafana/grafana-operator-experience-squad github.com/grafana/grafana-api-golang-client v0.27.0 // @grafana/alerting-backend - github.com/grafana/grafana-app-sdk v0.47.0 // @grafana/grafana-app-platform-squad - github.com/grafana/grafana-app-sdk/logging v0.46.0 // @grafana/grafana-app-platform-squad + github.com/grafana/grafana-app-sdk v0.48.1 // @grafana/grafana-app-platform-squad + github.com/grafana/grafana-app-sdk/logging v0.48.1 // @grafana/grafana-app-platform-squad github.com/grafana/grafana-aws-sdk v1.2.0 // @grafana/aws-datasources github.com/grafana/grafana-azure-sdk-go/v2 v2.3.1 // @grafana/partner-datasources github.com/grafana/grafana-cloud-migration-snapshot v1.9.0 // @grafana/grafana-operator-experience-squad @@ -199,15 +199,15 @@ require ( go.uber.org/zap v1.27.0 // @grafana/identity-access-team gocloud.dev v0.42.0 // @grafana/grafana-app-platform-squad gocloud.dev/secrets/hashivault v0.42.0 // @grafana/grafana-operator-experience-squad - golang.org/x/crypto v0.42.0 // @grafana/grafana-backend-group + golang.org/x/crypto v0.43.0 // @grafana/grafana-backend-group golang.org/x/exp v0.0.0-20251002181428-27f1f14c8bb9 // @grafana/alerting-backend - golang.org/x/mod v0.28.0 // indirect; @grafana/grafana-backend-group - golang.org/x/net v0.45.0 // @grafana/oss-big-tent @grafana/partner-datasources + golang.org/x/mod v0.29.0 // indirect; @grafana/grafana-backend-group + golang.org/x/net v0.46.0 // @grafana/oss-big-tent @grafana/partner-datasources golang.org/x/oauth2 v0.32.0 // @grafana/identity-access-team golang.org/x/sync v0.17.0 // @grafana/alerting-backend golang.org/x/text v0.30.0 // @grafana/grafana-backend-group - golang.org/x/time v0.13.0 // @grafana/grafana-backend-group - golang.org/x/tools v0.37.0 // indirect; @grafana/grafana-as-code + golang.org/x/time v0.14.0 // @grafana/grafana-backend-group + golang.org/x/tools v0.38.0 // indirect; @grafana/grafana-as-code gonum.org/v1/gonum v0.16.0 // @grafana/oss-big-tent google.golang.org/api v0.235.0 // @grafana/grafana-backend-group google.golang.org/grpc v1.76.0 // @grafana/plugins-platform-backend @@ -631,8 +631,8 @@ require ( go.yaml.in/yaml/v3 v3.0.4 // indirect go4.org/netipx v0.0.0-20230125063823-8449b0a6169f // indirect golang.org/x/sys v0.37.0 // indirect - golang.org/x/telemetry v0.0.0-20250908211612-aef8a434d053 // indirect - golang.org/x/term v0.35.0 // indirect + golang.org/x/telemetry v0.0.0-20251008203120-078029d740a8 // indirect + golang.org/x/term v0.36.0 // indirect golang.org/x/tools/godoc v0.1.0-deprecated // indirect golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect diff --git a/go.sum b/go.sum index 4e4f315150e..1bd04409bb4 100644 --- a/go.sum +++ b/go.sum @@ -1625,10 +1625,10 @@ github.com/grafana/gomemcache v0.0.0-20250318131618-74242eea118d h1:oXRJlb9UjVsl github.com/grafana/gomemcache v0.0.0-20250318131618-74242eea118d/go.mod h1:j/s0jkda4UXTemDs7Pgw/vMT06alWc42CHisvYac0qw= github.com/grafana/grafana-api-golang-client v0.27.0 h1:zIwMXcbCB4n588i3O2N6HfNcQogCNTd/vPkEXTr7zX8= github.com/grafana/grafana-api-golang-client v0.27.0/go.mod h1:uNLZEmgKtTjHBtCQMwNn3qsx2mpMb8zU+7T4Xv3NR9Y= -github.com/grafana/grafana-app-sdk v0.47.0 h1:zTKV+p6zM9y+In+dAcaHczbJJsQj9WKglSBcQXMOA+8= -github.com/grafana/grafana-app-sdk v0.47.0/go.mod h1:kywXmkppq0oReUMzkjTW8Fq2EBzyN7v914jttTWnWxA= -github.com/grafana/grafana-app-sdk/logging v0.46.0 h1:JhQ+ZK5orcmM+dZ3YZdT9uCizJEFU2I6JBNUSFWvCC8= -github.com/grafana/grafana-app-sdk/logging v0.46.0/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA= +github.com/grafana/grafana-app-sdk v0.48.1 h1:bKJadWH18WCpJ+Zk8AezRFXCcZgGredRv+fRS+8zkek= +github.com/grafana/grafana-app-sdk v0.48.1/go.mod h1:5LljCz+wvmGfkQ8ZKTOfserhtXNEF0cSFthoWShvN6c= +github.com/grafana/grafana-app-sdk/logging v0.48.1 h1:veM0X5LAPyN3KsDLglWjIofndbGuf7MqnrDuDN+F/Ng= +github.com/grafana/grafana-app-sdk/logging v0.48.1/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA= github.com/grafana/grafana-aws-sdk v1.2.0 h1:LLR4/g91WBuCRwm2cbWfCREq565+GxIFe08nqqIcIuw= github.com/grafana/grafana-aws-sdk v1.2.0/go.mod h1:bBo7qOmM3f61vO+2JxTolNUph1l2TmtzmWcU9/Im+8A= github.com/grafana/grafana-azure-sdk-go/v2 v2.3.1 h1:FFcEA01tW+SmuJIuDbHOdgUBL+d7DPrZ2N4zwzPhfGk= @@ -2751,8 +2751,8 @@ golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDf golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= -golang.org/x/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI= -golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8= +golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04= +golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -2815,8 +2815,8 @@ golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/mod v0.28.0 h1:gQBtGhjxykdjY9YhZpSlZIsbnaE2+PgjfLWUQTnoZ1U= -golang.org/x/mod v0.28.0/go.mod h1:yfB/L0NOf/kmEbXjzCPOx1iK1fRutOydrCMsqRhEBxI= +golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA= +golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w= golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 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= @@ -2902,8 +2902,8 @@ golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= -golang.org/x/net v0.45.0 h1:RLBg5JKixCy82FtLJpeNlVM0nrSqpCRYzVU1n8kj0tM= -golang.org/x/net v0.45.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY= +golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4= +golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -3102,8 +3102,8 @@ golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= -golang.org/x/telemetry v0.0.0-20250908211612-aef8a434d053 h1:dHQOQddU4YHS5gY33/6klKjq7Gp3WwMyOXGNp5nzRj8= -golang.org/x/telemetry v0.0.0-20250908211612-aef8a434d053/go.mod h1:+nZKN+XVh4LCiA9DV3ywrzN4gumyCnKjau3NGb9SGoE= +golang.org/x/telemetry v0.0.0-20251008203120-078029d740a8 h1:LvzTn0GQhWuvKH/kVRS3R3bVAsdQWI7hvfLHGgh9+lU= +golang.org/x/telemetry v0.0.0-20251008203120-078029d740a8/go.mod h1:Pi4ztBfryZoJEkyFTI5/Ocsu2jXyDr6iSdgJiYE/uwE= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -3122,8 +3122,8 @@ golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0= golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8= -golang.org/x/term v0.35.0 h1:bZBVKBudEyhRcajGcNc3jIfWPqV4y/Kt2XcoigOWtDQ= -golang.org/x/term v0.35.0/go.mod h1:TPGtkTLesOwf2DE8CgVYiZinHAOuy5AYUYT1lENIZnA= +golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q= +golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -3154,8 +3154,8 @@ golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.13.0 h1:eUlYslOIt32DgYD6utsuUeHs4d7AsEYLuIAdg7FlYgI= -golang.org/x/time v0.13.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= +golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= +golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -3232,8 +3232,8 @@ golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= -golang.org/x/tools v0.37.0 h1:DVSRzp7FwePZW356yEAChSdNcQo6Nsp+fex1SUW09lE= -golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w= +golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ= +golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs= golang.org/x/tools/godoc v0.1.0-deprecated h1:o+aZ1BOj6Hsx/GBdJO/s815sqftjSnrZZwyYTHODvtk= golang.org/x/tools/godoc v0.1.0-deprecated/go.mod h1:qM63CriJ961IHWmnWa9CjZnBndniPt4a3CK0PVB9bIg= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/go.work.sum b/go.work.sum index 17c8fc4b45a..d26aabd35b9 100644 --- a/go.work.sum +++ b/go.work.sum @@ -1086,6 +1086,8 @@ github.com/grafana/grafana-app-sdk/logging v0.43.0/go.mod h1:0xrjKSGY5z+NLGuGsXQ github.com/grafana/grafana-app-sdk/logging v0.43.1/go.mod h1:0xrjKSGY5z+NLGuGsXQpxiCHR4Smu79i/CbAfdkaB1M= github.com/grafana/grafana-app-sdk/logging v0.43.2/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA= github.com/grafana/grafana-app-sdk/logging v0.45.0/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA= +github.com/grafana/grafana-app-sdk/logging v0.48.0 h1:xolkQxBlA2LQF4hprKIAeu+zUem1DigYZ6XC1TOhFJE= +github.com/grafana/grafana-app-sdk/logging v0.48.0/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA= github.com/grafana/grafana-app-sdk/plugin v0.41.0 h1:ShUvGpAVzM3UxcsfwS6l/lwW4ytDeTbCQXf8w2P8Yp8= github.com/grafana/grafana-app-sdk/plugin v0.41.0/go.mod h1:YIhimVfAqtOp3kdhxOanaSZjypVKh/bYxf9wfFfhDm0= github.com/grafana/grafana-aws-sdk v0.38.2 h1:TzQD0OpWsNjtldi5G5TLDlBRk8OyDf+B5ujcoAu4Dp0= @@ -1969,6 +1971,7 @@ golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbV golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw= golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc= +golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8= golang.org/x/exp v0.0.0-20230321023759-10a507213a29/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w= golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8/go.mod h1:CQ1k9gNrJ50XIzaKCRR2hssIjF07kZFEiieALBM/ARQ= @@ -1995,6 +1998,7 @@ golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= golang.org/x/mod v0.27.0/go.mod h1:rWI627Fq0DEoudcK+MBkNkCe0EetEaDSwJJkCcjpazc= +golang.org/x/mod v0.28.0/go.mod h1:yfB/L0NOf/kmEbXjzCPOx1iK1fRutOydrCMsqRhEBxI= golang.org/x/net v0.0.0-20190921015927-1a5e07d1ff72/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= @@ -2015,6 +2019,7 @@ golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds= golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg= golang.org/x/net v0.44.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY= +golang.org/x/net v0.45.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY= golang.org/x/oauth2 v0.19.0/go.mod h1:vYi7skDa1x015PmRRYZ7+s1cWyPgrPiSYRe4rnsexc8= golang.org/x/oauth2 v0.22.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= @@ -2045,17 +2050,20 @@ golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/telemetry v0.0.0-20240521205824-bda55230c457 h1:zf5N6UOrA487eEFacMePxjXAJctxKmyjKUsjA11Uzuk= golang.org/x/telemetry v0.0.0-20240521205824-bda55230c457/go.mod h1:pRgIJT+bRLFKnoM1ldnzKoxTIn14Yxz928LQRYYgIN0= golang.org/x/telemetry v0.0.0-20250710130107-8d8967aff50b h1:DU+gwOBXU+6bO0sEyO7o/NeMlxZxCZEvI7v+J4a1zRQ= golang.org/x/telemetry v0.0.0-20250710130107-8d8967aff50b/go.mod h1:4ZwOYna0/zsOKwuR5X/m0QFOJpSZvAxFfkQT+Erd9D4= golang.org/x/telemetry v0.0.0-20250807160809-1a19826ec488 h1:3doPGa+Gg4snce233aCWnbZVFsyFMo/dR40KK/6skyE= golang.org/x/telemetry v0.0.0-20250807160809-1a19826ec488/go.mod h1:fGb/2+tgXXjhjHsTNdVEEMZNWA0quBnfrO+AfoDSAKw= +golang.org/x/telemetry v0.0.0-20250908211612-aef8a434d053/go.mod h1:+nZKN+XVh4LCiA9DV3ywrzN4gumyCnKjau3NGb9SGoE= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g= golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ= golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw= +golang.org/x/term v0.35.0/go.mod h1:TPGtkTLesOwf2DE8CgVYiZinHAOuy5AYUYT1lENIZnA= golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= @@ -2070,6 +2078,7 @@ golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/time v0.10.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/time v0.13.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= golang.org/x/tools v0.0.0-20190424220101-1e8e1cfdf96b/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ= @@ -2085,6 +2094,7 @@ golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI= golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg= golang.org/x/tools v0.36.0/go.mod h1:WBDiHKJK8YgLHlcQPYQzNCkUxUypCaa5ZegCVutKm+s= +golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w= golang.org/x/tools/go/expect v0.1.0-deprecated h1:jY2C5HGYR5lqex3gEniOQL0r7Dq5+VGVgY1nudX5lXY= golang.org/x/tools/go/expect v0.1.0-deprecated/go.mod h1:eihoPOH+FgIqa3FpoTwguz/bVUSGBlGQU67vpBeOrBY= golang.org/x/tools/go/expect v0.1.1-deprecated h1:jpBZDwmgPhXsKZC6WhL20P4b/wmnpsEAGHaNy0n/rJM= diff --git a/pkg/aggregator/go.mod b/pkg/aggregator/go.mod index a06401c33cb..82afd586730 100644 --- a/pkg/aggregator/go.mod +++ b/pkg/aggregator/go.mod @@ -118,18 +118,18 @@ require ( go.uber.org/zap v1.27.0 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/crypto v0.42.0 // indirect + golang.org/x/crypto v0.43.0 // indirect golang.org/x/exp v0.0.0-20251002181428-27f1f14c8bb9 // indirect - golang.org/x/mod v0.28.0 // indirect - golang.org/x/net v0.45.0 // indirect + golang.org/x/mod v0.29.0 // indirect + golang.org/x/net v0.46.0 // indirect golang.org/x/oauth2 v0.32.0 // indirect golang.org/x/sync v0.17.0 // indirect golang.org/x/sys v0.37.0 // indirect - golang.org/x/telemetry v0.0.0-20250908211612-aef8a434d053 // indirect - golang.org/x/term v0.35.0 // indirect + golang.org/x/telemetry v0.0.0-20251008203120-078029d740a8 // indirect + golang.org/x/term v0.36.0 // indirect golang.org/x/text v0.30.0 // indirect - golang.org/x/time v0.13.0 // indirect - golang.org/x/tools v0.37.0 // indirect + golang.org/x/time v0.14.0 // indirect + golang.org/x/tools v0.38.0 // indirect golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250908214217-97024824d090 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20251002232023-7c0ddcbb5797 // indirect diff --git a/pkg/aggregator/go.sum b/pkg/aggregator/go.sum index b257d642ece..5d30f79835b 100644 --- a/pkg/aggregator/go.sum +++ b/pkg/aggregator/go.sum @@ -314,15 +314,15 @@ go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= 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/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI= -golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8= +golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04= +golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0= golang.org/x/exp v0.0.0-20251002181428-27f1f14c8bb9 h1:TQwNpfvNkxAVlItJf6Cr5JTsVZoC/Sj7K3OZv2Pc14A= golang.org/x/exp v0.0.0-20251002181428-27f1f14c8bb9/go.mod h1:TwQYMMnGpvZyc+JpB/UAuTNIsVJifOlSkrZkhcvpVUk= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 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.28.0 h1:gQBtGhjxykdjY9YhZpSlZIsbnaE2+PgjfLWUQTnoZ1U= -golang.org/x/mod v0.28.0/go.mod h1:yfB/L0NOf/kmEbXjzCPOx1iK1fRutOydrCMsqRhEBxI= +golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA= +golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w= 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= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -330,8 +330,8 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.45.0 h1:RLBg5JKixCy82FtLJpeNlVM0nrSqpCRYzVU1n8kj0tM= -golang.org/x/net v0.45.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY= +golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4= +golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.32.0 h1:jsCblLleRMDrxMN29H3z/k1KliIvpLgCkE6R8FXXNgY= golang.org/x/oauth2 v0.32.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= @@ -355,23 +355,23 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/telemetry v0.0.0-20250908211612-aef8a434d053 h1:dHQOQddU4YHS5gY33/6klKjq7Gp3WwMyOXGNp5nzRj8= -golang.org/x/telemetry v0.0.0-20250908211612-aef8a434d053/go.mod h1:+nZKN+XVh4LCiA9DV3ywrzN4gumyCnKjau3NGb9SGoE= -golang.org/x/term v0.35.0 h1:bZBVKBudEyhRcajGcNc3jIfWPqV4y/Kt2XcoigOWtDQ= -golang.org/x/term v0.35.0/go.mod h1:TPGtkTLesOwf2DE8CgVYiZinHAOuy5AYUYT1lENIZnA= +golang.org/x/telemetry v0.0.0-20251008203120-078029d740a8 h1:LvzTn0GQhWuvKH/kVRS3R3bVAsdQWI7hvfLHGgh9+lU= +golang.org/x/telemetry v0.0.0-20251008203120-078029d740a8/go.mod h1:Pi4ztBfryZoJEkyFTI5/Ocsu2jXyDr6iSdgJiYE/uwE= +golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q= +golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k= golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= -golang.org/x/time v0.13.0 h1:eUlYslOIt32DgYD6utsuUeHs4d7AsEYLuIAdg7FlYgI= -golang.org/x/time v0.13.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= +golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= +golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 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.37.0 h1:DVSRzp7FwePZW356yEAChSdNcQo6Nsp+fex1SUW09lE= -golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w= +golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ= +golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs= 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= diff --git a/pkg/apimachinery/go.mod b/pkg/apimachinery/go.mod index 2ba49864c50..6ed1a0f5054 100644 --- a/pkg/apimachinery/go.mod +++ b/pkg/apimachinery/go.mod @@ -45,8 +45,8 @@ require ( go.opentelemetry.io/otel/trace v1.38.0 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/crypto v0.42.0 // indirect - golang.org/x/net v0.45.0 // indirect + golang.org/x/crypto v0.43.0 // indirect + golang.org/x/net v0.46.0 // indirect golang.org/x/sync v0.17.0 // indirect golang.org/x/sys v0.37.0 // indirect golang.org/x/text v0.30.0 // indirect diff --git a/pkg/apimachinery/go.sum b/pkg/apimachinery/go.sum index 5ed8ffe6086..e5f34d1e058 100644 --- a/pkg/apimachinery/go.sum +++ b/pkg/apimachinery/go.sum @@ -96,16 +96,16 @@ go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= 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/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI= -golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8= +golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04= +golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0= 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/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= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.45.0 h1:RLBg5JKixCy82FtLJpeNlVM0nrSqpCRYzVU1n8kj0tM= -golang.org/x/net v0.45.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY= +golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4= +golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= diff --git a/pkg/apiserver/go.mod b/pkg/apiserver/go.mod index 7d6f606ecfc..c33ac35fd40 100644 --- a/pkg/apiserver/go.mod +++ b/pkg/apiserver/go.mod @@ -5,7 +5,7 @@ go 1.25.3 require ( github.com/google/go-cmp v0.7.0 github.com/grafana/authlib/types v0.0.0-20250926065801-df98203cff37 - github.com/grafana/grafana-app-sdk/logging v0.46.0 + github.com/grafana/grafana-app-sdk/logging v0.48.1 github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250514132646-acbc7b54ed9e github.com/prometheus/client_golang v1.23.2 github.com/stretchr/testify v1.11.1 @@ -84,14 +84,15 @@ require ( go.uber.org/zap v1.27.0 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/crypto v0.42.0 // indirect - golang.org/x/net v0.45.0 // indirect + golang.org/x/crypto v0.43.0 // indirect + golang.org/x/net v0.46.0 // indirect golang.org/x/oauth2 v0.32.0 // indirect golang.org/x/sync v0.17.0 // indirect golang.org/x/sys v0.37.0 // indirect - golang.org/x/term v0.35.0 // indirect + golang.org/x/term v0.36.0 // indirect golang.org/x/text v0.30.0 // indirect - golang.org/x/time v0.13.0 // indirect + golang.org/x/time v0.14.0 // indirect + golang.org/x/tools v0.38.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250908214217-97024824d090 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20251002232023-7c0ddcbb5797 // indirect google.golang.org/grpc v1.76.0 // indirect diff --git a/pkg/apiserver/go.sum b/pkg/apiserver/go.sum index 13a308081e6..5c06779f641 100644 --- a/pkg/apiserver/go.sum +++ b/pkg/apiserver/go.sum @@ -71,8 +71,8 @@ github.com/grafana/authlib/types v0.0.0-20250926065801-df98203cff37 h1:qEwZ+7MbP github.com/grafana/authlib/types v0.0.0-20250926065801-df98203cff37/go.mod h1:qeWYbnWzaYGl88JlL9+DsP1GT2Cudm58rLtx13fKZdw= github.com/grafana/dskit v0.0.0-20250908063411-6b6da59b5cc4 h1:jSojuc7njleS3UOz223WDlXOinmuLAIPI0z2vtq8EgI= github.com/grafana/dskit v0.0.0-20250908063411-6b6da59b5cc4/go.mod h1:VahT+GtfQIM+o8ht2StR6J9g+Ef+C2Vokh5uuSmOD/4= -github.com/grafana/grafana-app-sdk/logging v0.46.0 h1:JhQ+ZK5orcmM+dZ3YZdT9uCizJEFU2I6JBNUSFWvCC8= -github.com/grafana/grafana-app-sdk/logging v0.46.0/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA= +github.com/grafana/grafana-app-sdk/logging v0.48.1 h1:veM0X5LAPyN3KsDLglWjIofndbGuf7MqnrDuDN+F/Ng= +github.com/grafana/grafana-app-sdk/logging v0.48.1/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA= github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250514132646-acbc7b54ed9e h1:BTKk7LHuG1kmAkucwTA7DuMbKpKvJTKrGdBmUNO4dfQ= github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250514132646-acbc7b54ed9e/go.mod h1:IA4SOwun8QyST9c5UNs/fN37XL6boXXDvRYFcFwbipg= github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0 h1:QGLs/O40yoNK9vmy4rhUGBVyMf1lISBGtXRpsu/Qu/o= @@ -207,8 +207,8 @@ go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= 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/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI= -golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8= +golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04= +golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= @@ -219,8 +219,8 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.45.0 h1:RLBg5JKixCy82FtLJpeNlVM0nrSqpCRYzVU1n8kj0tM= -golang.org/x/net v0.45.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY= +golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4= +golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.32.0 h1:jsCblLleRMDrxMN29H3z/k1KliIvpLgCkE6R8FXXNgY= golang.org/x/oauth2 v0.32.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= @@ -237,21 +237,21 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/term v0.35.0 h1:bZBVKBudEyhRcajGcNc3jIfWPqV4y/Kt2XcoigOWtDQ= -golang.org/x/term v0.35.0/go.mod h1:TPGtkTLesOwf2DE8CgVYiZinHAOuy5AYUYT1lENIZnA= +golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q= +golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k= golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= -golang.org/x/time v0.13.0 h1:eUlYslOIt32DgYD6utsuUeHs4d7AsEYLuIAdg7FlYgI= -golang.org/x/time v0.13.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= +golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= +golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 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.37.0 h1:DVSRzp7FwePZW356yEAChSdNcQo6Nsp+fex1SUW09lE= -golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w= +golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ= +golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs= 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= diff --git a/pkg/build/go.mod b/pkg/build/go.mod index bfa8a8c4735..05b30eb9bff 100644 --- a/pkg/build/go.mod +++ b/pkg/build/go.mod @@ -13,7 +13,7 @@ require ( go.opentelemetry.io/otel v1.38.0 // indirect; @grafana/grafana-backend-group go.opentelemetry.io/otel/sdk v1.38.0 // indirect; @grafana/grafana-backend-group go.opentelemetry.io/otel/trace v1.38.0 // indirect; @grafana/grafana-backend-group - golang.org/x/net v0.45.0 // indirect; @grafana/oss-big-tent @grafana/partner-datasources + golang.org/x/net v0.46.0 // indirect; @grafana/oss-big-tent @grafana/partner-datasources golang.org/x/sync v0.17.0 // @grafana/alerting-backend golang.org/x/text v0.30.0 // indirect; @grafana/grafana-backend-group google.golang.org/grpc v1.76.0 // indirect; @grafana/plugins-platform-backend diff --git a/pkg/build/go.sum b/pkg/build/go.sum index 31387b2c885..1f40522ad51 100644 --- a/pkg/build/go.sum +++ b/pkg/build/go.sum @@ -95,8 +95,8 @@ go.opentelemetry.io/proto/otlp v1.7.1 h1:gTOMpGDb0WTBOP8JaO72iL3auEZhVmAQg4ipjOV go.opentelemetry.io/proto/otlp v1.7.1/go.mod h1:b2rVh6rfI/s2pHWNlB7ILJcRALpcNDzKhACevjI+ZnE= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= -golang.org/x/net v0.45.0 h1:RLBg5JKixCy82FtLJpeNlVM0nrSqpCRYzVU1n8kj0tM= -golang.org/x/net v0.45.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY= +golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4= +golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug= golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= diff --git a/pkg/build/wire/go.mod b/pkg/build/wire/go.mod index 88e7efbc732..421c9a62583 100644 --- a/pkg/build/wire/go.mod +++ b/pkg/build/wire/go.mod @@ -6,10 +6,10 @@ require ( github.com/google/go-cmp v0.7.0 github.com/google/subcommands v1.2.0 github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 - golang.org/x/tools v0.37.0 + golang.org/x/tools v0.38.0 ) require ( - golang.org/x/mod v0.28.0 // indirect + golang.org/x/mod v0.29.0 // indirect golang.org/x/sync v0.17.0 // indirect ) diff --git a/pkg/build/wire/go.sum b/pkg/build/wire/go.sum index e4262703495..5b0e5da275a 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.28.0 h1:gQBtGhjxykdjY9YhZpSlZIsbnaE2+PgjfLWUQTnoZ1U= -golang.org/x/mod v0.28.0/go.mod h1:yfB/L0NOf/kmEbXjzCPOx1iK1fRutOydrCMsqRhEBxI= +golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA= +golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w= golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug= golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= -golang.org/x/tools v0.37.0 h1:DVSRzp7FwePZW356yEAChSdNcQo6Nsp+fex1SUW09lE= -golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w= +golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ= +golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs= diff --git a/pkg/codegen/go.mod b/pkg/codegen/go.mod index 6489520cdea..f17dead4c51 100644 --- a/pkg/codegen/go.mod +++ b/pkg/codegen/go.mod @@ -6,10 +6,10 @@ require ( cuelang.org/go v0.11.1 github.com/dave/dst v0.27.3 github.com/grafana/codejen v0.0.4-0.20230321061741-77f656893a3d - github.com/grafana/cog v0.0.43 + github.com/grafana/cog v0.0.44 github.com/grafana/cuetsy v0.1.11 github.com/matryer/is v1.4.1 - golang.org/x/tools v0.37.0 + golang.org/x/tools v0.38.0 ) require ( @@ -47,8 +47,8 @@ require ( github.com/woodsbury/decimal128 v1.3.0 // indirect github.com/xlab/treeprint v1.2.0 // indirect github.com/yalue/merged_fs v1.3.0 // indirect - golang.org/x/mod v0.28.0 // indirect - golang.org/x/net v0.45.0 // indirect + golang.org/x/mod v0.29.0 // indirect + golang.org/x/net v0.46.0 // indirect golang.org/x/sync v0.17.0 // indirect golang.org/x/text v0.30.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/pkg/codegen/go.sum b/pkg/codegen/go.sum index e5864b3b7d9..afbaacb7ae9 100644 --- a/pkg/codegen/go.sum +++ b/pkg/codegen/go.sum @@ -31,8 +31,8 @@ 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/grafana/codejen v0.0.4-0.20230321061741-77f656893a3d h1:hrXbGJ5jgp6yNITzs5o+zXq0V5yT3siNJ+uM8LGwWKk= github.com/grafana/codejen v0.0.4-0.20230321061741-77f656893a3d/go.mod h1:zmwwM/DRyQB7pfuBjTWII3CWtxcXh8LTwAYGfDfpR6s= -github.com/grafana/cog v0.0.43 h1:6EDzJVc8hbP3+AjPnRnAK6mKfyWgqLKbi/jmiStilFk= -github.com/grafana/cog v0.0.43/go.mod h1:TDunc7TYF7EfzjwFOlC5AkMe3To/U2KqyyG3QVvrF38= +github.com/grafana/cog v0.0.44 h1:N8UP7g6XBHZXf1wY7AOOWC2HdqlTPBJPJiAZQrkf4XQ= +github.com/grafana/cog v0.0.44/go.mod h1:TDunc7TYF7EfzjwFOlC5AkMe3To/U2KqyyG3QVvrF38= github.com/grafana/cue v0.0.0-20230926092038-971951014e3f h1:TmYAMnqg3d5KYEAaT6PtTguL2GjLfvr6wnAX8Azw6tQ= github.com/grafana/cue v0.0.0-20230926092038-971951014e3f/go.mod h1:okjJBHFQFer+a41sAe2SaGm1glWS8oEb6CmJvn5Zdws= github.com/grafana/cuetsy v0.1.11 h1:I3IwBhF+UaQxRM79HnImtrAn8REGdb5M3+C4QrYHoWk= @@ -100,16 +100,16 @@ github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ= github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0= github.com/yalue/merged_fs v1.3.0 h1:qCeh9tMPNy/i8cwDsQTJ5bLr6IRxbs6meakNE5O+wyY= github.com/yalue/merged_fs v1.3.0/go.mod h1:WqqchfVYQyclV2tnR7wtRhBddzBvLVR83Cjw9BKQw0M= -golang.org/x/mod v0.28.0 h1:gQBtGhjxykdjY9YhZpSlZIsbnaE2+PgjfLWUQTnoZ1U= -golang.org/x/mod v0.28.0/go.mod h1:yfB/L0NOf/kmEbXjzCPOx1iK1fRutOydrCMsqRhEBxI= -golang.org/x/net v0.45.0 h1:RLBg5JKixCy82FtLJpeNlVM0nrSqpCRYzVU1n8kj0tM= -golang.org/x/net v0.45.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY= +golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA= +golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w= +golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4= +golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug= golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k= golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= -golang.org/x/tools v0.37.0 h1:DVSRzp7FwePZW356yEAChSdNcQo6Nsp+fex1SUW09lE= -golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w= +golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ= +golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/pkg/kinds/dashboard/dashboard_spec_gen.go b/pkg/kinds/dashboard/dashboard_spec_gen.go index e64b5a73234..2ebe81760c9 100644 --- a/pkg/kinds/dashboard/dashboard_spec_gen.go +++ b/pkg/kinds/dashboard/dashboard_spec_gen.go @@ -206,7 +206,8 @@ type Panel struct { // NewPanel creates a new Panel object. func NewPanel() *Panel { return &Panel{ - Transparent: (func(input bool) *bool { return &input })(false), + Transparent: (func(input bool) *bool { return &input })(false), + RepeatDirection: (func(input PanelRepeatDirection) *PanelRepeatDirection { return &input })(PanelRepeatDirectionH), } } diff --git a/pkg/plugins/codegen/go.mod b/pkg/plugins/codegen/go.mod index b650d20f0e4..08295065017 100644 --- a/pkg/plugins/codegen/go.mod +++ b/pkg/plugins/codegen/go.mod @@ -7,7 +7,7 @@ replace github.com/grafana/grafana/pkg/codegen => ../../codegen require ( cuelang.org/go v0.11.1 github.com/grafana/codejen v0.0.4-0.20230321061741-77f656893a3d - github.com/grafana/cog v0.0.43 + github.com/grafana/cog v0.0.44 github.com/grafana/cuetsy v0.1.11 github.com/grafana/grafana/pkg/codegen v0.0.0-20250514132646-acbc7b54ed9e ) @@ -43,11 +43,11 @@ require ( github.com/woodsbury/decimal128 v1.3.0 // indirect github.com/xlab/treeprint v1.2.0 // indirect github.com/yalue/merged_fs v1.3.0 // indirect - golang.org/x/mod v0.28.0 // indirect - golang.org/x/net v0.45.0 // indirect + golang.org/x/mod v0.29.0 // indirect + golang.org/x/net v0.46.0 // indirect golang.org/x/oauth2 v0.27.0 // indirect golang.org/x/sync v0.17.0 // indirect golang.org/x/text v0.30.0 // indirect - golang.org/x/tools v0.37.0 // indirect + golang.org/x/tools v0.38.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/pkg/plugins/codegen/go.sum b/pkg/plugins/codegen/go.sum index b4b3bda5f8f..0e065f7c4cd 100644 --- a/pkg/plugins/codegen/go.sum +++ b/pkg/plugins/codegen/go.sum @@ -30,8 +30,8 @@ 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/grafana/codejen v0.0.4-0.20230321061741-77f656893a3d h1:hrXbGJ5jgp6yNITzs5o+zXq0V5yT3siNJ+uM8LGwWKk= github.com/grafana/codejen v0.0.4-0.20230321061741-77f656893a3d/go.mod h1:zmwwM/DRyQB7pfuBjTWII3CWtxcXh8LTwAYGfDfpR6s= -github.com/grafana/cog v0.0.43 h1:6EDzJVc8hbP3+AjPnRnAK6mKfyWgqLKbi/jmiStilFk= -github.com/grafana/cog v0.0.43/go.mod h1:TDunc7TYF7EfzjwFOlC5AkMe3To/U2KqyyG3QVvrF38= +github.com/grafana/cog v0.0.44 h1:N8UP7g6XBHZXf1wY7AOOWC2HdqlTPBJPJiAZQrkf4XQ= +github.com/grafana/cog v0.0.44/go.mod h1:TDunc7TYF7EfzjwFOlC5AkMe3To/U2KqyyG3QVvrF38= github.com/grafana/cuetsy v0.1.11 h1:I3IwBhF+UaQxRM79HnImtrAn8REGdb5M3+C4QrYHoWk= github.com/grafana/cuetsy v0.1.11/go.mod h1:Ix97+CPD8ws9oSSxR3/Lf4ahU1I4Np83kjJmDVnLZvc= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -94,20 +94,20 @@ github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ= github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0= github.com/yalue/merged_fs v1.3.0 h1:qCeh9tMPNy/i8cwDsQTJ5bLr6IRxbs6meakNE5O+wyY= github.com/yalue/merged_fs v1.3.0/go.mod h1:WqqchfVYQyclV2tnR7wtRhBddzBvLVR83Cjw9BKQw0M= -golang.org/x/mod v0.28.0 h1:gQBtGhjxykdjY9YhZpSlZIsbnaE2+PgjfLWUQTnoZ1U= -golang.org/x/mod v0.28.0/go.mod h1:yfB/L0NOf/kmEbXjzCPOx1iK1fRutOydrCMsqRhEBxI= -golang.org/x/net v0.45.0 h1:RLBg5JKixCy82FtLJpeNlVM0nrSqpCRYzVU1n8kj0tM= -golang.org/x/net v0.45.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY= +golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA= +golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w= +golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4= +golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= golang.org/x/oauth2 v0.27.0 h1:da9Vo7/tDv5RH/7nZDz1eMGS/q1Vv1N/7FCrBhI9I3M= golang.org/x/oauth2 v0.27.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug= golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= -golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k= -golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= +golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k= golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= -golang.org/x/tools v0.37.0 h1:DVSRzp7FwePZW356yEAChSdNcQo6Nsp+fex1SUW09lE= -golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w= +golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ= +golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= diff --git a/pkg/promlib/go.mod b/pkg/promlib/go.mod index 52911b5ae22..0f3cdb2d3d4 100644 --- a/pkg/promlib/go.mod +++ b/pkg/promlib/go.mod @@ -97,14 +97,14 @@ require ( go.yaml.in/yaml/v2 v2.4.3 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect golang.org/x/exp v0.0.0-20251002181428-27f1f14c8bb9 // indirect - golang.org/x/mod v0.28.0 // indirect - golang.org/x/net v0.45.0 // indirect + golang.org/x/mod v0.29.0 // indirect + golang.org/x/net v0.46.0 // indirect golang.org/x/sync v0.17.0 // indirect golang.org/x/sys v0.37.0 // indirect - golang.org/x/telemetry v0.0.0-20250908211612-aef8a434d053 // indirect + golang.org/x/telemetry v0.0.0-20251008203120-078029d740a8 // indirect golang.org/x/text v0.30.0 // indirect - golang.org/x/time v0.13.0 // indirect - golang.org/x/tools v0.37.0 // indirect + golang.org/x/time v0.14.0 // indirect + golang.org/x/tools v0.38.0 // indirect golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect google.golang.org/api v0.235.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250908214217-97024824d090 // indirect diff --git a/pkg/promlib/go.sum b/pkg/promlib/go.sum index 8166d4a39bd..7b561e15375 100644 --- a/pkg/promlib/go.sum +++ b/pkg/promlib/go.sum @@ -319,20 +319,20 @@ go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= 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/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI= -golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8= +golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04= +golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0= golang.org/x/exp v0.0.0-20251002181428-27f1f14c8bb9 h1:TQwNpfvNkxAVlItJf6Cr5JTsVZoC/Sj7K3OZv2Pc14A= golang.org/x/exp v0.0.0-20251002181428-27f1f14c8bb9/go.mod h1:TwQYMMnGpvZyc+JpB/UAuTNIsVJifOlSkrZkhcvpVUk= 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.28.0 h1:gQBtGhjxykdjY9YhZpSlZIsbnaE2+PgjfLWUQTnoZ1U= -golang.org/x/mod v0.28.0/go.mod h1:yfB/L0NOf/kmEbXjzCPOx1iK1fRutOydrCMsqRhEBxI= +golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA= +golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w= 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= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.45.0 h1:RLBg5JKixCy82FtLJpeNlVM0nrSqpCRYzVU1n8kj0tM= -golang.org/x/net v0.45.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY= +golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4= +golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= golang.org/x/oauth2 v0.32.0 h1:jsCblLleRMDrxMN29H3z/k1KliIvpLgCkE6R8FXXNgY= golang.org/x/oauth2 v0.32.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -352,20 +352,20 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/telemetry v0.0.0-20250908211612-aef8a434d053 h1:dHQOQddU4YHS5gY33/6klKjq7Gp3WwMyOXGNp5nzRj8= -golang.org/x/telemetry v0.0.0-20250908211612-aef8a434d053/go.mod h1:+nZKN+XVh4LCiA9DV3ywrzN4gumyCnKjau3NGb9SGoE= +golang.org/x/telemetry v0.0.0-20251008203120-078029d740a8 h1:LvzTn0GQhWuvKH/kVRS3R3bVAsdQWI7hvfLHGgh9+lU= +golang.org/x/telemetry v0.0.0-20251008203120-078029d740a8/go.mod h1:Pi4ztBfryZoJEkyFTI5/Ocsu2jXyDr6iSdgJiYE/uwE= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k= golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= -golang.org/x/time v0.13.0 h1:eUlYslOIt32DgYD6utsuUeHs4d7AsEYLuIAdg7FlYgI= -golang.org/x/time v0.13.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= +golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= +golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 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.37.0 h1:DVSRzp7FwePZW356yEAChSdNcQo6Nsp+fex1SUW09lE= -golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w= +golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ= +golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs= 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= From f76a4885ecea667d01a5f51e5d30c8b9b32da4fa Mon Sep 17 00:00:00 2001 From: Tobias Skarhed <1438972+tskarhed@users.noreply.github.com> Date: Mon, 27 Oct 2025 10:04:37 +0100 Subject: [PATCH 015/378] PanelStateWrapper: Add error boundary name (#112841) Add error boundary name to PanelStateWrapper --- public/app/features/dashboard/dashgrid/PanelStateWrapper.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/public/app/features/dashboard/dashgrid/PanelStateWrapper.tsx b/public/app/features/dashboard/dashgrid/PanelStateWrapper.tsx index 14fa037ee55..5d1558fa7f5 100644 --- a/public/app/features/dashboard/dashgrid/PanelStateWrapper.tsx +++ b/public/app/features/dashboard/dashgrid/PanelStateWrapper.tsx @@ -597,6 +597,7 @@ export class PanelStateWrapper extends PureComponent { {(innerWidth, innerHeight) => ( <> Date: Mon, 27 Oct 2025 10:38:31 +0100 Subject: [PATCH 016/378] Chore: Replace deprecated i18next-parser (#112512) * chore: replace deprecated i18next-parser * chore: bump i18next-cli to 1.11.6 * chore: revert translation files * chore: bumps to i18next-cli 1.11.9 * Trigger build * chore: revert translations files * chore: bump i18next-cli * chore: changes after yarn i18n-extract * chore: revert translation files * chore: bump i18next-cli to 1.11.12 * chore: fix select space * chore: add i18next to packages * chore: add i18next-cli to plugin dev deps * chore: fix yarn lock --- .github/CODEOWNERS | 4 +- Makefile | 6 +- i18next.config.ts | 13 + package.json | 2 +- packages/grafana-alerting/i18next.config.ts | 12 + packages/grafana-alerting/package.json | 3 +- .../src/locales/i18next-parser.config.cjs | 12 - packages/grafana-prometheus/i18next.config.ts | 12 + packages/grafana-prometheus/package.json | 4 +- .../src/locales/en-US/grafana-prometheus.json | 12 +- .../src/locales/i18next-parser.config.cjs | 12 - packages/grafana-sql/i18next.config.ts | 12 + packages/grafana-sql/package.json | 4 +- .../src/locales/en-US/grafana-sql.json | 10 +- .../src/locales/i18next-parser.config.cjs | 12 - .../src/components/Select/SelectMenu.tsx | 4 +- .../TableInputCSV/TableInputCSV.tsx | 5 +- .../triage/scene/AlertRuleInstances.tsx | 2 +- .../migrate-to-cloud/onprem/NameCell.tsx | 2 +- .../datasource/azuremonitor/i18next.config.ts | 12 + .../grafana-azure-monitor-datasource.json | 6 +- .../locales/i18next-parser.config.cjs | 12 - .../datasource/azuremonitor/package.json | 4 +- .../datasource/mssql/i18next.config.ts | 12 + .../datasource/mssql/locales/en-US/mssql.json | 26 +- .../mssql/locales/i18next-parser.config.cjs | 12 - .../app/plugins/datasource/mssql/package.json | 4 +- public/locales/en-US/grafana.json | 185 ++--- public/locales/enterprise/i18next.config.ts | 13 + .../i18next-parser-enterprise.config.cjs | 8 - public/locales/i18next-parser.config.cjs | 20 - yarn.lock | 696 ++++++++++++++++-- 32 files changed, 878 insertions(+), 275 deletions(-) create mode 100644 i18next.config.ts create mode 100644 packages/grafana-alerting/i18next.config.ts delete mode 100644 packages/grafana-alerting/src/locales/i18next-parser.config.cjs create mode 100644 packages/grafana-prometheus/i18next.config.ts delete mode 100644 packages/grafana-prometheus/src/locales/i18next-parser.config.cjs create mode 100644 packages/grafana-sql/i18next.config.ts delete mode 100644 packages/grafana-sql/src/locales/i18next-parser.config.cjs create mode 100644 public/app/plugins/datasource/azuremonitor/i18next.config.ts delete mode 100644 public/app/plugins/datasource/azuremonitor/locales/i18next-parser.config.cjs create mode 100644 public/app/plugins/datasource/mssql/i18next.config.ts delete mode 100644 public/app/plugins/datasource/mssql/locales/i18next-parser.config.cjs create mode 100644 public/locales/enterprise/i18next.config.ts delete mode 100644 public/locales/i18next-parser-enterprise.config.cjs delete mode 100644 public/locales/i18next-parser.config.cjs diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 006bf6f476f..1568a383809 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -413,8 +413,8 @@ /crowdin.yml @grafana/grafana-frontend-platform /public/locales/ @grafanabot -/public/locales/i18next-parser.config.cjs @grafana/grafana-frontend-platform -/public/locales/i18next-parser-enterprise.config.cjs @grafana/grafana-frontend-platform +i18next.config.ts @grafana/grafana-frontend-platform +/public/locales/enterprise/i18next.config.ts @grafana/grafana-frontend-platform /public/app/core/internationalization/ @grafana/grafana-frontend-platform /e2e/ @grafana/grafana-frontend-platform /e2e-playwright/cloud-plugins-suite/ @grafana/partner-datasources diff --git a/Makefile b/Makefile index c2ac23809c5..5bf0150e047 100644 --- a/Makefile +++ b/Makefile @@ -135,14 +135,14 @@ i18n-extract-enterprise: @echo "Skipping i18n extract for Enterprise: not enabled" else i18n-extract-enterprise: - @echo "Extracting i18n strings for Enterprise" - yarn run i18next --config public/locales/i18next-parser-enterprise.config.cjs + @echo "Extracting i18n strings for Enterprise" + cd public/locales/enterprise && yarn run i18next-cli extract --sync-primary endif .PHONY: i18n-extract i18n-extract: i18n-extract-enterprise @echo "Extracting i18n strings for OSS" - yarn run i18next --config public/locales/i18next-parser.config.cjs + yarn run i18next-cli extract --sync-primary @echo "Extracting i18n strings for packages" yarn run packages:i18n-extract @echo "Extracting i18n strings for plugins" diff --git a/i18next.config.ts b/i18next.config.ts new file mode 100644 index 00000000000..0098d5e8784 --- /dev/null +++ b/i18next.config.ts @@ -0,0 +1,13 @@ +import { defineConfig } from 'i18next-cli'; + +export default defineConfig({ + locales: ['en-US'], // Only en-US is updated - Crowdin will PR with other languages + extract: { + ignore: ['public/lib/monaco/**/*', 'public/app/extensions/**/*', 'public/app/plugins/datasource/**/*'], + input: ['public/**/*.{tsx,ts}', 'packages/grafana-ui/**/*.{tsx,ts}', 'packages/grafana-data/**/*.{tsx,ts}'], + output: 'public/locales/{{language}}/{{namespace}}.json', + defaultNS: 'grafana', + functions: ['t', '*.t'], + transComponents: ['Trans'], + }, +}); diff --git a/package.json b/package.json index df96a8b37a2..c57b1326372 100644 --- a/package.json +++ b/package.json @@ -210,7 +210,7 @@ "html-loader": "5.1.0", "html-webpack-plugin": "5.6.3", "http-server": "14.1.1", - "i18next-parser": "9.3.0", + "i18next-cli": "1.11.12", "ini": "^5.0.0", "jest": "29.7.0", "jest-canvas-mock": "2.5.2", diff --git a/packages/grafana-alerting/i18next.config.ts b/packages/grafana-alerting/i18next.config.ts new file mode 100644 index 00000000000..0663f4a043e --- /dev/null +++ b/packages/grafana-alerting/i18next.config.ts @@ -0,0 +1,12 @@ +import { defineConfig } from 'i18next-cli'; + +export default defineConfig({ + locales: ['en-US'], // Only en-US is updated - Crowdin will PR with other languages + extract: { + input: ['src/**/*.{tsx,ts}'], + output: 'src/locales/{{language}}/{{namespace}}.json', + defaultNS: 'grafana-alerting', + functions: ['t', '*.t'], + transComponents: ['Trans'], + }, +}); diff --git a/packages/grafana-alerting/package.json b/packages/grafana-alerting/package.json index 167358447d0..226771138ff 100644 --- a/packages/grafana-alerting/package.json +++ b/packages/grafana-alerting/package.json @@ -59,7 +59,7 @@ "codegen": "rtk-query-codegen-openapi ./scripts/codegen.ts", "prepack": "cp package.json package.json.bak && ALIAS_PACKAGE_NAME=testing,unstable node ../../scripts/prepare-npm-package.js", "postpack": "mv package.json.bak package.json && rimraf ./unstable ./testing", - "i18n-extract": "i18next --config src/locales/i18next-parser.config.cjs" + "i18n-extract": "i18next-cli extract --sync-primary" }, "devDependencies": { "@grafana/test-utils": "workspace:*", @@ -72,6 +72,7 @@ "@types/react-dom": "18.3.5", "@types/tinycolor2": "^1", "i18next": "^25.5.2", + "i18next-cli": "1.11.12", "react": "18.3.1", "react-dom": "18.3.1", "react-redux": "^9.2.0", diff --git a/packages/grafana-alerting/src/locales/i18next-parser.config.cjs b/packages/grafana-alerting/src/locales/i18next-parser.config.cjs deleted file mode 100644 index 47939b46cc9..00000000000 --- a/packages/grafana-alerting/src/locales/i18next-parser.config.cjs +++ /dev/null @@ -1,12 +0,0 @@ -module.exports = { - locales: ['en-US'], // Only en-US is updated - Crowdin will PR with other languages - sort: true, - createOldCatalogs: false, - failOnWarnings: true, - verbose: false, - resetDefaultValueLocale: 'en-US', // Updates extracted values when they change in code - - defaultNamespace: 'grafana-alerting', - input: ['../**/*.{tsx,ts}'], - output: './src/locales/$LOCALE/$NAMESPACE.json', -}; diff --git a/packages/grafana-prometheus/i18next.config.ts b/packages/grafana-prometheus/i18next.config.ts new file mode 100644 index 00000000000..8c5a67d2521 --- /dev/null +++ b/packages/grafana-prometheus/i18next.config.ts @@ -0,0 +1,12 @@ +import { defineConfig } from 'i18next-cli'; + +export default defineConfig({ + locales: ['en-US'], // Only en-US is updated - Crowdin will PR with other languages + extract: { + input: ['src/**/*.{tsx,ts}'], + output: 'src/locales/{{language}}/{{namespace}}.json', + defaultNS: 'grafana-prometheus', + functions: ['t', '*.t'], + transComponents: ['Trans'], + }, +}); diff --git a/packages/grafana-prometheus/package.json b/packages/grafana-prometheus/package.json index 772df81b58f..c7413cdd517 100644 --- a/packages/grafana-prometheus/package.json +++ b/packages/grafana-prometheus/package.json @@ -33,7 +33,7 @@ "build": "tsc -p ./tsconfig.build.json && rollup -c rollup.config.ts --configPlugin esbuild", "bundle": "rollup -c rollup.config.ts --configPlugin esbuild", "clean": "rimraf ./dist ./compiled ./package.tgz", - "i18n-extract": "i18next --config src/locales/i18next-parser.config.cjs", + "i18n-extract": "i18next-cli extract --sync-primary", "typecheck": "tsc --emitDeclarationOnly false --noEmit", "prepack": "cp package.json package.json.bak && node ../../scripts/prepare-npm-package.js", "postpack": "mv package.json.bak package.json" @@ -91,7 +91,7 @@ "@types/pluralize": "^0.0.33", "@types/prismjs": "1.26.5", "esbuild": "0.25.8", - "i18next-parser": "9.3.0", + "i18next-cli": "1.11.12", "jest": "29.7.0", "jest-environment-jsdom": "29.7.0", "react": "18.3.1", diff --git a/packages/grafana-prometheus/src/locales/en-US/grafana-prometheus.json b/packages/grafana-prometheus/src/locales/en-US/grafana-prometheus.json index 58c601d9514..d21b1c2d693 100644 --- a/packages/grafana-prometheus/src/locales/en-US/grafana-prometheus.json +++ b/packages/grafana-prometheus/src/locales/en-US/grafana-prometheus.json @@ -85,9 +85,9 @@ "tooltip-classic-query": "The original implementation of the Prometheus variable query editor. Enter a string with the correct query type and parameters as described in these docs. For example, {{exampleQuery}}.", "tooltip-label": "Returns a list of label values for the label name in all metrics unless the metric is specified.", "tooltip-metric-regex": "Returns a list of label names, optionally filtering by specified metric regex.", - "tooltip-query": "Returns a list of Prometheus query results for the query. This can include Prometheus functions, i.e.{{exampleQuery}}.", + "tooltip-query": "Returns a list of Prometheus query results for the query. This can include Prometheus functions, i.e. {{exampleQuery}}.", "tooltip-query-type": "The Prometheus data source plugin provides the following query types for template variables.", - "tooltip-series-query": "Enter a metric with labels, only a metric or only labels, i.e.{{example1}}, {{example2}}, or {{example3}}. Returns a list of time series associated with the entered data." + "tooltip-series-query": "Enter a metric with labels, only a metric or only labels, i.e. {{example1}}, {{example2}}, or {{example3}}. Returns a list of time series associated with the entered data." }, "selector-actions": { "aria-label-selector": "selector", @@ -175,16 +175,16 @@ "label-scrape-interval": "Scrape interval", "label-series-limit": "Series limit", "label-use-series-endpoint": "Use series endpoint", - "more-info": "For more information on configuring prometheus type and version in data sources, see the <2>provisioning documentation.", + "more-info": "For more information on configuring prometheus type and version in data sources, see the <2>provisioning documentation .", "placeholder-example-maxsourceresolutionmtimeout": "Example: {{example}}", "title-interval-behaviour": "Interval behaviour", "title-other": "Other", "title-performance": "Performance", "title-query-editor": "Query editor", "tooltip-cache-level": "Sets the browser caching level for editor queries. Higher cache settings are recommended for high cardinality data sources.", - "tooltip-custom-query-parameters": "Add custom parameters to the Prometheus query URL. For example {{example1}}, {{example2}}, {{example3}}, or{{example4}}. Multiple parameters should be concatenated together with {{concatenationChar}}.", + "tooltip-custom-query-parameters": "Add custom parameters to the Prometheus query URL. For example {{example1}}, {{example2}}, {{example3}}, or {{example4}}. Multiple parameters should be concatenated together with {{concatenationChar}}.", "tooltip-default-editor": "Set default editor option for all users of this data source.", - "tooltip-disable-metrics-lookup": "Checking this option will disable the metrics chooser and metric/label support in the query field's autocomplete. This helps if you have performance issues with bigger Prometheus instances. ", + "tooltip-disable-metrics-lookup": "Checking this option will disable the metrics chooser and metric/label support in the query field's autocomplete. This helps if you have performance issues with bigger Prometheus instances.", "tooltip-disable-recording-rules-beta": "This feature will disable recording rules. Turn this on to improve dashboard performance", "tooltip-http-method": "You can use either POST or GET HTTP method to query your Prometheus data source. POST is the recommended method as it allows bigger queries. Change this to GET if you have a Prometheus version older than 2.1 or if POST requests are restricted in your network.", "tooltip-incremental-querying-beta": "This feature will change the default behavior of relative queries to always request fresh data from the prometheus instance, instead query results will be cached, and only new records are requested. Turn this on to decrease database and network load.", @@ -479,7 +479,7 @@ "aria-label-selector": "selector" }, "results-table": { - "content-descriptive-type": "When creating a {{descriptiveType}}, Prometheus exposes multiple series with the type counter. ", + "content-descriptive-type": "When creating a {{descriptiveType}}, Prometheus exposes multiple series with the type counter.", "description": "Description", "message-expand-label-filters": "There are no metrics found. Try to expand your label filters.", "message-expand-search": "There are no metrics found. Try to expand your search and filters.", diff --git a/packages/grafana-prometheus/src/locales/i18next-parser.config.cjs b/packages/grafana-prometheus/src/locales/i18next-parser.config.cjs deleted file mode 100644 index 2e3161f3761..00000000000 --- a/packages/grafana-prometheus/src/locales/i18next-parser.config.cjs +++ /dev/null @@ -1,12 +0,0 @@ -module.exports = { - locales: ['en-US'], // Only en-US is updated - Crowdin will PR with other languages - sort: true, - createOldCatalogs: false, - failOnWarnings: true, - verbose: false, - resetDefaultValueLocale: 'en-US', // Updates extracted values when they change in code - - defaultNamespace: 'grafana-prometheus', - input: ['../**/*.{tsx,ts}'], - output: './src/locales/$LOCALE/$NAMESPACE.json', -}; diff --git a/packages/grafana-sql/i18next.config.ts b/packages/grafana-sql/i18next.config.ts new file mode 100644 index 00000000000..30e4acf0e63 --- /dev/null +++ b/packages/grafana-sql/i18next.config.ts @@ -0,0 +1,12 @@ +import { defineConfig } from 'i18next-cli'; + +export default defineConfig({ + locales: ['en-US'], // Only en-US is updated - Crowdin will PR with other languages + extract: { + input: ['src/**/*.{tsx,ts}'], + output: 'src/locales/{{language}}/{{namespace}}.json', + defaultNS: 'grafana-sql', + functions: ['t', '*.t'], + transComponents: ['Trans'], + }, +}); diff --git a/packages/grafana-sql/package.json b/packages/grafana-sql/package.json index 4d97947a200..2ea7c0f82c7 100644 --- a/packages/grafana-sql/package.json +++ b/packages/grafana-sql/package.json @@ -12,7 +12,7 @@ "main": "src/index.ts", "scripts": { "typecheck": "tsc --emitDeclarationOnly false --noEmit", - "i18n-extract": "i18next --config src/locales/i18next-parser.config.cjs" + "i18n-extract": "i18next-cli extract --sync-primary" }, "dependencies": { "@emotion/css": "11.13.5", @@ -48,7 +48,7 @@ "@types/react-virtualized-auto-sizer": "1.0.8", "@types/systemjs": "6.15.3", "@types/uuid": "10.0.0", - "i18next-parser": "9.3.0", + "i18next-cli": "1.11.12", "jest": "^29.6.4", "ts-jest": "29.4.0", "ts-node": "10.9.2", diff --git a/packages/grafana-sql/src/locales/en-US/grafana-sql.json b/packages/grafana-sql/src/locales/en-US/grafana-sql.json index bc986568f18..f2a06d8b983 100644 --- a/packages/grafana-sql/src/locales/en-US/grafana-sql.json +++ b/packages/grafana-sql/src/locales/en-US/grafana-sql.json @@ -11,10 +11,10 @@ }, "connection-limits": { "auto-max-idle": "Auto max idle", - "content-auto-max-idle": "If enabled, automatically set the number of <1>Maximum idle connections to the same value as<3> Max open connections. If the number of maximum open connections is not set it will be set to the default ({{defaultMaxIdle}}).", - "content-max-idle": "The maximum number of connections in the idle connection pool.If <1>Max open connections is greater than 0 but less than the <3>Max idle connections, then the <5>Max idle connections will be reduced to match the <8>Max open connections limit. If set to 0, no idle connections are retained.", + "content-auto-max-idle": "If enabled, automatically set the number of Maximum idle connections to the same value as Max open connections. If the number of maximum open connections is not set it will be set to the default ({{defaultMaxIdle}}).", + "content-max-idle": "The maximum number of connections in the idle connection pool.If Max open connections is greater than 0 but less than the Max idle connections, then the Max idle connections will be reduced to match the Max open connections limit. If set to 0, no idle connections are retained.", "content-max-lifetime": "The maximum amount of time in seconds a connection may be reused. If set to 0, connections are reused forever.", - "content-max-open": "The maximum number of open connections to the database. If <1>Max idle connections is greater than 0 and the <3>Max open connections is less than <5>Max idle connections, then<7>Max idle connections will be reduced to match the <9>Max open connections limit. If set to 0, there is no limit on the number of open connections.", + "content-max-open": "The maximum number of open connections to the database. If Max idle connections is greater than 0 and the Max open connections is less than Max idle connections, then Max idle connections will be reduced to match the Max open connections limit. If set to 0, there is no limit on the number of open connections.", "max-idle": "Max idle", "max-lifetime": "Max lifetime", "max-open": "Max open", @@ -54,7 +54,7 @@ } }, "query-header": { - "content-invalid-query": "Your query is invalid. Check below for details. <1>However, you can still run this query.", + "content-invalid-query": "Your query is invalid. Check below for details.
However, you can still run this query.", "editor-modes": { "label-builder": "Builder", "label-code": "Code" @@ -76,7 +76,7 @@ "tooltip-format-query": "Format query" }, "query-validator": { - "query-will-process": "<0> This query will process <2>{{bytes}} when run.", + "query-will-process": "<0> This query will process {{bytes}} when run.", "validating-query": "Validating query..." }, "raw-editor": { diff --git a/packages/grafana-sql/src/locales/i18next-parser.config.cjs b/packages/grafana-sql/src/locales/i18next-parser.config.cjs deleted file mode 100644 index 9ab1f779724..00000000000 --- a/packages/grafana-sql/src/locales/i18next-parser.config.cjs +++ /dev/null @@ -1,12 +0,0 @@ -module.exports = { - locales: ['en-US'], // Only en-US is updated - Crowdin will PR with other languages - sort: true, - createOldCatalogs: false, - failOnWarnings: true, - verbose: false, - resetDefaultValueLocale: 'en-US', // Updates extracted values when they change in code - - defaultNamespace: 'grafana-sql', - input: ['../**/*.{tsx,ts}'], - output: './src/locales/$LOCALE/$NAMESPACE.json', -}; diff --git a/packages/grafana-ui/src/components/Select/SelectMenu.tsx b/packages/grafana-ui/src/components/Select/SelectMenu.tsx index bb12cf4dcfb..bfb8b17a1c1 100644 --- a/packages/grafana-ui/src/components/Select/SelectMenu.tsx +++ b/packages/grafana-ui/src/components/Select/SelectMenu.tsx @@ -245,8 +245,8 @@ const ToggleAllOption = ({ innerProps: {}, children: ( <> - Selected - {`(${selectedCount ?? 0})`} + Selected + {` (${selectedCount ?? 0})`} ), })} diff --git a/packages/grafana-ui/src/components/TableInputCSV/TableInputCSV.tsx b/packages/grafana-ui/src/components/TableInputCSV/TableInputCSV.tsx index 98cc9447030..57c3b9943e4 100644 --- a/packages/grafana-ui/src/components/TableInputCSV/TableInputCSV.tsx +++ b/packages/grafana-ui/src/components/TableInputCSV/TableInputCSV.tsx @@ -88,9 +88,10 @@ export class UnThemedTableInputCSV extends PureComponent { return ( - Rows:{{ rows }}, Columns:{{ columns }}   - + Rows:{{ rows }}, Columns:{{ columns }} +   + ); })} diff --git a/public/app/features/alerting/unified/triage/scene/AlertRuleInstances.tsx b/public/app/features/alerting/unified/triage/scene/AlertRuleInstances.tsx index 6ac104d2a76..e08455a3430 100644 --- a/public/app/features/alerting/unified/triage/scene/AlertRuleInstances.tsx +++ b/public/app/features/alerting/unified/triage/scene/AlertRuleInstances.tsx @@ -72,7 +72,7 @@ export function AlertRuleInstances({ ruleUID, depth = 0 }: AlertRuleInstancesPro depth={depth} >
- No alert instances found for rule: {ruleUID} + No alert instances found for rule: {{ ruleUID }}
); diff --git a/public/app/features/migrate-to-cloud/onprem/NameCell.tsx b/public/app/features/migrate-to-cloud/onprem/NameCell.tsx index 0745b59ec99..c35aeb6a91a 100644 --- a/public/app/features/migrate-to-cloud/onprem/NameCell.tsx +++ b/public/app/features/migrate-to-cloud/onprem/NameCell.tsx @@ -176,7 +176,7 @@ function LibraryElementInfo({ data }: { data: ResourceTableItem }) { - Library Element {uid} + Library Element {{ uid }} ); diff --git a/public/app/plugins/datasource/azuremonitor/i18next.config.ts b/public/app/plugins/datasource/azuremonitor/i18next.config.ts new file mode 100644 index 00000000000..4c64b679b88 --- /dev/null +++ b/public/app/plugins/datasource/azuremonitor/i18next.config.ts @@ -0,0 +1,12 @@ +import { defineConfig } from 'i18next-cli'; + +export default defineConfig({ + locales: ['en-US'], // Only en-US is updated - Crowdin will PR with other languages + extract: { + input: ['**/*.{tsx,ts}'], + output: 'locales/{{language}}/{{namespace}}.json', + defaultNS: 'grafana-azure-monitor-datasource', + functions: ['t', '*.t'], + transComponents: ['Trans'], + }, +}); diff --git a/public/app/plugins/datasource/azuremonitor/locales/en-US/grafana-azure-monitor-datasource.json b/public/app/plugins/datasource/azuremonitor/locales/en-US/grafana-azure-monitor-datasource.json index 46adc53413c..1c84f68f612 100644 --- a/public/app/plugins/datasource/azuremonitor/locales/en-US/grafana-azure-monitor-datasource.json +++ b/public/app/plugins/datasource/azuremonitor/locales/en-US/grafana-azure-monitor-datasource.json @@ -13,11 +13,11 @@ "label-resource-group": "Resource Group", "label-resource-name": "Resource Name", "label-resource-number": "Resource {{resourceNum}}", - "label-resource-uri": "Resource URI(s) ", + "label-resource-uri": "Resource URI(s)", "label-subscription": "Subscription", "placeholder-resource-name": "name", "tooltip-region": "The code region of the resource. Optional for one resource but mandatory when selecting multiple ones.", - "tooltip-resource-uri": "Manually edit the <2>resource uri. Supports the use of multiple template variables (ex: /subscriptions/$subId/resourceGroups/$rg)" + "tooltip-resource-uri": "Manually edit the <2>resource uri . Supports the use of multiple template variables (ex: /subscriptions/$subId/resourceGroups/$rg)" }, "aggregate-item": { "aria-label-aggregate-function": "Aggregate function", @@ -68,7 +68,7 @@ }, "basic-logs-toggle": { "aria-label-enable-basic-logs": "Basic Logs", - "description-basic-logs": "Enabling this feature incurs Azure Monitor per-query costs on dashboard panels that query tables configured for <2>Basic Logs.", + "description-basic-logs": "Enabling this feature incurs Azure Monitor per-query costs on dashboard panels that query tables configured for <2>Basic Logs .", "label-enable-basic-logs": "Enable Basic Logs" }, "config-editor": { diff --git a/public/app/plugins/datasource/azuremonitor/locales/i18next-parser.config.cjs b/public/app/plugins/datasource/azuremonitor/locales/i18next-parser.config.cjs deleted file mode 100644 index 86be22e81b0..00000000000 --- a/public/app/plugins/datasource/azuremonitor/locales/i18next-parser.config.cjs +++ /dev/null @@ -1,12 +0,0 @@ -module.exports = { - locales: ['en-US'], // Only en-US is updated - Crowdin will PR with other languages - sort: true, - createOldCatalogs: false, - failOnWarnings: true, - verbose: false, - resetDefaultValueLocale: 'en-US', // Updates extracted values when they change in code - - defaultNamespace: 'grafana-azure-monitor-datasource', - input: ['../**/*.{tsx,ts}'], - output: './locales/$LOCALE/$NAMESPACE.json', -}; diff --git a/public/app/plugins/datasource/azuremonitor/package.json b/public/app/plugins/datasource/azuremonitor/package.json index a51ade7cbe8..363460331ab 100644 --- a/public/app/plugins/datasource/azuremonitor/package.json +++ b/public/app/plugins/datasource/azuremonitor/package.json @@ -38,7 +38,7 @@ "@types/prismjs": "1.26.5", "@types/react": "18.3.18", "@types/react-dom": "18.3.5", - "i18next-parser": "9.3.0", + "i18next-cli": "1.11.12", "jest": "29.7.0", "react-select-event": "5.5.1", "ts-node": "10.9.2", @@ -52,7 +52,7 @@ "build": "NODE_OPTIONS='--experimental-strip-types --no-warnings=ExperimentalWarning' webpack -c ./webpack.config.ts --env production", "build:commit": "NODE_OPTIONS='--experimental-strip-types --no-warnings=ExperimentalWarning' webpack -c ./webpack.config.ts --env production --env commit=$(git rev-parse --short HEAD)", "dev": "NODE_OPTIONS='--experimental-strip-types --no-warnings=ExperimentalWarning' webpack -w -c ./webpack.config.ts --env development", - "i18n-extract": "i18next --config locales/i18next-parser.config.cjs", + "i18n-extract": "i18next-cli extract --sync-primary", "test": "jest --watch --onlyChanged", "test:ci": "jest --maxWorkers 4" }, diff --git a/public/app/plugins/datasource/mssql/i18next.config.ts b/public/app/plugins/datasource/mssql/i18next.config.ts new file mode 100644 index 00000000000..f3cce99ff02 --- /dev/null +++ b/public/app/plugins/datasource/mssql/i18next.config.ts @@ -0,0 +1,12 @@ +import { defineConfig } from 'i18next-cli'; + +export default defineConfig({ + locales: ['en-US'], // Only en-US is updated - Crowdin will PR with other languages + extract: { + input: ['**/*.{tsx,ts}'], + output: 'locales/{{language}}/{{namespace}}.json', + defaultNS: 'mssql', + functions: ['t', '*.t'], + transComponents: ['Trans'], + }, +}); diff --git a/public/app/plugins/datasource/mssql/locales/en-US/mssql.json b/public/app/plugins/datasource/mssql/locales/en-US/mssql.json index 7311bb0add3..4e20b5d10c1 100644 --- a/public/app/plugins/datasource/mssql/locales/en-US/mssql.json +++ b/public/app/plugins/datasource/mssql/locales/en-US/mssql.json @@ -41,7 +41,7 @@ "fillvalue": "by setting fillvalue Grafana will fill in missing values according to the interval. fillvalue can be either a literal value, {{null}} or {{previous}}; {{previous}} will fill in the previous seen value or {{null}} if none has been seen yet", "macros": "Macros:", "optional": "Optional:", - "optional-tip": "return column named <1>{{columnName}} to represent the series name.", + "optional-tip": "return column named {{columnName}} to represent the series name.", "optional-tip-2": "If multiple value columns are returned the {{columnName}} column is used as prefix.", "optional-tip-3": "If no column named {{columnName}} is found the column name of the value column is used as series name", "resultsets-time-sorted": "Resultsets of time series queries need to be sorted by time.", @@ -56,20 +56,20 @@ "configuration-editor": { "body-user-permission": "The database user should only be granted {{permissionType}} permissions on the specified database and tables you want to query. Grafana does not validate that queries are safe so queries can contain any SQL statement. For example, statements like <3>{{example1}} and <5>{{example2}} would be executed. To protect against this we <7>highly recommend you create a specific MS SQL user with restricted permissions. Check out the <10>Microsoft SQL Server Data Source Docs for more information.", "description-additional-settings": "Additional settings are optional settings that can be configured for more control over your data source. This includes connection limits, connection timeout, group-by time interval, and Secure Socks Proxy.", - "description-auth-type-azure-auth": "<0>Azure Authentication Securely authenticate and access Azure resources and applications using Azure AD credentials - Managed Service Identity and Client Secret Credentials are supported.", - "description-auth-type-credential-cache": "<0>Windows AD: Credential cache Windows Active Directory - Sign on for domain user via credential cache.", - "description-auth-type-credential-cache-file": "<0>Windows AD: Credential cache file Windows Active Directory - Sign on for domain user via credential cache file.", - "description-auth-type-keytab": "<0>Windows AD: Keytab Windows Active Directory - Sign on for domain user via keytab file.", - "description-auth-type-sql-server": "<0>SQL Server Authentication This is the default mechanism to connect to MS SQL Server. Enter the SQL Server Authentication login or the Windows Authentication login in the DOMAIN\\User format.", - "description-auth-type-username-password": "<0>Windows AD: Username + password Windows Active Directory - Sign on for domain user via username/password.", - "description-auth-type-windows-auth": "<0>Windows Authentication Windows Integrated Security - single sign on for users who are already logged onto Windows and have enabled this option for MS SQL Server.", + "description-auth-type-azure-auth": "Azure Authentication Securely authenticate and access Azure resources and applications using Azure AD credentials - Managed Service Identity and Client Secret Credentials are supported.", + "description-auth-type-credential-cache": "Windows AD: Credential cache Windows Active Directory - Sign on for domain user via credential cache.", + "description-auth-type-credential-cache-file": "Windows AD: Credential cache file Windows Active Directory - Sign on for domain user via credential cache file.", + "description-auth-type-keytab": "Windows AD: Keytab Windows Active Directory - Sign on for domain user via keytab file.", + "description-auth-type-sql-server": "SQL Server Authentication This is the default mechanism to connect to MS SQL Server. Enter the SQL Server Authentication login or the Windows Authentication login in the DOMAIN\\User format.", + "description-auth-type-username-password": "Windows AD: Username + password Windows Active Directory - Sign on for domain user via username/password.", + "description-auth-type-windows-auth": "Windows Authentication Windows Integrated Security - single sign on for users who are already logged onto Windows and have enabled this option for MS SQL Server.", "description-connection-timeout": "The number of seconds to wait before canceling the request when connecting to the database. The default is <1>{{defaultTimeout}}, meaning no timeout.", "description-encrypt": "Determines whether or to which extent a secure SSL TCP/IP connection will be negotiated with the server.", - "description-encrypt-disable": "<0>{{encryptionValue}} - Data sent between client and server is not encrypted.", - "description-encrypt-false": "<0>{{encryptionValue}} - Data sent between client and server is not encrypted beyond the login packet. (default)", + "description-encrypt-disable": "{{encryptionValue}} - Data sent between client and server is not encrypted.", + "description-encrypt-false": "{{encryptionValue}} - Data sent between client and server is not encrypted beyond the login packet. (default)", "description-encrypt-older-version": "If you're using an older version of Microsoft SQL Server like 2008 and 2008R2 you may need to disable encryption to be able to connect.", - "description-encrypt-true": "<0>{{encryptionValue}} - Data sent between client and server is encrypted.", - "description-min-interval": "A lower limit for the auto group by time interval. Recommended to be set to write frequency, for example<1>{{exampleInterval}} if your data is written every minute.", + "description-encrypt-true": "{{encryptionValue}} - Data sent between client and server is encrypted.", + "description-min-interval": "A lower limit for the auto group by time interval. Recommended to be set to write frequency, for example <1>{{exampleInterval}} if your data is written every minute.", "description-tls-cert": "Path to file containing the public key certificate of the CA that signed the SQL Server certificate. Needed when the server certificate is self signed.", "label-auth-settings": "Azure Authentication Settings", "label-auth-type": "Authentication Type", @@ -104,7 +104,7 @@ }, "kerberos-advanced-settings": { "description-dns-lookup-kdc": "Indicate whether DNS `SRV` records should be used to locate the KDCs and other servers for a realm. The default is <1>{{default}}.", - "description-krb5-config-file-path": "The path to the configuration file for the <2>MIT krb5 package. The default is <4>{{default}}.", + "description-krb5-config-file-path": "The path to the configuration file for the <2>MIT krb5 package . The default is <4>{{default}}.", "description-udp-preference-limit": "The default is <1>{{default}} and means always use TCP and is optional.", "label-dns-lookup-kdc": "DNS Lookup KDC", "label-krb5-config-file-path": "krb5 config file path", diff --git a/public/app/plugins/datasource/mssql/locales/i18next-parser.config.cjs b/public/app/plugins/datasource/mssql/locales/i18next-parser.config.cjs deleted file mode 100644 index 26140245bab..00000000000 --- a/public/app/plugins/datasource/mssql/locales/i18next-parser.config.cjs +++ /dev/null @@ -1,12 +0,0 @@ -module.exports = { - locales: ['en-US'], // Only en-US is updated - Crowdin will PR with other languages - sort: true, - createOldCatalogs: false, - failOnWarnings: true, - verbose: false, - resetDefaultValueLocale: 'en-US', // Updates extracted values when they change in code - - defaultNamespace: 'mssql', - input: ['../**/*.{tsx,ts}'], - output: './locales/$LOCALE/$NAMESPACE.json', -}; diff --git a/public/app/plugins/datasource/mssql/package.json b/public/app/plugins/datasource/mssql/package.json index d8240f42af8..d69d7c10eb0 100644 --- a/public/app/plugins/datasource/mssql/package.json +++ b/public/app/plugins/datasource/mssql/package.json @@ -26,7 +26,7 @@ "@types/lodash": "4.17.20", "@types/node": "22.17.0", "@types/react": "18.3.18", - "i18next-parser": "9.3.0", + "i18next-cli": "1.11.12", "ts-node": "10.9.2", "typescript": "5.9.2", "webpack": "5.101.0" @@ -38,7 +38,7 @@ "build": "NODE_OPTIONS='--experimental-strip-types --no-warnings=ExperimentalWarning' webpack -c ./webpack.config.ts --env production", "build:commit": "NODE_OPTIONS='--experimental-strip-types --no-warnings=ExperimentalWarning' webpack -c ./webpack.config.ts --env production --env commit=$(git rev-parse --short HEAD)", "dev": "NODE_OPTIONS='--experimental-strip-types --no-warnings=ExperimentalWarning' webpack -w -c ./webpack.config.ts --env development", - "i18n-extract": "i18next --config locales/i18next-parser.config.cjs" + "i18n-extract": "i18next-cli extract --sync-primary" }, "packageManager": "yarn@4.10.3" } diff --git a/public/locales/en-US/grafana.json b/public/locales/en-US/grafana.json index a624584d7e1..050e39bb67b 100644 --- a/public/locales/en-US/grafana.json +++ b/public/locales/en-US/grafana.json @@ -108,7 +108,7 @@ "dismiss": "Dismiss", "heading": "Enterprise authentication", "learn-more-link": "Learn more", - "text": "Manage users, teams, and permissions automatically with <1>SAML, <3>SCIM, <6>LDAP, and <8>RBAC — available in Grafana Cloud and Enterprise." + "text": "Manage users, teams, and permissions automatically with SAML, SCIM, LDAP, and RBAC — available in Grafana Cloud and Enterprise." }, "feature-listing": { "title-auditing": "Auditing", @@ -209,7 +209,7 @@ "title-delete": "Delete" }, "orgs": { - "delete-body": "Are you sure you want to delete '{{deleteOrgName}}'?<3> <5>All dashboards for this organization will be removed!", + "delete-body": "Are you sure you want to delete '{{deleteOrgName}}'?
<5>All dashboards for this organization will be removed!", "id-header": "ID", "name-header": "Name", "new-org-button": "New org" @@ -719,6 +719,7 @@ "title-annotations": "Annotations" }, "link-dashboard-and-panel": "Link dashboard and panel", + "placeholder-value-input": "Enter a {{key}}...", "placeholder-value-input-default": "Enter custom annotation content..." }, "bulk-actions": { @@ -1144,7 +1145,7 @@ "title-something-wrong-trying-fetch-group-details": "Something went wrong when trying to fetch group details" }, "evaluation-interval-limit-exceeded": { - "body-minimum-interval": "A minimum evaluation interval of <1>{{minInterval}} has been configured in Grafana.<3>Please contact the administrator to configure a lower interval.", + "body-minimum-interval": "A minimum evaluation interval of {{minInterval}} has been configured in Grafana.
Please contact the administrator to configure a lower interval.", "title-global-evaluation-interval-limit-exceeded": "Global evaluation interval limit exceeded" }, "existing-rule-editor": { @@ -1292,7 +1293,7 @@ "resolved": "Resolved" } }, - "review-alert-payload": " Review alert data to add to the payload:", + "review-alert-payload": "Review alert data to add to the payload:", "title-add-custom-alerts": "Add custom alerts" }, "get-alert-suggestions": { @@ -1416,7 +1417,7 @@ "title-add-folder-and-labels": "Add folder and labels" }, "grafana-managed-rule-type": { - "description": "Supports multiple data sources of any kind.<1>Transform data with expressions." + "description": "Supports multiple data sources of any kind.
Transform data with expressions." }, "grafana-modify-export": { "body-invalid-rule-id": "The rule UID in the page URL is invalid. Please check the URL and try again.", @@ -1853,7 +1854,7 @@ "aria-label-new": "new" }, "mimir-flavored-type": { - "description": "Use a Mimir, Loki or Cortex datasource.<1>Expressions are not supported." + "description": "Use a Mimir, Loki or Cortex datasource.
Expressions are not supported." }, "min-interval-option": { "label-interval": "Interval", @@ -2082,7 +2083,7 @@ "warning-1": "Deleting this notification policy will permanently remove it.", "warning-2": "Are you sure you want to delete this policy?" }, - "filter-description": "Filter notification policies by using a comma separated list of matchers, e.g.:<1>severity=critical, region=EMEA", + "filter-description": "Filter notification policies by using a comma separated list of matchers, e.g.: <1>severity=critical, region=EMEA", "generated-policies": "Auto-generated policies", "matchers": "Matchers", "metadata": { @@ -2128,7 +2129,8 @@ "conflict": "The notification policy tree has been updated by another user.", "error-code": "Error message: \"{{error}}\"", "routes": { - "conflictingMatchers": "Cannot add or update route: matchers conflict with an external routing tree if we merged matchers {{-matchers}}. This would make the route unreachable." + "conflictingMatchers": "Cannot add or update route: matchers conflict with an external routing tree if we merged matchers {{-matchers}}. This would make the route unreachable.", + "unknownMatchers": "" }, "suffix": "Please refresh the page and try again.", "title": "Failed to add or update notification policy" @@ -2244,7 +2246,7 @@ "error-no-query-editor": "Could not load query editor due to: {{errorMessage}}" }, "recording-rule-type": { - "description": "Precompute expressions.<1>Should be combined with an alert rule." + "description": "Precompute expressions.
Should be combined with an alert rule." }, "recording-rules": { "description-target-data-source": "The Prometheus data source to store recording rules in", @@ -2257,7 +2259,7 @@ }, "redirect-to-clone-rule": { "body-evaluation-group": "You will need to set a new evaluation group for the copied rule because the original one has been provisioned and cannot be used for rules created in the UI.", - "body-not-provisioned": "The new rule will <1>not be marked as a provisioned rule.", + "body-not-provisioned": "The new rule will not be marked as a provisioned rule.", "confirmText-copy": "Copy", "title-copy-provisioned-alert-rule": "Copy provisioned alert rule" }, @@ -2292,13 +2294,13 @@ "routing-settings": { "aria-label-group-by": "Group by", "description-group-by": "Combine multiple alerts into a single notification by grouping them by the same label values. If empty, it is inherited from the default notification policy.", - "group-interval": "Group interval: <1>{{groupIntervalValue}}", - "group-wait": "Group wait: <1>{{groupWaitValue}}", - "grouping": "Grouping: <1>{{fields}}", + "group-interval": "Group interval: {{groupIntervalValue}}", + "group-wait": "Group wait: {{groupWaitValue}}", + "grouping": "Grouping: {{fields}}", "label-group-by": "Group by", "label-override-grouping": "Override grouping", "label-override-timings": "Override timings", - "repeat-interval": "Repeat interval: <1>{{repeatIntervalValue}}" + "repeat-interval": "Repeat interval: {{repeatIntervalValue}}" }, "rule-actions-buttons": { "title-edit": "Edit", @@ -2554,7 +2556,7 @@ "relative-with-to": "<0>{{from}} to <2>{{to}}" }, "rule-type-picker": { - "grafana-managed": "Select “Grafana managed” unless you have a Mimir, Loki or Cortex data source with the Ruler API enabled." + "grafana-managed": "Select “Grafana managed” unless you have a Mimir, Loki or Cortex data source with the Ruler API enabled." }, "rule-view": { "query": { @@ -2887,7 +2889,7 @@ "test-contact-point-modal": { "custom-notification-message": "You will send a test notification that uses the annotations defined below. This is a good option if you use custom templates and messages.", "notification-message": "Notification message", - "predefined-notification-message": "You will send a test notification that uses a predefined alert. If you have defined a custom template or message, for better results switch to <1>custom notification message, from above.", + "predefined-notification-message": "You will send a test notification that uses a predefined alert. If you have defined a custom template or message, for better results switch to custom notification message, from above.", "send-test-notification": "Send test notification", "title-test-contact-point": "Test contact point" }, @@ -2896,7 +2898,7 @@ }, "threshold-expression-viewer": { "input": "Input", - "stop-alerting-when": "Stop alerting (or pending state) when " + "stop-alerting-when": "Stop alerting (or pending state) when" }, "time-interval": { "add-time-interval": "Add time interval", @@ -2949,7 +2951,7 @@ "error-loading-rule": "Error loading rule", "firing-instances-count": "{{firingCount}} firing instances", "instance-details": "Instance Details", - "no-instances-found": "No alert instances found for rule: {ruleUID}", + "no-instances-found": "No alert instances found for rule: {{ruleUID}}", "no-labels": "No labels", "open-in-sidebar": "Open in sidebar", "open-rule-details": "Open rule details", @@ -3084,7 +3086,7 @@ "title-notification-policies": "Notification policies" }, "yaml-content-info": { - "body": "The YAML content in the editor only contains alert rule configuration <1>To configure Prometheus, you need to provide the rest of the <4>configuration file content." + "body": "The YAML content in the editor only contains alert rule configuration
To configure Prometheus, you need to provide the rest of the <4>configuration file content." } }, "alertlist": { @@ -3160,7 +3162,7 @@ "no-annotations-found": "No annotations found" }, "annotation-list-item": { - "tooltip-created-by": "Created by:<1> {{email}}" + "tooltip-created-by": "Created by:
{{email}}" }, "category-annotation-query": "Annotation query", "category-display": "Display", @@ -3198,7 +3200,7 @@ }, "empty-state": { "button-title": "Add annotation query", - "info-box-content": "<0>Annotations provide a way to integrate event data into your graphs. They are visualized as vertical lines and icons on all graph panels. When you hover over an annotation icon you can get event text & tags for the event. You can add annotation events directly from grafana by holding CTRL or CMD + click on graph (or drag region). These will be stored in Grafana's annotation database.", + "info-box-content": "

Annotations provide a way to integrate event data into your graphs. They are visualized as vertical lines and icons on all graph panels. When you hover over an annotation icon you can get event text & tags for the event. You can add annotation events directly from grafana by holding CTRL or CMD + click on graph (or drag region). These will be stored in Grafana's annotation database.

", "info-box-content-2": "Checkout the <2>Annotations documentation for more information.", "title": "There are no custom annotation queries added yet" }, @@ -3236,7 +3238,7 @@ "auth-settings": "Auth settings" }, "auth-drawer-unconneced": { - "subtitle": "Configure auth settings. Find out more in our <2>documentation." + "subtitle": "Configure auth settings. Find out more in our <2>documentation ." }, "auth-drawer-unconnected": { "advanced-auth": "Advanced Auth", @@ -3270,7 +3272,7 @@ "allowed-organizations-description": "List of comma- or space-separated organizations. The user should be a member \nof at least one organization to log in.", "allowed-organizations-label": "Allowed organizations", "allowed-organizations-placeholder": "Enter organizations (my-team, myteam...) and press Enter to add", - "api-url-description": "The user information endpoint of your OAuth2 provider. Information returned by this endpoint must be compatible with <2>OpenID UserInfo.", + "api-url-description": "The user information endpoint of your OAuth2 provider. Information returned by this endpoint must be compatible with <2>OpenID UserInfo .", "api-url-required": "This field must be a valid URL if set.", "auth-style-description": "It determines how \"{{ clientIDLabel }}\" and \"{{ clientSecretLabel }}\" are sent to Oauth2 provider. Default is AutoDetect.", "auth-style-label": "Auth style", @@ -3415,7 +3417,7 @@ } }, "auth-config-auth-config-page-unconnected": { - "subtitle": "Manage your auth settings and configure single sign-on. Find out more in our <2>documentation." + "subtitle": "Manage your auth settings and configure single sign-on. Find out more in our <2>documentation ." }, "bar-chart": { "warn": { @@ -4133,7 +4135,7 @@ }, "scopes": { "apply-selected-scopes": "Apply", - "selected-scopes-label": "Scopes: " + "selected-scopes-label": "Scopes:" }, "search-box": { "placeholder": "Search or jump to..." @@ -4275,7 +4277,7 @@ "okay": "Okay" }, "not-found-datasource": { - "body": "Maybe you mistyped the URL or the plugin with the id <1> is unavailable.<3>To see a list of available datasources please <5>click here." + "body": "Maybe you mistyped the URL or the plugin with the id <1> is unavailable.
To see a list of available datasources please <5>click here." }, "oss": { "connections-home-page": { @@ -4318,8 +4320,8 @@ "versionHistory": { "comparison": { "header": { - "hide-json-diff": "Hide JSON diff ", - "show-json-diff": "Show JSON diff ", + "hide-json-diff": "Hide JSON diff", + "show-json-diff": "Show JSON diff", "text": "Version {{version}} updated by {{createdBy}} ({{ageString}}) {{message}}" }, "select": "Select two versions to start comparing" @@ -4346,7 +4348,7 @@ "label-label": "Label", "label-placeholder": "e.g. Tempo traces", "label-required": "This field is required.", - "sub-text": "<0>Define text that will describe the correlation.", + "sub-text": "

Define text that will describe the correlation.

", "title": "Define correlation label (Step 1 of 3)" }, "configure-correlation-target-form": { @@ -4390,7 +4392,7 @@ }, "source-form": { "control-required": "This field is required.", - "description": "A data point needs to provide values to all variables as fields or as transformations output to make the correlation button appear in the visualization.<1>Note: Not every variable needs to be explicitly defined below. A transformation such as <4>logfmt will create variables for every key/value pair.", + "description": "A data point needs to provide values to all variables as fields or as transformations output to make the correlation button appear in the visualization.
Note: Not every variable needs to be explicitly defined below. A transformation such as <4>logfmt will create variables for every key/value pair.", "description-external-pre": "You have used following variables in the target URL:", "description-query-pre": "You have used following variables in the target query:", "external-title": "Configure the data source that will use the URL (Step 3 of 3)", @@ -4402,12 +4404,12 @@ "results-required": "This field is required.", "source-description": "Results from selected source data source have links displayed in the panel", "source-label": "Source", - "sub-text": "<0>Define what data source will display the correlation, and what data will replace previously defined variables." + "sub-text": "

Define what data source will display the correlation, and what data will replace previously defined variables.

" }, "sub-title": "Define how data living in different data sources relates to each other. Read more in the <2>documentation", "target-form": { "control-rules": "This field is required.", - "sub-text": "<0>Define what the correlation will link to. With the query type, a query will run when the correlation is clicked. With the external type, clicking the correlation will open a URL.", + "sub-text": "

Define what the correlation will link to. With the query type, a query will run when the correlation is clicked. With the external type, clicking the correlation will open a URL.

", "target-description-external": "Specify the URL that will open when the link is clicked", "target-description-query": "Specify which data source is queried when the link is clicked", "target-label": "Target", @@ -4614,7 +4616,7 @@ } }, "confirm-plugin-dashboard-save-modal": { - "body-plugin-dashboard": "Your changes will be lost when you update the plugin.<1><2>Use <1>Save As to create custom version.", + "body-plugin-dashboard": "Your changes will be lost when you update the plugin.
<2>Use Save As to create custom version.", "cancel": "Cancel", "overwrite": "Overwrite", "title-plugin-dashboard": "Plugin dashboard" @@ -4831,7 +4833,7 @@ "add-visualization-body": "Select a data source and then query and visualize your data with charts, stats and tables or create lists, markdowns and other widgets.", "add-visualization-button": "Add visualization", "add-visualization-header": "Start your new dashboard by adding a visualization", - "import-a-dashboard-body": "Import dashboards from files or <2>grafana.com.", + "import-a-dashboard-body": "Import dashboards from files or <2>grafana.com .", "import-a-dashboard-header": "Import a dashboard", "import-dashboard-button": "Import dashboard", "show-less-dashboards": "Show less", @@ -5289,8 +5291,8 @@ "title-provisioned": "Provisioned dashboard" }, "save-dashboard-error-proxy": { - "body-name-exists": "A dashboard with the same name in selected folder already exists.<1><2>Would you still like to save this dashboard?", - "body-version-mismatch": "Someone else has updated this dashboard<1><2>Would you still like to save this dashboard?", + "body-name-exists": "A dashboard with the same name in selected folder already exists.
<2>Would you still like to save this dashboard?", + "body-version-mismatch": "Someone else has updated this dashboard
<2>Would you still like to save this dashboard?", "confirmText-save-and-overwrite": "Save and overwrite", "title-name-exists": "Conflict", "title-version-mismatch": "Conflict" @@ -5308,7 +5310,7 @@ "cancel": "Cancel", "cannot-be-saved": "This dashboard cannot be saved from the Grafana UI because it has been provisioned from another source. Copy the JSON or save it to a file below, then you can update your dashboard in the provisioning source.", "copy-json-to-clipboard": "Copy JSON to clipboard", - "file-path": "<0>File path: {{filePath}}", + "file-path": "File path: {{filePath}}", "save-json-to-file": "Save JSON to file", "see-docs": "See <2>documentation for more information about provisioning." }, @@ -5507,7 +5509,7 @@ "transformation-picker": { "info": "Transformations allow you to join, calculate, re-order, hide, and rename your query results before they are visualized.", "info-graph-not-suitable": "Many transforms are not suitable if you're using the Graph visualization, as it currently only supports time series data.", - "info-switch-to-table": "It can help to switch to the Table visualization to understand what a transformation is doing. ", + "info-switch-to-table": "It can help to switch to the Table visualization to understand what a transformation is doing.", "placeholder-search-for-transformation": "Search for transformation", "read-more": "Read more", "title-transformations": "Transformations" @@ -5573,8 +5575,8 @@ "version-history-comparison": { "button-restore": "Restore to version {{version}}", "label-view-json-diff": "View JSON diff", - "new-updated-by": "<0>Version {{version}} updated by {{editor}} {{timeAgo}}", - "old-updated-by": "<0>Version {{version}} updated by {{editor}} {{timeAgo}}" + "new-updated-by": "Version {{version}} updated by {{editor}} {{timeAgo}}", + "old-updated-by": "Version {{version}} updated by {{editor}} {{timeAgo}}" }, "version-history-table": { "aria-label-toggle-selection": "Toggle selection of version {{version}}", @@ -5974,7 +5976,7 @@ "cancel": "Cancel" }, "render-save-button-and-error": { - "body-plugin-dashboard": "Your changes will be lost when you update the plugin. Use <1>Save as to create custom version.", + "body-plugin-dashboard": "Your changes will be lost when you update the plugin. Use Save as to create custom version.", "title-failed-to-save-dashboard": "Failed to save dashboard", "title-plugin-dashboard": "Plugin dashboard", "title-someone-else-has-updated-this-dashboard": "Someone else has updated this dashboard", @@ -5983,7 +5985,7 @@ "save-and-overwrite": "'Save and overwrite'" }, "library-viz-panel-info": { - "last-edited": "{{timeAgo}} by", + "last-edited": "{{timeAgo}} by ", "usage-count_one": "Used on {{count}} dashboards", "usage-count_other": "Used on {{count}} dashboards" }, @@ -6044,7 +6046,7 @@ }, "panel-data-queries-tab-rendered": { "add-query": "Add query", - "expression": "Expression " + "expression": "Expression" }, "panel-data-transformations-tab": { "tab-label": "Transformations" @@ -6102,7 +6104,7 @@ "query": "Query" }, "query-variable-editor-form": { - "description-examples": "Named capture groups can be used to separate the display text and value (<1>see examples).", + "description-examples": "Named capture groups can be used to separate the display text and value ( <1>see examples ).", "description-optional": "Optional, if you want to extract part of a series name or metric node segment.", "label-data-source": "Data source", "label-static-options-sort": "Static options sort", @@ -6163,7 +6165,7 @@ "label-message": "Message", "placeholder-describe-changes-optional": "Add a note to describe your changes (optional).", "render-footer": { - "body-plugin-dashboard": "Your changes will be lost when you update the plugin. Use <1>Save as to create custom version.", + "body-plugin-dashboard": "Your changes will be lost when you update the plugin. Use Save as to create custom version.", "no-changes-to-save": "No changes to save", "title-failed-to-save-dashboard": "Failed to save dashboard", "title-plugin-dashboard": "Plugin dashboard", @@ -6199,7 +6201,7 @@ "cancel": "Cancel", "cannot-be-saved": "This dashboard cannot be saved from the Grafana UI because it has been provisioned from another source. Copy the JSON or save it to a file below, then you can update your dashboard in the provisioning source.", "copy-json-to-clipboard": "Copy JSON to clipboard", - "file-path": "<0>File path: {{filePath}}", + "file-path": "File path: {{filePath}}", "label-description": "Description", "label-target-folder": "Target folder", "label-title": "Title", @@ -6368,8 +6370,8 @@ }, "version-history-comparison": { "label-view-json-diff": "View JSON diff", - "new-version-updated": "<0>Version {{version}} updated by {{editor}} {{timeAgo}}", - "old-version-updated": "<0>Version {{version}} updated by {{editor}} {{timeAgo}}" + "new-version-updated": "Version {{version}} updated by {{editor}} {{timeAgo}}", + "old-version-updated": "Version {{version}} updated by {{editor}} {{timeAgo}}" }, "version-history-header": { "compare-versions": "Comparing {{baseVersion}} <3> {{newVersion}}", @@ -6447,7 +6449,7 @@ "provisioned-delete-modal": { "confirm-button": "OK", "text-1": "This dashboard is managed by Grafana provisioning and cannot be deleted. Remove the dashboard from the config file to delete it.", - "text-2": "See grafana documentation for more information about provisioning. ", + "text-2": "See grafana documentation for more information about provisioning.", "text-3": "File path: {{provisionedId}}", "text-link": "Go to docs page", "title": "Cannot delete provisioned dashboard" @@ -6525,7 +6527,7 @@ }, "data-source-testing-status-page": { "error-more-details-link": "Click <2>here to learn more about this error.", - "success-more-details-links": "Next, you can start to visualize data by <2>building a dashboard, or by querying data in the <5>Explore view." + "success-more-details-links": "Next, you can start to visualize data by <2>building a dashboard , or by querying data in the <5>Explore view ." }, "data-sources": { "datasource-add-button": { @@ -6621,7 +6623,7 @@ "test": "Test" }, "cloud-info-box": { - "body-alert": "Or skip the effort and get {{mainDS}} (and {{extraDS}}) as fully-managed, scalable, and hosted data sources from Grafana Labs with the <6>free-forever Grafana Cloud plan.", + "body-alert": "Or skip the effort and get {{mainDS}} (and {{extraDS}}) as fully-managed, scalable, and hosted data sources from Grafana Labs with the <6>free-forever Grafana Cloud plan .", "title-alert": "Configure your {{mainDS}} data source below" }, "dashboards-table": { @@ -6749,18 +6751,18 @@ "no-events-yet": "No events yet" }, "render-info-viewer": { - "data-counter": "Data: {{numDataChanges}} ", + "data-counter": "Data: {{numDataChanges}}", "elapsed-time": "Time: {{elapsed}}ms", "field": "Field", "last": "Last", - "render-counter": "Render: {{numRenders}} ", - "schema-counter": "Schema: {{numSchemaChanges}} ", + "render-counter": "Render: {{numRenders}}", + "schema-counter": "Schema: {{numSchemaChanges}}", "title-reset-counters": "Reset counters", "tooltip-step-back": "Step back", "type": "Type" }, "state-view": { - "current-value": "Current value: {{currentValue}} ", + "current-value": "Current value: {{currentValue}}", "label-state-name": "State name" } }, @@ -7207,7 +7209,7 @@ }, "footer": { "learn-more": "Learn more", - "pro-tip-define-sources-through-configuration-files": " ProTip: You can also define data sources through configuration files. " + "pro-tip-define-sources-through-configuration-files": "ProTip: You can also define data sources through configuration files." } }, "pane": { @@ -7269,8 +7271,10 @@ "query-deleted": "Query deleted" }, "rich-history-queries-tab": { - "displaying-partial-queries": "Displaying {{ count }} queries", - "displaying-queries": "{{ count }} queries", + "displaying-partial-queries_one": "Displaying {{ count }} queries", + "displaying-partial-queries_other": "Displaying {{ count }} queries", + "displaying-queries_one": "{{ count }} queries", + "displaying-queries_other": "{{ count }} queries", "filter-aria-label": "Filter queries for data sources(s)", "filter-history": "Filter history", "filter-placeholder": "Filter queries for data sources(s)", @@ -7472,7 +7476,7 @@ "copy-shortened-link-menu": "Open copy link options", "refresh-picker-cancel": "Cancel", "refresh-picker-run": "Run query", - "split-close": " Close ", + "split-close": "Close", "split-close-tooltip": "Close split pane", "split-narrow": "Narrow pane", "split-title": "Split", @@ -7602,8 +7606,8 @@ }, "math": { "available-math-functions": "Available math functions", - "run-math-operations": "Run math operations on one or more queries. You reference the query by {{refExample}} ie. {{ref1}}, {{ref2}}, {{ref3}}etc.<10>Example: <12>{{example}}", - "tooltip-footer": "See our additional documentation on <2>Math expressions.", + "run-math-operations": "Run math operations on one or more queries. You reference the query by {{refExample}} ie. {{ref1}}, {{ref2}}, {{ref3}} etc.
Example: <12>{{example}}", + "tooltip-footer": "See our additional documentation on <2>Math expressions .", "tooltip-title": "Math operator", "tooltip-trigger": "Expression" }, @@ -8642,7 +8646,7 @@ }, "data-source-http-settings": { "access-help": "Help <1>", - "access-help-details": "Access mode controls how requests to the data source will be handled.<1> <1>Server should be the preferred way if nothing else is stated.", + "access-help-details": "Access mode controls how requests to the data source will be handled. Server should be the preferred way if nothing else is stated.", "access-help-title": "Access help", "access-label": "Access", "allowed-cookies": "Allowed cookies", @@ -8910,7 +8914,7 @@ "cell-inspect": "Inspect value", "cell-inspect-tooltip": "Inspect value", "copy": "Copy to Clipboard", - "csv-counts": "Rows:{{rows}}, Columns:{{columns}} <5>", + "csv-counts": "Rows:{{rows}}, Columns:{{columns}}", "csv-placeholder": "Enter CSV here...", "filter-placeholder": "Filter values", "filter-popup-apply": "Ok", @@ -9359,7 +9363,7 @@ "error-fetching": "Error fetching LDAP settings", "error-saving": "Error saving LDAP settings", "error-validate-form": "Error validating LDAP settings", - "feature-flag-disabled": "This page is only accessible by enabling the <1>ssoSettingsLDAP feature flag.", + "feature-flag-disabled": "This page is only accessible by enabling the ssoSettingsLDAP feature flag.", "saved": "LDAP settings saved" }, "bind-dn": { @@ -9400,7 +9404,7 @@ "label": "Search base DNS", "placeholder": "example: dc=grafana,dc=org" }, - "subtitle": "The LDAP integration in Grafana allows your Grafana users to log in with their LDAP credentials. Find out more in our <2><0>documentation.", + "subtitle": "The LDAP integration in Grafana allows your Grafana users to log in with their LDAP credentials. Find out more in our <2><0>documentation .", "title": "Basic Settings" }, "library-panel": { @@ -9444,7 +9448,7 @@ "dashboard-name": "Dashboard name" }, "library-panel-info": { - "last-edited": "Last edited on {{timeAgo}} by", + "last-edited": "Last edited on {{timeAgo}} by ", "usage-count_one": "Used on {{count}} dashboards", "usage-count_other": "Used on {{count}} dashboards" }, @@ -9749,7 +9753,7 @@ "tooltip-unpin-line": "Unpin line" }, "log-row-message": { - "ellipsis": "… ", + "ellipsis": "…", "more": "more", "see-details": "See log details", "tooltip-error": "Error: {{errorMessage}}" @@ -10145,7 +10149,7 @@ }, "resource-table": { "dashboard-load-error": "Unable to load dashboard", - "error-library-element-sub": "Library Element {uid}", + "error-library-element-sub": "Library Element {{uid}}", "error-library-element-title": "Unable to load library element", "unknown-datasource-title": "Data source {{datasourceUID}}", "unknown-datasource-type": "Unknown data source" @@ -10793,10 +10797,10 @@ "placeholder-optional": "(optional)", "role": "Role", "submit": "Submit", - "tooltip": "You can now select the \"No basic role\" option and add permissions to your custom needs. You can find more information in <1>our documentation." + "tooltip": "You can now select the \"No basic role\" option and add permissions to your custom needs. You can find more information in <1>our documentation ." }, "user-invite-page": { - "sub-title": "Send invitation or add existing Grafana user to the organization.<1> {{orgName}}", + "sub-title": "Send invitation or add existing Grafana user to the organization. <1> {{orgName}}", "text": { "invite-user": "Invite user" } @@ -10885,7 +10889,7 @@ "switch-to-table": "Switch to table" }, "panel-plugin-error": { - "text-load-error": "Check the server startup logs for more information. <1>If this plugin was loaded from Git, then make sure it was compiled.", + "text-load-error": "Check the server startup logs for more information.
If this plugin was loaded from Git, then make sure it was compiled.", "title-load-error": "Error loading: {{panelId}}", "title-not-found": "Panel plugin not found: {{id}}" }, @@ -11079,7 +11083,7 @@ }, "details": { "connections-tab": { - "description": "You currently have the following data sources configured for {{pluginName}}, click a tile to view the configuration details. You can find all of your data source connections in <4><0>Connections - <3>Data sources." + "description": "You currently have the following data sources configured for {{pluginName}}, click a tile to view the configuration details. You can find all of your data source connections in <4><5>Connections - <8>Data sources." }, "disabled-error": { "angular-deprecation-link": "Read more about angular deprecation", @@ -11096,7 +11100,7 @@ }, "labels": { "contactGrafanaLabs": "Contact Grafana Labs", - "customLinks": "Custom links ", + "customLinks": "Custom links", "customLinksTooltip": "These links are provided by the plugin developer to offer additional, developer-specific resources and information", "dependencies": "Dependencies", "documentation": "Documentation", @@ -11107,7 +11111,7 @@ "latestVersion": "Latest Version", "license": "License", "raiseAnIssue": "Raise an issue", - "reportAbuse": "Report a concern ", + "reportAbuse": "Report a concern", "reportAbuseTooltip": "Report issues related to malicious or harmful plugins directly to Grafana Labs.", "repository": "Repository", "signature": "Signature", @@ -11117,8 +11121,8 @@ "modal": { "cancel": "Cancel", "copyEmail": "Copy email address", - "description": "This feature is for reporting malicious or harmful behaviour within plugins. For plugin concerns, email us at: ", - "node": "Note: For general plugin issues like bugs or feature requests, please contact the plugin author using the provided links. ", + "description": "This feature is for reporting malicious or harmful behaviour within plugins. For plugin concerns, email us at:", + "node": "Note: For general plugin issues like bugs or feature requests, please contact the plugin author using the provided links.", "title": "Report a plugin concern" } }, @@ -11186,7 +11190,7 @@ "message": "All plugins are up to date" }, "not-found-plugin": { - "body-plugin-not-found": "That plugin cannot be found. Please check the url is correct or <1>go to the <3>plugin catalog.", + "body-plugin-not-found": "That plugin cannot be found. Please check the url is correct or
go to the <3>plugin catalog.", "title-plugin-not-found": "Plugin not found" }, "plugin-actions": { @@ -11494,7 +11498,7 @@ "actions": { "set-up-required-feature-toggles": "Set up required feature toggles" }, - "learn-more-documentation": "Want to learn more? See our <2>documentation.", + "learn-more-documentation": "Want to learn more? See our <2>documentation .", "manage-dashboards-provision-updates-automatically": "Manage dashboards as code in Git and provision updates automatically", "manage-your-dashboards-with-remote-provisioning": "Get started with Git Sync", "store-dashboards-in-version-controlled-storage": "Store dashboards in version-controlled storage for better organization and history tracking" @@ -12004,7 +12008,7 @@ "annotations-show-text": "Annotations = show", "time-range-picker-disabled-text": "Time range picker = disabled", "time-range-picker-enabled-text": "Time range picker = enabled", - "time-range-text": "Time range = " + "time-range-text": "Time range =" }, "share": { "success-delete": "Your dashboard is no longer shareable" @@ -12043,7 +12047,7 @@ "revoke-user-access-modal-desc-line1": "Are you sure you want to revoke access for {{email}}?" }, "delete-user-shared-dashboards-modal": { - "revoke-user-access-modal-desc-line2": "This action will immediately revoke {{email}}'s access to all shared dashboards." + "revoke-user-access-modal-desc-line2": "This action will immediately revoke {{email}}'s access to all shared dashboards." }, "modal": { "shared-dashboard-modal-title": "Shared dashboards" @@ -12212,7 +12216,7 @@ }, "menu": { "clear-button": "Clear all", - "tooltip": "You can now select the \"No basic role\" option and add permissions to your custom needs. You can find more information in <1>our documentation." + "tooltip": "You can now select the \"No basic role\" option and add permissions to your custom needs. You can find more information in <1>our documentation ." }, "menu-aria-label": "Role picker menu", "menu-group-option-aria-label": "Role picker option", @@ -12222,7 +12226,7 @@ }, "sub-menu-aria-label": "Role picker submenu", "title": { - "description": "Assign roles to users to ensure granular control over access to Grafana‘s features and resources. Find out more in our <2>documentation." + "description": "Assign roles to users to ensure granular control over access to Grafana‘s features and resources. Find out more in our <2>documentation ." } }, "role-picker-drawer": { @@ -12345,7 +12349,7 @@ }, "select": { "select-menu": { - "selected-count": "Selected " + "selected-count": "Selected" } }, "service-account-create-page": { @@ -12444,6 +12448,7 @@ "aria-label-role": "Role" }, "service-account-tokens-table": { + "aria-label-delete-button": "Delete service account token {{key}}", "created": "Created", "expires": "Expires", "last-used-at": "Last used at", @@ -12531,7 +12536,7 @@ "info-text": "Create a direct link to this dashboard or panel, customized with the options below.", "link-url": "Link URL", "render-alert": "Image renderer plugin not installed", - "render-instructions": "To render an image, you must install the <2>Grafana image renderer plugin. Please contact your Grafana administrator to install the plugin.", + "render-instructions": "To render an image, you must install the <2>Grafana image renderer plugin . Please contact your Grafana administrator to install the plugin.", "rendered-image": "Direct link rendered image", "save-alert": "Dashboard is not saved", "save-dashboard": "To render a panel image, you must save the dashboard first.", @@ -12555,7 +12560,7 @@ "info-text-1": "A snapshot is an instant way to share an interactive dashboard publicly. When created, we strip sensitive data like queries (metric, template, and annotation) and panel links, leaving only the visible metric data and series names embedded in your dashboard.", "info-text-2": "Keep in mind, your snapshot <1>can be viewed by anyone that has the link and can access the URL. Share wisely.", "local-button": "Publish Snapshot", - "mistake-message": "Did you make a mistake? ", + "mistake-message": "Did you make a mistake?", "name": "Snapshot name", "timeout": "Timeout (seconds)", "timeout-description": "You might need to configure the timeout value if it takes a long time to collect your dashboard metrics.", @@ -13167,7 +13172,7 @@ "forwards-time-aria-label": "Move time range forwards", "to": "to", "zoom-out-button": "Zoom out time range", - "zoom-out-tooltip": "Time range zoom out <1> CTRL+Z" + "zoom-out-tooltip": "Time range zoom out
CTRL+Z" }, "time-range": { "apply": "Apply time range", @@ -13292,7 +13297,7 @@ }, "transformations": { "empty": { - "add-transformation-body": "Transformations allow data to be changed in various ways before your visualization is shown.<1>This includes joining data together, renaming fields, making calculations, formatting data for display, and more.", + "add-transformation-body": "Transformations allow data to be changed in various ways before your visualization is shown.
This includes joining data together, renaming fields, making calculations, formatting data for display, and more.", "add-transformation-header": "Start transforming data" } }, @@ -13559,7 +13564,7 @@ "label-format": "Format", "label-set-timezone": "Set timezone", "label-time-field": "Time field", - "tooltip-format": "The output format for the field specified as a <2>Moment.js format string.", + "tooltip-format": "The output format for the field specified as a <2>Moment.js format string .", "tooltip-timezone-manually": "Set the timezone of the date manually" }, "format-time-transformer-editor": { @@ -14154,8 +14159,8 @@ "message": "No users found" }, "token-revoked-modal": { - "auto-revoked": "Your session token was automatically revoked because you have reached <2>the maximum number of {{numSessions}} concurrent sessions for your account.", - "resume-message": "<0>To resume your session, sign in again.Contact your administrator or visit the license page to review your quota if you are repeatedly signed out automatically.", + "auto-revoked": "Your session token was automatically revoked because you have reached the maximum number of {{numSessions}} concurrent sessions for your account.", + "resume-message": "To resume your session, sign in again. Contact your administrator or visit the license page to review your quota if you are repeatedly signed out automatically.", "sign-in": "Sign in", "title-you-have-been-automatically-signed-out": "You have been automatically signed out" }, diff --git a/public/locales/enterprise/i18next.config.ts b/public/locales/enterprise/i18next.config.ts new file mode 100644 index 00000000000..9aed42bb51e --- /dev/null +++ b/public/locales/enterprise/i18next.config.ts @@ -0,0 +1,13 @@ +import { defineConfig } from 'i18next-cli'; + +import baseConfig from '../../../i18next.config'; + +export default defineConfig({ + ...baseConfig, + extract: { + ...baseConfig.extract, + defaultNS: 'grafana-enterprise', + input: ['../../../public/app/extensions/**/*.{tsx,ts}'], + output: '../../../public/app/extensions/locales/{{language}}/{{namespace}}.json', + }, +}); diff --git a/public/locales/i18next-parser-enterprise.config.cjs b/public/locales/i18next-parser-enterprise.config.cjs deleted file mode 100644 index 66e8cd9cca2..00000000000 --- a/public/locales/i18next-parser-enterprise.config.cjs +++ /dev/null @@ -1,8 +0,0 @@ -const baseConfig = require('./i18next-parser.config.cjs'); - -module.exports = { - ...baseConfig, - defaultNamespace: 'grafana-enterprise', - input: ['../../public/app/extensions/**/*.{tsx,ts}'], - output: './public/app/extensions/locales/$LOCALE/$NAMESPACE.json', -}; diff --git a/public/locales/i18next-parser.config.cjs b/public/locales/i18next-parser.config.cjs deleted file mode 100644 index 972a9cad866..00000000000 --- a/public/locales/i18next-parser.config.cjs +++ /dev/null @@ -1,20 +0,0 @@ -module.exports = { - // Base config - same for both OSS and Enterprise - locales: ['en-US'], // Only en-US is updated - Crowdin will PR with other languages - sort: true, - createOldCatalogs: false, - failOnWarnings: true, - verbose: false, - resetDefaultValueLocale: 'en-US', // Updates extracted values when they change in code - - // OSS-specific config - defaultNamespace: 'grafana', - input: [ - '../../public/**/*.{tsx,ts}', - '!../../public/app/extensions/**/*', // Don't extract from Enterprise - '!../../public/app/plugins/datasource/**/*', // Don't extract from datasource plugins - '../../packages/grafana-ui/**/*.{tsx,ts}', - '../../packages/grafana-data/**/*.{tsx,ts}', - ], - output: './public/locales/$LOCALE/$NAMESPACE.json', -}; diff --git a/yarn.lock b/yarn.lock index 456bf083bed..ad8690ca104 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1473,7 +1473,7 @@ __metadata: languageName: node linkType: hard -"@babel/runtime@npm:^7.0.0, @babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.10.1, @babel/runtime@npm:^7.11.1, @babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.12.0, @babel/runtime@npm:^7.12.1, @babel/runtime@npm:^7.12.13, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.13.10, @babel/runtime@npm:^7.16.3, @babel/runtime@npm:^7.17.8, @babel/runtime@npm:^7.18.0, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.20.0, @babel/runtime@npm:^7.20.7, @babel/runtime@npm:^7.23.2, @babel/runtime@npm:^7.23.9, @babel/runtime@npm:^7.24.5, @babel/runtime@npm:^7.24.7, @babel/runtime@npm:^7.25.0, @babel/runtime@npm:^7.25.6, @babel/runtime@npm:^7.25.7, @babel/runtime@npm:^7.26.10, @babel/runtime@npm:^7.26.7, @babel/runtime@npm:^7.27.0, @babel/runtime@npm:^7.27.6, @babel/runtime@npm:^7.3.1, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.7.6, @babel/runtime@npm:^7.8.7": +"@babel/runtime@npm:^7.0.0, @babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.10.1, @babel/runtime@npm:^7.11.1, @babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.12.0, @babel/runtime@npm:^7.12.1, @babel/runtime@npm:^7.12.13, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.13.10, @babel/runtime@npm:^7.16.3, @babel/runtime@npm:^7.17.8, @babel/runtime@npm:^7.18.0, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.20.0, @babel/runtime@npm:^7.20.7, @babel/runtime@npm:^7.23.2, @babel/runtime@npm:^7.23.9, @babel/runtime@npm:^7.24.5, @babel/runtime@npm:^7.24.7, @babel/runtime@npm:^7.25.0, @babel/runtime@npm:^7.25.6, @babel/runtime@npm:^7.25.7, @babel/runtime@npm:^7.26.7, @babel/runtime@npm:^7.27.0, @babel/runtime@npm:^7.27.6, @babel/runtime@npm:^7.3.1, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.7.6, @babel/runtime@npm:^7.8.7": version: 7.28.4 resolution: "@babel/runtime@npm:7.28.4" checksum: 10/6c9a70452322ea80b3c9b2a412bcf60771819213a67576c8cec41e88a95bb7bf01fc983754cda35dc19603eef52df22203ccbf7777b9d6316932f9fb77c25163 @@ -2454,7 +2454,7 @@ __metadata: "@types/react-dom": "npm:18.3.5" fast-deep-equal: "npm:^3.1.3" i18next: "npm:^25.0.0" - i18next-parser: "npm:9.3.0" + i18next-cli: "npm:1.11.12" immer: "npm:10.1.3" jest: "npm:29.7.0" lodash: "npm:4.17.21" @@ -2739,7 +2739,7 @@ __metadata: "@types/lodash": "npm:4.17.20" "@types/node": "npm:22.17.0" "@types/react": "npm:18.3.18" - i18next-parser: "npm:9.3.0" + i18next-cli: "npm:1.11.12" lodash: "npm:4.17.21" react: "npm:18.3.1" rxjs: "npm:7.8.2" @@ -2979,6 +2979,7 @@ __metadata: "@types/tinycolor2": "npm:^1" fishery: "npm:^2.3.1" i18next: "npm:^25.5.2" + i18next-cli: "npm:1.11.12" lodash: "npm:^4.17.21" react: "npm:18.3.1" react-dom: "npm:18.3.1" @@ -3480,7 +3481,7 @@ __metadata: "@types/uuid": "npm:10.0.0" debounce-promise: "npm:3.1.2" esbuild: "npm:0.25.8" - i18next-parser: "npm:9.3.0" + i18next-cli: "npm:1.11.12" jest: "npm:29.7.0" jest-environment-jsdom: "npm:29.7.0" lodash: "npm:4.17.21" @@ -3668,7 +3669,7 @@ __metadata: "@types/react-virtualized-auto-sizer": "npm:1.0.8" "@types/systemjs": "npm:6.15.3" "@types/uuid": "npm:10.0.0" - i18next-parser: "npm:9.3.0" + i18next-cli: "npm:1.11.12" immutable: "npm:5.1.4" jest: "npm:^29.6.4" lodash: "npm:4.17.21" @@ -3969,6 +3970,31 @@ __metadata: languageName: node linkType: hard +"@inquirer/ansi@npm:^1.0.0, @inquirer/ansi@npm:^1.0.1": + version: 1.0.1 + resolution: "@inquirer/ansi@npm:1.0.1" + checksum: 10/0dda65720736f3e730715f3778e0e90f039ebd1382c277495a4d1cdbd2b2863095aa7291cd8ea7d3c0618bdee04a375db6e10a7bae5fb904df0b632a1c7774f9 + languageName: node + linkType: hard + +"@inquirer/checkbox@npm:^4.3.0": + version: 4.3.0 + resolution: "@inquirer/checkbox@npm:4.3.0" + dependencies: + "@inquirer/ansi": "npm:^1.0.1" + "@inquirer/core": "npm:^10.3.0" + "@inquirer/figures": "npm:^1.0.14" + "@inquirer/type": "npm:^3.0.9" + yoctocolors-cjs: "npm:^2.1.2" + peerDependencies: + "@types/node": ">=18" + peerDependenciesMeta: + "@types/node": + optional: true + checksum: 10/aa7ddf0816bc1718afdc38d7ed1e16207bbf944164a5a3ac0d87072a5a1b51cf3417617c72128a78d66b2e40a45f4a5658bdfc4bb546e92a208e30c8006674e6 + languageName: node + linkType: hard + "@inquirer/confirm@npm:^5.0.0": version: 5.0.2 resolution: "@inquirer/confirm@npm:5.0.2" @@ -3981,6 +4007,21 @@ __metadata: languageName: node linkType: hard +"@inquirer/confirm@npm:^5.1.19": + version: 5.1.19 + resolution: "@inquirer/confirm@npm:5.1.19" + dependencies: + "@inquirer/core": "npm:^10.3.0" + "@inquirer/type": "npm:^3.0.9" + peerDependencies: + "@types/node": ">=18" + peerDependenciesMeta: + "@types/node": + optional: true + checksum: 10/d65e0addf80c146d71a74057d77048bd78a4a80d74a9e0d774b759ff1adf38a33cde6c06a6d6ef802bb61ef9158770315dec3931f89b3624c0e63c595c0473c1 + languageName: node + linkType: hard + "@inquirer/core@npm:^10.1.0": version: 10.1.0 resolution: "@inquirer/core@npm:10.1.0" @@ -3998,6 +4039,81 @@ __metadata: languageName: node linkType: hard +"@inquirer/core@npm:^10.2.2, @inquirer/core@npm:^10.3.0": + version: 10.3.0 + resolution: "@inquirer/core@npm:10.3.0" + dependencies: + "@inquirer/ansi": "npm:^1.0.1" + "@inquirer/figures": "npm:^1.0.14" + "@inquirer/type": "npm:^3.0.9" + cli-width: "npm:^4.1.0" + mute-stream: "npm:^2.0.0" + signal-exit: "npm:^4.1.0" + wrap-ansi: "npm:^6.2.0" + yoctocolors-cjs: "npm:^2.1.2" + peerDependencies: + "@types/node": ">=18" + peerDependenciesMeta: + "@types/node": + optional: true + checksum: 10/41392e38dc3253b3dbebda9cca344ca5cfd72c05e1c5b8460cb00e0ce7fa665a1970a2c4af89dcb951d75fedfdf775cdd7ac3be0748dbe3dec47db5d899d6963 + languageName: node + linkType: hard + +"@inquirer/editor@npm:^4.2.21": + version: 4.2.21 + resolution: "@inquirer/editor@npm:4.2.21" + dependencies: + "@inquirer/core": "npm:^10.3.0" + "@inquirer/external-editor": "npm:^1.0.2" + "@inquirer/type": "npm:^3.0.9" + peerDependencies: + "@types/node": ">=18" + peerDependenciesMeta: + "@types/node": + optional: true + checksum: 10/cf2d4237dc86abb2143ba6e99a4a60368ee992ba56b0072457e4dd472e7ac99ebffcbd0895bf36d5f694f3e327ff0dbb70265952b03ec8a0dbf4abd1db306991 + languageName: node + linkType: hard + +"@inquirer/expand@npm:^4.0.21": + version: 4.0.21 + resolution: "@inquirer/expand@npm:4.0.21" + dependencies: + "@inquirer/core": "npm:^10.3.0" + "@inquirer/type": "npm:^3.0.9" + yoctocolors-cjs: "npm:^2.1.2" + peerDependencies: + "@types/node": ">=18" + peerDependenciesMeta: + "@types/node": + optional: true + checksum: 10/eb1900c443895377c03652c3e2b6ca29c572fe6ee2682e264572957b9b4a596d3d55c9ea271934846fb05d5cc5195cca0dffde1386e41358ac5c308698320e93 + languageName: node + linkType: hard + +"@inquirer/external-editor@npm:^1.0.2": + version: 1.0.2 + resolution: "@inquirer/external-editor@npm:1.0.2" + dependencies: + chardet: "npm:^2.1.0" + iconv-lite: "npm:^0.7.0" + peerDependencies: + "@types/node": ">=18" + peerDependenciesMeta: + "@types/node": + optional: true + checksum: 10/d0c5c73249b8153f4cf872c4fba01c57a7653142a4cad496f17ed03ef3769330a4b3c519b68d70af69d4bb33003d2599b66b2242be85411c0b027ff383619666 + languageName: node + linkType: hard + +"@inquirer/figures@npm:^1.0.14": + version: 1.0.14 + resolution: "@inquirer/figures@npm:1.0.14" + checksum: 10/39df361eb607cea5a020d457e25f9c6aee3a1de8975c6295a4b3bfe86ba7e7f7bfbefa6a52b145b1790f2690e5c8f10eb822e5bc764aff7ba00a6cd24eec5a25 + languageName: node + linkType: hard + "@inquirer/figures@npm:^1.0.3, @inquirer/figures@npm:^1.0.8": version: 1.0.11 resolution: "@inquirer/figures@npm:1.0.11" @@ -4005,6 +4121,126 @@ __metadata: languageName: node linkType: hard +"@inquirer/input@npm:^4.2.5": + version: 4.2.5 + resolution: "@inquirer/input@npm:4.2.5" + dependencies: + "@inquirer/core": "npm:^10.3.0" + "@inquirer/type": "npm:^3.0.9" + peerDependencies: + "@types/node": ">=18" + peerDependenciesMeta: + "@types/node": + optional: true + checksum: 10/150dee6d6094663439a9941e5df5f1dadb819cd5ac68a7b5be0e0aceb4b74db0c8fa9a5fa0d21879928df6a53c84c9214b699f3fddbb6c617dd9c253a9d95155 + languageName: node + linkType: hard + +"@inquirer/number@npm:^3.0.21": + version: 3.0.21 + resolution: "@inquirer/number@npm:3.0.21" + dependencies: + "@inquirer/core": "npm:^10.3.0" + "@inquirer/type": "npm:^3.0.9" + peerDependencies: + "@types/node": ">=18" + peerDependenciesMeta: + "@types/node": + optional: true + checksum: 10/7b254cb3947c78a83593d82347bf93929b0af714cffa20f9f4503ec338004b3c0d6813945e3e3d7062b5d50006412b181ed833ac88c7da4df538df8bb15775d0 + languageName: node + linkType: hard + +"@inquirer/password@npm:^4.0.21": + version: 4.0.21 + resolution: "@inquirer/password@npm:4.0.21" + dependencies: + "@inquirer/ansi": "npm:^1.0.1" + "@inquirer/core": "npm:^10.3.0" + "@inquirer/type": "npm:^3.0.9" + peerDependencies: + "@types/node": ">=18" + peerDependenciesMeta: + "@types/node": + optional: true + checksum: 10/07fb1527ea2d44a81b79d9263f59713e66977e21fbf44efedb6bf08d27d617900ef481c49c91b0a749caf1d282f2b5e19fe6b7474acc98db3edd174eb5d45416 + languageName: node + linkType: hard + +"@inquirer/prompts@npm:^7.8.6": + version: 7.9.0 + resolution: "@inquirer/prompts@npm:7.9.0" + dependencies: + "@inquirer/checkbox": "npm:^4.3.0" + "@inquirer/confirm": "npm:^5.1.19" + "@inquirer/editor": "npm:^4.2.21" + "@inquirer/expand": "npm:^4.0.21" + "@inquirer/input": "npm:^4.2.5" + "@inquirer/number": "npm:^3.0.21" + "@inquirer/password": "npm:^4.0.21" + "@inquirer/rawlist": "npm:^4.1.9" + "@inquirer/search": "npm:^3.2.0" + "@inquirer/select": "npm:^4.4.0" + peerDependencies: + "@types/node": ">=18" + peerDependenciesMeta: + "@types/node": + optional: true + checksum: 10/ca58889261018be39a58e93c03c542d47d25dd7f5bb93e98bde7e3bf63eb70f8d5243d32a3fd53797bb474471682490513d99ec5179323862e5a15cdeb35f4b5 + languageName: node + linkType: hard + +"@inquirer/rawlist@npm:^4.1.9": + version: 4.1.9 + resolution: "@inquirer/rawlist@npm:4.1.9" + dependencies: + "@inquirer/core": "npm:^10.3.0" + "@inquirer/type": "npm:^3.0.9" + yoctocolors-cjs: "npm:^2.1.2" + peerDependencies: + "@types/node": ">=18" + peerDependenciesMeta: + "@types/node": + optional: true + checksum: 10/ec23e087bfa9497b36d51b53e8da18c837e4a0c5c091bce7d1a6b52d9664035d7e22c3753993dd3c7c9ebfd5e9b71f1738873f2c25422668733ddb28d74bf26b + languageName: node + linkType: hard + +"@inquirer/search@npm:^3.2.0": + version: 3.2.0 + resolution: "@inquirer/search@npm:3.2.0" + dependencies: + "@inquirer/core": "npm:^10.3.0" + "@inquirer/figures": "npm:^1.0.14" + "@inquirer/type": "npm:^3.0.9" + yoctocolors-cjs: "npm:^2.1.2" + peerDependencies: + "@types/node": ">=18" + peerDependenciesMeta: + "@types/node": + optional: true + checksum: 10/b01a53d6f72090f45cda39b75dd2e613e2d7fa0f454c0781f846e543b833eed4da831fec8d9e5325ebd4383684a69a74c5a38520b7ee0734b1090f71cf5dd372 + languageName: node + linkType: hard + +"@inquirer/select@npm:^4.4.0": + version: 4.4.0 + resolution: "@inquirer/select@npm:4.4.0" + dependencies: + "@inquirer/ansi": "npm:^1.0.1" + "@inquirer/core": "npm:^10.3.0" + "@inquirer/figures": "npm:^1.0.14" + "@inquirer/type": "npm:^3.0.9" + yoctocolors-cjs: "npm:^2.1.2" + peerDependencies: + "@types/node": ">=18" + peerDependenciesMeta: + "@types/node": + optional: true + checksum: 10/97f1f167d640c668ea5f137fca76fd9096215546f0890732ab8ed0c58ac3d9f01db5d1877e877e74ef6877a139ab8970ee683c6c3f2c08f2e11522f5e0bfd61e + languageName: node + linkType: hard + "@inquirer/type@npm:^3.0.1": version: 3.0.1 resolution: "@inquirer/type@npm:3.0.1" @@ -4014,6 +4250,18 @@ __metadata: languageName: node linkType: hard +"@inquirer/type@npm:^3.0.8, @inquirer/type@npm:^3.0.9": + version: 3.0.9 + resolution: "@inquirer/type@npm:3.0.9" + peerDependencies: + "@types/node": ">=18" + peerDependenciesMeta: + "@types/node": + optional: true + checksum: 10/960ba4737405f70bac17e7cdc4696c60064b06c8dd13a4b3d0783763ba1714bdadbd598b88d537ab9415b7d5d61e011ac042cfbd1438b2a35298e2868724b853 + languageName: node + linkType: hard + "@internationalized/date@npm:^3.10.0": version: 3.10.0 resolution: "@internationalized/date@npm:3.10.0" @@ -7333,6 +7581,13 @@ __metadata: languageName: node linkType: hard +"@sec-ant/readable-stream@npm:^0.4.1": + version: 0.4.1 + resolution: "@sec-ant/readable-stream@npm:0.4.1" + checksum: 10/aac89581652ac85debe7c5303451c2ebf8bf25ca25db680e4b9b73168f6940616d9a4bbe3348981827b1159b14e2f2e6af4b7bd5735cac898c12d5c51909c102 + languageName: node + linkType: hard + "@selderee/plugin-htmlparser2@npm:^0.11.0": version: 0.11.0 resolution: "@selderee/plugin-htmlparser2@npm:0.11.0" @@ -7445,6 +7700,13 @@ __metadata: languageName: node linkType: hard +"@sindresorhus/merge-streams@npm:^4.0.0": + version: 4.0.0 + resolution: "@sindresorhus/merge-streams@npm:4.0.0" + checksum: 10/16551c787f5328c8ef05fd9831ade64369ccc992df78deb635ec6c44af217d2f1b43f8728c348cdc4e00585ff2fad6e00d8155199cbf6b154acc45fe65cbf0aa + languageName: node + linkType: hard + "@sinonjs/commons@npm:^3.0.0": version: 3.0.0 resolution: "@sinonjs/commons@npm:3.0.0" @@ -8578,6 +8840,13 @@ __metadata: languageName: node linkType: hard +"@swc/core-darwin-arm64@npm:1.13.19": + version: 1.13.19 + resolution: "@swc/core-darwin-arm64@npm:1.13.19" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + "@swc/core-darwin-arm64@npm:1.13.3": version: 1.13.3 resolution: "@swc/core-darwin-arm64@npm:1.13.3" @@ -8585,6 +8854,13 @@ __metadata: languageName: node linkType: hard +"@swc/core-darwin-x64@npm:1.13.19": + version: 1.13.19 + resolution: "@swc/core-darwin-x64@npm:1.13.19" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + "@swc/core-darwin-x64@npm:1.13.3": version: 1.13.3 resolution: "@swc/core-darwin-x64@npm:1.13.3" @@ -8592,6 +8868,13 @@ __metadata: languageName: node linkType: hard +"@swc/core-linux-arm-gnueabihf@npm:1.13.19": + version: 1.13.19 + resolution: "@swc/core-linux-arm-gnueabihf@npm:1.13.19" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + "@swc/core-linux-arm-gnueabihf@npm:1.13.3": version: 1.13.3 resolution: "@swc/core-linux-arm-gnueabihf@npm:1.13.3" @@ -8599,6 +8882,13 @@ __metadata: languageName: node linkType: hard +"@swc/core-linux-arm64-gnu@npm:1.13.19": + version: 1.13.19 + resolution: "@swc/core-linux-arm64-gnu@npm:1.13.19" + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + "@swc/core-linux-arm64-gnu@npm:1.13.3": version: 1.13.3 resolution: "@swc/core-linux-arm64-gnu@npm:1.13.3" @@ -8606,6 +8896,13 @@ __metadata: languageName: node linkType: hard +"@swc/core-linux-arm64-musl@npm:1.13.19": + version: 1.13.19 + resolution: "@swc/core-linux-arm64-musl@npm:1.13.19" + conditions: os=linux & cpu=arm64 & libc=musl + languageName: node + linkType: hard + "@swc/core-linux-arm64-musl@npm:1.13.3": version: 1.13.3 resolution: "@swc/core-linux-arm64-musl@npm:1.13.3" @@ -8613,6 +8910,13 @@ __metadata: languageName: node linkType: hard +"@swc/core-linux-x64-gnu@npm:1.13.19": + version: 1.13.19 + resolution: "@swc/core-linux-x64-gnu@npm:1.13.19" + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + "@swc/core-linux-x64-gnu@npm:1.13.3": version: 1.13.3 resolution: "@swc/core-linux-x64-gnu@npm:1.13.3" @@ -8620,6 +8924,13 @@ __metadata: languageName: node linkType: hard +"@swc/core-linux-x64-musl@npm:1.13.19": + version: 1.13.19 + resolution: "@swc/core-linux-x64-musl@npm:1.13.19" + conditions: os=linux & cpu=x64 & libc=musl + languageName: node + linkType: hard + "@swc/core-linux-x64-musl@npm:1.13.3": version: 1.13.3 resolution: "@swc/core-linux-x64-musl@npm:1.13.3" @@ -8627,6 +8938,13 @@ __metadata: languageName: node linkType: hard +"@swc/core-win32-arm64-msvc@npm:1.13.19": + version: 1.13.19 + resolution: "@swc/core-win32-arm64-msvc@npm:1.13.19" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + "@swc/core-win32-arm64-msvc@npm:1.13.3": version: 1.13.3 resolution: "@swc/core-win32-arm64-msvc@npm:1.13.3" @@ -8634,6 +8952,13 @@ __metadata: languageName: node linkType: hard +"@swc/core-win32-ia32-msvc@npm:1.13.19": + version: 1.13.19 + resolution: "@swc/core-win32-ia32-msvc@npm:1.13.19" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + "@swc/core-win32-ia32-msvc@npm:1.13.3": version: 1.13.3 resolution: "@swc/core-win32-ia32-msvc@npm:1.13.3" @@ -8641,6 +8966,13 @@ __metadata: languageName: node linkType: hard +"@swc/core-win32-x64-msvc@npm:1.13.19": + version: 1.13.19 + resolution: "@swc/core-win32-x64-msvc@npm:1.13.19" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + "@swc/core-win32-x64-msvc@npm:1.13.3": version: 1.13.3 resolution: "@swc/core-win32-x64-msvc@npm:1.13.3" @@ -8648,6 +8980,52 @@ __metadata: languageName: node linkType: hard +"@swc/core@npm:1.13.19": + version: 1.13.19 + resolution: "@swc/core@npm:1.13.19" + dependencies: + "@swc/core-darwin-arm64": "npm:1.13.19" + "@swc/core-darwin-x64": "npm:1.13.19" + "@swc/core-linux-arm-gnueabihf": "npm:1.13.19" + "@swc/core-linux-arm64-gnu": "npm:1.13.19" + "@swc/core-linux-arm64-musl": "npm:1.13.19" + "@swc/core-linux-x64-gnu": "npm:1.13.19" + "@swc/core-linux-x64-musl": "npm:1.13.19" + "@swc/core-win32-arm64-msvc": "npm:1.13.19" + "@swc/core-win32-ia32-msvc": "npm:1.13.19" + "@swc/core-win32-x64-msvc": "npm:1.13.19" + "@swc/counter": "npm:^0.1.3" + "@swc/types": "npm:^0.1.25" + peerDependencies: + "@swc/helpers": ">=0.5.17" + dependenciesMeta: + "@swc/core-darwin-arm64": + optional: true + "@swc/core-darwin-x64": + optional: true + "@swc/core-linux-arm-gnueabihf": + optional: true + "@swc/core-linux-arm64-gnu": + optional: true + "@swc/core-linux-arm64-musl": + optional: true + "@swc/core-linux-x64-gnu": + optional: true + "@swc/core-linux-x64-musl": + optional: true + "@swc/core-win32-arm64-msvc": + optional: true + "@swc/core-win32-ia32-msvc": + optional: true + "@swc/core-win32-x64-msvc": + optional: true + peerDependenciesMeta: + "@swc/helpers": + optional: true + checksum: 10/07d0f72d8c82070a1ec2b439964780f0ba7aec61b17fa6518b1c372373bbe208ea9ce68f70f606d42df71a33149e4f704eabe07c6197e15d133e375546915f57 + languageName: node + linkType: hard + "@swc/core@npm:1.13.3, @swc/core@npm:^1.10.8, @swc/core@npm:^1.5.22": version: 1.13.3 resolution: "@swc/core@npm:1.13.3" @@ -8732,6 +9110,15 @@ __metadata: languageName: node linkType: hard +"@swc/types@npm:^0.1.25": + version: 0.1.25 + resolution: "@swc/types@npm:0.1.25" + dependencies: + "@swc/counter": "npm:^0.1.3" + checksum: 10/f6741450224892d12df43e5ca7f3cc0287df644dcd672626eb0cc2a3a8e3e875f4b29eb11336f37c7240cf6e010ba59eb3a79f4fb8bee5cbd168dfc1326ff369 + languageName: node + linkType: hard + "@tanstack/react-virtual@npm:^3.5.1, @tanstack/react-virtual@npm:^3.9.0": version: 3.10.9 resolution: "@tanstack/react-virtual@npm:3.10.9" @@ -12799,6 +13186,13 @@ __metadata: languageName: node linkType: hard +"chalk@npm:5.6.2, chalk@npm:^5.2.0, chalk@npm:^5.3.0, chalk@npm:^5.4.1, chalk@npm:^5.6.2": + version: 5.6.2 + resolution: "chalk@npm:5.6.2" + checksum: 10/1b2f48f6fba1370670d5610f9cd54c391d6ede28f4b7062dd38244ea5768777af72e5be6b74fb6c6d54cb84c4a2dff3f3afa9b7cb5948f7f022cfd3d087989e0 + languageName: node + linkType: hard + "chalk@npm:^2.4.2": version: 2.4.2 resolution: "chalk@npm:2.4.2" @@ -12830,13 +13224,6 @@ __metadata: languageName: node linkType: hard -"chalk@npm:^5.2.0, chalk@npm:^5.3.0, chalk@npm:^5.4.1, chalk@npm:^5.6.2": - version: 5.6.2 - resolution: "chalk@npm:5.6.2" - checksum: 10/1b2f48f6fba1370670d5610f9cd54c391d6ede28f4b7062dd38244ea5768777af72e5be6b74fb6c6d54cb84c4a2dff3f3afa9b7cb5948f7f022cfd3d087989e0 - languageName: node - linkType: hard - "chance@npm:^1.1.13": version: 1.1.13 resolution: "chance@npm:1.1.13" @@ -12906,6 +13293,13 @@ __metadata: languageName: node linkType: hard +"chardet@npm:^2.1.0": + version: 2.1.0 + resolution: "chardet@npm:2.1.0" + checksum: 10/8085fd8e5b1234fafacb279b4dab84dc127f512f953441daf09fc71ade70106af0dff28e86bfda00bab0de61fb475fa9003c87f82cbad3da02a4f299bfd427da + languageName: node + linkType: hard + "check-error@npm:^2.1.1": version: 2.1.1 resolution: "check-error@npm:2.1.1" @@ -12967,6 +13361,15 @@ __metadata: languageName: node linkType: hard +"chokidar@npm:4.0.3, chokidar@npm:^4.0.0, chokidar@npm:^4.0.1": + version: 4.0.3 + resolution: "chokidar@npm:4.0.3" + dependencies: + readdirp: "npm:^4.0.1" + checksum: 10/bf2a575ea5596000e88f5db95461a9d59ad2047e939d5a4aac59dd472d126be8f1c1ff3c7654b477cf532d18f42a97279ef80ee847972fd2a25410bf00b80b59 + languageName: node + linkType: hard + "chokidar@npm:^3.5.3": version: 3.6.0 resolution: "chokidar@npm:3.6.0" @@ -12986,15 +13389,6 @@ __metadata: languageName: node linkType: hard -"chokidar@npm:^4.0.0, chokidar@npm:^4.0.1": - version: 4.0.3 - resolution: "chokidar@npm:4.0.3" - dependencies: - readdirp: "npm:^4.0.1" - checksum: 10/bf2a575ea5596000e88f5db95461a9d59ad2047e939d5a4aac59dd472d126be8f1c1ff3c7654b477cf532d18f42a97279ef80ee847972fd2a25410bf00b80b59 - languageName: node - linkType: hard - "chownr@npm:^2.0.0": version: 2.0.0 resolution: "chownr@npm:2.0.0" @@ -13433,6 +13827,13 @@ __metadata: languageName: node linkType: hard +"commander@npm:14.0.1": + version: 14.0.1 + resolution: "commander@npm:14.0.1" + checksum: 10/783115e9403caeca29c0fcbd4e0358f70c67760e4e4933f3453fcdd5ddba2ec44173c8da5213d7ce5e404f51c7e71203a42c548164dbe27b668b32a8981577f1 + languageName: node + linkType: hard + "commander@npm:2.11.x": version: 2.11.0 resolution: "commander@npm:2.11.0" @@ -16794,6 +17195,26 @@ __metadata: languageName: node linkType: hard +"execa@npm:9.6.0": + version: 9.6.0 + resolution: "execa@npm:9.6.0" + dependencies: + "@sindresorhus/merge-streams": "npm:^4.0.0" + cross-spawn: "npm:^7.0.6" + figures: "npm:^6.1.0" + get-stream: "npm:^9.0.0" + human-signals: "npm:^8.0.1" + is-plain-obj: "npm:^4.1.0" + is-stream: "npm:^4.0.1" + npm-run-path: "npm:^6.0.0" + pretty-ms: "npm:^9.2.0" + signal-exit: "npm:^4.1.0" + strip-final-newline: "npm:^4.0.0" + yoctocolors: "npm:^2.1.1" + checksum: 10/53443be93d847ff5b52d31ed3714f77aab764fb6c1d72dc7019214ab1cb1a69888e2158ba846426a8ea51443c110fe7a86de61ffb9ee5687b00120fbd739b8a4 + languageName: node + linkType: hard + "execa@npm:^5.0.0": version: 5.1.1 resolution: "execa@npm:5.1.1" @@ -17158,6 +17579,15 @@ __metadata: languageName: node linkType: hard +"figures@npm:^6.1.0": + version: 6.1.0 + resolution: "figures@npm:6.1.0" + dependencies: + is-unicode-supported: "npm:^2.0.0" + checksum: 10/9822d13630bee8e6a9f2da866713adf13854b07e0bfde042defa8bba32d47a1c0b2afa627ce73837c674cf9a5e3edce7e879ea72cb9ea7960b2390432d8e1167 + languageName: node + linkType: hard + "file-entry-cache@npm:^10.1.3": version: 10.1.3 resolution: "file-entry-cache@npm:10.1.3" @@ -17934,6 +18364,16 @@ __metadata: languageName: node linkType: hard +"get-stream@npm:^9.0.0": + version: 9.0.1 + resolution: "get-stream@npm:9.0.1" + dependencies: + "@sec-ant/readable-stream": "npm:^0.4.1" + is-stream: "npm:^4.0.1" + checksum: 10/ce56e6db6bcd29ca9027b0546af035c3e93dcd154ca456b54c298901eb0e5b2ce799c5d727341a100c99e14c523f267f1205f46f153f7b75b1f4da6d98a21c5e + languageName: node + linkType: hard + "get-symbol-description@npm:^1.1.0": version: 1.1.0 resolution: "get-symbol-description@npm:1.1.0" @@ -18584,7 +19024,7 @@ __metadata: http-server: "npm:14.1.1" i18next: "npm:^25.0.0" i18next-browser-languagedetector: "npm:^8.0.0" - i18next-parser: "npm:9.3.0" + i18next-cli: "npm:1.11.12" i18next-pseudo: "npm:^2.2.1" immer: "npm:10.1.3" immutable: "npm:5.1.4" @@ -19405,6 +19845,13 @@ __metadata: languageName: node linkType: hard +"human-signals@npm:^8.0.1": + version: 8.0.1 + resolution: "human-signals@npm:8.0.1" + checksum: 10/903389a018b16f330c5e0f6e8b76d592c79552152ea892f249e5290e71c790f5722dc9b740fedd4bdef30566754a69012aaed97a6a528da0d417fad990a6f515 + languageName: node + linkType: hard + "humanize-duration@npm:^3.27.3": version: 3.32.1 resolution: "humanize-duration@npm:3.32.1" @@ -19437,6 +19884,28 @@ __metadata: languageName: node linkType: hard +"i18next-cli@npm:1.11.12": + version: 1.11.12 + resolution: "i18next-cli@npm:1.11.12" + dependencies: + "@swc/core": "npm:1.13.19" + chalk: "npm:5.6.2" + chokidar: "npm:4.0.3" + commander: "npm:14.0.1" + execa: "npm:9.6.0" + glob: "npm:11.0.3" + i18next-resources-for-ts: "npm:1.7.4" + inquirer: "npm:12.9.6" + jiti: "npm:2.6.1" + jsonc-parser: "npm:3.3.1" + ora: "npm:9.0.0" + swc-walk: "npm:1.0.0" + bin: + i18next-cli: dist/esm/cli.js + checksum: 10/b714cddb1fc5a611541a83f54320a84f4df5bd8308cd5b0c7abf6222d6d8e8cdac1e41fd9ecbb4d2930cf994e98d60235201f22e4f15baff0defb1759b2f3541 + languageName: node + linkType: hard + "i18next-parser@npm:9.3.0": version: 9.3.0 resolution: "i18next-parser@npm:9.3.0" @@ -19473,6 +19942,18 @@ __metadata: languageName: node linkType: hard +"i18next-resources-for-ts@npm:1.7.4": + version: 1.7.4 + resolution: "i18next-resources-for-ts@npm:1.7.4" + dependencies: + "@babel/runtime": "npm:^7.27.0" + yaml: "npm:^2.7.1" + bin: + i18next-resources-for-ts: bin/i18next-resources-for-ts.js + checksum: 10/02ce71939dc6f38672d3b33281367ad7f2c52623371fd88fc1d0033eac5a6385ef45fed49c7a49e5bac0f9a8a97cdc95ec3ee1c68f26cc75dcbdcb5b525ca6cc + languageName: node + linkType: hard + "i18next@npm:^19.1.0": version: 19.9.2 resolution: "i18next@npm:19.9.2" @@ -19492,22 +19973,22 @@ __metadata: linkType: hard "i18next@npm:^23.5.1 || ^24.2.0": - version: 24.2.3 - resolution: "i18next@npm:24.2.3" + version: 24.2.2 + resolution: "i18next@npm:24.2.2" dependencies: - "@babel/runtime": "npm:^7.26.10" + "@babel/runtime": "npm:^7.23.2" peerDependencies: typescript: ^5 peerDependenciesMeta: typescript: optional: true - checksum: 10/6c73d964f2a98b1aa2c2717fe6da66fc265bcbbc5fcd52b2bfff51ff013d30d4f7d7449c4eb7f464d27af43e2e73f2e7f1d46a144d731bd3bdb1385d4c199e4c + checksum: 10/f66ed9e56d9412e59502f5df39163631daf9f1264774732fb21edbd66a528ca7a6b67dc2e2aec95683c6c7956e42c651587a54bd8ee082bd12008880ce6cd326 languageName: node linkType: hard "i18next@npm:^25.0.0, i18next@npm:^25.5.2": - version: 25.6.0 - resolution: "i18next@npm:25.6.0" + version: 25.5.2 + resolution: "i18next@npm:25.5.2" dependencies: "@babel/runtime": "npm:^7.27.6" peerDependencies: @@ -19515,7 +19996,7 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 10/3eaa354f7028ff6051e4294c09bf518183c6653c019cfeed73fc4504786b3a474c3b55ed6b9832e122ba2538167b3eb85ae71fdd6423fb9ec9ebe2156b061d66 + checksum: 10/8d52e82386722a228f4465aa5cf39d82bd9861ea9cc8b31d7cc4d22d5e70b2740ee006068b09f486d5273cabd227a2ac14f37d68fab26344524200083f679bcd languageName: node linkType: hard @@ -19537,6 +20018,15 @@ __metadata: languageName: node linkType: hard +"iconv-lite@npm:^0.7.0": + version: 0.7.0 + resolution: "iconv-lite@npm:0.7.0" + dependencies: + safer-buffer: "npm:>= 2.1.2 < 3.0.0" + checksum: 10/5bfc897fedfb7e29991ae5ef1c061ed4f864005f8c6d61ef34aba6a3885c04bd207b278c0642b041383aeac2d11645b4319d0ca7b863b0be4be0cde1c9238ca7 + languageName: node + linkType: hard + "icss-utils@npm:^5.0.0, icss-utils@npm:^5.1.0": version: 5.1.0 resolution: "icss-utils@npm:5.1.0" @@ -19779,6 +20269,26 @@ __metadata: languageName: node linkType: hard +"inquirer@npm:12.9.6": + version: 12.9.6 + resolution: "inquirer@npm:12.9.6" + dependencies: + "@inquirer/ansi": "npm:^1.0.0" + "@inquirer/core": "npm:^10.2.2" + "@inquirer/prompts": "npm:^7.8.6" + "@inquirer/type": "npm:^3.0.8" + mute-stream: "npm:^2.0.0" + run-async: "npm:^4.0.5" + rxjs: "npm:^7.8.2" + peerDependencies: + "@types/node": ">=18" + peerDependenciesMeta: + "@types/node": + optional: true + checksum: 10/bcac231b3eba055aa16dbdb60ba6d7bfe66109be654bfb19f92095f703af07fc01528f716e86ec62f7bf7bd17b4e21ad4bb32b677cf42075dee04568afe9686b + languageName: node + linkType: hard + "inquirer@npm:^8.2.4": version: 8.2.6 resolution: "inquirer@npm:8.2.6" @@ -20313,7 +20823,7 @@ __metadata: languageName: node linkType: hard -"is-plain-obj@npm:^4.0.0": +"is-plain-obj@npm:^4.0.0, is-plain-obj@npm:^4.1.0": version: 4.1.0 resolution: "is-plain-obj@npm:4.1.0" checksum: 10/6dc45da70d04a81f35c9310971e78a6a3c7a63547ef782e3a07ee3674695081b6ca4e977fbb8efc48dae3375e0b34558d2bcd722aec9bddfa2d7db5b041be8ce @@ -20417,6 +20927,13 @@ __metadata: languageName: node linkType: hard +"is-stream@npm:^4.0.1": + version: 4.0.1 + resolution: "is-stream@npm:4.0.1" + checksum: 10/cbea3f1fc271b21ceb228819d0c12a0965a02b57f39423925f99530b4eb86935235f258f06310b67cd02b2d10b49e9a0998f5ececf110ab7d3760bae4055ad23 + languageName: node + linkType: hard + "is-string@npm:^1.1.1": version: 1.1.1 resolution: "is-string@npm:1.1.1" @@ -21430,6 +21947,15 @@ __metadata: languageName: node linkType: hard +"jiti@npm:2.6.1": + version: 2.6.1 + resolution: "jiti@npm:2.6.1" + bin: + jiti: lib/jiti-cli.mjs + checksum: 10/8cd72c5fd03a0502564c3f46c49761090f6dadead21fa191b73535724f095ad86c2fa89ee6fe4bc3515337e8d406cc8fb2d37b73fa0c99a34584bac35cd4a4de + languageName: node + linkType: hard + "jiti@npm:^1.20.0": version: 1.21.6 resolution: "jiti@npm:1.21.6" @@ -21745,7 +22271,7 @@ __metadata: languageName: node linkType: hard -"jsonc-parser@npm:^3.2.0": +"jsonc-parser@npm:3.3.1, jsonc-parser@npm:^3.2.0": version: 3.3.1 resolution: "jsonc-parser@npm:3.3.1" checksum: 10/9b0dc391f20b47378f843ef1e877e73ec652a5bdc3c5fa1f36af0f119a55091d147a86c1ee86a232296f55c929bba174538c2bf0312610e0817a22de131cc3f4 @@ -24233,6 +24759,16 @@ __metadata: languageName: node linkType: hard +"npm-run-path@npm:^6.0.0": + version: 6.0.0 + resolution: "npm-run-path@npm:6.0.0" + dependencies: + path-key: "npm:^4.0.0" + unicorn-magic: "npm:^0.3.0" + checksum: 10/1a1b50aba6e6af7fd34a860ba2e252e245c4a59b316571a990356417c0cdf0414cabf735f7f52d9c330899cb56f0ab804a8e21fb12a66d53d7843e39ada4a3b6 + languageName: node + linkType: hard + "npmlog@npm:^4.1.2": version: 4.1.2 resolution: "npmlog@npm:4.1.2" @@ -24871,6 +25407,23 @@ __metadata: languageName: node linkType: hard +"ora@npm:9.0.0, ora@npm:^9.0.0": + version: 9.0.0 + resolution: "ora@npm:9.0.0" + dependencies: + chalk: "npm:^5.6.2" + cli-cursor: "npm:^5.0.0" + cli-spinners: "npm:^3.2.0" + is-interactive: "npm:^2.0.0" + is-unicode-supported: "npm:^2.1.0" + log-symbols: "npm:^7.0.1" + stdin-discarder: "npm:^0.2.2" + string-width: "npm:^8.1.0" + strip-ansi: "npm:^7.1.2" + checksum: 10/b6074c9cec4a39c1b4f41c2ce2741982a99c53c86bd6f07a28fb6274857263af7fe1a340136629939934b553af35b03fc62ca2a88baa6803b2f9bfdf269fb850 + languageName: node + linkType: hard + "ora@npm:^5.4.1": version: 5.4.1 resolution: "ora@npm:5.4.1" @@ -24905,23 +25458,6 @@ __metadata: languageName: node linkType: hard -"ora@npm:^9.0.0": - version: 9.0.0 - resolution: "ora@npm:9.0.0" - dependencies: - chalk: "npm:^5.6.2" - cli-cursor: "npm:^5.0.0" - cli-spinners: "npm:^3.2.0" - is-interactive: "npm:^2.0.0" - is-unicode-supported: "npm:^2.1.0" - log-symbols: "npm:^7.0.1" - stdin-discarder: "npm:^0.2.2" - string-width: "npm:^8.1.0" - strip-ansi: "npm:^7.1.2" - checksum: 10/b6074c9cec4a39c1b4f41c2ce2741982a99c53c86bd6f07a28fb6274857263af7fe1a340136629939934b553af35b03fc62ca2a88baa6803b2f9bfdf269fb850 - languageName: node - linkType: hard - "os-homedir@npm:^1.0.1": version: 1.0.2 resolution: "os-homedir@npm:1.0.2" @@ -25381,6 +25917,13 @@ __metadata: languageName: node linkType: hard +"parse-ms@npm:^4.0.0": + version: 4.0.0 + resolution: "parse-ms@npm:4.0.0" + checksum: 10/673c801d9f957ff79962d71ed5a24850163f4181a90dd30c4e3666b3a804f53b77f1f0556792e8b2adbb5d58757907d1aa51d7d7dc75997c2a56d72937cbc8b7 + languageName: node + linkType: hard + "parse-passwd@npm:^1.0.0": version: 1.0.0 resolution: "parse-passwd@npm:1.0.0" @@ -25543,6 +26086,13 @@ __metadata: languageName: node linkType: hard +"path-key@npm:^4.0.0": + version: 4.0.0 + resolution: "path-key@npm:4.0.0" + checksum: 10/8e6c314ae6d16b83e93032c61020129f6f4484590a777eed709c4a01b50e498822b00f76ceaf94bc64dbd90b327df56ceadce27da3d83393790f1219e07721d7 + languageName: node + linkType: hard + "path-parse@npm:^1.0.7": version: 1.0.7 resolution: "path-parse@npm:1.0.7" @@ -26424,6 +26974,15 @@ __metadata: languageName: node linkType: hard +"pretty-ms@npm:^9.2.0": + version: 9.3.0 + resolution: "pretty-ms@npm:9.3.0" + dependencies: + parse-ms: "npm:^4.0.0" + checksum: 10/beb4e04dc17071885b827e3f33d36be279791f2f36a8c29a45c77e59979dad79a5d7e5211922c72a3f6f109bb64a707d70fcdba6746e077122afcd88ce202e98 + languageName: node + linkType: hard + "pretty-time@npm:^1.1.0": version: 1.1.0 resolution: "pretty-time@npm:1.1.0" @@ -28916,6 +29475,13 @@ __metadata: languageName: node linkType: hard +"run-async@npm:^4.0.5": + version: 4.0.6 + resolution: "run-async@npm:4.0.6" + checksum: 10/d23929e36d0422b871a8964d5cfcb1b88295950ea5f72e1dfed458d4c3f3a33a7395e08167d8a4446f2110cfaac7d7653d9c804d2becab8afa8a63e16b97da81 + languageName: node + linkType: hard + "run-parallel@npm:^1.1.9": version: 1.2.0 resolution: "run-parallel@npm:1.2.0" @@ -28941,7 +29507,7 @@ __metadata: languageName: node linkType: hard -"rxjs@npm:7.8.2, rxjs@npm:^7.2.0, rxjs@npm:^7.5.1, rxjs@npm:^7.5.5, rxjs@npm:^7.8.1": +"rxjs@npm:7.8.2, rxjs@npm:^7.2.0, rxjs@npm:^7.5.1, rxjs@npm:^7.5.5, rxjs@npm:^7.8.1, rxjs@npm:^7.8.2": version: 7.8.2 resolution: "rxjs@npm:7.8.2" dependencies: @@ -30501,6 +31067,13 @@ __metadata: languageName: node linkType: hard +"strip-final-newline@npm:^4.0.0": + version: 4.0.0 + resolution: "strip-final-newline@npm:4.0.0" + checksum: 10/b5fe48f695d74863153a3b3155220e6e9bf51f4447832998c8edec38e6559b3af87a9fe5ac0df95570a78a26f5fa91701358842eab3c15480e27980b154a145f + languageName: node + linkType: hard + "strip-indent@npm:^3.0.0": version: 3.0.0 resolution: "strip-indent@npm:3.0.0" @@ -30838,6 +31411,15 @@ __metadata: languageName: node linkType: hard +"swc-walk@npm:1.0.0": + version: 1.0.0 + resolution: "swc-walk@npm:1.0.0" + dependencies: + acorn-walk: "npm:^8.3.4" + checksum: 10/f6dc27eef421033956acbe12061e5f43a18b28747fd914734589f25d4144b0ef7de53bb1bf24fcf3a2355f305a3eb0593d0eaa006a43316113c79672b0c070bd + languageName: node + linkType: hard + "symbol-observable@npm:4.0.0": version: 4.0.0 resolution: "symbol-observable@npm:4.0.0" @@ -32094,6 +32676,13 @@ __metadata: languageName: node linkType: hard +"unicorn-magic@npm:^0.3.0": + version: 0.3.0 + resolution: "unicorn-magic@npm:0.3.0" + checksum: 10/bdd7d7c522f9456f32a0b77af23f8854f9a7db846088c3868ec213f9550683ab6a2bdf3803577eacbafddb4e06900974385841ccb75338d17346ccef45f9cb01 + languageName: node + linkType: hard + "union@npm:~0.5.0": version: 0.5.0 resolution: "union@npm:0.5.0" @@ -33540,6 +34129,15 @@ __metadata: languageName: node linkType: hard +"yaml@npm:^2.7.1": + version: 2.8.1 + resolution: "yaml@npm:2.8.1" + bin: + yaml: bin.mjs + checksum: 10/eae07b3947d405012672ec17ce27348aea7d1fa0534143355d24a43a58f5e05652157ea2182c4fe0604f0540be71f99f1173f9d61018379404507790dff17665 + languageName: node + linkType: hard + "yargs-parser@npm:21.1.1, yargs-parser@npm:^21.1.1": version: 21.1.1 resolution: "yargs-parser@npm:21.1.1" From 3c57a1880c8207cf0f55a8eb112ddbdfdcaf4762 Mon Sep 17 00:00:00 2001 From: Sonia Aguilar <33540275+soniaAguilarPeiron@users.noreply.github.com> Date: Mon, 27 Oct 2025 10:54:50 +0100 Subject: [PATCH 017/378] Alerting: Fix enrichment tab to be rendered only for grafana alerting rules (#113030) fix enrichment tab to be rendered only for grafana alerting rules --- .../rule-view-page/extensions.tsx | 41 ++++++++++++++++--- .../rule-view-page/navigation.test.ts | 13 ++++-- .../rule-view-page/navigation.ts | 4 +- 3 files changed, 48 insertions(+), 10 deletions(-) diff --git a/public/app/features/alerting/unified/enterprise-components/rule-view-page/extensions.tsx b/public/app/features/alerting/unified/enterprise-components/rule-view-page/extensions.tsx index d26e996686c..a4d5034e103 100644 --- a/public/app/features/alerting/unified/enterprise-components/rule-view-page/extensions.tsx +++ b/public/app/features/alerting/unified/enterprise-components/rule-view-page/extensions.tsx @@ -4,6 +4,9 @@ import { FeatureState, NavModelItem } from '@grafana/data'; import { t } from '@grafana/i18n'; import { FeatureBadge, useStyles2 } from '@grafana/ui'; +import { useAlertRule } from '../../components/rule-viewer/RuleContext'; +import { rulerRuleType } from '../../utils/rules'; + type SetActiveTab = (tab: string) => void; type RuleViewTabBuilderArgs = { @@ -12,15 +15,31 @@ type RuleViewTabBuilderArgs = { }; type RuleViewTabBuilder = (args: RuleViewTabBuilderArgs) => NavModelItem; +type RuleViewTabBuilderConfig = { + filterOnlyGrafanaAlertRules: boolean; + ruleViewTabBuilder: RuleViewTabBuilder; +}; -const ruleViewTabBuilders: RuleViewTabBuilder[] = []; +const ruleViewTabBuilders: RuleViewTabBuilderConfig[] = []; -export function registerRuleViewTab(builder: RuleViewTabBuilder) { - ruleViewTabBuilders.push(builder); +function registerRuleViewTab(builder: RuleViewTabBuilder) { + ruleViewTabBuilders.push({ + filterOnlyGrafanaAlertRules: true, + ruleViewTabBuilder: builder, + }); } -export function getRuleViewExtensionTabs(args: RuleViewTabBuilderArgs): NavModelItem[] { - return ruleViewTabBuilders.map((builder) => builder(args)); +export function useRuleViewExtensionTabs(args: RuleViewTabBuilderArgs): NavModelItem[] { + const { rule } = useAlertRule(); + const isGrafanaAlertRule = rulerRuleType.grafana.alertingRule(rule.rulerRule); + return ruleViewTabBuilders + .filter((config) => { + if (config.filterOnlyGrafanaAlertRules) { + return isGrafanaAlertRule; + } + return true; + }) + .map((config) => config.ruleViewTabBuilder(args)); } export function addEnrichmentSection() { @@ -40,6 +59,18 @@ export function __clearRuleViewTabsForTests() { ruleViewTabBuilders.splice(0, ruleViewTabBuilders.length); } +// ONLY FOR TESTS: non-hook version for testing +export function getRuleViewExtensionTabs(args: RuleViewTabBuilderArgs, isGrafanaAlertRule: boolean): NavModelItem[] { + return ruleViewTabBuilders + .filter((config) => { + if (config.filterOnlyGrafanaAlertRules) { + return isGrafanaAlertRule; + } + return true; + }) + .map((config) => config.ruleViewTabBuilder(args)); +} + function getStyles() { return { tabSuffix: css({ diff --git a/public/app/features/alerting/unified/enterprise-components/rule-view-page/navigation.test.ts b/public/app/features/alerting/unified/enterprise-components/rule-view-page/navigation.test.ts index 18599640e3d..9fdaa2a74d9 100644 --- a/public/app/features/alerting/unified/enterprise-components/rule-view-page/navigation.test.ts +++ b/public/app/features/alerting/unified/enterprise-components/rule-view-page/navigation.test.ts @@ -10,14 +10,14 @@ describe('rule-view-page navigation', () => { }); it('does not include Alert enrichment tab when not registered', () => { - const tabs = getRuleViewExtensionTabs({ activeTab: 'query', setActiveTab: () => {} }); + const tabs = getRuleViewExtensionTabs({ activeTab: 'query', setActiveTab: () => {} }, true); const hasEnrichment = tabs.some((t) => t.text === 'Alert enrichment'); expect(hasEnrichment).toBe(false); }); it('includes Alert enrichment tab when registered (enterprise + toggle on)', () => { addEnrichmentSection(); - const tabs = getRuleViewExtensionTabs({ activeTab: 'query', setActiveTab: () => {} }); + const tabs = getRuleViewExtensionTabs({ activeTab: 'query', setActiveTab: () => {} }, true); const enrichment = tabs.find((t) => t.text === 'Alert enrichment'); expect(enrichment).toBeTruthy(); expect(enrichment!.active).toBe(false); @@ -25,12 +25,19 @@ describe('rule-view-page navigation', () => { it('marks Alert enrichment tab active when selected', () => { addEnrichmentSection(); - const tabs = getRuleViewExtensionTabs({ activeTab: 'enrichment', setActiveTab: () => {} }); + const tabs = getRuleViewExtensionTabs({ activeTab: 'enrichment', setActiveTab: () => {} }, true); const enrichment = tabs.find((t) => t.text === 'Alert enrichment'); expect(enrichment).toBeTruthy(); expect(enrichment!.active).toBe(true); }); + it('excludes Alert enrichment tab when not a Grafana alert rule', () => { + addEnrichmentSection(); + const tabs = getRuleViewExtensionTabs({ activeTab: 'query', setActiveTab: () => {} }, false); + const enrichment = tabs.find((t) => t.text === 'Alert enrichment'); + expect(enrichment).toBeUndefined(); + }); + describe('enrichment section registration', () => { it('should register enrichment section with correct prop interface', () => { const mockEnrichmentSection = jest.fn(() => null); diff --git a/public/app/features/alerting/unified/enterprise-components/rule-view-page/navigation.ts b/public/app/features/alerting/unified/enterprise-components/rule-view-page/navigation.ts index 2f1f4d0d5eb..313b26da7b6 100644 --- a/public/app/features/alerting/unified/enterprise-components/rule-view-page/navigation.ts +++ b/public/app/features/alerting/unified/enterprise-components/rule-view-page/navigation.ts @@ -1,7 +1,7 @@ import { NavModelItem } from '@grafana/data'; -import { getRuleViewExtensionTabs } from './extensions'; +import { useRuleViewExtensionTabs } from './extensions'; export function useRuleViewExtensionsNav(activeTab: string, setActiveTab: (tab: string) => void): NavModelItem[] { - return getRuleViewExtensionTabs({ activeTab, setActiveTab }); + return useRuleViewExtensionTabs({ activeTab, setActiveTab }); } From 7cd3e5dc54db0e2770caafb1637597b6a9988891 Mon Sep 17 00:00:00 2001 From: "renovate-sh-app[bot]" <219655108+renovate-sh-app[bot]@users.noreply.github.com> Date: Mon, 27 Oct 2025 09:57:37 +0000 Subject: [PATCH 018/378] chore(deps): update dependency @reduxjs/toolkit to v2.9.1 (#112975) | datasource | package | from | to | | ---------- | ---------------- | ----- | ----- | | npm | @reduxjs/toolkit | 2.9.0 | 2.9.1 | Signed-off-by: renovate-sh-app[bot] <219655108+renovate-sh-app[bot]@users.noreply.github.com> Co-authored-by: renovate-sh-app[bot] <219655108+renovate-sh-app[bot]@users.noreply.github.com> --- yarn.lock | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/yarn.lock b/yarn.lock index ad8690ca104..8c4162c22ce 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7079,7 +7079,7 @@ __metadata: languageName: node linkType: hard -"@reduxjs/toolkit@npm:2.9.0, @reduxjs/toolkit@npm:^2.9.0": +"@reduxjs/toolkit@npm:2.9.0": version: 2.9.0 resolution: "@reduxjs/toolkit@npm:2.9.0" dependencies: @@ -7101,6 +7101,28 @@ __metadata: languageName: node linkType: hard +"@reduxjs/toolkit@npm:^2.9.0": + version: 2.9.2 + resolution: "@reduxjs/toolkit@npm:2.9.2" + dependencies: + "@standard-schema/spec": "npm:^1.0.0" + "@standard-schema/utils": "npm:^0.3.0" + immer: "npm:^10.0.3" + redux: "npm:^5.0.1" + redux-thunk: "npm:^3.1.0" + reselect: "npm:^5.1.0" + peerDependencies: + react: ^16.9.0 || ^17.0.0 || ^18 || ^19 + react-redux: ^7.2.1 || ^8.1.3 || ^9.0.0 + peerDependenciesMeta: + react: + optional: true + react-redux: + optional: true + checksum: 10/7a8fa57086bc44dafe2f04428d6557edad46ee6eb46b2fe80468ebf934a441a7d4d750b50a6d41bc360d9ab61baadb1dddb5a8f556cfac68977f56e832f509a2 + languageName: node + linkType: hard + "@remix-run/router@npm:1.19.1": version: 1.19.1 resolution: "@remix-run/router@npm:1.19.1" From 5a5aa1857093be7aeb694e5bc050d004ba4c15a5 Mon Sep 17 00:00:00 2001 From: Levente Balogh Date: Mon, 27 Oct 2025 11:40:47 +0100 Subject: [PATCH 019/378] Dashboard Controls: Address the spacing between switch variables (#112819) fix: adjust switch variable height in dashboard-controls menu --- .../dashboard-scene/scene/DashboardControlsMenu.tsx | 6 +++--- .../app/features/dashboard-scene/scene/VariableControls.tsx | 4 +++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/public/app/features/dashboard-scene/scene/DashboardControlsMenu.tsx b/public/app/features/dashboard-scene/scene/DashboardControlsMenu.tsx index e6db4f54b5f..bee89dc8565 100644 --- a/public/app/features/dashboard-scene/scene/DashboardControlsMenu.tsx +++ b/public/app/features/dashboard-scene/scene/DashboardControlsMenu.tsx @@ -75,7 +75,7 @@ function DashboardControlsMenu({ variables, links, dashboardUID }: DashboardCont > {/* Variables */} {variables.map((variable, index) => ( -
0 && styles.menuItem)} key={variable.state.key}> +
0 })} key={variable.state.key}>
))} @@ -98,10 +98,10 @@ function DashboardControlsMenu({ variables, links, dashboardUID }: DashboardCont const getStyles = (theme: GrafanaTheme2) => ({ divider: css({ - marginTop: theme.spacing(1), + marginTop: theme.spacing(2), padding: theme.spacing(0, 0.5), }), - menuItem: css({ + variableItem: css({ marginTop: theme.spacing(2), }), }); diff --git a/public/app/features/dashboard-scene/scene/VariableControls.tsx b/public/app/features/dashboard-scene/scene/VariableControls.tsx index 4052efc6bd4..f28ad7d174d 100644 --- a/public/app/features/dashboard-scene/scene/VariableControls.tsx +++ b/public/app/features/dashboard-scene/scene/VariableControls.tsx @@ -160,10 +160,12 @@ const getStyles = (theme: GrafanaTheme2) => ({ border: 'none', background: 'transparent', paddingRight: theme.spacing(0.5), + height: theme.spacing(2), }, }), switchLabel: css({ - marginTop: theme.spacing(0.5), + marginTop: 0, + marginBottom: 0, }), labelWrapper: css({ display: 'flex', From b53e3ac860a9d1f8f181694a94a0bb51de481a1e Mon Sep 17 00:00:00 2001 From: Alex Khomenko Date: Mon, 27 Oct 2025 13:03:22 +0200 Subject: [PATCH 020/378] Provisioning: Update pulling disabled badge (#112832) * Provisioning: Update pulling disabled badge * Move props * Use early return --- .../provisioning/Shared/StatusBadge.tsx | 154 +++++++++--------- public/locales/en-US/grafana.json | 13 +- 2 files changed, 91 insertions(+), 76 deletions(-) diff --git a/public/app/features/provisioning/Shared/StatusBadge.tsx b/public/app/features/provisioning/Shared/StatusBadge.tsx index 385e8d91bd0..7ddb8bb3d9d 100644 --- a/public/app/features/provisioning/Shared/StatusBadge.tsx +++ b/public/app/features/provisioning/Shared/StatusBadge.tsx @@ -1,3 +1,5 @@ +import { useCallback } from 'react'; + import { t } from '@grafana/i18n'; import { locationService } from '@grafana/runtime'; import { Badge, BadgeColor, IconName } from '@grafana/ui'; @@ -5,85 +7,93 @@ import { Repository } from 'app/api/clients/provisioning/v0alpha1'; import { PROVISIONING_URL } from '../constants'; +interface BadgeConfig { + color: BadgeColor; + text: string; + icon: IconName; + tooltip?: string; +} + +function getBadgeConfig(repo: Repository): BadgeConfig { + if (repo.metadata?.deletionTimestamp) { + return { + color: 'red', + text: t('provisioning.status-badge.deleting', 'Deleting'), + icon: 'spinner', + }; + } + + if (!repo.spec?.sync?.enabled) { + return { + color: 'orange', + text: t('provisioning.status-badge.automatic-pulling-disabled', 'Automatic pulling disabled'), + icon: 'info-circle', + }; + } + + if (!repo.status?.sync?.state?.length) { + return { + color: 'darkgrey', + text: t('provisioning.status-badge.pending', 'Pending'), + icon: 'spinner', + tooltip: t('provisioning.status-badge.waiting-for-health-check', 'Waiting for health check to run'), + }; + } + + // Sync state + switch (repo.status?.sync?.state) { + case 'success': + return { + icon: 'check', + text: t('provisioning.status-badge.up-to-date', 'Up-to-date'), + color: 'green', + }; + case 'warning': + return { + color: 'orange', + text: t('provisioning.status-badge.warning', 'Warning'), + icon: 'exclamation-triangle', + }; + case 'working': + case 'pending': + return { + color: 'darkgrey', + text: t('provisioning.status-badge.pulling', 'Pulling'), + icon: 'spinner', + }; + case 'error': + return { + color: 'red', + text: t('provisioning.status-badge.error', 'Error'), + icon: 'exclamation-triangle', + }; + default: + return { + color: 'purple', + text: t('provisioning.status-badge.unknown', 'Unknown'), + icon: 'exclamation-triangle', + }; + } +} + interface StatusBadgeProps { repo?: Repository; displayOnly?: boolean; // if true, disable click action and cursor will be default } -/** - * @description Displays a status badge for the given provisioned repository. - */ export function StatusBadge({ repo, displayOnly = false }: StatusBadgeProps) { + const handleClick = useCallback(() => { + if (displayOnly || !repo?.metadata?.name) { + return; + } + locationService.push(`${PROVISIONING_URL}/${repo.metadata.name}/?tab=overview`); + }, [repo?.metadata?.name, displayOnly]); + if (!repo) { return null; } - // TODO: remove after 12.2 - if (repo.spec?.type !== 'local' && !repo.secure?.token?.name) { - return ( - { - // navigate to edit page, rather than view page - locationService.push(`${PROVISIONING_URL}/${repo.metadata?.name}/edit`); - }} - /> - ); - } - - let tooltip: string | undefined = undefined; - let color: BadgeColor = 'purple'; - let text = 'Unknown'; - let icon: IconName = 'exclamation-triangle'; - - if (repo.metadata?.deletionTimestamp) { - color = 'red'; - text = 'Deleting'; - icon = 'spinner'; - } else if (!repo.spec?.sync?.enabled) { - color = 'red'; - text = 'Automatic pulling disabled'; - icon = 'info-circle'; - } else if (!repo.status?.sync?.state?.length) { - color = 'darkgrey'; - text = 'Pending'; - icon = 'spinner'; - tooltip = 'Waiting for health check to run'; - } else { - // Sync state - switch (repo.status?.sync?.state) { - case 'success': - icon = 'check'; - text = 'Up-to-date'; - color = 'green'; - break; - case 'working': - case 'warning': - color = 'orange'; - text = 'warning'; - icon = 'exclamation-triangle'; - break; - case 'pending': - color = 'darkgrey'; - text = 'Pulling'; - icon = 'spinner'; - break; - case 'error': - color = 'red'; - text = 'Error'; - icon = 'exclamation-triangle'; - break; - default: - break; - } - } + const { color, text, icon, tooltip } = getBadgeConfig(repo); return ( { - if (!displayOnly) { - locationService.push(`${PROVISIONING_URL}/${repo.metadata?.name}/?tab=overview`); - } - }} + onClick={handleClick} /> ); } diff --git a/public/locales/en-US/grafana.json b/public/locales/en-US/grafana.json index 050e39bb67b..24db448f23e 100644 --- a/public/locales/en-US/grafana.json +++ b/public/locales/en-US/grafana.json @@ -9199,7 +9199,6 @@ "name-line-width": "Line width", "name-stacking": "Stacking" }, - "inline-token-warning-badge-tooltip": "The method to save the token is to re-enter it in the repository settings.", "inspector": { "inspect-data-tab": { "loading": "Loading", @@ -11654,7 +11653,6 @@ "unsupported-repository-type": "Unsupported repository type: {{repositoryType}}" }, "inline-secure-values-warning": "You need to save your access tokens again due to a system update", - "inline-token-warning-badge-text": "Token needs to be saved again", "job-status": { "label-view-details": "View details", "loading-finished-job": "Loading finished job...", @@ -11831,6 +11829,17 @@ "label-current-step": "Current step", "label-pending-step": "Pending step" }, + "status-badge": { + "automatic-pulling-disabled": "Automatic pulling disabled", + "deleting": "Deleting", + "error": "Error", + "pending": "Pending", + "pulling": "Pulling", + "unknown": "Unknown", + "up-to-date": "Up-to-date", + "waiting-for-health-check": "Waiting for health check to run", + "warning": "Warning" + }, "success-title-default": "Success", "sync-job": { "error-no-job-id": "Failed to start job", From bc9540fadbfb18b16bef192d0e5fe5496a4aa7e6 Mon Sep 17 00:00:00 2001 From: Georges Chaudy Date: Mon, 27 Oct 2025 12:27:31 +0100 Subject: [PATCH 021/378] kvstore: use batch delete to cleanup old events (#112737) * use batchdelete for cleaning up old events * comment --- pkg/storage/unified/resource/datastore.go | 2 +- pkg/storage/unified/resource/eventstore.go | 42 ++++++++++++---- .../unified/resource/eventstore_test.go | 50 +++++++++++++++++++ 3 files changed, 82 insertions(+), 12 deletions(-) diff --git a/pkg/storage/unified/resource/datastore.go b/pkg/storage/unified/resource/datastore.go index 8ecb878b675..1b23a84e922 100644 --- a/pkg/storage/unified/resource/datastore.go +++ b/pkg/storage/unified/resource/datastore.go @@ -364,7 +364,7 @@ func (d *dataStore) Get(ctx context.Context, key DataKey) (io.ReadCloser, error) // BatchGet retrieves multiple data objects in batches. // It returns an iterator that yields DataObj results for the given keys. -// Keys are processed in batches (default 50) to balance between efficiency and memory usage. +// Keys are processed in batches (default 50). // Non-existent entries will not appear in the result. func (d *dataStore) BatchGet(ctx context.Context, keys []DataKey) iter.Seq2[DataObj, error] { return func(yield func(DataObj, error) bool) { diff --git a/pkg/storage/unified/resource/eventstore.go b/pkg/storage/unified/resource/eventstore.go index 04a35606f81..828e3cececf 100644 --- a/pkg/storage/unified/resource/eventstore.go +++ b/pkg/storage/unified/resource/eventstore.go @@ -15,7 +15,8 @@ import ( ) const ( - eventsSection = "unified/events" + eventsSection = "unified/events" + deleteEventBatchSize = 50 ) // eventStore is a store for events. @@ -231,24 +232,43 @@ func (n *eventStore) ListSince(ctx context.Context, sinceRV int64) iter.Seq2[Eve // CleanupOldEvents deletes events older than the specified retention period. func (n *eventStore) CleanupOldEvents(ctx context.Context, cutoff time.Time) (int, error) { - deletedCount := 0 - // Keys are stored in the format of "resource_version~namespace~group~resource~name" // With a start key of "1" and an end key of the cutoff time we can get all expired events. endKey := fmt.Sprintf("%d", snowflakeFromTime(cutoff)) + + // Collect keys to delete + keysToDelete := make([]string, 0, deleteEventBatchSize) for key, err := range n.kv.Keys(ctx, eventsSection, ListOptions{StartKey: "1", EndKey: endKey}) { if err != nil { - return deletedCount, fmt.Errorf("failed to list event keys: %w", err) + return 0, fmt.Errorf("failed to list event keys: %w", err) } - - // TODO should use batch deletes here when available - if err := n.kv.Delete(ctx, eventsSection, key); err != nil { - return deletedCount, fmt.Errorf("failed to delete event key %s: %w", key, err) - } - deletedCount++ + keysToDelete = append(keysToDelete, key) } - return deletedCount, nil + // Use batch delete + if err := n.batchDelete(ctx, keysToDelete); err != nil { + return 0, fmt.Errorf("failed to batch delete events: %w", err) + } + + return len(keysToDelete), nil +} + +// batchDelete deletes multiple events in batches. +// Keys are processed in batches (default 50). +func (n *eventStore) batchDelete(ctx context.Context, keys []string) error { + for len(keys) > 0 { + batch := keys + if len(batch) > deleteEventBatchSize { + batch = batch[:deleteEventBatchSize] + } + keys = keys[len(batch):] + + if err := n.kv.BatchDelete(ctx, eventsSection, batch); err != nil { + return err + } + } + + return nil } // snowflake id with last two sections set to 0 (machine id and sequence) diff --git a/pkg/storage/unified/resource/eventstore_test.go b/pkg/storage/unified/resource/eventstore_test.go index b846536e864..5744d81c985 100644 --- a/pkg/storage/unified/resource/eventstore_test.go +++ b/pkg/storage/unified/resource/eventstore_test.go @@ -610,3 +610,53 @@ func TestEventStore_CleanupOldEvents_EmptyStore(t *testing.T) { require.NoError(t, err) assert.Equal(t, 0, deletedCount, "Should not have deleted any events from empty store") } + +func TestEventStore_BatchDelete(t *testing.T) { + ctx := context.Background() + store := setupTestEventStore(t) + + // Create multiple events (more than batch size to test batching) + eventKeys := make([]string, 75) + for i := 0; i < 75; i++ { + event := Event{ + Namespace: "default", + Group: "apps", + Resource: "deployments", + Name: "test-deployment", + ResourceVersion: int64(1000 + i), + Action: DataActionCreated, + Folder: "test-folder", + PreviousRV: int64(999 + i), + } + err := store.Save(ctx, event) + require.NoError(t, err) + + eventKeys[i] = EventKey{ + Namespace: event.Namespace, + Group: event.Group, + Resource: event.Resource, + Name: event.Name, + ResourceVersion: event.ResourceVersion, + Action: event.Action, + Folder: event.Folder, + }.String() + } + + // Batch delete all events + err := store.batchDelete(ctx, eventKeys) + require.NoError(t, err) + + // Verify all events were deleted + for i := 0; i < 75; i++ { + _, err := store.Get(ctx, EventKey{ + Namespace: "default", + Group: "apps", + Resource: "deployments", + Name: "test-deployment", + ResourceVersion: int64(1000 + i), + Action: DataActionCreated, + Folder: "test-folder", + }) + require.Error(t, err, "Event should have been deleted") + } +} From 0e9a3881e7b6c78cab61298aa08f7cfc9619902d Mon Sep 17 00:00:00 2001 From: Kyle Brandt Date: Mon, 27 Oct 2025 08:22:51 -0400 Subject: [PATCH 022/378] SQL Expressions: (Chore) Update GMS (go-mysql-server) dependency (#112289) - Added gms_pure_go build tags to disable cgo - (cgo was added to GMS since we last updated it) - Docs note on regex limitations --------- Co-authored-by: Matheus Macabu --- .github/workflows/backend-unit-tests.yml | 4 ++-- .github/workflows/pr-test-integration.yml | 8 ++++---- Makefile | 10 ++++++++++ apps/iam/go.mod | 7 +++---- apps/iam/go.sum | 14 ++++++-------- .../query-transform-data/sql-expressions/index.md | 10 ++++++++++ go.mod | 7 +++---- go.sum | 14 ++++++-------- go.work.sum | 11 +++++++++++ pkg/build/daggerbuild/flags/packages.go | 1 + pkg/expr/sql/db_test.go | 12 ------------ 11 files changed, 56 insertions(+), 42 deletions(-) diff --git a/.github/workflows/backend-unit-tests.yml b/.github/workflows/backend-unit-tests.yml index 3dd179c5c87..628dd44ef1f 100644 --- a/.github/workflows/backend-unit-tests.yml +++ b/.github/workflows/backend-unit-tests.yml @@ -68,7 +68,7 @@ jobs: run: | set -euo pipefail readarray -t PACKAGES <<< "$(./scripts/ci/backend-tests/shard.sh -N"$SHARD")" - CGO_ENABLED=0 go test -short -timeout=30m "${PACKAGES[@]}" + CGO_ENABLED=0 go test -tags=gms_pure_go -short -timeout=30m "${PACKAGES[@]}" grafana-enterprise: # Run this workflow for non-PR events (like pushes to `main` or `release-*`) OR for internal PRs (PRs not from forks) @@ -118,7 +118,7 @@ jobs: readarray -t PACKAGES <<< "$(./scripts/ci/backend-tests/shard.sh -N"$SHARD")" # This tee requires pipefail to be set, otherwise `go test`'s exit code is thrown away. # That means having no `-o pipefail` => failing tests => exit code 0, which is wrong. - CGO_ENABLED=0 go test -short -timeout=30m "${PACKAGES[@]}" + CGO_ENABLED=0 go test -tags=gms_pure_go -short -timeout=30m "${PACKAGES[@]}" # This is the job that is actually required by rulesets. # We need to require EITHER the OSS or the Enterprise job to pass. diff --git a/.github/workflows/pr-test-integration.yml b/.github/workflows/pr-test-integration.yml index 7e7545bead0..ef601303e3e 100644 --- a/.github/workflows/pr-test-integration.yml +++ b/.github/workflows/pr-test-integration.yml @@ -68,7 +68,7 @@ jobs: run: | set -euo pipefail readarray -t PACKAGES <<< "$(./scripts/ci/backend-tests/pkgs-with-tests-named.sh -b TestIntegration | ./scripts/ci/backend-tests/shard.sh -N"$SHARD" -d-)" - go test -tags=sqlite -timeout=8m -run '^TestIntegration' "${PACKAGES[@]}" + go test -tags=sqlite,gms_pure_go -timeout=8m -run '^TestIntegration' "${PACKAGES[@]}" sqlite_nocgo: needs: detect-changes @@ -102,7 +102,7 @@ jobs: set -euo pipefail readarray -t PACKAGES <<< "$(./scripts/ci/backend-tests/pkgs-with-tests-named.sh -b TestIntegration | ./scripts/ci/backend-tests/shard.sh -N"$SHARD" -d-)" # ionice since tests are IO intensive - CGO_ENABLED=0 ionice -c2 -n7 go test -p=4 -tags=sqlite -timeout=8m -run '^TestIntegration' "${PACKAGES[@]}" + CGO_ENABLED=0 ionice -c2 -n7 go test -p=4 -tags=sqlite,gms_pure_go -timeout=8m -run '^TestIntegration' "${PACKAGES[@]}" mysql: needs: detect-changes if: needs.detect-changes.outputs.changed == 'true' @@ -152,7 +152,7 @@ jobs: run: | set -euo pipefail readarray -t PACKAGES <<< "$(./scripts/ci/backend-tests/pkgs-with-tests-named.sh -b TestIntegration | ./scripts/ci/backend-tests/shard.sh -N"$SHARD" -d-)" - CGO_ENABLED=0 go test -p=1 -tags=mysql -timeout=8m -run '^TestIntegration' "${PACKAGES[@]}" + CGO_ENABLED=0 go test -p=1 -tags=mysql,gms_pure_go -timeout=8m -run '^TestIntegration' "${PACKAGES[@]}" postgres: needs: detect-changes if: needs.detect-changes.outputs.changed == 'true' @@ -201,7 +201,7 @@ jobs: run: | set -euo pipefail readarray -t PACKAGES <<< "$(./scripts/ci/backend-tests/pkgs-with-tests-named.sh -b TestIntegration | ./scripts/ci/backend-tests/shard.sh -N"$SHARD" -d-)" - CGO_ENABLED=0 go test -p=1 -tags=postgres -timeout=8m -run '^TestIntegration' "${PACKAGES[@]}" + CGO_ENABLED=0 go test -p=1 -tags=postgres,gms_pure_go -timeout=8m -run '^TestIntegration' "${PACKAGES[@]}" # This is the job that is actually required by rulesets. # We want to only require one job instead of all the individual tests and shards. diff --git a/Makefile b/Makefile index 5bf0150e047..e5713db14b1 100644 --- a/Makefile +++ b/Makefile @@ -14,6 +14,16 @@ GO_TEST_FILES ?= $(shell ./scripts/go-workspace/test-includes.sh) SH_FILES ?= $(shell find ./scripts -name *.sh) GO_RACE := $(shell [ -n "$(GO_RACE)" -o -e ".go-race-enabled-locally" ] && echo 1 ) GO_RACE_FLAG := $(if $(GO_RACE),-race) + +## Always include gms_pure_go for go-mysql-server dependency +ifneq (,$(findstring gms_pure_go,$(GO_BUILD_TAGS))) + GO_BUILD_TAGS := $(GO_BUILD_TAGS) +else ifneq (,$(strip $(GO_BUILD_TAGS))) + GO_BUILD_TAGS := $(GO_BUILD_TAGS),gms_pure_go +else + GO_BUILD_TAGS := gms_pure_go +endif + GO_BUILD_FLAGS += $(if $(GO_BUILD_DEV),-dev) GO_BUILD_FLAGS += $(if $(GO_BUILD_TAGS),-build-tags=$(GO_BUILD_TAGS)) GO_BUILD_FLAGS += $(GO_RACE_FLAG) diff --git a/apps/iam/go.mod b/apps/iam/go.mod index 63dae42947a..cb946d8d694 100644 --- a/apps/iam/go.mod +++ b/apps/iam/go.mod @@ -162,10 +162,10 @@ require ( github.com/dlmiddlecote/sqlstats v1.0.2 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/dolthub/flatbuffers/v23 v23.3.3-dh.2 // indirect - github.com/dolthub/go-icu-regex v0.0.0-20250327004329-6799764f2dad // indirect - github.com/dolthub/go-mysql-server v0.19.1-0.20250410182021-5632d67cd46e // indirect + github.com/dolthub/go-icu-regex v0.0.0-20250916051405-78a38d478790 // indirect + github.com/dolthub/go-mysql-server v0.20.1-0.20251009205227-b4366f30538c // indirect github.com/dolthub/jsonpath v0.0.2-0.20240227200619-19675ab05c71 // indirect - github.com/dolthub/vitess v0.0.0-20250410090211-143e6b272ad4 // indirect + github.com/dolthub/vitess v0.0.0-20250930230441-70c2c6a98e33 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/emicklei/go-restful/v3 v3.13.0 // indirect github.com/emirpasic/gods v1.18.1 // indirect @@ -381,7 +381,6 @@ require ( github.com/stretchr/objx v0.5.2 // indirect github.com/stretchr/testify v1.11.1 // indirect github.com/subosito/gotenv v1.6.0 // indirect - github.com/tetratelabs/wazero v1.8.2 // indirect github.com/thomaspoignant/go-feature-flag v1.42.0 // indirect github.com/tjhop/slog-gokit v0.1.3 // indirect github.com/uber/jaeger-client-go v2.30.0+incompatible // indirect diff --git a/apps/iam/go.sum b/apps/iam/go.sum index 9aaebddce10..156abe868d7 100644 --- a/apps/iam/go.sum +++ b/apps/iam/go.sum @@ -489,16 +489,16 @@ github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4 github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/dolthub/flatbuffers/v23 v23.3.3-dh.2 h1:u3PMzfF8RkKd3lB9pZ2bfn0qEG+1Gms9599cr0REMww= github.com/dolthub/flatbuffers/v23 v23.3.3-dh.2/go.mod h1:mIEZOHnFx4ZMQeawhw9rhsj+0zwQj7adVsnBX7t+eKY= -github.com/dolthub/go-icu-regex v0.0.0-20250327004329-6799764f2dad h1:66ZPawHszNu37VPQckdhX1BPPVzREsGgNxQeefnlm3g= -github.com/dolthub/go-icu-regex v0.0.0-20250327004329-6799764f2dad/go.mod h1:ylU4XjUpsMcvl/BKeRRMXSH7e7WBrPXdSLvnRJYrxEA= -github.com/dolthub/go-mysql-server v0.19.1-0.20250410182021-5632d67cd46e h1:7pAttAqWaudUAsM9iHASi/4eFBK+qn4qeaNto7g8bK4= -github.com/dolthub/go-mysql-server v0.19.1-0.20250410182021-5632d67cd46e/go.mod h1:KZyoO3jngyZCLyCf100FEQTrwAHj33AIMj4Zv4u3MNE= +github.com/dolthub/go-icu-regex v0.0.0-20250916051405-78a38d478790 h1:zxMsH7RLiG+dlZ/y0LgJHTV26XoiSJcuWq+em6t6VVc= +github.com/dolthub/go-icu-regex v0.0.0-20250916051405-78a38d478790/go.mod h1:F3cnm+vMRK1HaU6+rNqQrOCyR03HHhR1GWG2gnPOqaE= +github.com/dolthub/go-mysql-server v0.20.1-0.20251009205227-b4366f30538c h1:vElww7wlYrlu1dldciCcYOvVuh73gw8i6mkcTUvH6nQ= +github.com/dolthub/go-mysql-server v0.20.1-0.20251009205227-b4366f30538c/go.mod h1:EeYR0apo+8j2Dyxmn2ghkPlirO2S5mT1xHBrA+Efys8= github.com/dolthub/jsonpath v0.0.2-0.20240227200619-19675ab05c71 h1:bMGS25NWAGTEtT5tOBsCuCrlYnLRKpbJVJkDbrTRhwQ= github.com/dolthub/jsonpath v0.0.2-0.20240227200619-19675ab05c71/go.mod h1:2/2zjLQ/JOOSbbSboojeg+cAwcRV0fDLzIiWch/lhqI= github.com/dolthub/maphash v0.1.0 h1:bsQ7JsF4FkkWyrP3oCnFJgrCUAFbFf3kOl4L/QxPDyQ= github.com/dolthub/maphash v0.1.0/go.mod h1:gkg4Ch4CdCDu5h6PMriVLawB7koZ+5ijb9puGMV50a4= -github.com/dolthub/vitess v0.0.0-20250410090211-143e6b272ad4 h1:LGTt2LtYX8vaai32d+c9L0sMcP+Dg9w1kO6+lbsxxYg= -github.com/dolthub/vitess v0.0.0-20250410090211-143e6b272ad4/go.mod h1:1gQZs/byeHLMSul3Lvl3MzioMtOW1je79QYGyi2fd70= +github.com/dolthub/vitess v0.0.0-20250930230441-70c2c6a98e33 h1:ScHTwNbcVC6JH1OSyXzj8S4w67BIpRXwTSjrac3/PSw= +github.com/dolthub/vitess v0.0.0-20250930230441-70c2c6a98e33/go.mod h1:8pvvk5OLaLN9LLxghyczUapn/97l+mBgIb10qC1LG84= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= 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= @@ -1496,8 +1496,6 @@ github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= -github.com/tetratelabs/wazero v1.8.2 h1:yIgLR/b2bN31bjxwXHD8a3d+BogigR952csSDdLYEv4= -github.com/tetratelabs/wazero v1.8.2/go.mod h1:yAI0XTsMBhREkM/YDAK/zNou3GoiAce1P6+rp/wQhjs= github.com/thejerf/slogassert v0.3.4 h1:VoTsXixRbXMrRSSxDjYTiEDCM4VWbsYPW5rB/hX24kM= github.com/thejerf/slogassert v0.3.4/go.mod h1:0zn9ISLVKo1aPMTqcGfG1o6dWwt+Rk574GlUxHD4rs8= github.com/thomaspoignant/go-feature-flag v1.42.0 h1:C7embmOTzaLyRki+OoU2RvtVjJE9IrvgBA2C1mRN1lc= diff --git a/docs/sources/visualizations/panels-visualizations/query-transform-data/sql-expressions/index.md b/docs/sources/visualizations/panels-visualizations/query-transform-data/sql-expressions/index.md index 7cb91aaeb7f..992bc7611b5 100644 --- a/docs/sources/visualizations/panels-visualizations/query-transform-data/sql-expressions/index.md +++ b/docs/sources/visualizations/panels-visualizations/query-transform-data/sql-expressions/index.md @@ -307,6 +307,16 @@ FULL OUTER JOIN ( This approach ensures that a schema exists even when one query returns no data. +### Regular Expressions + +Regular expressions are not fully compatible with MySQL standards. SQL expressions that use regular expression functions will have limitations such as: + +- Lack of back-references +- No before/after text matching +- Differences in handling CR ('\r') + +There may be other minor differences as well. + ## SQL expressions examples 1. Create the following Prometheus query: diff --git a/go.mod b/go.mod index 8c587d67a29..4d7ec58ef44 100644 --- a/go.mod +++ b/go.mod @@ -52,8 +52,8 @@ require ( github.com/crewjam/saml v0.4.14 // @grafana/identity-access-team github.com/dgraph-io/badger/v4 v4.7.0 // @grafana/grafana-search-and-storage github.com/dlmiddlecote/sqlstats v1.0.2 // @grafana/grafana-backend-group - github.com/dolthub/go-mysql-server v0.19.1-0.20250410182021-5632d67cd46e // @grafana/grafana-datasources-core-services - github.com/dolthub/vitess v0.0.0-20250410090211-143e6b272ad4 // @grafana/grafana-datasources-core-services + github.com/dolthub/go-mysql-server v0.20.1-0.20251009205227-b4366f30538c // @grafana/grafana-datasources-core-services + github.com/dolthub/vitess v0.0.0-20250930230441-70c2c6a98e33 // @grafana/grafana-datasources-core-services github.com/dustin/go-humanize v1.0.1 // @grafana/observability-traces-and-profiling github.com/emicklei/go-restful/v3 v3.13.0 // @grafana/grafana-app-platform-squad github.com/fatih/color v1.18.0 // @grafana/grafana-backend-group @@ -403,7 +403,7 @@ require ( github.com/docker/go-connections v0.6.0 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/dolthub/flatbuffers/v23 v23.3.3-dh.2 // indirect - github.com/dolthub/go-icu-regex v0.0.0-20250327004329-6799764f2dad // indirect + github.com/dolthub/go-icu-regex v0.0.0-20250916051405-78a38d478790 // indirect github.com/dolthub/jsonpath v0.0.2-0.20240227200619-19675ab05c71 // indirect github.com/dolthub/maphash v0.1.0 // indirect github.com/edsrzf/mmap-go v1.2.0 // indirect @@ -584,7 +584,6 @@ require ( github.com/stoewer/go-strcase v1.3.1 // indirect github.com/stretchr/objx v0.5.2 // indirect github.com/subosito/gotenv v1.6.0 // indirect - github.com/tetratelabs/wazero v1.8.2 // indirect github.com/uber/jaeger-client-go v2.30.0+incompatible // indirect github.com/uber/jaeger-lib v2.4.1+incompatible // indirect github.com/unknwon/bra v0.0.0-20200517080246-1e3013ecaff8 // indirect diff --git a/go.sum b/go.sum index 1bd04409bb4..ccf6b889d50 100644 --- a/go.sum +++ b/go.sum @@ -1118,16 +1118,16 @@ github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZ github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/dolthub/flatbuffers/v23 v23.3.3-dh.2 h1:u3PMzfF8RkKd3lB9pZ2bfn0qEG+1Gms9599cr0REMww= github.com/dolthub/flatbuffers/v23 v23.3.3-dh.2/go.mod h1:mIEZOHnFx4ZMQeawhw9rhsj+0zwQj7adVsnBX7t+eKY= -github.com/dolthub/go-icu-regex v0.0.0-20250327004329-6799764f2dad h1:66ZPawHszNu37VPQckdhX1BPPVzREsGgNxQeefnlm3g= -github.com/dolthub/go-icu-regex v0.0.0-20250327004329-6799764f2dad/go.mod h1:ylU4XjUpsMcvl/BKeRRMXSH7e7WBrPXdSLvnRJYrxEA= -github.com/dolthub/go-mysql-server v0.19.1-0.20250410182021-5632d67cd46e h1:7pAttAqWaudUAsM9iHASi/4eFBK+qn4qeaNto7g8bK4= -github.com/dolthub/go-mysql-server v0.19.1-0.20250410182021-5632d67cd46e/go.mod h1:KZyoO3jngyZCLyCf100FEQTrwAHj33AIMj4Zv4u3MNE= +github.com/dolthub/go-icu-regex v0.0.0-20250916051405-78a38d478790 h1:zxMsH7RLiG+dlZ/y0LgJHTV26XoiSJcuWq+em6t6VVc= +github.com/dolthub/go-icu-regex v0.0.0-20250916051405-78a38d478790/go.mod h1:F3cnm+vMRK1HaU6+rNqQrOCyR03HHhR1GWG2gnPOqaE= +github.com/dolthub/go-mysql-server v0.20.1-0.20251009205227-b4366f30538c h1:vElww7wlYrlu1dldciCcYOvVuh73gw8i6mkcTUvH6nQ= +github.com/dolthub/go-mysql-server v0.20.1-0.20251009205227-b4366f30538c/go.mod h1:EeYR0apo+8j2Dyxmn2ghkPlirO2S5mT1xHBrA+Efys8= github.com/dolthub/jsonpath v0.0.2-0.20240227200619-19675ab05c71 h1:bMGS25NWAGTEtT5tOBsCuCrlYnLRKpbJVJkDbrTRhwQ= github.com/dolthub/jsonpath v0.0.2-0.20240227200619-19675ab05c71/go.mod h1:2/2zjLQ/JOOSbbSboojeg+cAwcRV0fDLzIiWch/lhqI= github.com/dolthub/maphash v0.1.0 h1:bsQ7JsF4FkkWyrP3oCnFJgrCUAFbFf3kOl4L/QxPDyQ= github.com/dolthub/maphash v0.1.0/go.mod h1:gkg4Ch4CdCDu5h6PMriVLawB7koZ+5ijb9puGMV50a4= -github.com/dolthub/vitess v0.0.0-20250410090211-143e6b272ad4 h1:LGTt2LtYX8vaai32d+c9L0sMcP+Dg9w1kO6+lbsxxYg= -github.com/dolthub/vitess v0.0.0-20250410090211-143e6b272ad4/go.mod h1:1gQZs/byeHLMSul3Lvl3MzioMtOW1je79QYGyi2fd70= +github.com/dolthub/vitess v0.0.0-20250930230441-70c2c6a98e33 h1:ScHTwNbcVC6JH1OSyXzj8S4w67BIpRXwTSjrac3/PSw= +github.com/dolthub/vitess v0.0.0-20250930230441-70c2c6a98e33/go.mod h1:8pvvk5OLaLN9LLxghyczUapn/97l+mBgIb10qC1LG84= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= 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= @@ -2461,8 +2461,6 @@ github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= -github.com/tetratelabs/wazero v1.8.2 h1:yIgLR/b2bN31bjxwXHD8a3d+BogigR952csSDdLYEv4= -github.com/tetratelabs/wazero v1.8.2/go.mod h1:yAI0XTsMBhREkM/YDAK/zNou3GoiAce1P6+rp/wQhjs= github.com/thanos-io/objstore v0.0.0-20240818203309-0363dadfdfb1 h1:z0v9BB/p7s4J6R//+0a5M3wCld8KzNjrGRLIwXfrAZk= github.com/thanos-io/objstore v0.0.0-20240818203309-0363dadfdfb1/go.mod h1:3ukSkG4rIRUGkKM4oIz+BSuUx2e3RlQVVv3Cc3W+Tv4= github.com/thejerf/slogassert v0.3.4 h1:VoTsXixRbXMrRSSxDjYTiEDCM4VWbsYPW5rB/hX24kM= diff --git a/go.work.sum b/go.work.sum index d26aabd35b9..3b88b54f3dd 100644 --- a/go.work.sum +++ b/go.work.sum @@ -550,6 +550,7 @@ github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53 h1:sR+/8Yb4s github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53/go.mod h1:+3IMCy2vIlbG1XG/0ggNQv0SvxCAIpPM5b1nCz56Xno= github.com/CloudyKit/jet/v6 v6.2.0 h1:EpcZ6SR9n28BUGtNJSvlBqf90IpjeFr36Tizxhn/oME= github.com/CloudyKit/jet/v6 v6.2.0/go.mod h1:d3ypHeIRNo2+XyqnGA8s+aphtcVpjP5hPwP/Lzo7Ro4= +github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= github.com/DataDog/datadog-go v3.2.0+incompatible h1:qSG2N4FghB1He/r2mFrWKCaL7dXCilEuNEeAn20fdD4= github.com/DataDog/sketches-go v1.4.6 h1:acd5fb+QdUzGrosfNLwrIhqyrbMORpvBy7mE+vHlT3I= github.com/DataDog/sketches-go v1.4.6/go.mod h1:7Y8GN8Jf66DLyDhc94zuWA3uHEt/7ttt8jHOBWWrSOg= @@ -828,6 +829,8 @@ github.com/dchest/siphash v1.2.3/go.mod h1:0NvQU092bT0ipiFN++/rXm69QG9tVxLAlQHIX github.com/dchest/uniuri v1.2.0 h1:koIcOUdrTIivZgSLhHQvKgqdWZq5d7KdMEWF1Ud6+5g= github.com/dchest/uniuri v1.2.0/go.mod h1:fSzm4SLHzNZvWLvWJew423PhAzkpNQYq+uNLq4kxhkY= github.com/denisenkom/go-mssqldb v0.0.0-20190515213511-eb9f6a1743f3 h1:tkum0XDgfR0jcVVXuTsYv/erY2NnEDqwRojbxR1rBYA= +github.com/denisenkom/go-mssqldb v0.10.0 h1:QykgLZBorFE95+gO3u9esLd0BmbvpWp0/waNNZfHBM8= +github.com/denisenkom/go-mssqldb v0.10.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= github.com/dgryski/go-ddmin v0.0.0-20210904190556-96a6d69f1034 h1:BuCyszxPxUjBrYW2HNVrimC0rBUs2U27jCJGVh0IKTM= github.com/dgryski/go-ddmin v0.0.0-20210904190556-96a6d69f1034/go.mod h1:zz4KxBkcXUWKjIcrc+uphJ1gPh/t18ymGm3PmQ+VGTk= github.com/dgryski/go-sip13 v0.0.0-20190329191031-25c5027a8c7b h1:Yqiad0+sloMPdd/0Fg22actpFx0dekpzt1xJmVNVkU0= @@ -991,6 +994,7 @@ github.com/gogo/status v1.1.0/go.mod h1:BFv9nrluPLmrS0EmGVvLaPNmRosr9KapBYd5/hpY github.com/golang-jwt/jwt v3.2.1+incompatible h1:73Z+4BJcrTC+KczS6WvTPvRGOp1WmfEP4Q1lOd9Z/+c= github.com/golang-jwt/jwt v3.2.1+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= +github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g= github.com/gomarkdown/markdown v0.0.0-20230716120725-531d2d74bc12 h1:uK3X/2mt4tbSGoHvbLBHUny7CKiuwUip3MArtukol4E= github.com/gomarkdown/markdown v0.0.0-20230716120725-531d2d74bc12/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA= @@ -1204,6 +1208,7 @@ github.com/jedib0t/go-pretty/v6 v6.6.7/go.mod h1:YwC5CE4fJ1HFUDeivSV1r//AmANFHyq github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jhump/gopoet v0.1.0 h1:gYjOPnzHd2nzB37xYQZxj4EIQNpBrBskRqQQ3q4ZgSg= github.com/jhump/goprotoc v0.5.0 h1:Y1UgUX+txUznfqcGdDef8ZOVlyQvnV0pKWZH08RmZuo= +github.com/jmoiron/sqlx v1.3.4/go.mod h1:2BljVx/86SuTyjE+aPYlHCTNvZrnJXghYGpNiXLBMCQ= github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901 h1:rp+c0RAYOWj8l6qbCUTSiRLG/iKnW3K3/QfPPuSsBt4= github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901/go.mod h1:Z86h9688Y0wesXCyonoVr47MasHilkuLMqGhRZ4Hpak= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= @@ -1293,6 +1298,7 @@ github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= github.com/leodido/ragel-machinery v0.0.0-20190525184631-5f46317e436b h1:11UHH39z1RhZ5dc4y4r/4koJo6IYFgTRMe/LlwRTEw0= github.com/leodido/ragel-machinery v0.0.0-20190525184631-5f46317e436b/go.mod h1:WZxr2/6a/Ar9bMDc2rN/LJrE/hF6bXE4LPyDSIxwAfg= +github.com/lib/pq v1.10.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lightstep/go-expohisto v1.0.0 h1:UPtTS1rGdtehbbAF7o/dhkWLTDI73UifG8LbfQI7cA4= github.com/lightstep/go-expohisto v1.0.0/go.mod h1:xDXD0++Mu2FOaItXtdDfksfgxfV0z1TMPa+e/EUd0cs= github.com/lithammer/fuzzysearch v1.1.8 h1:/HIuJnjHuXS8bKaiTMeeDlW2/AyIWk2brx1V8LFgLN4= @@ -1317,6 +1323,7 @@ github.com/matryer/moq v0.5.2/go.mod h1:W/k5PLfou4f+bzke9VPXTbfJljxoeR1tLHigsmbs github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-sqlite3 v1.14.7/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg= github.com/maxbrunsfeld/counterfeiter/v6 v6.11.2 h1:yVCLo4+ACVroOEr4iFU1iH46Ldlzz2rTuu18Ra7M8sU= github.com/maxbrunsfeld/counterfeiter/v6 v6.11.2/go.mod h1:VzB2VoMh1Y32/QqDfg9ZJYHj99oM4LiGtqPZydTiQSQ= @@ -1564,6 +1571,7 @@ github.com/shirou/gopsutil/v4 v4.25.5 h1:rtd9piuSMGeU8g1RMXjZs9y9luK5BwtnG7dZaQU github.com/shirou/gopsutil/v4 v4.25.5/go.mod h1:PfybzyydfZcN+JMMjkF6Zb8Mq1A/VcogFFg7hj50W9c= github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= +github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shurcooL/go v0.0.0-20200502201357-93f07166e636 h1:aSISeOcal5irEhJd1M+IrApc0PdcN7e7Aj4yuEnOrfQ= github.com/shurcooL/go v0.0.0-20200502201357-93f07166e636/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= @@ -2116,6 +2124,7 @@ google.golang.org/api v0.229.0/go.mod h1:wyDfmq5g1wYJWn29O22FDWN48P7Xcz0xz+LBppt google.golang.org/api v0.232.0/go.mod h1:p9QCfBWZk1IJETUdbTKloR5ToFdKbYh2fkjsUL6vNoY= google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= +google.golang.org/genproto v0.0.0-20190926190326-7ee9db18f195/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d/go.mod h1:yZTlhN0tQnXo3h00fuXNCxJdLdIdnVFVBaRJ5LWBbw4= google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80/go.mod h1:cc8bqMqtv9gMOr0zHg2Vzff5ULhhL2IXP4sbcn32Dro= google.golang.org/genproto v0.0.0-20241118233622-e639e219e697/go.mod h1:JJrvXBWRZaFMxBufik1a4RpFw4HhgVtBBWQeQgUj2cc= @@ -2187,6 +2196,7 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5/go. google.golang.org/genproto/googleapis/rpc v0.0.0-20250826171959-ef028d996bc1/go.mod h1:GmFNa4BdJZ2a8G+wCe9Bg3wwThLrJun751XstdJt5Og= google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090/go.mod h1:GmFNa4BdJZ2a8G+wCe9Bg3wwThLrJun751XstdJt5Og= google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= google.golang.org/grpc v1.61.0/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs= google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= @@ -2221,6 +2231,7 @@ google.golang.org/protobuf v1.36.7/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/ google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU= google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU= gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc= +gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0 h1:0vLT13EuvQ0hNvakwLuFZ/jYrLp5F3kcWHXdRggjCE8= gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/go-jose/go-jose.v2 v2.6.3 h1:nt80fvSDlhKWQgSWyHyy5CfmlQr+asih51R8PTWNKKs= diff --git a/pkg/build/daggerbuild/flags/packages.go b/pkg/build/daggerbuild/flags/packages.go index 897364b6f07..dcc9011949d 100644 --- a/pkg/build/daggerbuild/flags/packages.go +++ b/pkg/build/daggerbuild/flags/packages.go @@ -8,6 +8,7 @@ import ( var DefaultTags = []string{ "osusergo", "timetzdata", + "gms_pure_go", } const ( diff --git a/pkg/expr/sql/db_test.go b/pkg/expr/sql/db_test.go index ff5ecac022f..c67c23b32b9 100644 --- a/pkg/expr/sql/db_test.go +++ b/pkg/expr/sql/db_test.go @@ -278,18 +278,6 @@ func TestNaNBecomesNull(t *testing.T) { require.NoError(t, err) } -func TestErrorsFromGoMySQLServerAreFlagged(t *testing.T) { - const GmsNotImplemented = "TRUNCATE" // not implemented in go-mysql-server as of 2025-04-11 - - db := DB{} - - query := `SELECT ` + GmsNotImplemented + `(123.456, 2);` - - _, err := db.QueryFrames(context.Background(), &testTracer{}, "sqlExpressionRefId", query, nil) - require.Error(t, err) - require.Contains(t, err.Error(), "error from the sql expression engine") -} - func TestFrameToSQLAndBack_JSONRoundtrip(t *testing.T) { expectedFrame := &data.Frame{ RefID: "json_test", From 7b2ea9a735e2434e864b09f64b29f1a9023546b0 Mon Sep 17 00:00:00 2001 From: Gilles De Mey Date: Mon, 27 Oct 2025 13:47:51 +0100 Subject: [PATCH 023/378] Alerting: Rename triage to alerts (#113039) --- pkg/services/navtree/navtreeimpl/navtree.go | 2 +- public/app/features/alerting/routes.tsx | 2 +- public/app/features/alerting/unified/triage/Triage.tsx | 9 ++++++--- public/locales/en-US/grafana.json | 4 ++-- 4 files changed, 10 insertions(+), 7 deletions(-) diff --git a/pkg/services/navtree/navtreeimpl/navtree.go b/pkg/services/navtree/navtreeimpl/navtree.go index 955c0b32ce1..31fe4d2982f 100644 --- a/pkg/services/navtree/navtreeimpl/navtree.go +++ b/pkg/services/navtree/navtreeimpl/navtree.go @@ -443,7 +443,7 @@ func (s *ServiceImpl) buildAlertNavLinks(c *contextmodel.ReqContext) *navtree.Na if s.features.IsEnabled(c.Req.Context(), featuremgmt.FlagAlertingTriage) { if hasAccess(ac.EvalAny(ac.EvalPermission(ac.ActionAlertingRuleRead), ac.EvalPermission(ac.ActionAlertingRuleExternalRead))) { alertChildNavs = append(alertChildNavs, &navtree.NavLink{ - Text: "Triage", SubTitle: "Triage alerts", Id: "alert-triage", Url: s.cfg.AppSubURL + "/alerting/triage", Icon: "medkit", IsNew: true, + Text: "Alerts", SubTitle: "Visualize active and pending alerts", Id: "alert-alerts", Url: s.cfg.AppSubURL + "/alerting/alerts", Icon: "bell", IsNew: true, }) } } diff --git a/public/app/features/alerting/routes.tsx b/public/app/features/alerting/routes.tsx index da4c513388a..34459b9581e 100644 --- a/public/app/features/alerting/routes.tsx +++ b/public/app/features/alerting/routes.tsx @@ -335,7 +335,7 @@ export function getAlertingRoutes(cfg = config): RouteDescriptor[] { if (cfg.featureToggles.alertingTriage) { routes.push({ - path: '/alerting/triage', + path: '/alerting/alerts', roles: evaluateAccess([AccessControlAction.AlertingRuleRead, AccessControlAction.AlertingRuleExternalRead]), component: importAlertingComponent( () => import(/* webpackChunkName: "AlertingTriage" */ 'app/features/alerting/unified/triage/Triage') diff --git a/public/app/features/alerting/unified/triage/Triage.tsx b/public/app/features/alerting/unified/triage/Triage.tsx index 284be52fa41..3659af822a0 100644 --- a/public/app/features/alerting/unified/triage/Triage.tsx +++ b/public/app/features/alerting/unified/triage/Triage.tsx @@ -9,10 +9,13 @@ import { TriageScene, triageScene } from './scene/TriageScene'; export const TriagePage = () => { return ( diff --git a/public/locales/en-US/grafana.json b/public/locales/en-US/grafana.json index 24db448f23e..092df4634f1 100644 --- a/public/locales/en-US/grafana.json +++ b/public/locales/en-US/grafana.json @@ -2043,8 +2043,8 @@ }, "pages": { "triage": { - "subtitle": "Learn about problems in your systems moments after they occur", - "title": "Triage" + "subtitle": "See what is currently alerting and explore historical data to investigate current or past issues.", + "title": "Alerts" } }, "panel-alert-tab-content": { From f9fb2cfd506ae50f6bdc378251c259ddd940334e Mon Sep 17 00:00:00 2001 From: Samarth Bagga <69239707+SamarthBagga@users.noreply.github.com> Date: Mon, 27 Oct 2025 18:33:19 +0530 Subject: [PATCH 024/378] Flame Graph: Anchor exact match when clicking a table symbol in search (#111101) * fixed #110680 * Edit * Fixed test --------- Co-authored-by: Samarth Bagga --- .../src/FlameGraphContainer.test.tsx | 6 +++--- .../src/FlameGraphContainer.tsx | 16 ++++++++++++---- .../src/TopTable/FlameGraphTopTableContainer.tsx | 3 ++- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/packages/grafana-flamegraph/src/FlameGraphContainer.test.tsx b/packages/grafana-flamegraph/src/FlameGraphContainer.test.tsx index 10e2eeb8d03..4fdb00d6748 100644 --- a/packages/grafana-flamegraph/src/FlameGraphContainer.test.tsx +++ b/packages/grafana-flamegraph/src/FlameGraphContainer.test.tsx @@ -55,15 +55,15 @@ describe('FlameGraphContainer', () => { it('should update search when row selected in top table', async () => { render(); await userEvent.click((await screen.findAllByTitle('Highlight symbol'))[0]); - expect(screen.getByDisplayValue('net/http.HandlerFunc.ServeHTTP')).toBeInTheDocument(); + expect(screen.getByDisplayValue('^net/http\\.HandlerFunc\\.ServeHTTP$')).toBeInTheDocument(); // Unclick the selection so that we can click something else and continue test checks await userEvent.click((await screen.findAllByTitle('Highlight symbol'))[0]); await userEvent.click((await screen.findAllByTitle('Highlight symbol'))[1]); - expect(screen.getByDisplayValue('total')).toBeInTheDocument(); + expect(screen.getByDisplayValue('^total$')).toBeInTheDocument(); // after it is highlighted it will be the only (first) item in the table so [1] -> [0] await userEvent.click((await screen.findAllByTitle('Highlight symbol'))[0]); - expect(screen.queryByDisplayValue('total')).not.toBeInTheDocument(); + expect(screen.queryByDisplayValue('^total$')).not.toBeInTheDocument(); }); it('should render options', async () => { diff --git a/packages/grafana-flamegraph/src/FlameGraphContainer.tsx b/packages/grafana-flamegraph/src/FlameGraphContainer.tsx index da09ea26739..5d95051e353 100644 --- a/packages/grafana-flamegraph/src/FlameGraphContainer.tsx +++ b/packages/grafana-flamegraph/src/FlameGraphContainer.tsx @@ -4,7 +4,7 @@ import { useCallback, useEffect, useMemo, useState } from 'react'; import * as React from 'react'; import { useMeasure } from 'react-use'; -import { DataFrame, GrafanaTheme2 } from '@grafana/data'; +import { DataFrame, GrafanaTheme2, escapeStringForRegex } from '@grafana/data'; import { ThemeContext } from '@grafana/ui'; import FlameGraph from './FlameGraph/FlameGraph'; @@ -189,11 +189,13 @@ const FlameGraphContainer = ({ const onSymbolClick = useCallback( (symbol: string) => { - if (search === symbol) { + const anchored = `^${escapeStringForRegex(symbol)}$`; + + if (search === anchored) { setSearch(''); } else { onTableSymbolClick?.(symbol); - setSearch(symbol); + setSearch(anchored); resetFocus(); } }, @@ -241,7 +243,13 @@ const FlameGraphContainer = ({ matchedLabels={matchedLabels} sandwichItem={sandwichItem} onSandwich={setSandwichItem} - onSearch={setSearch} + onSearch={(str) => { + if (!str) { + setSearch(''); + return; + } + setSearch(`^${escapeStringForRegex(str)}$`); + }} onTableSort={onTableSort} colorScheme={colorScheme} /> diff --git a/packages/grafana-flamegraph/src/TopTable/FlameGraphTopTableContainer.tsx b/packages/grafana-flamegraph/src/TopTable/FlameGraphTopTableContainer.tsx index 8c5461bb053..b9072f42c29 100644 --- a/packages/grafana-flamegraph/src/TopTable/FlameGraphTopTableContainer.tsx +++ b/packages/grafana-flamegraph/src/TopTable/FlameGraphTopTableContainer.tsx @@ -10,6 +10,7 @@ import { FieldType, GrafanaTheme2, MappingType, + escapeStringForRegex, } from '@grafana/data'; import { IconButton, @@ -332,7 +333,7 @@ type ActionCellProps = { function ActionCell(props: ActionCellProps) { const styles = getStylesActionCell(); const symbol = props.frame.fields.find((f: Field) => f.name === 'Symbol')?.values[props.rowIndex]; - const isSearched = props.search === symbol; + const isSearched = props.search === `^${escapeStringForRegex(String(symbol))}$`; const isSandwiched = props.sandwichItem === symbol; return ( From 6783c7f99817b1e8fccd7d29f6894caddcef7663 Mon Sep 17 00:00:00 2001 From: Ryan McKinley Date: Mon, 27 Oct 2025 16:12:31 +0300 Subject: [PATCH 025/378] Dashboards: Remove unused version types (#113036) --- .../pkg/apis/dashboard/v0alpha1/register.go | 2 - .../pkg/apis/dashboard/v0alpha1/types.go | 41 ----- .../v0alpha1/zz_generated.conversion.go | 31 ---- .../v0alpha1/zz_generated.deepcopy.go | 72 --------- .../v0alpha1/zz_generated.openapi.go | 140 ------------------ 5 files changed, 286 deletions(-) diff --git a/apps/dashboard/pkg/apis/dashboard/v0alpha1/register.go b/apps/dashboard/pkg/apis/dashboard/v0alpha1/register.go index 16e30b909b6..7b3934492fa 100644 --- a/apps/dashboard/pkg/apis/dashboard/v0alpha1/register.go +++ b/apps/dashboard/pkg/apis/dashboard/v0alpha1/register.go @@ -92,8 +92,6 @@ func addKnownTypes(scheme *runtime.Scheme) error { &Dashboard{}, &DashboardList{}, &DashboardWithAccessInfo{}, - &DashboardVersionList{}, - &VersionsQueryOptions{}, &LibraryPanel{}, &LibraryPanelList{}, &metav1.PartialObjectMetadata{}, diff --git a/apps/dashboard/pkg/apis/dashboard/v0alpha1/types.go b/apps/dashboard/pkg/apis/dashboard/v0alpha1/types.go index 1589fc62c8a..141141f861f 100644 --- a/apps/dashboard/pkg/apis/dashboard/v0alpha1/types.go +++ b/apps/dashboard/pkg/apis/dashboard/v0alpha1/types.go @@ -7,47 +7,6 @@ import ( common "github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1" ) -// +k8s:deepcopy-gen=true -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object -type DashboardVersionList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - - Items []DashboardVersionInfo `json:"items"` -} - -// +k8s:deepcopy-gen=true -type DashboardVersionInfo struct { - // The internal ID for this version (will be replaced with resourceVersion) - Version int `json:"version"` - - // If the dashboard came from a previous version, it is set here - ParentVersion int `json:"parentVersion,omitempty"` - - // The creation timestamp for this version - Created int64 `json:"created"` - - // The user who created this version - CreatedBy string `json:"createdBy,omitempty"` - - // Message passed while saving the version - Message string `json:"message,omitempty"` -} - -// +k8s:deepcopy-gen=true -// +k8s:conversion-gen:explicit-from=net/url.Values -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object -type VersionsQueryOptions struct { - metav1.TypeMeta `json:",inline"` - - // Path is the URL path - // +optional - Path string `json:"path,omitempty"` - - // +optional - Version int64 `json:"version,omitempty"` -} - // +k8s:deepcopy-gen=true // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object type LibraryPanel struct { diff --git a/apps/dashboard/pkg/apis/dashboard/v0alpha1/zz_generated.conversion.go b/apps/dashboard/pkg/apis/dashboard/v0alpha1/zz_generated.conversion.go index b76e6b614ab..626201ec314 100644 --- a/apps/dashboard/pkg/apis/dashboard/v0alpha1/zz_generated.conversion.go +++ b/apps/dashboard/pkg/apis/dashboard/v0alpha1/zz_generated.conversion.go @@ -8,7 +8,6 @@ package v0alpha1 import ( - url "net/url" unsafe "unsafe" dashboard "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard" @@ -53,11 +52,6 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } - if err := s.AddGeneratedConversionFunc((*url.Values)(nil), (*VersionsQueryOptions)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_url_Values_To_v0alpha1_VersionsQueryOptions(a.(*url.Values), b.(*VersionsQueryOptions), scope) - }); err != nil { - return err - } return nil } @@ -148,28 +142,3 @@ func autoConvert_dashboard_DashboardAccess_To_v0alpha1_DashboardAccess(in *dashb func Convert_dashboard_DashboardAccess_To_v0alpha1_DashboardAccess(in *dashboard.DashboardAccess, out *DashboardAccess, s conversion.Scope) error { return autoConvert_dashboard_DashboardAccess_To_v0alpha1_DashboardAccess(in, out, s) } - -func autoConvert_url_Values_To_v0alpha1_VersionsQueryOptions(in *url.Values, out *VersionsQueryOptions, s conversion.Scope) error { - // WARNING: Field TypeMeta does not have json tag, skipping. - - if values, ok := map[string][]string(*in)["path"]; ok && len(values) > 0 { - if err := runtime.Convert_Slice_string_To_string(&values, &out.Path, s); err != nil { - return err - } - } else { - out.Path = "" - } - if values, ok := map[string][]string(*in)["version"]; ok && len(values) > 0 { - if err := runtime.Convert_Slice_string_To_int64(&values, &out.Version, s); err != nil { - return err - } - } else { - out.Version = 0 - } - return nil -} - -// Convert_url_Values_To_v0alpha1_VersionsQueryOptions is an autogenerated conversion function. -func Convert_url_Values_To_v0alpha1_VersionsQueryOptions(in *url.Values, out *VersionsQueryOptions, s conversion.Scope) error { - return autoConvert_url_Values_To_v0alpha1_VersionsQueryOptions(in, out, s) -} diff --git a/apps/dashboard/pkg/apis/dashboard/v0alpha1/zz_generated.deepcopy.go b/apps/dashboard/pkg/apis/dashboard/v0alpha1/zz_generated.deepcopy.go index efdbdf07999..bb1a1216a36 100644 --- a/apps/dashboard/pkg/apis/dashboard/v0alpha1/zz_generated.deepcopy.go +++ b/apps/dashboard/pkg/apis/dashboard/v0alpha1/zz_generated.deepcopy.go @@ -98,53 +98,6 @@ func (in *DashboardHit) DeepCopy() *DashboardHit { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *DashboardVersionInfo) DeepCopyInto(out *DashboardVersionInfo) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DashboardVersionInfo. -func (in *DashboardVersionInfo) DeepCopy() *DashboardVersionInfo { - if in == nil { - return nil - } - out := new(DashboardVersionInfo) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *DashboardVersionList) DeepCopyInto(out *DashboardVersionList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]DashboardVersionInfo, len(*in)) - copy(*out, *in) - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DashboardVersionList. -func (in *DashboardVersionList) DeepCopy() *DashboardVersionList { - if in == nil { - return nil - } - out := new(DashboardVersionList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *DashboardVersionList) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *DashboardWithAccessInfo) DeepCopyInto(out *DashboardWithAccessInfo) { *out = *in @@ -454,28 +407,3 @@ func (in *TermFacet) DeepCopy() *TermFacet { in.DeepCopyInto(out) return out } - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *VersionsQueryOptions) DeepCopyInto(out *VersionsQueryOptions) { - *out = *in - out.TypeMeta = in.TypeMeta - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VersionsQueryOptions. -func (in *VersionsQueryOptions) DeepCopy() *VersionsQueryOptions { - if in == nil { - return nil - } - out := new(VersionsQueryOptions) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *VersionsQueryOptions) DeepCopyObject() runtime.Object { - if c := in.DeepCopy(); c != nil { - return c - } - return nil -} diff --git a/apps/dashboard/pkg/apis/dashboard/v0alpha1/zz_generated.openapi.go b/apps/dashboard/pkg/apis/dashboard/v0alpha1/zz_generated.openapi.go index 63af5e26b7e..efb39a56d7d 100644 --- a/apps/dashboard/pkg/apis/dashboard/v0alpha1/zz_generated.openapi.go +++ b/apps/dashboard/pkg/apis/dashboard/v0alpha1/zz_generated.openapi.go @@ -26,8 +26,6 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v0alpha1.DashboardList": schema_pkg_apis_dashboard_v0alpha1_DashboardList(ref), "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v0alpha1.DashboardMetadata": schema_pkg_apis_dashboard_v0alpha1_DashboardMetadata(ref), "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v0alpha1.DashboardStatus": schema_pkg_apis_dashboard_v0alpha1_DashboardStatus(ref), - "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v0alpha1.DashboardVersionInfo": schema_pkg_apis_dashboard_v0alpha1_DashboardVersionInfo(ref), - "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v0alpha1.DashboardVersionList": schema_pkg_apis_dashboard_v0alpha1_DashboardVersionList(ref), "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v0alpha1.DashboardWithAccessInfo": schema_pkg_apis_dashboard_v0alpha1_DashboardWithAccessInfo(ref), "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v0alpha1.FacetResult": schema_pkg_apis_dashboard_v0alpha1_FacetResult(ref), "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v0alpha1.GridPos": schema_pkg_apis_dashboard_v0alpha1_GridPos(ref), @@ -41,7 +39,6 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v0alpha1.SortableField": schema_pkg_apis_dashboard_v0alpha1_SortableField(ref), "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v0alpha1.SortableFields": schema_pkg_apis_dashboard_v0alpha1_SortableFields(ref), "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v0alpha1.TermFacet": schema_pkg_apis_dashboard_v0alpha1_TermFacet(ref), - "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v0alpha1.VersionsQueryOptions": schema_pkg_apis_dashboard_v0alpha1_VersionsQueryOptions(ref), "github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1.Unstructured": commonv0alpha1.Unstructured{}.OpenAPIDefinition(), } } @@ -555,104 +552,6 @@ func schema_pkg_apis_dashboard_v0alpha1_DashboardStatus(ref common.ReferenceCall } } -func schema_pkg_apis_dashboard_v0alpha1_DashboardVersionInfo(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "version": { - SchemaProps: spec.SchemaProps{ - Description: "The internal ID for this version (will be replaced with resourceVersion)", - Default: 0, - Type: []string{"integer"}, - Format: "int32", - }, - }, - "parentVersion": { - SchemaProps: spec.SchemaProps{ - Description: "If the dashboard came from a previous version, it is set here", - Type: []string{"integer"}, - Format: "int32", - }, - }, - "created": { - SchemaProps: spec.SchemaProps{ - Description: "The creation timestamp for this version", - Default: 0, - Type: []string{"integer"}, - Format: "int64", - }, - }, - "createdBy": { - SchemaProps: spec.SchemaProps{ - Description: "The user who created this version", - Type: []string{"string"}, - Format: "", - }, - }, - "message": { - SchemaProps: spec.SchemaProps{ - Description: "Message passed while saving the version", - Type: []string{"string"}, - Format: "", - }, - }, - }, - Required: []string{"version", "created"}, - }, - }, - } -} - -func schema_pkg_apis_dashboard_v0alpha1_DashboardVersionList(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "kind": { - SchemaProps: spec.SchemaProps{ - Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", - Type: []string{"string"}, - Format: "", - }, - }, - "apiVersion": { - SchemaProps: spec.SchemaProps{ - Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", - Type: []string{"string"}, - Format: "", - }, - }, - "metadata": { - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"), - }, - }, - "items": { - SchemaProps: spec.SchemaProps{ - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v0alpha1.DashboardVersionInfo"), - }, - }, - }, - }, - }, - }, - Required: []string{"items"}, - }, - }, - Dependencies: []string{ - "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v0alpha1.DashboardVersionInfo", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"}, - } -} - func schema_pkg_apis_dashboard_v0alpha1_DashboardWithAccessInfo(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ @@ -1283,42 +1182,3 @@ func schema_pkg_apis_dashboard_v0alpha1_TermFacet(ref common.ReferenceCallback) }, } } - -func schema_pkg_apis_dashboard_v0alpha1_VersionsQueryOptions(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "kind": { - SchemaProps: spec.SchemaProps{ - Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", - Type: []string{"string"}, - Format: "", - }, - }, - "apiVersion": { - SchemaProps: spec.SchemaProps{ - Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", - Type: []string{"string"}, - Format: "", - }, - }, - "path": { - SchemaProps: spec.SchemaProps{ - Description: "Path is the URL path", - Type: []string{"string"}, - Format: "", - }, - }, - "version": { - SchemaProps: spec.SchemaProps{ - Type: []string{"integer"}, - Format: "int64", - }, - }, - }, - }, - }, - } -} From 5673d0b5321e293186cd91916b8ba303aff791a0 Mon Sep 17 00:00:00 2001 From: Yuri Tseretyan Date: Mon, 27 Oct 2025 11:03:06 -0400 Subject: [PATCH 026/378] Alerting: Skip logging in case of invalid receivers during auto generating policies (#111838) * skip logging of invalid receivers during autogen * log warn instead of error --- pkg/services/ngalert/ngalert.go | 7 +++--- pkg/services/ngalert/notifier/alertmanager.go | 10 ++++---- .../ngalert/notifier/alertmanager_config.go | 2 +- .../ngalert/notifier/autogen_alertmanager.go | 25 +++++++++++++------ .../notifier/autogen_alertmanager_test.go | 7 ++++-- pkg/services/ngalert/remote/alertmanager.go | 16 ++++++------ .../ngalert/remote/alertmanager_test.go | 6 ++--- 7 files changed, 44 insertions(+), 29 deletions(-) diff --git a/pkg/services/ngalert/ngalert.go b/pkg/services/ngalert/ngalert.go index 88898de2d64..77484ba43c4 100644 --- a/pkg/services/ngalert/ngalert.go +++ b/pkg/services/ngalert/ngalert.go @@ -10,11 +10,12 @@ import ( notificationHistorian "github.com/grafana/alerting/notify/historian" "github.com/grafana/alerting/notify/historian/lokiclient" "github.com/grafana/alerting/notify/nfstatus" - "github.com/grafana/grafana/pkg/services/ngalert/lokiconfig" "github.com/prometheus/alertmanager/featurecontrol" "github.com/prometheus/alertmanager/matchers/compat" "golang.org/x/sync/errgroup" + "github.com/grafana/grafana/pkg/services/ngalert/lokiconfig" + "github.com/grafana/grafana/pkg/api/routing" "github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/events" @@ -219,8 +220,8 @@ func (ng *AlertNG) init() error { SmtpConfig: smtpCfg, Timeout: ng.Cfg.UnifiedAlerting.RemoteAlertmanager.Timeout, } - autogenFn := func(ctx context.Context, logger log.Logger, orgID int64, cfg *definitions.PostableApiAlertingConfig, skipInvalid bool) error { - return notifier.AddAutogenConfig(ctx, logger, ng.store, orgID, cfg, skipInvalid, ng.FeatureToggles) + autogenFn := func(ctx context.Context, logger log.Logger, orgID int64, cfg *definitions.PostableApiAlertingConfig, invalidReceiverAction notifier.InvalidReceiversAction) error { + return notifier.AddAutogenConfig(ctx, logger, ng.store, orgID, cfg, invalidReceiverAction, ng.FeatureToggles) } // This function will be used by the MOA to create new Alertmanagers. diff --git a/pkg/services/ngalert/notifier/alertmanager.go b/pkg/services/ngalert/notifier/alertmanager.go index f4454d87c5f..dc2f63fb0ec 100644 --- a/pkg/services/ngalert/notifier/alertmanager.go +++ b/pkg/services/ngalert/notifier/alertmanager.go @@ -194,7 +194,7 @@ func (am *alertmanager) SaveAndApplyDefaultConfig(ctx context.Context) error { } err = am.Store.SaveAlertmanagerConfigurationWithCallback(ctx, cmd, func() error { - _, err = am.applyConfig(ctx, cfg, true) + _, err = am.applyConfig(ctx, cfg, LogInvalidReceivers) return err }) if err != nil { @@ -233,7 +233,7 @@ func (am *alertmanager) SaveAndApplyConfig(ctx context.Context, cfg *apimodels.P } err = am.Store.SaveAlertmanagerConfigurationWithCallback(ctx, cmd, func() error { - _, err = am.applyConfig(ctx, cfg, false) // fail if the autogen config is invalid + _, err = am.applyConfig(ctx, cfg, LogInvalidReceivers) // fail if the autogen config is invalid return err }) if err != nil { @@ -259,7 +259,7 @@ func (am *alertmanager) ApplyConfig(ctx context.Context, dbCfg *ngmodels.AlertCo // Since we will now update last_applied when autogen changes even if the user-created config remains the same. // To fix this however, the local alertmanager needs to be able to tell the difference between user-created and // autogen config, which may introduce cross-cutting complexity. - configChanged, err := am.applyConfig(ctx, cfg, true) + configChanged, err := am.applyConfig(ctx, cfg, ErrorOnInvalidReceivers) if err != nil { outerErr = fmt.Errorf("unable to apply configuration: %w", err) return @@ -330,7 +330,7 @@ func (am *alertmanager) aggregateInhibitMatchers(rules []config.InhibitRule, amu // applyConfig applies a new configuration by re-initializing all components using the configuration provided. // It returns a boolean indicating whether the user config was changed and an error. // It is not safe to call concurrently. -func (am *alertmanager) applyConfig(ctx context.Context, cfg *apimodels.PostableUserConfig, skipInvalid bool) (bool, error) { +func (am *alertmanager) applyConfig(ctx context.Context, cfg *apimodels.PostableUserConfig, onInvalid InvalidReceiversAction) (bool, error) { err := am.crypto.DecryptExtraConfigs(ctx, cfg) if err != nil { return false, fmt.Errorf("failed to decrypt external configurations: %w", err) @@ -347,7 +347,7 @@ func (am *alertmanager) applyConfig(ctx context.Context, cfg *apimodels.Postable templates := alertingNotify.PostableAPITemplatesToTemplateDefinitions(cfg.GetMergedTemplateDefinitions()) // Now add autogenerated config to the route. - err = AddAutogenConfig(ctx, am.logger, am.Store, am.Base.TenantID(), &amConfig, skipInvalid, am.features) + err = AddAutogenConfig(ctx, am.logger, am.Store, am.Base.TenantID(), &amConfig, onInvalid, am.features) if err != nil { return false, err } diff --git a/pkg/services/ngalert/notifier/alertmanager_config.go b/pkg/services/ngalert/notifier/alertmanager_config.go index 514da9be686..87d573124e7 100644 --- a/pkg/services/ngalert/notifier/alertmanager_config.go +++ b/pkg/services/ngalert/notifier/alertmanager_config.go @@ -133,7 +133,7 @@ func (moa *MultiOrgAlertmanager) GetAlertmanagerConfiguration(ctx context.Contex // Otherwise, broken settings (e.g. a receiver that doesn't exist) will cause the config returned here to be // different than the config currently in-use. // TODO: Preferably, we'd be getting the config directly from the in-memory AM so adding the autogen config would not be necessary. - err := AddAutogenConfig(ctx, moa.logger, moa.configStore, org, &cfg.AlertmanagerConfig, true, moa.featureManager) + err := AddAutogenConfig(ctx, moa.logger, moa.configStore, org, &cfg.AlertmanagerConfig, LogInvalidReceivers, moa.featureManager) if err != nil { return definitions.GettableUserConfig{}, err } diff --git a/pkg/services/ngalert/notifier/autogen_alertmanager.go b/pkg/services/ngalert/notifier/autogen_alertmanager.go index 7523e368ad5..f0a3ae040ee 100644 --- a/pkg/services/ngalert/notifier/autogen_alertmanager.go +++ b/pkg/services/ngalert/notifier/autogen_alertmanager.go @@ -21,10 +21,18 @@ type autogenRuleStore interface { ListNotificationSettings(ctx context.Context, q models.ListNotificationSettingsQuery) (map[models.AlertRuleKey][]models.NotificationSettings, error) } +type InvalidReceiversAction string + +const ( + ErrorOnInvalidReceivers InvalidReceiversAction = "error" + LogInvalidReceivers InvalidReceiversAction = "log" + IgnoreInvalidReceivers InvalidReceiversAction = "ignore" +) + // AddAutogenConfig creates the autogenerated configuration and adds it to the given apiAlertingConfig. // If skipInvalid is true, then invalid notification settings are skipped, otherwise an error is returned. -func AddAutogenConfig[R receiver](ctx context.Context, logger log.Logger, store autogenRuleStore, orgId int64, cfg apiAlertingConfig[R], skipInvalid bool, features featuremgmt.FeatureToggles) error { - autogenRoute, err := newAutogeneratedRoute(ctx, logger, store, orgId, cfg, skipInvalid, features) +func AddAutogenConfig[R receiver](ctx context.Context, logger log.Logger, store autogenRuleStore, orgId int64, cfg apiAlertingConfig[R], invalidReceiverAction InvalidReceiversAction, features featuremgmt.FeatureToggles) error { + autogenRoute, err := newAutogeneratedRoute(ctx, logger, store, orgId, cfg, invalidReceiverAction, features) if err != nil { return err } @@ -40,7 +48,7 @@ func AddAutogenConfig[R receiver](ctx context.Context, logger log.Logger, store // newAutogeneratedRoute creates a new autogenerated route based on the notification settings for the given org. // cfg is used to construct the settings validator and to ensure we create a dedicated route for each receiver. // skipInvalid is used to skip invalid settings instead of returning an error. -func newAutogeneratedRoute[R receiver](ctx context.Context, logger log.Logger, store autogenRuleStore, orgId int64, cfg apiAlertingConfig[R], skipInvalid bool, features featuremgmt.FeatureToggles) (autogeneratedRoute, error) { +func newAutogeneratedRoute[R receiver](ctx context.Context, logger log.Logger, store autogenRuleStore, orgId int64, cfg apiAlertingConfig[R], invalidReceiverAction InvalidReceiversAction, features featuremgmt.FeatureToggles) (autogeneratedRoute, error) { settings, err := store.ListNotificationSettings(ctx, models.ListNotificationSettingsQuery{OrgID: orgId}) if err != nil { return autogeneratedRoute{}, fmt.Errorf("failed to list alert rules: %w", err) @@ -60,11 +68,14 @@ func newAutogeneratedRoute[R receiver](ctx context.Context, logger log.Logger, s for _, setting := range ruleSettings { // TODO we should register this errors and somehow present to the users or make sure the config is always valid. if err = validator.Validate(setting); err != nil { - if skipInvalid { - logger.Error("Rule notification settings are invalid. Skipping", append(ruleKey.LogContext(), "error", err)...) - continue + switch invalidReceiverAction { + case ErrorOnInvalidReceivers: + return autogeneratedRoute{}, fmt.Errorf("invalid notification settings for rule %s: %w", ruleKey.UID, err) + case LogInvalidReceivers: + logger.Warn("Rule notification settings are invalid. Skipping", append(ruleKey.LogContext(), "error", err)...) + case IgnoreInvalidReceivers: // do nothing } - return autogeneratedRoute{}, fmt.Errorf("invalid notification settings for rule %s: %w", ruleKey.UID, err) + continue } fp := setting.Fingerprint(features) // Keep only unique settings. diff --git a/pkg/services/ngalert/notifier/autogen_alertmanager_test.go b/pkg/services/ngalert/notifier/autogen_alertmanager_test.go index bf376502caa..f0695e513bb 100644 --- a/pkg/services/ngalert/notifier/autogen_alertmanager_test.go +++ b/pkg/services/ngalert/notifier/autogen_alertmanager_test.go @@ -289,8 +289,11 @@ func TestAddAutogenConfig(t *testing.T) { for _, setting := range tt.storeSettings { store.notificationSettings[orgId][models.AlertRuleKey{OrgID: orgId, UID: util.GenerateShortUID()}] = []models.NotificationSettings{setting} } - - err := AddAutogenConfig(context.Background(), &logtest.Fake{}, store, orgId, tt.existingConfig, tt.skipInvalid, nil) + onInvalid := ErrorOnInvalidReceivers + if tt.skipInvalid { + onInvalid = IgnoreInvalidReceivers + } + err := AddAutogenConfig(context.Background(), &logtest.Fake{}, store, orgId, tt.existingConfig, onInvalid, nil) if tt.expErrorContains != "" { require.Error(t, err) require.ErrorContains(t, err, tt.expErrorContains) diff --git a/pkg/services/ngalert/remote/alertmanager.go b/pkg/services/ngalert/remote/alertmanager.go index 78fbbfe3a5b..81e3ef40181 100644 --- a/pkg/services/ngalert/remote/alertmanager.go +++ b/pkg/services/ngalert/remote/alertmanager.go @@ -47,10 +47,10 @@ type stateStore interface { } // AutogenFn is a function that adds auto-generated routes to a configuration. -type AutogenFn func(ctx context.Context, logger log.Logger, orgId int64, config *apimodels.PostableApiAlertingConfig, skipInvalid bool) error +type AutogenFn func(ctx context.Context, logger log.Logger, orgId int64, config *apimodels.PostableApiAlertingConfig, invalidReceiverAction notifier.InvalidReceiversAction) error // NoopAutogenFn is used to skip auto-generating routes. -func NoopAutogenFn(_ context.Context, _ log.Logger, _ int64, _ *apimodels.PostableApiAlertingConfig, _ bool) error { +func NoopAutogenFn(_ context.Context, _ log.Logger, _ int64, _ *apimodels.PostableApiAlertingConfig, _ notifier.InvalidReceiversAction) error { return nil } @@ -206,7 +206,7 @@ func NewAlertmanager(ctx context.Context, cfg AlertmanagerConfig, store stateSto // (grouping, group timing, time intervals etc) changes the autogenerated configuration. // The `default` flag is sent to the remote Alertmanager for informational purposes, so we can tolerate this. err = func() error { - defaultCfg, err := am.buildConfiguration(ctx, []byte(cfg.DefaultConfig), 0) + defaultCfg, err := am.buildConfiguration(ctx, []byte(cfg.DefaultConfig), 0, notifier.IgnoreInvalidReceivers) if err != nil { return fmt.Errorf("unable to build default configuration: %w", err) } @@ -271,7 +271,7 @@ func (am *Alertmanager) checkReadiness(ctx context.Context) error { // CompareAndSendConfiguration checks whether a given configuration is being used by the remote Alertmanager. // If not, it sends the configuration to the remote Alertmanager. func (am *Alertmanager) CompareAndSendConfiguration(ctx context.Context, config *models.AlertConfiguration) error { - payload, err := am.buildConfiguration(ctx, []byte(config.AlertmanagerConfiguration), config.CreatedAt) + payload, err := am.buildConfiguration(ctx, []byte(config.AlertmanagerConfiguration), config.CreatedAt, notifier.LogInvalidReceivers) if err != nil { return fmt.Errorf("unable to build configuration: %w", err) } @@ -303,14 +303,14 @@ func decrypter(ctx context.Context, crypto Crypto) models.DecryptFn { // buildConfiguration takes a raw Alertmanager configuration and returns a config that the remote Alertmanager can use. // It parses the initial configuration, adds auto-generated routes, decrypts receivers, and merges the extra configs. -func (am *Alertmanager) buildConfiguration(ctx context.Context, raw []byte, createdAtEpoch int64) (remoteClient.UserGrafanaConfig, error) { +func (am *Alertmanager) buildConfiguration(ctx context.Context, raw []byte, createdAtEpoch int64, autogenInvalidReceiverAction notifier.InvalidReceiversAction) (remoteClient.UserGrafanaConfig, error) { c, err := notifier.Load(raw) if err != nil { return remoteClient.UserGrafanaConfig{}, err } // Add auto-generated routes and decrypt before comparing. - if err := am.autogenFn(ctx, am.log, am.orgID, &c.AlertmanagerConfig, true); err != nil { + if err := am.autogenFn(ctx, am.log, am.orgID, &c.AlertmanagerConfig, autogenInvalidReceiverAction); err != nil { return remoteClient.UserGrafanaConfig{}, err } @@ -433,7 +433,7 @@ func (am *Alertmanager) SaveAndApplyConfig(ctx context.Context, cfg *apimodels.P return err } - payload, err := am.buildConfiguration(ctx, rawCopy, time.Now().Unix()) + payload, err := am.buildConfiguration(ctx, rawCopy, time.Now().Unix(), notifier.LogInvalidReceivers) if err != nil { return fmt.Errorf("unable to build configuration: %w", err) } @@ -444,7 +444,7 @@ func (am *Alertmanager) SaveAndApplyConfig(ctx context.Context, cfg *apimodels.P // SaveAndApplyDefaultConfig sends the default Grafana Alertmanager configuration to the remote Alertmanager. func (am *Alertmanager) SaveAndApplyDefaultConfig(ctx context.Context) error { am.log.Debug("Sending default configuration to a remote Alertmanager", "url", am.url) - payload, err := am.buildConfiguration(ctx, []byte(am.defaultConfig), time.Now().Unix()) + payload, err := am.buildConfiguration(ctx, []byte(am.defaultConfig), time.Now().Unix(), notifier.LogInvalidReceivers) if err != nil { return fmt.Errorf("unable to build default configuration: %w", err) } diff --git a/pkg/services/ngalert/remote/alertmanager_test.go b/pkg/services/ngalert/remote/alertmanager_test.go index 0ca0bbc950f..b183943d2ac 100644 --- a/pkg/services/ngalert/remote/alertmanager_test.go +++ b/pkg/services/ngalert/remote/alertmanager_test.go @@ -453,7 +453,7 @@ func TestCompareAndSendConfiguration(t *testing.T) { DefaultConfig: defaultGrafanaConfig, } - testAutogenFn := func(_ context.Context, _ log.Logger, _ int64, config *apimodels.PostableApiAlertingConfig, _ bool) error { + testAutogenFn := func(_ context.Context, _ log.Logger, _ int64, config *apimodels.PostableApiAlertingConfig, _ notifier.InvalidReceiversAction) error { newRoute := definition.Route{ Receiver: config.Receivers[0].Name, Match: map[string]string{"auto-gen-test": "true"}, @@ -497,7 +497,7 @@ func TestCompareAndSendConfiguration(t *testing.T) { testAutogenRoutes, err := notifier.Load([]byte(testGrafanaConfigWithSecret)) require.NoError(t, err) - require.NoError(t, testAutogenFn(nil, nil, 0, &testAutogenRoutes.AlertmanagerConfig, false)) + require.NoError(t, testAutogenFn(nil, nil, 0, &testAutogenRoutes.AlertmanagerConfig, notifier.ErrorOnInvalidReceivers)) cfgWithAutogenRoutes := client.GrafanaAlertmanagerConfig{ TemplateFiles: testAutogenRoutes.TemplateFiles, AlertmanagerConfig: testAutogenRoutes.AlertmanagerConfig, @@ -1420,7 +1420,7 @@ func genAlert(active bool, labels map[string]string) amv2.PostableAlert { } // errAutogenFn is an AutogenFn that always returns an error. -func errAutogenFn(_ context.Context, _ log.Logger, _ int64, _ *definition.PostableApiAlertingConfig, _ bool) error { +func errAutogenFn(_ context.Context, _ log.Logger, _ int64, _ *definition.PostableApiAlertingConfig, _ notifier.InvalidReceiversAction) error { return errTest } From e91144950b019281bd4dc320b7c4da28d9b31941 Mon Sep 17 00:00:00 2001 From: Bogdan Matei Date: Mon, 27 Oct 2025 17:23:03 +0200 Subject: [PATCH 027/378] Dashboard: Fix eslint suppressions in conditional rendering (#113045) --- eslint-suppressions.json | 15 --------------- .../conditions/ConditionalRenderingData.tsx | 2 +- .../ConditionalRenderingTimeRangeSize.tsx | 2 +- .../conditions/ConditionalRenderingVariable.tsx | 2 +- .../group/ConditionalRenderingGroup.tsx | 2 +- 5 files changed, 4 insertions(+), 19 deletions(-) diff --git a/eslint-suppressions.json b/eslint-suppressions.json index 7016dcf8169..364c4e1b646 100644 --- a/eslint-suppressions.json +++ b/eslint-suppressions.json @@ -2062,21 +2062,6 @@ "count": 2 } }, - "public/app/features/dashboard-scene/conditional-rendering/conditions/ConditionalRenderingData.tsx": { - "react-prefer-function-component/react-prefer-function-component": { - "count": 1 - } - }, - "public/app/features/dashboard-scene/conditional-rendering/conditions/ConditionalRenderingTimeRangeSize.tsx": { - "react-prefer-function-component/react-prefer-function-component": { - "count": 1 - } - }, - "public/app/features/dashboard-scene/conditional-rendering/conditions/ConditionalRenderingVariable.tsx": { - "react-prefer-function-component/react-prefer-function-component": { - "count": 1 - } - }, "public/app/features/dashboard-scene/edit-pane/DashboardEditPaneRenderer.tsx": { "@typescript-eslint/consistent-type-assertions": { "count": 1 diff --git a/public/app/features/dashboard-scene/conditional-rendering/conditions/ConditionalRenderingData.tsx b/public/app/features/dashboard-scene/conditional-rendering/conditions/ConditionalRenderingData.tsx index bb366768d06..bc1078b7f1b 100644 --- a/public/app/features/dashboard-scene/conditional-rendering/conditions/ConditionalRenderingData.tsx +++ b/public/app/features/dashboard-scene/conditional-rendering/conditions/ConditionalRenderingData.tsx @@ -133,7 +133,7 @@ export class ConditionalRenderingData extends SceneObjectBase; } diff --git a/public/app/features/dashboard-scene/conditional-rendering/conditions/ConditionalRenderingTimeRangeSize.tsx b/public/app/features/dashboard-scene/conditional-rendering/conditions/ConditionalRenderingTimeRangeSize.tsx index fadd4c623e0..a717b68ea79 100644 --- a/public/app/features/dashboard-scene/conditional-rendering/conditions/ConditionalRenderingTimeRangeSize.tsx +++ b/public/app/features/dashboard-scene/conditional-rendering/conditions/ConditionalRenderingTimeRangeSize.tsx @@ -80,7 +80,7 @@ export class ConditionalRenderingTimeRangeSize extends SceneObjectBase; } diff --git a/public/app/features/dashboard-scene/conditional-rendering/conditions/ConditionalRenderingVariable.tsx b/public/app/features/dashboard-scene/conditional-rendering/conditions/ConditionalRenderingVariable.tsx index 39d81f80ef7..8f82b1f459f 100644 --- a/public/app/features/dashboard-scene/conditional-rendering/conditions/ConditionalRenderingVariable.tsx +++ b/public/app/features/dashboard-scene/conditional-rendering/conditions/ConditionalRenderingVariable.tsx @@ -127,7 +127,7 @@ export class ConditionalRenderingVariable extends SceneObjectBase; } diff --git a/public/app/features/dashboard-scene/conditional-rendering/group/ConditionalRenderingGroup.tsx b/public/app/features/dashboard-scene/conditional-rendering/group/ConditionalRenderingGroup.tsx index 37253e0e448..5f0b3319e25 100644 --- a/public/app/features/dashboard-scene/conditional-rendering/group/ConditionalRenderingGroup.tsx +++ b/public/app/features/dashboard-scene/conditional-rendering/group/ConditionalRenderingGroup.tsx @@ -218,7 +218,7 @@ function ConditionalRenderingGroupRenderer({ model }: SceneComponentProps )} - {conditions.map((currentCondition) => currentCondition.render())} + {conditions.map((currentCondition) => currentCondition.renderCmp())} 0} From 9c8a13c8c8d56c3dae0c410144a60618825a7fc5 Mon Sep 17 00:00:00 2001 From: "renovate-sh-app[bot]" <219655108+renovate-sh-app[bot]@users.noreply.github.com> Date: Mon, 27 Oct 2025 15:23:37 +0000 Subject: [PATCH 028/378] chore(deps): update dependency nanoid to v5.1.6 (#113040) | datasource | package | from | to | | ---------- | ------- | ----- | ----- | | npm | nanoid | 5.1.5 | 5.1.6 | Signed-off-by: renovate-sh-app[bot] <219655108+renovate-sh-app[bot]@users.noreply.github.com> Co-authored-by: renovate-sh-app[bot] <219655108+renovate-sh-app[bot]@users.noreply.github.com> --- yarn.lock | 90 +++++++------------------------------------------------ 1 file changed, 10 insertions(+), 80 deletions(-) diff --git a/yarn.lock b/yarn.lock index 8c4162c22ce..74808967fd1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3995,19 +3995,7 @@ __metadata: languageName: node linkType: hard -"@inquirer/confirm@npm:^5.0.0": - version: 5.0.2 - resolution: "@inquirer/confirm@npm:5.0.2" - dependencies: - "@inquirer/core": "npm:^10.1.0" - "@inquirer/type": "npm:^3.0.1" - peerDependencies: - "@types/node": ">=18" - checksum: 10/4e775b80b689adeb0b2852ed79b368ef23a82fe3d5f580a562f4af7cdf002a19e0ec1b3b95acc6d49427a72c0fcb5b6548e0cdcafe2f0d3f3d6a923e04aabd0c - languageName: node - linkType: hard - -"@inquirer/confirm@npm:^5.1.19": +"@inquirer/confirm@npm:^5.0.0, @inquirer/confirm@npm:^5.1.19": version: 5.1.19 resolution: "@inquirer/confirm@npm:5.1.19" dependencies: @@ -4022,23 +4010,6 @@ __metadata: languageName: node linkType: hard -"@inquirer/core@npm:^10.1.0": - version: 10.1.0 - resolution: "@inquirer/core@npm:10.1.0" - dependencies: - "@inquirer/figures": "npm:^1.0.8" - "@inquirer/type": "npm:^3.0.1" - ansi-escapes: "npm:^4.3.2" - cli-width: "npm:^4.1.0" - mute-stream: "npm:^2.0.0" - signal-exit: "npm:^4.1.0" - strip-ansi: "npm:^6.0.1" - wrap-ansi: "npm:^6.2.0" - yoctocolors-cjs: "npm:^2.1.2" - checksum: 10/5d097d0484c1b758f788b792d29395199bdc84af3e8cd4d9273e31de2c5202839b6edf299056956044ba7fb097c4cee7b5c0288e094a380c045082b044f9946e - languageName: node - linkType: hard - "@inquirer/core@npm:^10.2.2, @inquirer/core@npm:^10.3.0": version: 10.3.0 resolution: "@inquirer/core@npm:10.3.0" @@ -4107,20 +4078,13 @@ __metadata: languageName: node linkType: hard -"@inquirer/figures@npm:^1.0.14": +"@inquirer/figures@npm:^1.0.14, @inquirer/figures@npm:^1.0.3": version: 1.0.14 resolution: "@inquirer/figures@npm:1.0.14" checksum: 10/39df361eb607cea5a020d457e25f9c6aee3a1de8975c6295a4b3bfe86ba7e7f7bfbefa6a52b145b1790f2690e5c8f10eb822e5bc764aff7ba00a6cd24eec5a25 languageName: node linkType: hard -"@inquirer/figures@npm:^1.0.3, @inquirer/figures@npm:^1.0.8": - version: 1.0.11 - resolution: "@inquirer/figures@npm:1.0.11" - checksum: 10/357ddd2e83718bc3c9189d518b93fd69099af9c860354df9a5ac0ec024cb5df1228ae4608d2de7625624d2adcd047db813f29426a610eaae7b9e449f8c753c6b - languageName: node - linkType: hard - "@inquirer/input@npm:^4.2.5": version: 4.2.5 resolution: "@inquirer/input@npm:4.2.5" @@ -4241,15 +4205,6 @@ __metadata: languageName: node linkType: hard -"@inquirer/type@npm:^3.0.1": - version: 3.0.1 - resolution: "@inquirer/type@npm:3.0.1" - peerDependencies: - "@types/node": ">=18" - checksum: 10/af412f1e7541d43554b02199ae71a2039a1bff5dc51ceefd87de9ece55b199682733b28810fb4b6cb3ed4a159af4cc4a26d4bb29c58dd127e7d9dbda0797d8e7 - languageName: node - linkType: hard - "@inquirer/type@npm:^3.0.8, @inquirer/type@npm:^3.0.9": version: 3.0.9 resolution: "@inquirer/type@npm:3.0.9" @@ -9002,7 +8957,7 @@ __metadata: languageName: node linkType: hard -"@swc/core@npm:1.13.19": +"@swc/core@npm:1.13.19, @swc/core@npm:^1.10.8, @swc/core@npm:^1.5.22": version: 1.13.19 resolution: "@swc/core@npm:1.13.19" dependencies: @@ -9048,7 +9003,7 @@ __metadata: languageName: node linkType: hard -"@swc/core@npm:1.13.3, @swc/core@npm:^1.10.8, @swc/core@npm:^1.5.22": +"@swc/core@npm:1.13.3": version: 1.13.3 resolution: "@swc/core@npm:1.13.3" dependencies: @@ -9123,16 +9078,7 @@ __metadata: languageName: node linkType: hard -"@swc/types@npm:^0.1.23": - version: 0.1.23 - resolution: "@swc/types@npm:0.1.23" - dependencies: - "@swc/counter": "npm:^0.1.3" - checksum: 10/8d9d73dd1fc9335105105da57595ab913bad6addd4fbcb2eb147300694630232225eb7dc74b733205af33352803e4fcefc18e3a36f8924cf821ef91384767670 - languageName: node - linkType: hard - -"@swc/types@npm:^0.1.25": +"@swc/types@npm:^0.1.23, @swc/types@npm:^0.1.25": version: 0.1.25 resolution: "@swc/types@npm:0.1.25" dependencies: @@ -13849,7 +13795,7 @@ __metadata: languageName: node linkType: hard -"commander@npm:14.0.1": +"commander@npm:14.0.1, commander@npm:~14.0.0": version: 14.0.1 resolution: "commander@npm:14.0.1" checksum: 10/783115e9403caeca29c0fcbd4e0358f70c67760e4e4933f3453fcdd5ddba2ec44173c8da5213d7ce5e404f51c7e71203a42c548164dbe27b668b32a8981577f1 @@ -13926,13 +13872,6 @@ __metadata: languageName: node linkType: hard -"commander@npm:~14.0.0": - version: 14.0.0 - resolution: "commander@npm:14.0.0" - checksum: 10/c05418bfc35a3e8b5c67bd9f75f5b773f386f9b85f83e70e7c926047f270929cb06cf13cd68f387dd6e7e23c6157de8171b28ba606abd3e6256028f1f789becf - languageName: node - linkType: hard - "comment-parser@npm:1.4.1": version: 1.4.1 resolution: "comment-parser@npm:1.4.1" @@ -24271,11 +24210,11 @@ __metadata: linkType: hard "nanoid@npm:^5.0.9": - version: 5.1.5 - resolution: "nanoid@npm:5.1.5" + version: 5.1.6 + resolution: "nanoid@npm:5.1.6" bin: nanoid: bin/nanoid.js - checksum: 10/6de2d006b51c983be385ef7ee285f7f2a57bd96f8c0ca881c4111461644bd81fafc2544f8e07cb834ca0f3e0f3f676c1fe78052183f008b0809efe6e273119f5 + checksum: 10/4109dbcf596d7f297a9b42f459b8f01694a03ebbdd2f41408d963ad54e5ec7234cbe7b4acad137751f31add11bb4fb3415a3e688082516745812811f05570014 languageName: node linkType: hard @@ -34142,16 +34081,7 @@ __metadata: languageName: node linkType: hard -"yaml@npm:^2.0.0, yaml@npm:^2.3.4, yaml@npm:^2.6.0": - version: 2.8.0 - resolution: "yaml@npm:2.8.0" - bin: - yaml: bin.mjs - checksum: 10/7d4bd9c10d0e467601f496193f2ac254140f8e36f96f5ff7f852b9ce37974168eb7354f4c36dc8837dde527a2043d004b6aff48818ec24a69ab2dd3c6b6c381c - languageName: node - linkType: hard - -"yaml@npm:^2.7.1": +"yaml@npm:^2.0.0, yaml@npm:^2.3.4, yaml@npm:^2.6.0, yaml@npm:^2.7.1": version: 2.8.1 resolution: "yaml@npm:2.8.1" bin: From d25f5199c7f1c4d1ae37b548b72d14d18ee1033c Mon Sep 17 00:00:00 2001 From: ksemtinimahmoud <10269091+ksemtinimahmoud@users.noreply.github.com> Date: Mon, 27 Oct 2025 16:29:12 +0100 Subject: [PATCH 029/378] Docs: Fix incorrect label in recording rules documentation (#111464) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix incorrect label: 'New Grafana recording rule' → 'New Data source recording rule' * lowercase --- .../create-data-source-managed-recording-rules.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sources/alerting/alerting-rules/create-recording-rules/create-data-source-managed-recording-rules.md b/docs/sources/alerting/alerting-rules/create-recording-rules/create-data-source-managed-recording-rules.md index e8dd965ffff..ab14f760d65 100644 --- a/docs/sources/alerting/alerting-rules/create-recording-rules/create-data-source-managed-recording-rules.md +++ b/docs/sources/alerting/alerting-rules/create-recording-rules/create-data-source-managed-recording-rules.md @@ -47,7 +47,7 @@ Note that in data source-managed groups, the alert rules and recording rules wit To create a new data source-managed recording rule: 1. Click **Alerts & IRM** -> **Alerting** -> **Alert rules**. -1. At the top of the Alert rules page, click **More** -> **New Grafana recording rule**. +1. At the top of the Alert rules page, click **More** -> **New Data source recording rule**. ## Enter recording rule name From bf65c4378365ed8e2e88f8b767574ce0073e350a Mon Sep 17 00:00:00 2001 From: Austin Pond Date: Mon, 27 Oct 2025 12:01:10 -0400 Subject: [PATCH 030/378] Apps: Add Example App to `./apps` (#112069) * [API Server] Add Example App for reference use. * Remove Printlns. * Upgrade app-sdk to v0.46.0, update apps to handle breaking changes. * Only start the reconciler for the example app if the v1alpha1 API version is enabled. * Some comment doc updates. * Run make update-workspace * Set codeowner for /apps/example * Run make gofmt and make update-workspace * Run prettier on apps/example/README.md * Add COPY apps/example to Dockerfile * Add an authorizer to the example app. * Fix import ordering. * Update apps/example/kinds/manifest.cue Co-authored-by: Owen Diehl * Run make update-workspace * Re-run make gen-go for enterprise import updates * Run make update-workspace --------- Co-authored-by: Owen Diehl --- .github/CODEOWNERS | 1 + Dockerfile | 1 + apps/example/Makefile | 9 + apps/example/README.md | 120 ++++++ apps/example/go.mod | 100 +++++ apps/example/go.sum | 256 ++++++++++++ apps/example/kinds/cue.mod/module.cue | 2 + apps/example/kinds/example.cue | 52 +++ apps/example/kinds/example_v0alpha1.cue | 15 + apps/example/kinds/example_v1alpha1.cue | 76 ++++ apps/example/kinds/manifest.cue | 116 ++++++ .../pkg/apis/example/v0alpha1/constants.go | 18 + .../example/v0alpha1/example_client_gen.go | 99 +++++ .../example/v0alpha1/example_codec_gen.go | 28 ++ .../example/v0alpha1/example_metadata_gen.go | 31 ++ .../example/v0alpha1/example_object_gen.go | 319 +++++++++++++++ .../example/v0alpha1/example_schema_gen.go | 34 ++ .../apis/example/v0alpha1/example_spec_gen.go | 14 + .../example/v0alpha1/example_status_gen.go | 45 +++ .../pkg/apis/example/v1alpha1/constants.go | 18 + .../example/v1alpha1/example_client_gen.go | 144 +++++++ .../example/v1alpha1/example_codec_gen.go | 28 ++ .../example/v1alpha1/example_custom_gen.go | 25 ++ .../example_getfoo_request_body_types_gen.go | 12 + ...xample_getfoo_request_params_object_gen.go | 33 ++ ...example_getfoo_request_params_types_gen.go | 12 + .../example_getfoo_response_body_types_gen.go | 14 + ...xample_getfoo_response_object_types_gen.go | 37 ++ .../example/v1alpha1/example_metadata_gen.go | 31 ++ .../example/v1alpha1/example_object_gen.go | 347 ++++++++++++++++ .../example/v1alpha1/example_schema_gen.go | 34 ++ .../apis/example/v1alpha1/example_spec_gen.go | 34 ++ .../example/v1alpha1/example_status_gen.go | 48 +++ .../getother_request_params_object_gen.go | 33 ++ .../getother_request_params_types_gen.go | 12 + .../v1alpha1/getother_response_types_gen.go | 13 + .../getsomething_request_params_object_gen.go | 33 ++ .../getsomething_request_params_types_gen.go | 12 + .../getsomething_response_body_types_gen.go | 14 + .../getsomething_response_object_types_gen.go | 37 ++ apps/example/pkg/apis/example_manifest.go | 374 ++++++++++++++++++ apps/example/pkg/app/app.go | 143 +++++++ apps/example/pkg/app/authorizer.go | 55 +++ apps/example/pkg/app/config.go | 7 + apps/example/pkg/app/conversion.go | 126 ++++++ apps/example/pkg/app/mutation.go | 31 ++ apps/example/pkg/app/reconciler.go | 58 +++ apps/example/pkg/app/routes.go | 50 +++ apps/example/pkg/app/validation.go | 28 ++ .../example/v0alpha1/example_object_gen.ts | 49 +++ .../example/v0alpha1/types.metadata.gen.ts | 30 ++ .../example/v0alpha1/types.spec.gen.ts | 11 + .../example/v0alpha1/types.status.gen.ts | 32 ++ .../example/v1alpha1/example_object_gen.ts | 51 +++ .../example/v1alpha1/types.custom.gen.ts | 21 + .../example/v1alpha1/types.metadata.gen.ts | 30 ++ .../example/v1alpha1/types.routes.gen.ts | 35 ++ .../example/v1alpha1/types.spec.gen.ts | 30 ++ .../example/v1alpha1/types.status.gen.ts | 35 ++ .../v1alpha1/examplekind_object_gen.ts | 49 +++ .../v1alpha1/types.metadata.gen.ts | 30 ++ .../examplekind/v1alpha1/types.spec.gen.ts | 25 ++ .../examplekind/v1alpha1/types.status.gen.ts | 30 ++ go.work | 1 + pkg/extensions/enterprise_imports.go | 1 - pkg/registry/apps/apps.go | 3 + pkg/registry/apps/apps_test.go | 4 +- pkg/registry/apps/example/register.go | 80 ++++ pkg/registry/apps/wireset.go | 2 + pkg/server/wire_gen.go | 13 +- pkg/services/apiserver/appinstaller/server.go | 7 + 71 files changed, 3744 insertions(+), 4 deletions(-) create mode 100644 apps/example/Makefile create mode 100644 apps/example/README.md create mode 100644 apps/example/go.mod create mode 100644 apps/example/go.sum create mode 100644 apps/example/kinds/cue.mod/module.cue create mode 100644 apps/example/kinds/example.cue create mode 100644 apps/example/kinds/example_v0alpha1.cue create mode 100644 apps/example/kinds/example_v1alpha1.cue create mode 100644 apps/example/kinds/manifest.cue create mode 100644 apps/example/pkg/apis/example/v0alpha1/constants.go create mode 100644 apps/example/pkg/apis/example/v0alpha1/example_client_gen.go create mode 100644 apps/example/pkg/apis/example/v0alpha1/example_codec_gen.go create mode 100644 apps/example/pkg/apis/example/v0alpha1/example_metadata_gen.go create mode 100644 apps/example/pkg/apis/example/v0alpha1/example_object_gen.go create mode 100644 apps/example/pkg/apis/example/v0alpha1/example_schema_gen.go create mode 100644 apps/example/pkg/apis/example/v0alpha1/example_spec_gen.go create mode 100644 apps/example/pkg/apis/example/v0alpha1/example_status_gen.go create mode 100644 apps/example/pkg/apis/example/v1alpha1/constants.go create mode 100644 apps/example/pkg/apis/example/v1alpha1/example_client_gen.go create mode 100644 apps/example/pkg/apis/example/v1alpha1/example_codec_gen.go create mode 100644 apps/example/pkg/apis/example/v1alpha1/example_custom_gen.go create mode 100644 apps/example/pkg/apis/example/v1alpha1/example_getfoo_request_body_types_gen.go create mode 100644 apps/example/pkg/apis/example/v1alpha1/example_getfoo_request_params_object_gen.go create mode 100644 apps/example/pkg/apis/example/v1alpha1/example_getfoo_request_params_types_gen.go create mode 100644 apps/example/pkg/apis/example/v1alpha1/example_getfoo_response_body_types_gen.go create mode 100644 apps/example/pkg/apis/example/v1alpha1/example_getfoo_response_object_types_gen.go create mode 100644 apps/example/pkg/apis/example/v1alpha1/example_metadata_gen.go create mode 100644 apps/example/pkg/apis/example/v1alpha1/example_object_gen.go create mode 100644 apps/example/pkg/apis/example/v1alpha1/example_schema_gen.go create mode 100644 apps/example/pkg/apis/example/v1alpha1/example_spec_gen.go create mode 100644 apps/example/pkg/apis/example/v1alpha1/example_status_gen.go create mode 100644 apps/example/pkg/apis/example/v1alpha1/getother_request_params_object_gen.go create mode 100644 apps/example/pkg/apis/example/v1alpha1/getother_request_params_types_gen.go create mode 100644 apps/example/pkg/apis/example/v1alpha1/getother_response_types_gen.go create mode 100644 apps/example/pkg/apis/example/v1alpha1/getsomething_request_params_object_gen.go create mode 100644 apps/example/pkg/apis/example/v1alpha1/getsomething_request_params_types_gen.go create mode 100644 apps/example/pkg/apis/example/v1alpha1/getsomething_response_body_types_gen.go create mode 100644 apps/example/pkg/apis/example/v1alpha1/getsomething_response_object_types_gen.go create mode 100644 apps/example/pkg/apis/example_manifest.go create mode 100644 apps/example/pkg/app/app.go create mode 100644 apps/example/pkg/app/authorizer.go create mode 100644 apps/example/pkg/app/config.go create mode 100644 apps/example/pkg/app/conversion.go create mode 100644 apps/example/pkg/app/mutation.go create mode 100644 apps/example/pkg/app/reconciler.go create mode 100644 apps/example/pkg/app/routes.go create mode 100644 apps/example/pkg/app/validation.go create mode 100644 apps/example/plugin/src/generated/example/v0alpha1/example_object_gen.ts create mode 100644 apps/example/plugin/src/generated/example/v0alpha1/types.metadata.gen.ts create mode 100644 apps/example/plugin/src/generated/example/v0alpha1/types.spec.gen.ts create mode 100644 apps/example/plugin/src/generated/example/v0alpha1/types.status.gen.ts create mode 100644 apps/example/plugin/src/generated/example/v1alpha1/example_object_gen.ts create mode 100644 apps/example/plugin/src/generated/example/v1alpha1/types.custom.gen.ts create mode 100644 apps/example/plugin/src/generated/example/v1alpha1/types.metadata.gen.ts create mode 100644 apps/example/plugin/src/generated/example/v1alpha1/types.routes.gen.ts create mode 100644 apps/example/plugin/src/generated/example/v1alpha1/types.spec.gen.ts create mode 100644 apps/example/plugin/src/generated/example/v1alpha1/types.status.gen.ts create mode 100644 apps/example/plugin/src/generated/examplekind/v1alpha1/examplekind_object_gen.ts create mode 100644 apps/example/plugin/src/generated/examplekind/v1alpha1/types.metadata.gen.ts create mode 100644 apps/example/plugin/src/generated/examplekind/v1alpha1/types.spec.gen.ts create mode 100644 apps/example/plugin/src/generated/examplekind/v1alpha1/types.status.gen.ts create mode 100644 pkg/registry/apps/example/register.go diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 1568a383809..ce7089273ef 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -96,6 +96,7 @@ /apps/iam/ @grafana/access-squad /apps/sdk.mk @grafana/grafana-app-platform-squad /apps/correlations @grafana/datapro +/apps/example/ @grafana/grafana-app-platform-squad /apps/logsdrilldown/ @grafana/observability-logs /pkg/api/ @grafana/grafana-backend-group /pkg/apis/ @grafana/grafana-app-platform-squad diff --git a/Dockerfile b/Dockerfile index 16efe807bfc..0edb989ac76 100644 --- a/Dockerfile +++ b/Dockerfile @@ -114,6 +114,7 @@ COPY apps/alerting/notifications apps/alerting/notifications COPY apps/alerting/rules apps/alerting/rules COPY pkg/codegen pkg/codegen COPY pkg/plugins/codegen pkg/plugins/codegen +COPY apps/example apps/example RUN go mod download diff --git a/apps/example/Makefile b/apps/example/Makefile new file mode 100644 index 00000000000..230bfd4149a --- /dev/null +++ b/apps/example/Makefile @@ -0,0 +1,9 @@ +include ../sdk.mk + +.PHONY: generate # Run Grafana App SDK code generation +generate: install-app-sdk update-app-sdk + @$(APP_SDK_BIN) generate \ + --source=./kinds/ \ + --gogenpath=./pkg/apis \ + --grouping=group \ + --defencoding=none \ No newline at end of file diff --git a/apps/example/README.md b/apps/example/README.md new file mode 100644 index 00000000000..8a69389c3fa --- /dev/null +++ b/apps/example/README.md @@ -0,0 +1,120 @@ +# Example App + +This App is an example of general app capabilities when developing on the grafana app platform. + +## Enabling the App + +By default, the example app is disabled. To enable this App, add the following to your `conf/custom.ini`: + +``` +[grafana-apiserver] +runtime_config = example.grafana.app/v0alpha1=true,example.grafana.app/v1alpha1=true +``` + +## Manifest + +The source of the app's schemas and list of capabilities is the manifest, which is generated from [kinds/manifest.cue](./kinds/manifest.cue). +The `Example` kind is defined for [v0alpha1 here](./kinds/example_v0alpha1) and [v1alpha1 (default) here](./kinds/example_v1alpha1.cue). +The root definition of the `Example` kind that both versions share is defined [here](./kinds/example.cue). + +The CUE is used to generate code (and the AppManifest) when `make generate` is run. + +## Code + +All of the app's code is located in [pkg/app](./pkg/app/). The [New() function](./pkg/app/app.go#20) in `pkg/app/app.go` is the entry point of the app, +and everything should be discoverable from there. + +The code to register the app with the grafana API server (including inserting the app-specific config [ExampleConfig](./pkg/app/config.go)) +is located in [/pkg/registry/apps/example/register.go](../../pkg/registry/apps/example/register.go). + +Any app must also have its installer listed in [WireSet](../../pkg/registry/apps/wireset.go) and added to `installers` in [ProvideAppInstallers](../../pkg/registry/apps/apps.go). When building a new app, make to to regerate wire (`make build` in the root of the repo does this). + +### Generated Code + +The [pkg/apis](./pkg/apis/) package, and all its subdirectories, contain code generated by `make generate`. +This code should not be edited, but it can be useful to look at when working through the flow of the app. + +## Sample Swagger Payloads + +Navigate to [localhost:3000/swagger?api=example.grafana.app-v1alpha1](http://localhost:3000/swagger?api=example.grafana.app-v1alpha1) to view the swagger for the app's `v1alpha1` version +(this version has the most capabilities/endpoints). You can use the `Execute` button to make requests via the swagger UI. + +Create a new `Example` resource with via swagger with: + +```json +{ + "apiVersion": "example.grafana.app/v1alpha1", + "kind": "Example", + "metadata": { + "name": "test", + "namespace": "default" + }, + "spec": { + "firstField": "test", + "secondField": 0, + "list": { + "info": "foo", + "next": { + "info": "bar" + } + } + } +} +``` + +Create an invalid object which will be rejected by validation: + +```json +{ + "apiVersion": "example.grafana.app/v1alpha1", + "kind": "Example", + "metadata": { + "name": "invalid", + "namespace": "default" + }, + "spec": { + "firstField": "test", + "secondField": 0, + "list": { + "info": "foo", + "next": { + "info": "bar" + } + } + } +} +``` + +Update `custom` subresource: + +```json +{ + "apiVersion": "example.grafana.app/v1alpha1", + "kind": "Example", + "metadata": { + "namespace": "default", + "name": "test", + "resourceVersion": "" + }, + "custom": { + "myField": "foo", + "otherField": "bar" + } +} +``` + +(`metadata.resourceVersion` is required for an update, use the value you get from a GET request) + +## cURL + +You can also interact with the grafana API server via a kubeconfig set up for it, or via `curl` using the `-u :` flag. +Currently, cluster-scoped custom routes are erased from the swagger as part of grafana's APIServer code, but can still be called via `curl`, like so: + +```bash +curl -u admin:admin http://localhost:3000/apis/example.grafana.app/v1alpha1/other +``` + +``` +% curl -u admin:admin http://localhost:3000/apis/example.grafana.app/v1alpha1/other +{"message":"This is a cluster route"} +``` diff --git a/apps/example/go.mod b/apps/example/go.mod new file mode 100644 index 00000000000..2a3e75d75c0 --- /dev/null +++ b/apps/example/go.mod @@ -0,0 +1,100 @@ +module github.com/grafana/grafana/apps/example + +go 1.25.3 + +require ( + github.com/grafana/grafana-app-sdk v0.48.1 + github.com/grafana/grafana-app-sdk/logging v0.48.1 + github.com/grafana/grafana/pkg/apimachinery v0.0.0-20251017153501-8512b219c5fe + k8s.io/apimachinery v0.34.1 + k8s.io/apiserver v0.34.1 + k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 +) + +require ( + github.com/beorn7/perks v1.0.1 // indirect + github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874 // indirect + github.com/cenkalti/backoff/v5 v5.0.3 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/emicklei/go-restful/v3 v3.13.0 // indirect + github.com/evanphx/json-patch v5.9.11+incompatible // indirect + github.com/fxamacker/cbor/v2 v2.9.0 // indirect + github.com/getkin/kin-openapi v0.133.0 // indirect + github.com/go-jose/go-jose/v4 v4.1.2 // indirect + github.com/go-logr/logr v1.4.3 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-openapi/jsonpointer v0.22.1 // indirect + github.com/go-openapi/jsonreference v0.21.2 // indirect + github.com/go-openapi/swag v0.23.0 // indirect + github.com/go-openapi/swag/jsonname v0.25.1 // indirect + github.com/go-test/deep v1.1.1 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/google/gnostic-models v0.7.0 // indirect + github.com/google/go-cmp v0.7.0 // indirect + github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/grafana/authlib v0.0.0-20250930082137-a40e2c2b094f // indirect + github.com/grafana/authlib/types v0.0.0-20250926065801-df98203cff37 // indirect + github.com/grafana/dskit v0.0.0-20250908063411-6b6da59b5cc4 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/mailru/easyjson v0.9.0 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect + github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 // indirect + github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 // indirect + github.com/onsi/ginkgo/v2 v2.22.2 // indirect + github.com/onsi/gomega v1.36.2 // indirect + github.com/patrickmn/go-cache v2.1.0+incompatible // indirect + github.com/perimeterx/marshmallow v1.1.5 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/prometheus/client_golang v1.23.2 // indirect + github.com/prometheus/client_model v0.6.2 // indirect + github.com/prometheus/common v0.67.1 // indirect + github.com/prometheus/procfs v0.16.1 // indirect + github.com/puzpuzpuz/xsync/v2 v2.5.1 // indirect + github.com/spf13/pflag v1.0.10 // indirect + github.com/woodsbury/decimal128 v1.3.0 // indirect + github.com/x448/float16 v0.8.4 // indirect + go.opentelemetry.io/auto/sdk v1.1.0 // indirect + go.opentelemetry.io/otel v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 // indirect + go.opentelemetry.io/otel/metric v1.38.0 // indirect + go.opentelemetry.io/otel/sdk v1.38.0 // indirect + go.opentelemetry.io/otel/trace v1.38.0 // indirect + go.opentelemetry.io/proto/otlp v1.7.1 // indirect + go.yaml.in/yaml/v2 v2.4.3 // indirect + go.yaml.in/yaml/v3 v3.0.4 // indirect + golang.org/x/crypto v0.43.0 // indirect + golang.org/x/net v0.46.0 // indirect + golang.org/x/oauth2 v0.32.0 // indirect + golang.org/x/sync v0.17.0 // indirect + golang.org/x/sys v0.37.0 // indirect + golang.org/x/term v0.36.0 // indirect + golang.org/x/text v0.30.0 // indirect + golang.org/x/time v0.14.0 // indirect + gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20250908214217-97024824d090 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20251002232023-7c0ddcbb5797 // indirect + google.golang.org/grpc v1.76.0 // indirect + google.golang.org/protobuf v1.36.10 // indirect + gopkg.in/inf.v0 v0.9.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + k8s.io/api v0.34.1 // indirect + k8s.io/apiextensions-apiserver v0.34.1 // indirect + k8s.io/client-go v0.34.1 // indirect + k8s.io/klog/v2 v2.130.1 // indirect + k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 // indirect + sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect + sigs.k8s.io/randfill v1.0.0 // indirect + sigs.k8s.io/structured-merge-diff/v6 v6.3.0 // indirect + sigs.k8s.io/yaml v1.6.0 // indirect +) diff --git a/apps/example/go.sum b/apps/example/go.sum new file mode 100644 index 00000000000..fcab8eb625f --- /dev/null +++ b/apps/example/go.sum @@ -0,0 +1,256 @@ +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/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874 h1:N7oVaKyGp8bttX0bfZGmcGkjz7DLQXhAn3DNd3T0ous= +github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874/go.mod h1:r5xuitiExdLAJ09PR7vBVENGvp4ZuTBeWTGtxuX3K+c= +github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= +github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +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.13.0 h1:C4Bl2xDndpU6nJ4bc1jXd+uTmYPVUwkD6bFY/oTyCes= +github.com/emicklei/go-restful/v3 v3.13.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/evanphx/json-patch v5.9.11+incompatible h1:ixHHqfcGvxhWkniF1tWxBHA0yb4Z+d1UQi45df52xW8= +github.com/evanphx/json-patch v5.9.11+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM= +github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= +github.com/getkin/kin-openapi v0.133.0 h1:pJdmNohVIJ97r4AUFtEXRXwESr8b0bD721u/Tz6k8PQ= +github.com/getkin/kin-openapi v0.133.0/go.mod h1:boAciF6cXk5FhPqe/NQeBTeenbjqU4LhWBf09ILVvWE= +github.com/go-jose/go-jose/v4 v4.1.2 h1:TK/7NqRQZfgAh+Td8AlsrvtPoUyiHh0LqVvokh+1vHI= +github.com/go-jose/go-jose/v4 v4.1.2/go.mod h1:22cg9HWM1pOlnRiY+9cQYJ9XHmya1bYW8OeDM6Ku6Oo= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= +github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +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.22.1 h1:sHYI1He3b9NqJ4wXLoJDKmUmHkWy/L7rtEo92JUxBNk= +github.com/go-openapi/jsonpointer v0.22.1/go.mod h1:pQT9OsLkfz1yWoMgYFy4x3U5GY5nUlsOn1qSBH5MkCM= +github.com/go-openapi/jsonreference v0.21.2 h1:Wxjda4M/BBQllegefXrY/9aq1fxBA8sI5M/lFU6tSWU= +github.com/go-openapi/jsonreference v0.21.2/go.mod h1:pp3PEjIsJ9CZDGCNOyXIQxsNuroxm8FAJ/+quA0yKzQ= +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-openapi/swag/jsonname v0.25.1 h1:Sgx+qbwa4ej6AomWC6pEfXrA6uP2RkaNjA9BR8a1RJU= +github.com/go-openapi/swag/jsonname v0.25.1/go.mod h1:71Tekow6UOLBD3wS7XhdT98g5J5GR13NOTQ9/6Q11Zo= +github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= +github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= +github.com/go-test/deep v1.1.1 h1:0r/53hagsehfO4bzD2Pgr/+RgHqhmf+k1Bpse2cTu1U= +github.com/go-test/deep v1.1.1/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= +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= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/google/gnostic-models v0.7.0 h1:qwTtogB15McXDaNqTZdzPJRHvaVJlAl+HVQnLmJEJxo= +github.com/google/gnostic-models v0.7.0/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 h1:BHT72Gu3keYf3ZEu2J0b1vyeLSOYI8bm5wbJM/8yDe8= +github.com/google/pprof v0.0.0-20250403155104-27863c87afa6/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= +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/grafana/authlib v0.0.0-20250930082137-a40e2c2b094f h1:Cbm6OKkOcJ+7CSZsGsEJzktC/SIa5bxVeYKQLuYK86o= +github.com/grafana/authlib v0.0.0-20250930082137-a40e2c2b094f/go.mod h1:axY0cdOg3q0TZHwpHnIz5x16xZ8ZBxJHShsSHHXcHQg= +github.com/grafana/authlib/types v0.0.0-20250926065801-df98203cff37 h1:qEwZ+7MbPjzRvTi31iT9w7NBhKIpKwZrFbYmOZLqkwA= +github.com/grafana/authlib/types v0.0.0-20250926065801-df98203cff37/go.mod h1:qeWYbnWzaYGl88JlL9+DsP1GT2Cudm58rLtx13fKZdw= +github.com/grafana/dskit v0.0.0-20250908063411-6b6da59b5cc4 h1:jSojuc7njleS3UOz223WDlXOinmuLAIPI0z2vtq8EgI= +github.com/grafana/dskit v0.0.0-20250908063411-6b6da59b5cc4/go.mod h1:VahT+GtfQIM+o8ht2StR6J9g+Ef+C2Vokh5uuSmOD/4= +github.com/grafana/grafana-app-sdk v0.48.1 h1:bKJadWH18WCpJ+Zk8AezRFXCcZgGredRv+fRS+8zkek= +github.com/grafana/grafana-app-sdk v0.48.1/go.mod h1:5LljCz+wvmGfkQ8ZKTOfserhtXNEF0cSFthoWShvN6c= +github.com/grafana/grafana-app-sdk/logging v0.48.1 h1:veM0X5LAPyN3KsDLglWjIofndbGuf7MqnrDuDN+F/Ng= +github.com/grafana/grafana-app-sdk/logging v0.48.1/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA= +github.com/grafana/grafana/pkg/apimachinery v0.0.0-20251017153501-8512b219c5fe h1:pPoFj2bQKDBg5EyEdOU+Jn+0hQN+M775Qihk73RbdSs= +github.com/grafana/grafana/pkg/apimachinery v0.0.0-20251017153501-8512b219c5fe/go.mod h1:zn/yoxKpWA2KUsxOhQbSbL8OCkF2JNLpSEHs+hQYvdM= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 h1:8Tjv8EJ+pM1xP8mK6egEbD1OgnVTyacbefKhmbLhIhU= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2/go.mod h1:pkJQ2tZHJ0aFOVEEot6oZmaVEZcRme73eIFmhiVuRWs= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +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= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= +github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= +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= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4= +github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= +github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= +github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 h1:G7ERwszslrBzRxj//JalHPu/3yz+De2J+4aLtSRlHiY= +github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037/go.mod h1:2bpvgLBZEtENV5scfDFEtB/5+1M4hkQhDQrccEJ/qGw= +github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 h1:bQx3WeLcUWy+RletIKwUIt4x3t8n2SxavmoclizMb8c= +github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90/go.mod h1:y5+oSEHCPT/DGrS++Wc/479ERge0zTFxaF8PbGKcg2o= +github.com/onsi/ginkgo/v2 v2.22.2 h1:/3X8Panh8/WwhU/3Ssa6rCKqPLuAkVY2I0RoyDLySlU= +github.com/onsi/ginkgo/v2 v2.22.2/go.mod h1:oeMosUL+8LtarXBHu/c0bx2D/K9zyQ6uX3cTyztHwsk= +github.com/onsi/gomega v1.36.2 h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8= +github.com/onsi/gomega v1.36.2/go.mod h1:DdwyADRjrc825LhMEkD76cHR5+pUnjhUN8GlHlRPHzY= +github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= +github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= +github.com/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX50IvK2s= +github.com/perimeterx/marshmallow v1.1.5/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +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.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o= +github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg= +github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= +github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= +github.com/prometheus/common v0.67.1 h1:OTSON1P4DNxzTg4hmKCc37o4ZAZDv0cfXLkOt0oEowI= +github.com/prometheus/common v0.67.1/go.mod h1:RpmT9v35q2Y+lsieQsdOh5sXZ6ajUGC8NjZAmr8vb0Q= +github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= +github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= +github.com/puzpuzpuz/xsync/v2 v2.5.1 h1:mVGYAvzDSu52+zaGyNjC+24Xw2bQi3kTr4QJ6N9pIIU= +github.com/puzpuzpuz/xsync/v2 v2.5.1/go.mod h1:gD2H2krq/w52MfPLE+Uy64TzJDVY7lP2znR9qmR35kU= +github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= +github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= +github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= +github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +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.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= +github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +github.com/woodsbury/decimal128 v1.3.0 h1:8pffMNWIlC0O5vbyHWFZAt5yWvWcrHA+3ovIIjVWss0= +github.com/woodsbury/decimal128 v1.3.0/go.mod h1:C5UTmyTjW3JftjUFzOVhC20BEQa2a4ZKOB5I6Zjb+ds= +github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= +github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= +go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= +go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= +go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 h1:GqRJVj7UmLjCVyVJ3ZFLdPRmhDUp2zFmQe3RHIOsw24= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0/go.mod h1:ri3aaHSmCTVYu2AWv44YMauwAQc0aqI9gHKIcSbI1pU= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 h1:lwI4Dc5leUqENgGuQImwLo4WnuXFPetmPpkLi2IrX54= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0/go.mod h1:Kz/oCE7z5wuyhPxsXDuaPteSWqjSBD5YaSdbxZYGbGk= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 h1:aTL7F04bJHUlztTsNGJ2l+6he8c+y/b//eR0jjjemT4= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0/go.mod h1:kldtb7jDTeol0l3ewcmd8SDvx3EmIE7lyvqbasU3QC4= +go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= +go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= +go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= +go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= +go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= +go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= +go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= +go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= +go.opentelemetry.io/proto/otlp v1.7.1 h1:gTOMpGDb0WTBOP8JaO72iL3auEZhVmAQg4ipjOVAtj4= +go.opentelemetry.io/proto/otlp v1.7.1/go.mod h1:b2rVh6rfI/s2pHWNlB7ILJcRALpcNDzKhACevjI+ZnE= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0= +go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8= +go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= +go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= +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/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04= +golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0= +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/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= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4= +golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= +golang.org/x/oauth2 v0.32.0 h1:jsCblLleRMDrxMN29H3z/k1KliIvpLgCkE6R8FXXNgY= +golang.org/x/oauth2 v0.32.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug= +golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= +golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q= +golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k= +golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= +golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= +golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +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.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ= +golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs= +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= +gomodules.xyz/jsonpatch/v2 v2.5.0 h1:JELs8RLM12qJGXU4u/TO3V25KW8GreMKl9pdkk14RM0= +gomodules.xyz/jsonpatch/v2 v2.5.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= +gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= +gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= +google.golang.org/genproto/googleapis/api v0.0.0-20250908214217-97024824d090 h1:d8Nakh1G+ur7+P3GcMjpRDEkoLUcLW2iU92XVqR+XMQ= +google.golang.org/genproto/googleapis/api v0.0.0-20250908214217-97024824d090/go.mod h1:U8EXRNSd8sUYyDfs/It7KVWodQr+Hf9xtxyxWudSwEw= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251002232023-7c0ddcbb5797 h1:CirRxTOwnRWVLKzDNrs0CXAaVozJoR4G9xvdRecrdpk= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251002232023-7c0ddcbb5797/go.mod h1:HSkG/KdJWusxU1F6CNrwNDjBMgisKxGnc5dAZfT0mjQ= +google.golang.org/grpc v1.76.0 h1:UnVkv1+uMLYXoIz6o7chp59WfQUYA2ex/BXQ9rHZu7A= +google.golang.org/grpc v1.76.0/go.mod h1:Ju12QI8M6iQJtbcsV+awF5a4hfJMLi4X0JLo94ULZ6c= +google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= +google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4= +gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M= +gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +k8s.io/api v0.34.1 h1:jC+153630BMdlFukegoEL8E/yT7aLyQkIVuwhmwDgJM= +k8s.io/api v0.34.1/go.mod h1:SB80FxFtXn5/gwzCoN6QCtPD7Vbu5w2n1S0J5gFfTYk= +k8s.io/apiextensions-apiserver v0.34.1 h1:NNPBva8FNAPt1iSVwIE0FsdrVriRXMsaWFMqJbII2CI= +k8s.io/apiextensions-apiserver v0.34.1/go.mod h1:hP9Rld3zF5Ay2Of3BeEpLAToP+l4s5UlxiHfqRaRcMc= +k8s.io/apimachinery v0.34.1 h1:dTlxFls/eikpJxmAC7MVE8oOeP1zryV7iRyIjB0gky4= +k8s.io/apimachinery v0.34.1/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= +k8s.io/apiserver v0.34.1 h1:U3JBGdgANK3dfFcyknWde1G6X1F4bg7PXuvlqt8lITA= +k8s.io/apiserver v0.34.1/go.mod h1:eOOc9nrVqlBI1AFCvVzsob0OxtPZUCPiUJL45JOTBG0= +k8s.io/client-go v0.34.1 h1:ZUPJKgXsnKwVwmKKdPfw4tB58+7/Ik3CrjOEhsiZ7mY= +k8s.io/client-go v0.34.1/go.mod h1:kA8v0FP+tk6sZA0yKLRG67LWjqufAoSHA2xVGKw9Of8= +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-20250910181357-589584f1c912 h1:Y3gxNAuB0OBLImH611+UDZcmKS3g6CthxToOb37KgwE= +k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912/go.mod h1:kdmbQkyfwUagLfXIad1y2TdrjPFWp2Q89B3qkRwf/pQ= +k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 h1:hwvWFiBzdWw1FhfY1FooPn3kzWuJ8tmbZBHi4zVsl1Y= +k8s.io/utils v0.0.0-20250604170112-4c0f3b243397/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 h1:gBQPwqORJ8d8/YNZWEjoZs7npUVDpVXUUOFfW6CgAqE= +sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= +sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= +sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= +sigs.k8s.io/structured-merge-diff/v6 v6.3.0 h1:jTijUJbW353oVOd9oTlifJqOGEkUw2jB/fXCbTiQEco= +sigs.k8s.io/structured-merge-diff/v6 v6.3.0/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= +sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= +sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= diff --git a/apps/example/kinds/cue.mod/module.cue b/apps/example/kinds/cue.mod/module.cue new file mode 100644 index 00000000000..b2f49fc6dc6 --- /dev/null +++ b/apps/example/kinds/cue.mod/module.cue @@ -0,0 +1,2 @@ +module: "github.com/grafana/grafana/apps/example/kinds" +language: version: "v0.8.2" diff --git a/apps/example/kinds/example.cue b/apps/example/kinds/example.cue new file mode 100644 index 00000000000..12e7f5a496d --- /dev/null +++ b/apps/example/kinds/example.cue @@ -0,0 +1,52 @@ +package kinds + +// This is our ExampleKind definition, which contains kind metadata. It is the same across all versions of the kind. +exampleKind: { + // Name is the human-readable name which is used for generated type names. + kind: "Example" + // Scope determines the scope of the kind in the API server. It currently allows two values: + // * Namespaced - resources for this kind are created inside namespaces + // * Cluster - resource for this kind are always cluster-wide (this can be thought of as a "global" namespace) + // If not present, this defaults to "Namespaced" + scope: "Namespaced" + // [OPTIONAL] + // The human-readable plural form of the "name" field. + // Will default to +"s" if not present. + pluralName: "Examples" + validation: { + operations: [ + "CREATE", + "UPDATE", + ] + } + mutation: { + operations: [ + "CREATE", + "UPDATE", + ] + } + conversion: true + // [OPTIONAL] + // Codegen is a trait that tells the grafana-app-sdk, or other code generation tooling, how to process this kind. + // If not present, default values within the codegen trait are used. + // If you wish to specify codegen per-version, put this section in the version's object + // (for example, exampleKindv1alpha1) instead. + codegen: { + // [OPTIONAL] + // ts contains TypeScript code generation properties for the kind + ts: { + // [OPTIONAL] + // enabled indicates whether the CLI should generate front-end TypeScript code for the kind. + // Defaults to true if not present. + enabled: true + } + // [OPTIONAL] + // go contains go code generation properties for the kind + go: { + // [OPTIONAL] + // enabled indicates whether the CLI should generate back-end go code for the kind. + // Defaults to true if not present. + enabled: true + } + } +} diff --git a/apps/example/kinds/example_v0alpha1.cue b/apps/example/kinds/example_v0alpha1.cue new file mode 100644 index 00000000000..645189f7dc2 --- /dev/null +++ b/apps/example/kinds/example_v0alpha1.cue @@ -0,0 +1,15 @@ +package kinds + +// This is the v0alpha1 version of the kind. Please see v1alpha1 for more complete comments +// and a more complex schema and set of capabilities. +examplev0alpha1: exampleKind & { + schema: { + // Spec is the schema of our resource. The spec should include all the user-editable information for the kind. + spec: { + firstField: int + } + status: { + lastObservedGeneration: int64 + } + } +} \ No newline at end of file diff --git a/apps/example/kinds/example_v1alpha1.cue b/apps/example/kinds/example_v1alpha1.cue new file mode 100644 index 00000000000..bb54c59d56c --- /dev/null +++ b/apps/example/kinds/example_v1alpha1.cue @@ -0,0 +1,76 @@ +package kinds + +// This is the v1alpha1 version of the kind, which joins the kind metadata and +// version-specific information for the kind, such as the schema +examplev1alpha1: exampleKind & { + // schema is the schema for this version of the kind + // As an API server-expressable resource, the schema has a restricted format: + // { + // spec: { ... } + // status: { ... } // optional + // metadata: { ... } // optional + // } + // `spec` must always be present, and is the schema for the object. + // `status` is optional, and should contain status or state information which is typically not user-editable + // (controlled by controllers/operators). The kind system adds some implicit status information which is + // common across all kinds, and becomes present in the unified lineage used for code generation and other tooling. + // `metadata` is optional, and should contain kind- or schema-specific metadata. The kind system adds + // an explicit set of common metadata which can be found in the definition file for a CUE kind at + // [https://github.com/grafana/grafana-app-sdk/blob/main/codegen/cuekind/def.cue] + // additional metadata fields cannot conflict with the common metadata field names + schema: { + // #DefinedType is a re-usable definition for us to use in our schema. + // Fields leading with # are definitions in CUE and won't be included in the generated types. + #DefinedType: { + // Info is information about this entry. This comment, like all comments + // on fields or definitions, will be copied into the generated types as well. + info: string + // Next is an optional next element in the DefinedType, allowing for a self-referential + // linked-list like structure. The ? in the field makes this optional. + next?: #DefinedType + } + // Spec is the schema of our resource. The spec should include all the user-editable information for the kind. + spec: { + // Example fields + firstField: string + secondField: int + list?: #DefinedType + } + // status is where state and status information which may be used or updated by the operator or back-end should be placed + // If you do not have any such information, you do not need to include this field, + // however, as mentioned above, certain fields will be added by the kind system regardless. + status: { + lastObservedGeneration: int64 + } + // Custom is a subresource that will be stored the same way status is stored, + // and requires using the /custom route to update. + // Its content is returned as part of a GET to the resource itself, just like with status. + // To route a subresource to an arbitrary handler, use the 'routes' field instead (see below). + custom: { + myField: string + otherField: string + } + // metadata if where kind- and schema-specific metadata goes. This is converted into typed annotations + // with getters and setters by the code generation. + //metadata: { + // kindSpecificField: string + //} + } + + // routes contains subresource routes for the kind, which are exposed as HTTP handlers on 'examples//'. + // This allows you to add additional non-storage-based handlers to your kind. + // These should only be used if the behavior cannot be accomplished by reconciliation on storage events. + routes: { + // This will add a handler for /foo on the resource + "foo": { + // GET request handler. A subresource route can have multiple methods attached to it. + // Allowed values are GET, POST, PUT, DELETE, PATCH, HEAD, and OPTIONS + "GET": { + // The response type for the GET /foo method. This will generate a go type, and will also be used for the OpenAPI definition for the route. + response: { + message: string + } + } + } + } +} \ No newline at end of file diff --git a/apps/example/kinds/manifest.cue b/apps/example/kinds/manifest.cue new file mode 100644 index 00000000000..934d419623d --- /dev/null +++ b/apps/example/kinds/manifest.cue @@ -0,0 +1,116 @@ +package kinds + +manifest: { + // appName is the unique name of your app. It is used to reference the app from other config objects, + // and to generate the group used by your app in the app platform API. + appName: "example" + // groupOverride can be used to specify a non-appName-based API group. + // By default, an app's API group is LOWER(REPLACE(appName, '-', '')).ext.grafana.com, + // but there are cases where this needs to be changed. + // Keep in mind that changing this after an app is deployed can cause problems with clients and/or kind data. + groupOverride: "example.grafana.app" + + // versions is a map of versions supported by your app. Version names should follow the format "v" or + // "v(alpha|beta)". Each version contains the kinds your app manages for that version. + // If your app needs access to kinds managed by another app, use permissions.accessKinds to allow your app access. + versions: { + "v0alpha1": v0alpha1 + "v1alpha1": v1alpha1 + } + // extraPermissions contains any additional permissions your app may require to function. + // Your app will always have all permissions for each kind it manages (the items defined in 'kinds'). + extraPermissions: { + // If your app needs access to additional kinds supplied by other apps, you can list them here + accessKinds: [ + // Here is an example for your app accessing the playlist kind for reads and watch + // { + // group: "playlist.grafana.app" + // resource: "playlists" + // actions: ["get","list","watch"] + // } + ] + } +} + +v0alpha1: { + kinds: [examplev0alpha1] + // This is explicitly set to false to keep the example app disabled by default. + // It can be enabled via conf overrides, or by setting this value to true and regenerating. + served: false +} + +// v1alpha1 is the v1alpha1 version of the app's API. +// It includes kinds which the v1alpha1 API serves, and (future) custom routes served globally from the v1alpha1 version. +v1alpha1: { + // kinds is the list of kinds served by this version + kinds:[examplev1alpha1] + // [OPTIONAL] + // served indicates whether this particular version is served by the API server. + // served should be set to false before a version is removed from the manifest entirely. + // served defaults to true if not present. + // This is explicitly set to false to keep the example app disabled by default. + // It can be enabled via conf overrides, or by setting this value to true and regenerating. + served: false + // routes contains resource routes for the version, which are split into 'namespaced' and 'cluster' scoped routes. + // This allows you to add additional non-storage- and non-kind- based handlers for your app. + // These should only be used if the behavior cannot be accomplished by reconciliation on storage events or subresource routes on a kind. + routes: { + // namespaced contains namespace-scoped resource routes for the version, + // which are exposed as HTTP handlers on '/namespaces//'. + namespaced: { + "/something": { + "GET": { + response: { + namespace: string + message: string + } + request: { + query: { + message?: string + } + } + } + } + } + // cluster contains cluster-scoped resource routes for the version, + // which are exposed as HTTP handlers on '/'. + cluster: { + "/other": { + "GET": { + response: { + message: string + } + request: { + query: { + message?: string + } + } + responseMetadata: typeMeta: false // Don't generate or return kubernetes type metadata for this object + } + } + } + } + // [OPTIONAL] + // Codegen is a trait that tells the grafana-app-sdk, or other code generation tooling, how to process this kind. + // If not present, default values within the codegen trait are used. + // If you wish to specify codegen per-version, put this section in the version's object + // (for example, v1alpha1) instead. + codegen: { + // [OPTIONAL] + // ts contains TypeScript code generation properties for the kind + ts: { + // [OPTIONAL] + // enabled indicates whether the CLI should generate front-end TypeScript code for the kind. + // Defaults to true if not present. + enabled: true + } + // [OPTIONAL] + // go contains go code generation properties for the kind + go: { + // [OPTIONAL] + // enabled indicates whether the CLI should generate back-end go code for the kind. + // Defaults to true if not present. + enabled: true + } + } +} \ No newline at end of file diff --git a/apps/example/pkg/apis/example/v0alpha1/constants.go b/apps/example/pkg/apis/example/v0alpha1/constants.go new file mode 100644 index 00000000000..edbbe6d97c2 --- /dev/null +++ b/apps/example/pkg/apis/example/v0alpha1/constants.go @@ -0,0 +1,18 @@ +package v0alpha1 + +import "k8s.io/apimachinery/pkg/runtime/schema" + +const ( + // APIGroup is the API group used by all kinds in this package + APIGroup = "example.grafana.app" + // APIVersion is the API version used by all kinds in this package + APIVersion = "v0alpha1" +) + +var ( + // GroupVersion is a schema.GroupVersion consisting of the Group and Version constants for this package + GroupVersion = schema.GroupVersion{ + Group: APIGroup, + Version: APIVersion, + } +) diff --git a/apps/example/pkg/apis/example/v0alpha1/example_client_gen.go b/apps/example/pkg/apis/example/v0alpha1/example_client_gen.go new file mode 100644 index 00000000000..e528b6b5cbc --- /dev/null +++ b/apps/example/pkg/apis/example/v0alpha1/example_client_gen.go @@ -0,0 +1,99 @@ +package v0alpha1 + +import ( + "context" + + "github.com/grafana/grafana-app-sdk/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +type ExampleClient struct { + client *resource.TypedClient[*Example, *ExampleList] +} + +func NewExampleClient(client resource.Client) *ExampleClient { + return &ExampleClient{ + client: resource.NewTypedClient[*Example, *ExampleList](client, ExampleKind()), + } +} + +func NewExampleClientFromGenerator(generator resource.ClientGenerator) (*ExampleClient, error) { + c, err := generator.ClientFor(ExampleKind()) + if err != nil { + return nil, err + } + return NewExampleClient(c), nil +} + +func (c *ExampleClient) Get(ctx context.Context, identifier resource.Identifier) (*Example, error) { + return c.client.Get(ctx, identifier) +} + +func (c *ExampleClient) List(ctx context.Context, namespace string, opts resource.ListOptions) (*ExampleList, error) { + return c.client.List(ctx, namespace, opts) +} + +func (c *ExampleClient) ListAll(ctx context.Context, namespace string, opts resource.ListOptions) (*ExampleList, error) { + resp, err := c.client.List(ctx, namespace, resource.ListOptions{ + ResourceVersion: opts.ResourceVersion, + Limit: opts.Limit, + LabelFilters: opts.LabelFilters, + FieldSelectors: opts.FieldSelectors, + }) + if err != nil { + return nil, err + } + for resp.GetContinue() != "" { + page, err := c.client.List(ctx, namespace, resource.ListOptions{ + Continue: resp.GetContinue(), + ResourceVersion: opts.ResourceVersion, + Limit: opts.Limit, + LabelFilters: opts.LabelFilters, + FieldSelectors: opts.FieldSelectors, + }) + if err != nil { + return nil, err + } + resp.SetContinue(page.GetContinue()) + resp.SetResourceVersion(page.GetResourceVersion()) + resp.SetItems(append(resp.GetItems(), page.GetItems()...)) + } + return resp, nil +} + +func (c *ExampleClient) Create(ctx context.Context, obj *Example, opts resource.CreateOptions) (*Example, error) { + // Make sure apiVersion and kind are set + obj.APIVersion = GroupVersion.Identifier() + obj.Kind = ExampleKind().Kind() + return c.client.Create(ctx, obj, opts) +} + +func (c *ExampleClient) Update(ctx context.Context, obj *Example, opts resource.UpdateOptions) (*Example, error) { + return c.client.Update(ctx, obj, opts) +} + +func (c *ExampleClient) Patch(ctx context.Context, identifier resource.Identifier, req resource.PatchRequest, opts resource.PatchOptions) (*Example, error) { + return c.client.Patch(ctx, identifier, req, opts) +} + +func (c *ExampleClient) UpdateStatus(ctx context.Context, identifier resource.Identifier, newStatus ExampleStatus, opts resource.UpdateOptions) (*Example, error) { + return c.client.Update(ctx, &Example{ + TypeMeta: metav1.TypeMeta{ + Kind: ExampleKind().Kind(), + APIVersion: GroupVersion.Identifier(), + }, + ObjectMeta: metav1.ObjectMeta{ + ResourceVersion: opts.ResourceVersion, + Namespace: identifier.Namespace, + Name: identifier.Name, + }, + Status: newStatus, + }, resource.UpdateOptions{ + Subresource: "status", + ResourceVersion: opts.ResourceVersion, + }) +} + +func (c *ExampleClient) Delete(ctx context.Context, identifier resource.Identifier, opts resource.DeleteOptions) error { + return c.client.Delete(ctx, identifier, opts) +} diff --git a/apps/example/pkg/apis/example/v0alpha1/example_codec_gen.go b/apps/example/pkg/apis/example/v0alpha1/example_codec_gen.go new file mode 100644 index 00000000000..67bb330bfe6 --- /dev/null +++ b/apps/example/pkg/apis/example/v0alpha1/example_codec_gen.go @@ -0,0 +1,28 @@ +// +// Code generated by grafana-app-sdk. DO NOT EDIT. +// + +package v0alpha1 + +import ( + "encoding/json" + "io" + + "github.com/grafana/grafana-app-sdk/resource" +) + +// ExampleJSONCodec is an implementation of resource.Codec for kubernetes JSON encoding +type ExampleJSONCodec struct{} + +// Read reads JSON-encoded bytes from `reader` and unmarshals them into `into` +func (*ExampleJSONCodec) Read(reader io.Reader, into resource.Object) error { + return json.NewDecoder(reader).Decode(into) +} + +// Write writes JSON-encoded bytes into `writer` marshaled from `from` +func (*ExampleJSONCodec) Write(writer io.Writer, from resource.Object) error { + return json.NewEncoder(writer).Encode(from) +} + +// Interface compliance checks +var _ resource.Codec = &ExampleJSONCodec{} diff --git a/apps/example/pkg/apis/example/v0alpha1/example_metadata_gen.go b/apps/example/pkg/apis/example/v0alpha1/example_metadata_gen.go new file mode 100644 index 00000000000..1e390bb070f --- /dev/null +++ b/apps/example/pkg/apis/example/v0alpha1/example_metadata_gen.go @@ -0,0 +1,31 @@ +// Code generated - EDITING IS FUTILE. DO NOT EDIT. + +package v0alpha1 + +import ( + time "time" +) + +// metadata contains embedded CommonMetadata and can be extended with custom string fields +// TODO: use CommonMetadata instead of redefining here; currently needs to be defined here +// without external reference as using the CommonMetadata reference breaks thema codegen. +type ExampleMetadata struct { + UpdateTimestamp time.Time `json:"updateTimestamp"` + CreatedBy string `json:"createdBy"` + Uid string `json:"uid"` + CreationTimestamp time.Time `json:"creationTimestamp"` + DeletionTimestamp *time.Time `json:"deletionTimestamp,omitempty"` + Finalizers []string `json:"finalizers"` + ResourceVersion string `json:"resourceVersion"` + Generation int64 `json:"generation"` + UpdatedBy string `json:"updatedBy"` + Labels map[string]string `json:"labels"` +} + +// NewExampleMetadata creates a new ExampleMetadata object. +func NewExampleMetadata() *ExampleMetadata { + return &ExampleMetadata{ + Finalizers: []string{}, + Labels: map[string]string{}, + } +} diff --git a/apps/example/pkg/apis/example/v0alpha1/example_object_gen.go b/apps/example/pkg/apis/example/v0alpha1/example_object_gen.go new file mode 100644 index 00000000000..9b846649ebd --- /dev/null +++ b/apps/example/pkg/apis/example/v0alpha1/example_object_gen.go @@ -0,0 +1,319 @@ +// +// Code generated by grafana-app-sdk. DO NOT EDIT. +// + +package v0alpha1 + +import ( + "fmt" + "github.com/grafana/grafana-app-sdk/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/types" + "time" +) + +// +k8s:openapi-gen=true +type Example struct { + metav1.TypeMeta `json:",inline" yaml:",inline"` + metav1.ObjectMeta `json:"metadata" yaml:"metadata"` + + // Spec is the spec of the Example + Spec ExampleSpec `json:"spec" yaml:"spec"` + + Status ExampleStatus `json:"status" yaml:"status"` +} + +func (o *Example) GetSpec() any { + return o.Spec +} + +func (o *Example) SetSpec(spec any) error { + cast, ok := spec.(ExampleSpec) + if !ok { + return fmt.Errorf("cannot set spec type %#v, not of type Spec", spec) + } + o.Spec = cast + return nil +} + +func (o *Example) GetSubresources() map[string]any { + return map[string]any{ + "status": o.Status, + } +} + +func (o *Example) GetSubresource(name string) (any, bool) { + switch name { + case "status": + return o.Status, true + default: + return nil, false + } +} + +func (o *Example) SetSubresource(name string, value any) error { + switch name { + case "status": + cast, ok := value.(ExampleStatus) + if !ok { + return fmt.Errorf("cannot set status type %#v, not of type ExampleStatus", value) + } + o.Status = cast + return nil + default: + return fmt.Errorf("subresource '%s' does not exist", name) + } +} + +func (o *Example) GetStaticMetadata() resource.StaticMetadata { + gvk := o.GroupVersionKind() + return resource.StaticMetadata{ + Name: o.ObjectMeta.Name, + Namespace: o.ObjectMeta.Namespace, + Group: gvk.Group, + Version: gvk.Version, + Kind: gvk.Kind, + } +} + +func (o *Example) SetStaticMetadata(metadata resource.StaticMetadata) { + o.Name = metadata.Name + o.Namespace = metadata.Namespace + o.SetGroupVersionKind(schema.GroupVersionKind{ + Group: metadata.Group, + Version: metadata.Version, + Kind: metadata.Kind, + }) +} + +func (o *Example) GetCommonMetadata() resource.CommonMetadata { + dt := o.DeletionTimestamp + var deletionTimestamp *time.Time + if dt != nil { + deletionTimestamp = &dt.Time + } + // Legacy ExtraFields support + extraFields := make(map[string]any) + if o.Annotations != nil { + extraFields["annotations"] = o.Annotations + } + if o.ManagedFields != nil { + extraFields["managedFields"] = o.ManagedFields + } + if o.OwnerReferences != nil { + extraFields["ownerReferences"] = o.OwnerReferences + } + return resource.CommonMetadata{ + UID: string(o.UID), + ResourceVersion: o.ResourceVersion, + Generation: o.Generation, + Labels: o.Labels, + CreationTimestamp: o.CreationTimestamp.Time, + DeletionTimestamp: deletionTimestamp, + Finalizers: o.Finalizers, + UpdateTimestamp: o.GetUpdateTimestamp(), + CreatedBy: o.GetCreatedBy(), + UpdatedBy: o.GetUpdatedBy(), + ExtraFields: extraFields, + } +} + +func (o *Example) SetCommonMetadata(metadata resource.CommonMetadata) { + o.UID = types.UID(metadata.UID) + o.ResourceVersion = metadata.ResourceVersion + o.Generation = metadata.Generation + o.Labels = metadata.Labels + o.CreationTimestamp = metav1.NewTime(metadata.CreationTimestamp) + if metadata.DeletionTimestamp != nil { + dt := metav1.NewTime(*metadata.DeletionTimestamp) + o.DeletionTimestamp = &dt + } else { + o.DeletionTimestamp = nil + } + o.Finalizers = metadata.Finalizers + if o.Annotations == nil { + o.Annotations = make(map[string]string) + } + if !metadata.UpdateTimestamp.IsZero() { + o.SetUpdateTimestamp(metadata.UpdateTimestamp) + } + if metadata.CreatedBy != "" { + o.SetCreatedBy(metadata.CreatedBy) + } + if metadata.UpdatedBy != "" { + o.SetUpdatedBy(metadata.UpdatedBy) + } + // Legacy support for setting Annotations, ManagedFields, and OwnerReferences via ExtraFields + if metadata.ExtraFields != nil { + if annotations, ok := metadata.ExtraFields["annotations"]; ok { + if cast, ok := annotations.(map[string]string); ok { + o.Annotations = cast + } + } + if managedFields, ok := metadata.ExtraFields["managedFields"]; ok { + if cast, ok := managedFields.([]metav1.ManagedFieldsEntry); ok { + o.ManagedFields = cast + } + } + if ownerReferences, ok := metadata.ExtraFields["ownerReferences"]; ok { + if cast, ok := ownerReferences.([]metav1.OwnerReference); ok { + o.OwnerReferences = cast + } + } + } +} + +func (o *Example) GetCreatedBy() string { + if o.ObjectMeta.Annotations == nil { + o.ObjectMeta.Annotations = make(map[string]string) + } + + return o.ObjectMeta.Annotations["grafana.com/createdBy"] +} + +func (o *Example) SetCreatedBy(createdBy string) { + if o.ObjectMeta.Annotations == nil { + o.ObjectMeta.Annotations = make(map[string]string) + } + + o.ObjectMeta.Annotations["grafana.com/createdBy"] = createdBy +} + +func (o *Example) GetUpdateTimestamp() time.Time { + if o.ObjectMeta.Annotations == nil { + o.ObjectMeta.Annotations = make(map[string]string) + } + + parsed, _ := time.Parse(time.RFC3339, o.ObjectMeta.Annotations["grafana.com/updateTimestamp"]) + return parsed +} + +func (o *Example) SetUpdateTimestamp(updateTimestamp time.Time) { + if o.ObjectMeta.Annotations == nil { + o.ObjectMeta.Annotations = make(map[string]string) + } + + o.ObjectMeta.Annotations["grafana.com/updateTimestamp"] = updateTimestamp.Format(time.RFC3339) +} + +func (o *Example) GetUpdatedBy() string { + if o.ObjectMeta.Annotations == nil { + o.ObjectMeta.Annotations = make(map[string]string) + } + + return o.ObjectMeta.Annotations["grafana.com/updatedBy"] +} + +func (o *Example) SetUpdatedBy(updatedBy string) { + if o.ObjectMeta.Annotations == nil { + o.ObjectMeta.Annotations = make(map[string]string) + } + + o.ObjectMeta.Annotations["grafana.com/updatedBy"] = updatedBy +} + +func (o *Example) Copy() resource.Object { + return resource.CopyObject(o) +} + +func (o *Example) DeepCopyObject() runtime.Object { + return o.Copy() +} + +func (o *Example) DeepCopy() *Example { + cpy := &Example{} + o.DeepCopyInto(cpy) + return cpy +} + +func (o *Example) DeepCopyInto(dst *Example) { + dst.TypeMeta.APIVersion = o.TypeMeta.APIVersion + dst.TypeMeta.Kind = o.TypeMeta.Kind + o.ObjectMeta.DeepCopyInto(&dst.ObjectMeta) + o.Spec.DeepCopyInto(&dst.Spec) + o.Status.DeepCopyInto(&dst.Status) +} + +// Interface compliance compile-time check +var _ resource.Object = &Example{} + +// +k8s:openapi-gen=true +type ExampleList struct { + metav1.TypeMeta `json:",inline" yaml:",inline"` + metav1.ListMeta `json:"metadata" yaml:"metadata"` + Items []Example `json:"items" yaml:"items"` +} + +func (o *ExampleList) DeepCopyObject() runtime.Object { + return o.Copy() +} + +func (o *ExampleList) Copy() resource.ListObject { + cpy := &ExampleList{ + TypeMeta: o.TypeMeta, + Items: make([]Example, len(o.Items)), + } + o.ListMeta.DeepCopyInto(&cpy.ListMeta) + for i := 0; i < len(o.Items); i++ { + if item, ok := o.Items[i].Copy().(*Example); ok { + cpy.Items[i] = *item + } + } + return cpy +} + +func (o *ExampleList) GetItems() []resource.Object { + items := make([]resource.Object, len(o.Items)) + for i := 0; i < len(o.Items); i++ { + items[i] = &o.Items[i] + } + return items +} + +func (o *ExampleList) SetItems(items []resource.Object) { + o.Items = make([]Example, len(items)) + for i := 0; i < len(items); i++ { + o.Items[i] = *items[i].(*Example) + } +} + +func (o *ExampleList) DeepCopy() *ExampleList { + cpy := &ExampleList{} + o.DeepCopyInto(cpy) + return cpy +} + +func (o *ExampleList) DeepCopyInto(dst *ExampleList) { + resource.CopyObjectInto(dst, o) +} + +// Interface compliance compile-time check +var _ resource.ListObject = &ExampleList{} + +// Copy methods for all subresource types + +// DeepCopy creates a full deep copy of Spec +func (s *ExampleSpec) DeepCopy() *ExampleSpec { + cpy := &ExampleSpec{} + s.DeepCopyInto(cpy) + return cpy +} + +// DeepCopyInto deep copies Spec into another Spec object +func (s *ExampleSpec) DeepCopyInto(dst *ExampleSpec) { + resource.CopyObjectInto(dst, s) +} + +// DeepCopy creates a full deep copy of ExampleStatus +func (s *ExampleStatus) DeepCopy() *ExampleStatus { + cpy := &ExampleStatus{} + s.DeepCopyInto(cpy) + return cpy +} + +// DeepCopyInto deep copies ExampleStatus into another ExampleStatus object +func (s *ExampleStatus) DeepCopyInto(dst *ExampleStatus) { + resource.CopyObjectInto(dst, s) +} diff --git a/apps/example/pkg/apis/example/v0alpha1/example_schema_gen.go b/apps/example/pkg/apis/example/v0alpha1/example_schema_gen.go new file mode 100644 index 00000000000..1feaa8d42d1 --- /dev/null +++ b/apps/example/pkg/apis/example/v0alpha1/example_schema_gen.go @@ -0,0 +1,34 @@ +// +// Code generated by grafana-app-sdk. DO NOT EDIT. +// + +package v0alpha1 + +import ( + "github.com/grafana/grafana-app-sdk/resource" +) + +// schema is unexported to prevent accidental overwrites +var ( + schemaExample = resource.NewSimpleSchema("example.grafana.app", "v0alpha1", &Example{}, &ExampleList{}, resource.WithKind("Example"), + resource.WithPlural("examples"), resource.WithScope(resource.NamespacedScope)) + kindExample = resource.Kind{ + Schema: schemaExample, + Codecs: map[resource.KindEncoding]resource.Codec{ + resource.KindEncodingJSON: &ExampleJSONCodec{}, + }, + } +) + +// Kind returns a resource.Kind for this Schema with a JSON codec +func ExampleKind() resource.Kind { + return kindExample +} + +// Schema returns a resource.SimpleSchema representation of Example +func ExampleSchema() *resource.SimpleSchema { + return schemaExample +} + +// Interface compliance checks +var _ resource.Schema = kindExample diff --git a/apps/example/pkg/apis/example/v0alpha1/example_spec_gen.go b/apps/example/pkg/apis/example/v0alpha1/example_spec_gen.go new file mode 100644 index 00000000000..f0e408554ab --- /dev/null +++ b/apps/example/pkg/apis/example/v0alpha1/example_spec_gen.go @@ -0,0 +1,14 @@ +// Code generated - EDITING IS FUTILE. DO NOT EDIT. + +package v0alpha1 + +// Spec is the schema of our resource. The spec should include all the user-editable information for the kind. +// +k8s:openapi-gen=true +type ExampleSpec struct { + FirstField int64 `json:"firstField"` +} + +// NewExampleSpec creates a new ExampleSpec object. +func NewExampleSpec() *ExampleSpec { + return &ExampleSpec{} +} diff --git a/apps/example/pkg/apis/example/v0alpha1/example_status_gen.go b/apps/example/pkg/apis/example/v0alpha1/example_status_gen.go new file mode 100644 index 00000000000..75c78737ada --- /dev/null +++ b/apps/example/pkg/apis/example/v0alpha1/example_status_gen.go @@ -0,0 +1,45 @@ +// Code generated - EDITING IS FUTILE. DO NOT EDIT. + +package v0alpha1 + +// +k8s:openapi-gen=true +type ExamplestatusOperatorState struct { + // lastEvaluation is the ResourceVersion last evaluated + LastEvaluation string `json:"lastEvaluation"` + // state describes the state of the lastEvaluation. + // It is limited to three possible states for machine evaluation. + State ExampleStatusOperatorStateState `json:"state"` + // descriptiveState is an optional more descriptive state field which has no requirements on format + DescriptiveState *string `json:"descriptiveState,omitempty"` + // details contains any extra information that is operator-specific + Details map[string]interface{} `json:"details,omitempty"` +} + +// NewExamplestatusOperatorState creates a new ExamplestatusOperatorState object. +func NewExamplestatusOperatorState() *ExamplestatusOperatorState { + return &ExamplestatusOperatorState{} +} + +// +k8s:openapi-gen=true +type ExampleStatus struct { + LastObservedGeneration int64 `json:"lastObservedGeneration"` + // operatorStates is a map of operator ID to operator state evaluations. + // Any operator which consumes this kind SHOULD add its state evaluation information to this field. + OperatorStates map[string]ExamplestatusOperatorState `json:"operatorStates,omitempty"` + // additionalFields is reserved for future use + AdditionalFields map[string]interface{} `json:"additionalFields,omitempty"` +} + +// NewExampleStatus creates a new ExampleStatus object. +func NewExampleStatus() *ExampleStatus { + return &ExampleStatus{} +} + +// +k8s:openapi-gen=true +type ExampleStatusOperatorStateState string + +const ( + ExampleStatusOperatorStateStateSuccess ExampleStatusOperatorStateState = "success" + ExampleStatusOperatorStateStateInProgress ExampleStatusOperatorStateState = "in_progress" + ExampleStatusOperatorStateStateFailed ExampleStatusOperatorStateState = "failed" +) diff --git a/apps/example/pkg/apis/example/v1alpha1/constants.go b/apps/example/pkg/apis/example/v1alpha1/constants.go new file mode 100644 index 00000000000..68a0c69a614 --- /dev/null +++ b/apps/example/pkg/apis/example/v1alpha1/constants.go @@ -0,0 +1,18 @@ +package v1alpha1 + +import "k8s.io/apimachinery/pkg/runtime/schema" + +const ( + // APIGroup is the API group used by all kinds in this package + APIGroup = "example.grafana.app" + // APIVersion is the API version used by all kinds in this package + APIVersion = "v1alpha1" +) + +var ( + // GroupVersion is a schema.GroupVersion consisting of the Group and Version constants for this package + GroupVersion = schema.GroupVersion{ + Group: APIGroup, + Version: APIVersion, + } +) diff --git a/apps/example/pkg/apis/example/v1alpha1/example_client_gen.go b/apps/example/pkg/apis/example/v1alpha1/example_client_gen.go new file mode 100644 index 00000000000..686c663c12c --- /dev/null +++ b/apps/example/pkg/apis/example/v1alpha1/example_client_gen.go @@ -0,0 +1,144 @@ +package v1alpha1 + +import ( + "context" + "encoding/json" + "fmt" + "net/http" + "net/url" + + "github.com/grafana/grafana-app-sdk/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +type ExampleClient struct { + client *resource.TypedClient[*Example, *ExampleList] +} + +func NewExampleClient(client resource.Client) *ExampleClient { + return &ExampleClient{ + client: resource.NewTypedClient[*Example, *ExampleList](client, ExampleKind()), + } +} + +func NewExampleClientFromGenerator(generator resource.ClientGenerator) (*ExampleClient, error) { + c, err := generator.ClientFor(ExampleKind()) + if err != nil { + return nil, err + } + return NewExampleClient(c), nil +} + +func (c *ExampleClient) Get(ctx context.Context, identifier resource.Identifier) (*Example, error) { + return c.client.Get(ctx, identifier) +} + +func (c *ExampleClient) List(ctx context.Context, namespace string, opts resource.ListOptions) (*ExampleList, error) { + return c.client.List(ctx, namespace, opts) +} + +func (c *ExampleClient) ListAll(ctx context.Context, namespace string, opts resource.ListOptions) (*ExampleList, error) { + resp, err := c.client.List(ctx, namespace, resource.ListOptions{ + ResourceVersion: opts.ResourceVersion, + Limit: opts.Limit, + LabelFilters: opts.LabelFilters, + FieldSelectors: opts.FieldSelectors, + }) + if err != nil { + return nil, err + } + for resp.GetContinue() != "" { + page, err := c.client.List(ctx, namespace, resource.ListOptions{ + Continue: resp.GetContinue(), + ResourceVersion: opts.ResourceVersion, + Limit: opts.Limit, + LabelFilters: opts.LabelFilters, + FieldSelectors: opts.FieldSelectors, + }) + if err != nil { + return nil, err + } + resp.SetContinue(page.GetContinue()) + resp.SetResourceVersion(page.GetResourceVersion()) + resp.SetItems(append(resp.GetItems(), page.GetItems()...)) + } + return resp, nil +} + +func (c *ExampleClient) Create(ctx context.Context, obj *Example, opts resource.CreateOptions) (*Example, error) { + // Make sure apiVersion and kind are set + obj.APIVersion = GroupVersion.Identifier() + obj.Kind = ExampleKind().Kind() + return c.client.Create(ctx, obj, opts) +} + +func (c *ExampleClient) Update(ctx context.Context, obj *Example, opts resource.UpdateOptions) (*Example, error) { + return c.client.Update(ctx, obj, opts) +} + +func (c *ExampleClient) Patch(ctx context.Context, identifier resource.Identifier, req resource.PatchRequest, opts resource.PatchOptions) (*Example, error) { + return c.client.Patch(ctx, identifier, req, opts) +} + +func (c *ExampleClient) UpdateCustom(ctx context.Context, identifier resource.Identifier, newCustom ExampleCustom, opts resource.UpdateOptions) (*Example, error) { + return c.client.Update(ctx, &Example{ + TypeMeta: metav1.TypeMeta{ + Kind: ExampleKind().Kind(), + APIVersion: GroupVersion.Identifier(), + }, + ObjectMeta: metav1.ObjectMeta{ + ResourceVersion: opts.ResourceVersion, + Namespace: identifier.Namespace, + Name: identifier.Name, + }, + Custom: newCustom, + }, resource.UpdateOptions{ + Subresource: "custom", + ResourceVersion: opts.ResourceVersion, + }) +} +func (c *ExampleClient) UpdateStatus(ctx context.Context, identifier resource.Identifier, newStatus ExampleStatus, opts resource.UpdateOptions) (*Example, error) { + return c.client.Update(ctx, &Example{ + TypeMeta: metav1.TypeMeta{ + Kind: ExampleKind().Kind(), + APIVersion: GroupVersion.Identifier(), + }, + ObjectMeta: metav1.ObjectMeta{ + ResourceVersion: opts.ResourceVersion, + Namespace: identifier.Namespace, + Name: identifier.Name, + }, + Status: newStatus, + }, resource.UpdateOptions{ + Subresource: "status", + ResourceVersion: opts.ResourceVersion, + }) +} + +func (c *ExampleClient) Delete(ctx context.Context, identifier resource.Identifier, opts resource.DeleteOptions) error { + return c.client.Delete(ctx, identifier, opts) +} + +type GetFooRequest struct { + Params GetFooRequestParams + Headers http.Header +} + +func (c *ExampleClient) GetFoo(ctx context.Context, identifier resource.Identifier, request GetFooRequest) (*GetFoo, error) { + params := url.Values{} + resp, err := c.client.SubresourceRequest(ctx, identifier, resource.CustomRouteRequestOptions{ + Path: "foo", + Verb: "GET", + Query: params, + Headers: request.Headers, + }) + if err != nil { + return nil, err + } + cast := GetFoo{} + err = json.Unmarshal(resp, &cast) + if err != nil { + return nil, fmt.Errorf("unable to unmarshal response bytes into GetFoo: %w", err) + } + return &cast, nil +} diff --git a/apps/example/pkg/apis/example/v1alpha1/example_codec_gen.go b/apps/example/pkg/apis/example/v1alpha1/example_codec_gen.go new file mode 100644 index 00000000000..80cee2b1cfc --- /dev/null +++ b/apps/example/pkg/apis/example/v1alpha1/example_codec_gen.go @@ -0,0 +1,28 @@ +// +// Code generated by grafana-app-sdk. DO NOT EDIT. +// + +package v1alpha1 + +import ( + "encoding/json" + "io" + + "github.com/grafana/grafana-app-sdk/resource" +) + +// ExampleJSONCodec is an implementation of resource.Codec for kubernetes JSON encoding +type ExampleJSONCodec struct{} + +// Read reads JSON-encoded bytes from `reader` and unmarshals them into `into` +func (*ExampleJSONCodec) Read(reader io.Reader, into resource.Object) error { + return json.NewDecoder(reader).Decode(into) +} + +// Write writes JSON-encoded bytes into `writer` marshaled from `from` +func (*ExampleJSONCodec) Write(writer io.Writer, from resource.Object) error { + return json.NewEncoder(writer).Encode(from) +} + +// Interface compliance checks +var _ resource.Codec = &ExampleJSONCodec{} diff --git a/apps/example/pkg/apis/example/v1alpha1/example_custom_gen.go b/apps/example/pkg/apis/example/v1alpha1/example_custom_gen.go new file mode 100644 index 00000000000..bcb4f4bb363 --- /dev/null +++ b/apps/example/pkg/apis/example/v1alpha1/example_custom_gen.go @@ -0,0 +1,25 @@ +// Code generated - EDITING IS FUTILE. DO NOT EDIT. + +package v1alpha1 + +// Custom is a subresource that will be stored the same way status is stored, +// and requires using the /custom route to update. +// Its content is returned as part of a GET to the resource itself, just like with status. +// To route a subresource to an arbitrary handler, use the 'routes' field instead (see below). +// metadata if where kind- and schema-specific metadata goes. This is converted into typed annotations +// with getters and setters by the code generation. +// +// metadata: { +// kindSpecificField: string +// } +// +// +k8s:openapi-gen=true +type ExampleCustom struct { + MyField string `json:"myField"` + OtherField string `json:"otherField"` +} + +// NewExampleCustom creates a new ExampleCustom object. +func NewExampleCustom() *ExampleCustom { + return &ExampleCustom{} +} diff --git a/apps/example/pkg/apis/example/v1alpha1/example_getfoo_request_body_types_gen.go b/apps/example/pkg/apis/example/v1alpha1/example_getfoo_request_body_types_gen.go new file mode 100644 index 00000000000..42344f1cb6d --- /dev/null +++ b/apps/example/pkg/apis/example/v1alpha1/example_getfoo_request_body_types_gen.go @@ -0,0 +1,12 @@ +// Code generated - EDITING IS FUTILE. DO NOT EDIT. + +package v1alpha1 + +type GetFooRequestBody struct { + Bar string `json:"bar"` +} + +// NewGetFooRequestBody creates a new GetFooRequestBody object. +func NewGetFooRequestBody() *GetFooRequestBody { + return &GetFooRequestBody{} +} diff --git a/apps/example/pkg/apis/example/v1alpha1/example_getfoo_request_params_object_gen.go b/apps/example/pkg/apis/example/v1alpha1/example_getfoo_request_params_object_gen.go new file mode 100644 index 00000000000..bf6a51b1815 --- /dev/null +++ b/apps/example/pkg/apis/example/v1alpha1/example_getfoo_request_params_object_gen.go @@ -0,0 +1,33 @@ +// Code generated - EDITING IS FUTILE. DO NOT EDIT. + +package v1alpha1 + +import ( + "github.com/grafana/grafana-app-sdk/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" +) + +type GetFooRequestParamsObject struct { + metav1.TypeMeta `json:",inline"` + GetFooRequestParams `json:",inline"` +} + +func NewGetFooRequestParamsObject() *GetFooRequestParamsObject { + return &GetFooRequestParamsObject{} +} + +func (o *GetFooRequestParamsObject) DeepCopyObject() runtime.Object { + dst := NewGetFooRequestParamsObject() + o.DeepCopyInto(dst) + return dst +} + +func (o *GetFooRequestParamsObject) DeepCopyInto(dst *GetFooRequestParamsObject) { + dst.TypeMeta.APIVersion = o.TypeMeta.APIVersion + dst.TypeMeta.Kind = o.TypeMeta.Kind + dstGetFooRequestParams := GetFooRequestParams{} + _ = resource.CopyObjectInto(&dstGetFooRequestParams, &o.GetFooRequestParams) +} + +var _ runtime.Object = NewGetFooRequestParamsObject() diff --git a/apps/example/pkg/apis/example/v1alpha1/example_getfoo_request_params_types_gen.go b/apps/example/pkg/apis/example/v1alpha1/example_getfoo_request_params_types_gen.go new file mode 100644 index 00000000000..f0f04d7d0a2 --- /dev/null +++ b/apps/example/pkg/apis/example/v1alpha1/example_getfoo_request_params_types_gen.go @@ -0,0 +1,12 @@ +// Code generated - EDITING IS FUTILE. DO NOT EDIT. + +package v1alpha1 + +type GetFooRequestParams struct { + Message *string `json:"message,omitempty"` +} + +// NewGetFooRequestParams creates a new GetFooRequestParams object. +func NewGetFooRequestParams() *GetFooRequestParams { + return &GetFooRequestParams{} +} diff --git a/apps/example/pkg/apis/example/v1alpha1/example_getfoo_response_body_types_gen.go b/apps/example/pkg/apis/example/v1alpha1/example_getfoo_response_body_types_gen.go new file mode 100644 index 00000000000..ab77d0905b1 --- /dev/null +++ b/apps/example/pkg/apis/example/v1alpha1/example_getfoo_response_body_types_gen.go @@ -0,0 +1,14 @@ +// Code generated - EDITING IS FUTILE. DO NOT EDIT. + +package v1alpha1 + +// The response type for the GET /foo method. This will generate a go type, and will also be used for the OpenAPI definition for the route. +// +k8s:openapi-gen=true +type GetFooBody struct { + Message string `json:"message"` +} + +// NewGetFooBody creates a new GetFooBody object. +func NewGetFooBody() *GetFooBody { + return &GetFooBody{} +} diff --git a/apps/example/pkg/apis/example/v1alpha1/example_getfoo_response_object_types_gen.go b/apps/example/pkg/apis/example/v1alpha1/example_getfoo_response_object_types_gen.go new file mode 100644 index 00000000000..ba41aba79c5 --- /dev/null +++ b/apps/example/pkg/apis/example/v1alpha1/example_getfoo_response_object_types_gen.go @@ -0,0 +1,37 @@ +// Code generated - EDITING IS FUTILE. DO NOT EDIT. + +package v1alpha1 + +import ( + "github.com/grafana/grafana-app-sdk/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" +) + +// +k8s:openapi-gen=true +type GetFoo struct { + metav1.TypeMeta `json:",inline"` + GetFooBody `json:",inline"` +} + +func NewGetFoo() *GetFoo { + return &GetFoo{} +} + +func (t *GetFooBody) DeepCopyInto(dst *GetFooBody) { + _ = resource.CopyObjectInto(dst, t) +} + +func (o *GetFoo) DeepCopyObject() runtime.Object { + dst := NewGetFoo() + o.DeepCopyInto(dst) + return dst +} + +func (o *GetFoo) DeepCopyInto(dst *GetFoo) { + dst.TypeMeta.APIVersion = o.TypeMeta.APIVersion + dst.TypeMeta.Kind = o.TypeMeta.Kind + o.GetFooBody.DeepCopyInto(&dst.GetFooBody) +} + +var _ runtime.Object = NewGetFoo() diff --git a/apps/example/pkg/apis/example/v1alpha1/example_metadata_gen.go b/apps/example/pkg/apis/example/v1alpha1/example_metadata_gen.go new file mode 100644 index 00000000000..e3974409f20 --- /dev/null +++ b/apps/example/pkg/apis/example/v1alpha1/example_metadata_gen.go @@ -0,0 +1,31 @@ +// Code generated - EDITING IS FUTILE. DO NOT EDIT. + +package v1alpha1 + +import ( + time "time" +) + +// metadata contains embedded CommonMetadata and can be extended with custom string fields +// TODO: use CommonMetadata instead of redefining here; currently needs to be defined here +// without external reference as using the CommonMetadata reference breaks thema codegen. +type ExampleMetadata struct { + UpdateTimestamp time.Time `json:"updateTimestamp"` + CreatedBy string `json:"createdBy"` + Uid string `json:"uid"` + CreationTimestamp time.Time `json:"creationTimestamp"` + DeletionTimestamp *time.Time `json:"deletionTimestamp,omitempty"` + Finalizers []string `json:"finalizers"` + ResourceVersion string `json:"resourceVersion"` + Generation int64 `json:"generation"` + UpdatedBy string `json:"updatedBy"` + Labels map[string]string `json:"labels"` +} + +// NewExampleMetadata creates a new ExampleMetadata object. +func NewExampleMetadata() *ExampleMetadata { + return &ExampleMetadata{ + Finalizers: []string{}, + Labels: map[string]string{}, + } +} diff --git a/apps/example/pkg/apis/example/v1alpha1/example_object_gen.go b/apps/example/pkg/apis/example/v1alpha1/example_object_gen.go new file mode 100644 index 00000000000..efd1374e855 --- /dev/null +++ b/apps/example/pkg/apis/example/v1alpha1/example_object_gen.go @@ -0,0 +1,347 @@ +// +// Code generated by grafana-app-sdk. DO NOT EDIT. +// + +package v1alpha1 + +import ( + "fmt" + "github.com/grafana/grafana-app-sdk/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/types" + "time" +) + +// +k8s:openapi-gen=true +type Example struct { + metav1.TypeMeta `json:",inline" yaml:",inline"` + metav1.ObjectMeta `json:"metadata" yaml:"metadata"` + + // Spec is the spec of the Example + Spec ExampleSpec `json:"spec" yaml:"spec"` + + Status ExampleStatus `json:"status" yaml:"status"` + + Custom ExampleCustom `json:"custom" yaml:"custom"` +} + +func (o *Example) GetSpec() any { + return o.Spec +} + +func (o *Example) SetSpec(spec any) error { + cast, ok := spec.(ExampleSpec) + if !ok { + return fmt.Errorf("cannot set spec type %#v, not of type Spec", spec) + } + o.Spec = cast + return nil +} + +func (o *Example) GetSubresources() map[string]any { + return map[string]any{ + "status": o.Status, + + "custom": o.Custom, + } +} + +func (o *Example) GetSubresource(name string) (any, bool) { + switch name { + case "status": + return o.Status, true + + case "custom": + return o.Custom, true + default: + return nil, false + } +} + +func (o *Example) SetSubresource(name string, value any) error { + switch name { + case "status": + cast, ok := value.(ExampleStatus) + if !ok { + return fmt.Errorf("cannot set status type %#v, not of type ExampleStatus", value) + } + o.Status = cast + return nil + + case "custom": + cast, ok := value.(ExampleCustom) + if !ok { + return fmt.Errorf("cannot set custom type %#v, not of type ExampleCustom", value) + } + o.Custom = cast + return nil + default: + return fmt.Errorf("subresource '%s' does not exist", name) + } +} + +func (o *Example) GetStaticMetadata() resource.StaticMetadata { + gvk := o.GroupVersionKind() + return resource.StaticMetadata{ + Name: o.ObjectMeta.Name, + Namespace: o.ObjectMeta.Namespace, + Group: gvk.Group, + Version: gvk.Version, + Kind: gvk.Kind, + } +} + +func (o *Example) SetStaticMetadata(metadata resource.StaticMetadata) { + o.Name = metadata.Name + o.Namespace = metadata.Namespace + o.SetGroupVersionKind(schema.GroupVersionKind{ + Group: metadata.Group, + Version: metadata.Version, + Kind: metadata.Kind, + }) +} + +func (o *Example) GetCommonMetadata() resource.CommonMetadata { + dt := o.DeletionTimestamp + var deletionTimestamp *time.Time + if dt != nil { + deletionTimestamp = &dt.Time + } + // Legacy ExtraFields support + extraFields := make(map[string]any) + if o.Annotations != nil { + extraFields["annotations"] = o.Annotations + } + if o.ManagedFields != nil { + extraFields["managedFields"] = o.ManagedFields + } + if o.OwnerReferences != nil { + extraFields["ownerReferences"] = o.OwnerReferences + } + return resource.CommonMetadata{ + UID: string(o.UID), + ResourceVersion: o.ResourceVersion, + Generation: o.Generation, + Labels: o.Labels, + CreationTimestamp: o.CreationTimestamp.Time, + DeletionTimestamp: deletionTimestamp, + Finalizers: o.Finalizers, + UpdateTimestamp: o.GetUpdateTimestamp(), + CreatedBy: o.GetCreatedBy(), + UpdatedBy: o.GetUpdatedBy(), + ExtraFields: extraFields, + } +} + +func (o *Example) SetCommonMetadata(metadata resource.CommonMetadata) { + o.UID = types.UID(metadata.UID) + o.ResourceVersion = metadata.ResourceVersion + o.Generation = metadata.Generation + o.Labels = metadata.Labels + o.CreationTimestamp = metav1.NewTime(metadata.CreationTimestamp) + if metadata.DeletionTimestamp != nil { + dt := metav1.NewTime(*metadata.DeletionTimestamp) + o.DeletionTimestamp = &dt + } else { + o.DeletionTimestamp = nil + } + o.Finalizers = metadata.Finalizers + if o.Annotations == nil { + o.Annotations = make(map[string]string) + } + if !metadata.UpdateTimestamp.IsZero() { + o.SetUpdateTimestamp(metadata.UpdateTimestamp) + } + if metadata.CreatedBy != "" { + o.SetCreatedBy(metadata.CreatedBy) + } + if metadata.UpdatedBy != "" { + o.SetUpdatedBy(metadata.UpdatedBy) + } + // Legacy support for setting Annotations, ManagedFields, and OwnerReferences via ExtraFields + if metadata.ExtraFields != nil { + if annotations, ok := metadata.ExtraFields["annotations"]; ok { + if cast, ok := annotations.(map[string]string); ok { + o.Annotations = cast + } + } + if managedFields, ok := metadata.ExtraFields["managedFields"]; ok { + if cast, ok := managedFields.([]metav1.ManagedFieldsEntry); ok { + o.ManagedFields = cast + } + } + if ownerReferences, ok := metadata.ExtraFields["ownerReferences"]; ok { + if cast, ok := ownerReferences.([]metav1.OwnerReference); ok { + o.OwnerReferences = cast + } + } + } +} + +func (o *Example) GetCreatedBy() string { + if o.ObjectMeta.Annotations == nil { + o.ObjectMeta.Annotations = make(map[string]string) + } + + return o.ObjectMeta.Annotations["grafana.com/createdBy"] +} + +func (o *Example) SetCreatedBy(createdBy string) { + if o.ObjectMeta.Annotations == nil { + o.ObjectMeta.Annotations = make(map[string]string) + } + + o.ObjectMeta.Annotations["grafana.com/createdBy"] = createdBy +} + +func (o *Example) GetUpdateTimestamp() time.Time { + if o.ObjectMeta.Annotations == nil { + o.ObjectMeta.Annotations = make(map[string]string) + } + + parsed, _ := time.Parse(time.RFC3339, o.ObjectMeta.Annotations["grafana.com/updateTimestamp"]) + return parsed +} + +func (o *Example) SetUpdateTimestamp(updateTimestamp time.Time) { + if o.ObjectMeta.Annotations == nil { + o.ObjectMeta.Annotations = make(map[string]string) + } + + o.ObjectMeta.Annotations["grafana.com/updateTimestamp"] = updateTimestamp.Format(time.RFC3339) +} + +func (o *Example) GetUpdatedBy() string { + if o.ObjectMeta.Annotations == nil { + o.ObjectMeta.Annotations = make(map[string]string) + } + + return o.ObjectMeta.Annotations["grafana.com/updatedBy"] +} + +func (o *Example) SetUpdatedBy(updatedBy string) { + if o.ObjectMeta.Annotations == nil { + o.ObjectMeta.Annotations = make(map[string]string) + } + + o.ObjectMeta.Annotations["grafana.com/updatedBy"] = updatedBy +} + +func (o *Example) Copy() resource.Object { + return resource.CopyObject(o) +} + +func (o *Example) DeepCopyObject() runtime.Object { + return o.Copy() +} + +func (o *Example) DeepCopy() *Example { + cpy := &Example{} + o.DeepCopyInto(cpy) + return cpy +} + +func (o *Example) DeepCopyInto(dst *Example) { + dst.TypeMeta.APIVersion = o.TypeMeta.APIVersion + dst.TypeMeta.Kind = o.TypeMeta.Kind + o.ObjectMeta.DeepCopyInto(&dst.ObjectMeta) + o.Spec.DeepCopyInto(&dst.Spec) + o.Status.DeepCopyInto(&dst.Status) + o.Custom.DeepCopyInto(&dst.Custom) +} + +// Interface compliance compile-time check +var _ resource.Object = &Example{} + +// +k8s:openapi-gen=true +type ExampleList struct { + metav1.TypeMeta `json:",inline" yaml:",inline"` + metav1.ListMeta `json:"metadata" yaml:"metadata"` + Items []Example `json:"items" yaml:"items"` +} + +func (o *ExampleList) DeepCopyObject() runtime.Object { + return o.Copy() +} + +func (o *ExampleList) Copy() resource.ListObject { + cpy := &ExampleList{ + TypeMeta: o.TypeMeta, + Items: make([]Example, len(o.Items)), + } + o.ListMeta.DeepCopyInto(&cpy.ListMeta) + for i := 0; i < len(o.Items); i++ { + if item, ok := o.Items[i].Copy().(*Example); ok { + cpy.Items[i] = *item + } + } + return cpy +} + +func (o *ExampleList) GetItems() []resource.Object { + items := make([]resource.Object, len(o.Items)) + for i := 0; i < len(o.Items); i++ { + items[i] = &o.Items[i] + } + return items +} + +func (o *ExampleList) SetItems(items []resource.Object) { + o.Items = make([]Example, len(items)) + for i := 0; i < len(items); i++ { + o.Items[i] = *items[i].(*Example) + } +} + +func (o *ExampleList) DeepCopy() *ExampleList { + cpy := &ExampleList{} + o.DeepCopyInto(cpy) + return cpy +} + +func (o *ExampleList) DeepCopyInto(dst *ExampleList) { + resource.CopyObjectInto(dst, o) +} + +// Interface compliance compile-time check +var _ resource.ListObject = &ExampleList{} + +// Copy methods for all subresource types + +// DeepCopy creates a full deep copy of Spec +func (s *ExampleSpec) DeepCopy() *ExampleSpec { + cpy := &ExampleSpec{} + s.DeepCopyInto(cpy) + return cpy +} + +// DeepCopyInto deep copies Spec into another Spec object +func (s *ExampleSpec) DeepCopyInto(dst *ExampleSpec) { + resource.CopyObjectInto(dst, s) +} + +// DeepCopy creates a full deep copy of ExampleStatus +func (s *ExampleStatus) DeepCopy() *ExampleStatus { + cpy := &ExampleStatus{} + s.DeepCopyInto(cpy) + return cpy +} + +// DeepCopyInto deep copies ExampleStatus into another ExampleStatus object +func (s *ExampleStatus) DeepCopyInto(dst *ExampleStatus) { + resource.CopyObjectInto(dst, s) +} + +// DeepCopy creates a full deep copy of ExampleCustom +func (s *ExampleCustom) DeepCopy() *ExampleCustom { + cpy := &ExampleCustom{} + s.DeepCopyInto(cpy) + return cpy +} + +// DeepCopyInto deep copies ExampleCustom into another ExampleCustom object +func (s *ExampleCustom) DeepCopyInto(dst *ExampleCustom) { + resource.CopyObjectInto(dst, s) +} diff --git a/apps/example/pkg/apis/example/v1alpha1/example_schema_gen.go b/apps/example/pkg/apis/example/v1alpha1/example_schema_gen.go new file mode 100644 index 00000000000..e1f7dca0b02 --- /dev/null +++ b/apps/example/pkg/apis/example/v1alpha1/example_schema_gen.go @@ -0,0 +1,34 @@ +// +// Code generated by grafana-app-sdk. DO NOT EDIT. +// + +package v1alpha1 + +import ( + "github.com/grafana/grafana-app-sdk/resource" +) + +// schema is unexported to prevent accidental overwrites +var ( + schemaExample = resource.NewSimpleSchema("example.grafana.app", "v1alpha1", &Example{}, &ExampleList{}, resource.WithKind("Example"), + resource.WithPlural("examples"), resource.WithScope(resource.NamespacedScope)) + kindExample = resource.Kind{ + Schema: schemaExample, + Codecs: map[resource.KindEncoding]resource.Codec{ + resource.KindEncodingJSON: &ExampleJSONCodec{}, + }, + } +) + +// Kind returns a resource.Kind for this Schema with a JSON codec +func ExampleKind() resource.Kind { + return kindExample +} + +// Schema returns a resource.SimpleSchema representation of Example +func ExampleSchema() *resource.SimpleSchema { + return schemaExample +} + +// Interface compliance checks +var _ resource.Schema = kindExample diff --git a/apps/example/pkg/apis/example/v1alpha1/example_spec_gen.go b/apps/example/pkg/apis/example/v1alpha1/example_spec_gen.go new file mode 100644 index 00000000000..3f73653ac1c --- /dev/null +++ b/apps/example/pkg/apis/example/v1alpha1/example_spec_gen.go @@ -0,0 +1,34 @@ +// Code generated - EDITING IS FUTILE. DO NOT EDIT. + +package v1alpha1 + +// #DefinedType is a re-usable definition for us to use in our schema. +// Fields leading with # are definitions in CUE and won't be included in the generated types. +// +k8s:openapi-gen=true +type ExampleDefinedType struct { + // Info is information about this entry. This comment, like all comments + // on fields or definitions, will be copied into the generated types as well. + Info string `json:"info"` + // Next is an optional next element in the DefinedType, allowing for a self-referential + // linked-list like structure. The ? in the field makes this optional. + Next *ExampleDefinedType `json:"next,omitempty"` +} + +// NewExampleDefinedType creates a new ExampleDefinedType object. +func NewExampleDefinedType() *ExampleDefinedType { + return &ExampleDefinedType{} +} + +// Spec is the schema of our resource. The spec should include all the user-editable information for the kind. +// +k8s:openapi-gen=true +type ExampleSpec struct { + // Example fields + FirstField string `json:"firstField"` + SecondField int64 `json:"secondField"` + List *ExampleDefinedType `json:"list,omitempty"` +} + +// NewExampleSpec creates a new ExampleSpec object. +func NewExampleSpec() *ExampleSpec { + return &ExampleSpec{} +} diff --git a/apps/example/pkg/apis/example/v1alpha1/example_status_gen.go b/apps/example/pkg/apis/example/v1alpha1/example_status_gen.go new file mode 100644 index 00000000000..ced0f82949e --- /dev/null +++ b/apps/example/pkg/apis/example/v1alpha1/example_status_gen.go @@ -0,0 +1,48 @@ +// Code generated - EDITING IS FUTILE. DO NOT EDIT. + +package v1alpha1 + +// +k8s:openapi-gen=true +type ExamplestatusOperatorState struct { + // lastEvaluation is the ResourceVersion last evaluated + LastEvaluation string `json:"lastEvaluation"` + // state describes the state of the lastEvaluation. + // It is limited to three possible states for machine evaluation. + State ExampleStatusOperatorStateState `json:"state"` + // descriptiveState is an optional more descriptive state field which has no requirements on format + DescriptiveState *string `json:"descriptiveState,omitempty"` + // details contains any extra information that is operator-specific + Details map[string]interface{} `json:"details,omitempty"` +} + +// NewExamplestatusOperatorState creates a new ExamplestatusOperatorState object. +func NewExamplestatusOperatorState() *ExamplestatusOperatorState { + return &ExamplestatusOperatorState{} +} + +// status is where state and status information which may be used or updated by the operator or back-end should be placed +// If you do not have any such information, you do not need to include this field, +// however, as mentioned above, certain fields will be added by the kind system regardless. +// +k8s:openapi-gen=true +type ExampleStatus struct { + LastObservedGeneration int64 `json:"lastObservedGeneration"` + // operatorStates is a map of operator ID to operator state evaluations. + // Any operator which consumes this kind SHOULD add its state evaluation information to this field. + OperatorStates map[string]ExamplestatusOperatorState `json:"operatorStates,omitempty"` + // additionalFields is reserved for future use + AdditionalFields map[string]interface{} `json:"additionalFields,omitempty"` +} + +// NewExampleStatus creates a new ExampleStatus object. +func NewExampleStatus() *ExampleStatus { + return &ExampleStatus{} +} + +// +k8s:openapi-gen=true +type ExampleStatusOperatorStateState string + +const ( + ExampleStatusOperatorStateStateSuccess ExampleStatusOperatorStateState = "success" + ExampleStatusOperatorStateStateInProgress ExampleStatusOperatorStateState = "in_progress" + ExampleStatusOperatorStateStateFailed ExampleStatusOperatorStateState = "failed" +) diff --git a/apps/example/pkg/apis/example/v1alpha1/getother_request_params_object_gen.go b/apps/example/pkg/apis/example/v1alpha1/getother_request_params_object_gen.go new file mode 100644 index 00000000000..25fa13336e2 --- /dev/null +++ b/apps/example/pkg/apis/example/v1alpha1/getother_request_params_object_gen.go @@ -0,0 +1,33 @@ +// Code generated - EDITING IS FUTILE. DO NOT EDIT. + +package v1alpha1 + +import ( + "github.com/grafana/grafana-app-sdk/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" +) + +type GetOtherRequestParamsObject struct { + metav1.TypeMeta `json:",inline"` + GetOtherRequestParams `json:",inline"` +} + +func NewGetOtherRequestParamsObject() *GetOtherRequestParamsObject { + return &GetOtherRequestParamsObject{} +} + +func (o *GetOtherRequestParamsObject) DeepCopyObject() runtime.Object { + dst := NewGetOtherRequestParamsObject() + o.DeepCopyInto(dst) + return dst +} + +func (o *GetOtherRequestParamsObject) DeepCopyInto(dst *GetOtherRequestParamsObject) { + dst.TypeMeta.APIVersion = o.TypeMeta.APIVersion + dst.TypeMeta.Kind = o.TypeMeta.Kind + dstGetOtherRequestParams := GetOtherRequestParams{} + _ = resource.CopyObjectInto(&dstGetOtherRequestParams, &o.GetOtherRequestParams) +} + +var _ runtime.Object = NewGetOtherRequestParamsObject() diff --git a/apps/example/pkg/apis/example/v1alpha1/getother_request_params_types_gen.go b/apps/example/pkg/apis/example/v1alpha1/getother_request_params_types_gen.go new file mode 100644 index 00000000000..09b886b1df7 --- /dev/null +++ b/apps/example/pkg/apis/example/v1alpha1/getother_request_params_types_gen.go @@ -0,0 +1,12 @@ +// Code generated - EDITING IS FUTILE. DO NOT EDIT. + +package v1alpha1 + +type GetOtherRequestParams struct { + Message *string `json:"message,omitempty"` +} + +// NewGetOtherRequestParams creates a new GetOtherRequestParams object. +func NewGetOtherRequestParams() *GetOtherRequestParams { + return &GetOtherRequestParams{} +} diff --git a/apps/example/pkg/apis/example/v1alpha1/getother_response_types_gen.go b/apps/example/pkg/apis/example/v1alpha1/getother_response_types_gen.go new file mode 100644 index 00000000000..e6c7bdf6ad8 --- /dev/null +++ b/apps/example/pkg/apis/example/v1alpha1/getother_response_types_gen.go @@ -0,0 +1,13 @@ +// Code generated - EDITING IS FUTILE. DO NOT EDIT. + +package v1alpha1 + +// +k8s:openapi-gen=true +type GetOther struct { + Message string `json:"message"` +} + +// NewGetOther creates a new GetOther object. +func NewGetOther() *GetOther { + return &GetOther{} +} diff --git a/apps/example/pkg/apis/example/v1alpha1/getsomething_request_params_object_gen.go b/apps/example/pkg/apis/example/v1alpha1/getsomething_request_params_object_gen.go new file mode 100644 index 00000000000..83cdd19ad7f --- /dev/null +++ b/apps/example/pkg/apis/example/v1alpha1/getsomething_request_params_object_gen.go @@ -0,0 +1,33 @@ +// Code generated - EDITING IS FUTILE. DO NOT EDIT. + +package v1alpha1 + +import ( + "github.com/grafana/grafana-app-sdk/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" +) + +type GetSomethingRequestParamsObject struct { + metav1.TypeMeta `json:",inline"` + GetSomethingRequestParams `json:",inline"` +} + +func NewGetSomethingRequestParamsObject() *GetSomethingRequestParamsObject { + return &GetSomethingRequestParamsObject{} +} + +func (o *GetSomethingRequestParamsObject) DeepCopyObject() runtime.Object { + dst := NewGetSomethingRequestParamsObject() + o.DeepCopyInto(dst) + return dst +} + +func (o *GetSomethingRequestParamsObject) DeepCopyInto(dst *GetSomethingRequestParamsObject) { + dst.TypeMeta.APIVersion = o.TypeMeta.APIVersion + dst.TypeMeta.Kind = o.TypeMeta.Kind + dstGetSomethingRequestParams := GetSomethingRequestParams{} + _ = resource.CopyObjectInto(&dstGetSomethingRequestParams, &o.GetSomethingRequestParams) +} + +var _ runtime.Object = NewGetSomethingRequestParamsObject() diff --git a/apps/example/pkg/apis/example/v1alpha1/getsomething_request_params_types_gen.go b/apps/example/pkg/apis/example/v1alpha1/getsomething_request_params_types_gen.go new file mode 100644 index 00000000000..30ff91085ce --- /dev/null +++ b/apps/example/pkg/apis/example/v1alpha1/getsomething_request_params_types_gen.go @@ -0,0 +1,12 @@ +// Code generated - EDITING IS FUTILE. DO NOT EDIT. + +package v1alpha1 + +type GetSomethingRequestParams struct { + Message *string `json:"message,omitempty"` +} + +// NewGetSomethingRequestParams creates a new GetSomethingRequestParams object. +func NewGetSomethingRequestParams() *GetSomethingRequestParams { + return &GetSomethingRequestParams{} +} diff --git a/apps/example/pkg/apis/example/v1alpha1/getsomething_response_body_types_gen.go b/apps/example/pkg/apis/example/v1alpha1/getsomething_response_body_types_gen.go new file mode 100644 index 00000000000..c785f9c4ecd --- /dev/null +++ b/apps/example/pkg/apis/example/v1alpha1/getsomething_response_body_types_gen.go @@ -0,0 +1,14 @@ +// Code generated - EDITING IS FUTILE. DO NOT EDIT. + +package v1alpha1 + +// +k8s:openapi-gen=true +type GetSomethingBody struct { + Namespace string `json:"namespace"` + Message string `json:"message"` +} + +// NewGetSomethingBody creates a new GetSomethingBody object. +func NewGetSomethingBody() *GetSomethingBody { + return &GetSomethingBody{} +} diff --git a/apps/example/pkg/apis/example/v1alpha1/getsomething_response_object_types_gen.go b/apps/example/pkg/apis/example/v1alpha1/getsomething_response_object_types_gen.go new file mode 100644 index 00000000000..2e6ce668030 --- /dev/null +++ b/apps/example/pkg/apis/example/v1alpha1/getsomething_response_object_types_gen.go @@ -0,0 +1,37 @@ +// Code generated - EDITING IS FUTILE. DO NOT EDIT. + +package v1alpha1 + +import ( + "github.com/grafana/grafana-app-sdk/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" +) + +// +k8s:openapi-gen=true +type GetSomething struct { + metav1.TypeMeta `json:",inline"` + GetSomethingBody `json:",inline"` +} + +func NewGetSomething() *GetSomething { + return &GetSomething{} +} + +func (t *GetSomethingBody) DeepCopyInto(dst *GetSomethingBody) { + _ = resource.CopyObjectInto(dst, t) +} + +func (o *GetSomething) DeepCopyObject() runtime.Object { + dst := NewGetSomething() + o.DeepCopyInto(dst) + return dst +} + +func (o *GetSomething) DeepCopyInto(dst *GetSomething) { + dst.TypeMeta.APIVersion = o.TypeMeta.APIVersion + dst.TypeMeta.Kind = o.TypeMeta.Kind + o.GetSomethingBody.DeepCopyInto(&dst.GetSomethingBody) +} + +var _ runtime.Object = NewGetSomething() diff --git a/apps/example/pkg/apis/example_manifest.go b/apps/example/pkg/apis/example_manifest.go new file mode 100644 index 00000000000..eab0ee792ab --- /dev/null +++ b/apps/example/pkg/apis/example_manifest.go @@ -0,0 +1,374 @@ +// +// This file is generated by grafana-app-sdk +// DO NOT EDIT +// + +package apis + +import ( + "encoding/json" + "fmt" + "strings" + + "github.com/grafana/grafana-app-sdk/app" + "github.com/grafana/grafana-app-sdk/resource" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/kube-openapi/pkg/spec3" + "k8s.io/kube-openapi/pkg/validation/spec" + + v0alpha1 "github.com/grafana/grafana/apps/example/pkg/apis/example/v0alpha1" + v1alpha1 "github.com/grafana/grafana/apps/example/pkg/apis/example/v1alpha1" +) + +var ( + rawSchemaExamplev0alpha1 = []byte(`{"Example":{"properties":{"spec":{"$ref":"#/components/schemas/spec"},"status":{"$ref":"#/components/schemas/status"}},"required":["spec"]},"OperatorState":{"additionalProperties":false,"properties":{"descriptiveState":{"description":"descriptiveState is an optional more descriptive state field which has no requirements on format","type":"string"},"details":{"additionalProperties":{"additionalProperties":{},"type":"object"},"description":"details contains any extra information that is operator-specific","type":"object"},"lastEvaluation":{"description":"lastEvaluation is the ResourceVersion last evaluated","type":"string"},"state":{"description":"state describes the state of the lastEvaluation.\nIt is limited to three possible states for machine evaluation.","enum":["success","in_progress","failed"],"type":"string"}},"required":["lastEvaluation","state"],"type":"object"},"spec":{"additionalProperties":false,"description":"Spec is the schema of our resource. The spec should include all the user-editable information for the kind.","properties":{"firstField":{"type":"integer"}},"required":["firstField"],"type":"object"},"status":{"additionalProperties":false,"properties":{"additionalFields":{"additionalProperties":{"additionalProperties":{},"type":"object"},"description":"additionalFields is reserved for future use","type":"object"},"lastObservedGeneration":{"type":"integer"},"operatorStates":{"additionalProperties":{"$ref":"#/components/schemas/OperatorState"},"description":"operatorStates is a map of operator ID to operator state evaluations.\nAny operator which consumes this kind SHOULD add its state evaluation information to this field.","type":"object"}},"required":["lastObservedGeneration"],"type":"object"}}`) + versionSchemaExamplev0alpha1 app.VersionSchema + _ = json.Unmarshal(rawSchemaExamplev0alpha1, &versionSchemaExamplev0alpha1) + rawSchemaExamplev1alpha1 = []byte(`{"DefinedType":{"additionalProperties":false,"description":"#DefinedType is a re-usable definition for us to use in our schema.\nFields leading with # are definitions in CUE and won't be included in the generated types.","properties":{"info":{"description":"Info is information about this entry. This comment, like all comments\non fields or definitions, will be copied into the generated types as well.","type":"string"},"next":{"$ref":"#/components/schemas/DefinedType","description":"Next is an optional next element in the DefinedType, allowing for a self-referential\nlinked-list like structure. The ? in the field makes this optional."}},"required":["info"],"type":"object"},"Example":{"properties":{"custom":{"$ref":"#/components/schemas/custom"},"spec":{"$ref":"#/components/schemas/spec"},"status":{"$ref":"#/components/schemas/status"}},"required":["spec"]},"OperatorState":{"additionalProperties":false,"properties":{"descriptiveState":{"description":"descriptiveState is an optional more descriptive state field which has no requirements on format","type":"string"},"details":{"additionalProperties":{"additionalProperties":{},"type":"object"},"description":"details contains any extra information that is operator-specific","type":"object"},"lastEvaluation":{"description":"lastEvaluation is the ResourceVersion last evaluated","type":"string"},"state":{"description":"state describes the state of the lastEvaluation.\nIt is limited to three possible states for machine evaluation.","enum":["success","in_progress","failed"],"type":"string"}},"required":["lastEvaluation","state"],"type":"object"},"custom":{"additionalProperties":false,"description":"Custom is a subresource that will be stored the same way status is stored,\nand requires using the /custom route to update.\nIts content is returned as part of a GET to the resource itself, just like with status.\nTo route a subresource to an arbitrary handler, use the 'routes' field instead (see below).\nmetadata if where kind- and schema-specific metadata goes. This is converted into typed annotations\nwith getters and setters by the code generation.\nmetadata: {\n\tkindSpecificField: string\n}","properties":{"myField":{"type":"string"},"otherField":{"type":"string"}},"required":["myField","otherField"],"type":"object"},"spec":{"additionalProperties":false,"description":"Spec is the schema of our resource. The spec should include all the user-editable information for the kind.","properties":{"firstField":{"description":"Example fields","type":"string"},"list":{"$ref":"#/components/schemas/DefinedType"},"secondField":{"type":"integer"}},"required":["firstField","secondField"],"type":"object"},"status":{"additionalProperties":false,"description":"status is where state and status information which may be used or updated by the operator or back-end should be placed\nIf you do not have any such information, you do not need to include this field,\nhowever, as mentioned above, certain fields will be added by the kind system regardless.","properties":{"additionalFields":{"additionalProperties":{"additionalProperties":{},"type":"object"},"description":"additionalFields is reserved for future use","type":"object"},"lastObservedGeneration":{"type":"integer"},"operatorStates":{"additionalProperties":{"$ref":"#/components/schemas/OperatorState"},"description":"operatorStates is a map of operator ID to operator state evaluations.\nAny operator which consumes this kind SHOULD add its state evaluation information to this field.","type":"object"}},"required":["lastObservedGeneration"],"type":"object"}}`) + versionSchemaExamplev1alpha1 app.VersionSchema + _ = json.Unmarshal(rawSchemaExamplev1alpha1, &versionSchemaExamplev1alpha1) +) + +var appManifestData = app.ManifestData{ + AppName: "example", + Group: "example.grafana.app", + PreferredVersion: "v1alpha1", + Versions: []app.ManifestVersion{ + { + Name: "v0alpha1", + Served: false, + Kinds: []app.ManifestVersionKind{ + { + Kind: "Example", + Plural: "Examples", + Scope: "Namespaced", + Conversion: true, + Admission: &app.AdmissionCapabilities{ + Validation: &app.ValidationCapability{ + Operations: []app.AdmissionOperation{ + app.AdmissionOperationCreate, + app.AdmissionOperationUpdate, + }, + }, + Mutation: &app.MutationCapability{ + Operations: []app.AdmissionOperation{ + app.AdmissionOperationCreate, + app.AdmissionOperationUpdate, + }, + }, + }, + Schema: &versionSchemaExamplev0alpha1, + }, + }, + Routes: app.ManifestVersionRoutes{ + Namespaced: map[string]spec3.PathProps{}, + Cluster: map[string]spec3.PathProps{}, + }, + }, + + { + Name: "v1alpha1", + Served: false, + Kinds: []app.ManifestVersionKind{ + { + Kind: "Example", + Plural: "Examples", + Scope: "Namespaced", + Conversion: true, + Admission: &app.AdmissionCapabilities{ + Validation: &app.ValidationCapability{ + Operations: []app.AdmissionOperation{ + app.AdmissionOperationCreate, + app.AdmissionOperationUpdate, + }, + }, + Mutation: &app.MutationCapability{ + Operations: []app.AdmissionOperation{ + app.AdmissionOperationCreate, + app.AdmissionOperationUpdate, + }, + }, + }, + Schema: &versionSchemaExamplev1alpha1, + Routes: map[string]spec3.PathProps{ + "foo": { + Get: &spec3.Operation{ + OperationProps: spec3.OperationProps{ + + OperationId: "getFoo", + + Parameters: []*spec3.Parameter{ + + { + ParameterProps: spec3.ParameterProps{ + Name: "message", + In: "query", + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + }, + }, + }, + }, + }, + + Responses: &spec3.Responses{ + ResponsesProps: spec3.ResponsesProps{ + Default: &spec3.Response{ + ResponseProps: spec3.ResponseProps{ + Description: "Default OK response", + Content: map[string]*spec3.MediaType{ + "application/json": { + MediaTypeProps: spec3.MediaTypeProps{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Description: "The response type for the GET /foo method. This will generate a go type, and will also be used for the OpenAPI definition for the route.", + Properties: map[string]spec.Schema{ + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + }, + }, + "kind": { + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + }, + }, + "message": { + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + }, + }, + }, + Required: []string{ + "message", + "apiVersion", + "kind", + }, + }}, + }}, + }, + }, + }, + }}, + }, + }, + }, + }, + }, + }, + Routes: app.ManifestVersionRoutes{ + Namespaced: map[string]spec3.PathProps{ + "/something": { + Get: &spec3.Operation{ + OperationProps: spec3.OperationProps{ + + OperationId: "getSomething", + + Parameters: []*spec3.Parameter{ + + { + ParameterProps: spec3.ParameterProps{ + Name: "message", + In: "query", + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + }, + }, + }, + }, + }, + + Responses: &spec3.Responses{ + ResponsesProps: spec3.ResponsesProps{ + Default: &spec3.Response{ + ResponseProps: spec3.ResponseProps{ + Description: "Default OK response", + Content: map[string]*spec3.MediaType{ + "application/json": { + MediaTypeProps: spec3.MediaTypeProps{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + }, + }, + "kind": { + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + }, + }, + "message": { + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + }, + }, + "namespace": { + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + }, + }, + }, + Required: []string{ + "namespace", + "message", + "apiVersion", + "kind", + }, + }}, + }}, + }, + }, + }, + }}, + }, + }, + }, + }, + Cluster: map[string]spec3.PathProps{ + "/other": { + Get: &spec3.Operation{ + OperationProps: spec3.OperationProps{ + + OperationId: "getOther", + + Parameters: []*spec3.Parameter{ + + { + ParameterProps: spec3.ParameterProps{ + Name: "message", + In: "query", + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + }, + }, + }, + }, + }, + + Responses: &spec3.Responses{ + ResponsesProps: spec3.ResponsesProps{ + Default: &spec3.Response{ + ResponseProps: spec3.ResponseProps{ + Description: "Default OK response", + Content: map[string]*spec3.MediaType{ + "application/json": { + MediaTypeProps: spec3.MediaTypeProps{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "message": { + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + }, + }, + }, + Required: []string{ + "message", + }, + }}, + }}, + }, + }, + }, + }}, + }, + }, + }, + }, + }, + }, + }, +} + +func LocalManifest() app.Manifest { + return app.NewEmbeddedManifest(appManifestData) +} + +func RemoteManifest() app.Manifest { + return app.NewAPIServerManifest("example") +} + +var kindVersionToGoType = map[string]resource.Kind{ + "Example/v0alpha1": v0alpha1.ExampleKind(), + "Example/v1alpha1": v1alpha1.ExampleKind(), +} + +// ManifestGoTypeAssociator returns the associated resource.Kind instance for a given Kind and Version, if one exists. +// If there is no association for the provided Kind and Version, exists will return false. +func ManifestGoTypeAssociator(kind, version string) (goType resource.Kind, exists bool) { + goType, exists = kindVersionToGoType[fmt.Sprintf("%s/%s", kind, version)] + return goType, exists +} + +var customRouteToGoResponseType = map[string]any{ + + "v1alpha1|Example|foo|GET": v1alpha1.GetFoo{}, + + "v1alpha1||/something|GET": v1alpha1.GetSomething{}, + "v1alpha1||other|GET": v1alpha1.GetOther{}, +} + +// ManifestCustomRouteResponsesAssociator returns the associated response go type for a given kind, version, custom route path, and method, if one exists. +// kind may be empty for custom routes which are not kind subroutes. Leading slashes are removed from subroute paths. +// If there is no association for the provided kind, version, custom route path, and method, exists will return false. +// Resource routes (those without a kind) should prefix their route with "/" if the route is namespaced (otherwise the route is assumed to be cluster-scope) +func ManifestCustomRouteResponsesAssociator(kind, version, path, verb string) (goType any, exists bool) { + if len(path) > 0 && path[0] == '/' { + path = path[1:] + } + goType, exists = customRouteToGoResponseType[fmt.Sprintf("%s|%s|%s|%s", version, kind, path, strings.ToUpper(verb))] + return goType, exists +} + +var customRouteToGoParamsType = map[string]runtime.Object{ + "v1alpha1|Example|foo|GET": &v1alpha1.GetFooRequestParamsObject{}, +} + +func ManifestCustomRouteQueryAssociator(kind, version, path, verb string) (goType runtime.Object, exists bool) { + if len(path) > 0 && path[0] == '/' { + path = path[1:] + } + goType, exists = customRouteToGoParamsType[fmt.Sprintf("%s|%s|%s|%s", version, kind, path, strings.ToUpper(verb))] + return goType, exists +} + +var customRouteToGoRequestBodyType = map[string]any{} + +func ManifestCustomRouteRequestBodyAssociator(kind, version, path, verb string) (goType any, exists bool) { + if len(path) > 0 && path[0] == '/' { + path = path[1:] + } + goType, exists = customRouteToGoRequestBodyType[fmt.Sprintf("%s|%s|%s|%s", version, kind, path, strings.ToUpper(verb))] + return goType, exists +} + +type GoTypeAssociator struct{} + +func NewGoTypeAssociator() *GoTypeAssociator { + return &GoTypeAssociator{} +} + +func (g *GoTypeAssociator) KindToGoType(kind, version string) (goType resource.Kind, exists bool) { + return ManifestGoTypeAssociator(kind, version) +} +func (g *GoTypeAssociator) CustomRouteReturnGoType(kind, version, path, verb string) (goType any, exists bool) { + return ManifestCustomRouteResponsesAssociator(kind, version, path, verb) +} +func (g *GoTypeAssociator) CustomRouteQueryGoType(kind, version, path, verb string) (goType runtime.Object, exists bool) { + return ManifestCustomRouteQueryAssociator(kind, version, path, verb) +} +func (g *GoTypeAssociator) CustomRouteRequestBodyGoType(kind, version, path, verb string) (goType any, exists bool) { + return ManifestCustomRouteRequestBodyAssociator(kind, version, path, verb) +} diff --git a/apps/example/pkg/app/app.go b/apps/example/pkg/app/app.go new file mode 100644 index 00000000000..3d189ca6155 --- /dev/null +++ b/apps/example/pkg/app/app.go @@ -0,0 +1,143 @@ +package app + +import ( + "fmt" + "log/slog" + "os" + + "github.com/grafana/grafana-app-sdk/app" + "github.com/grafana/grafana-app-sdk/k8s" + "github.com/grafana/grafana-app-sdk/logging" + "github.com/grafana/grafana-app-sdk/operator" + "github.com/grafana/grafana-app-sdk/resource" + "github.com/grafana/grafana-app-sdk/simple" + "k8s.io/apimachinery/pkg/runtime/schema" + + examplev0alpha1 "github.com/grafana/grafana/apps/example/pkg/apis/example/v0alpha1" + examplev1alpha1 "github.com/grafana/grafana/apps/example/pkg/apis/example/v1alpha1" +) + +// New creates a new instance of the Example App. It gets called after the app's APIs have been registered, +// and is used for routing non-storage API requests, admission control, conversion, and can run +// reconcilers on kinds. +func New(cfg app.Config) (app.App, error) { + // APIPath needs to be set to `/apis`, as it defaults to empty + cfg.KubeConfig.APIPath = "/apis" + // We create a client to work with our Example kind in our reconciler + client, err := k8s.NewClientRegistry(cfg.KubeConfig, k8s.DefaultClientConfig()).ClientFor(examplev1alpha1.ExampleKind()) + if err != nil { + return nil, fmt.Errorf("unable to create example client: %w", err) + } + var reconciler operator.Reconciler + exampleConfig, ok := cfg.SpecificConfig.(*ExampleConfig) + if ok && exampleConfig.EnableReconciler { + reconciler = NewExampleReconciler(client) + // Set the default logger if the reconciler is enabled--this should be done in grafana's API server handling instead, + // and will be corrected in a future PR + logging.DefaultLogger = logging.NewSLogLogger(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{ + Level: slog.LevelDebug, // Temporarily hardcoded to debug for the example + })) + } + + // This is the configuration for our App. + simpleConfig := simple.AppConfig{ + Name: "example", + KubeConfig: cfg.KubeConfig, + // ManagedKinds is the list of all kinds our app manages (the kinds owned by our app). + // Here, a Kind is defined as a distinct Group, Version, and Kind combination, + // so for each version of our Example kind, we need to add it to this list. + // Each kind can also have admission control attached to it--different versions can have different admission control attached. + // Handlers for custom routes defined in the manifest for the kind go here--this is where they actuall get routed, + // they are only defined in the manifest. + // Reconcilers and/or Watchers are also attached here, though they should only be attached to a single version per kind. + ManagedKinds: []simple.AppManagedKind{ + { + Kind: examplev0alpha1.ExampleKind(), + // Validator is run on ingress and is it returns an error the request is rejected + Validator: NewValidator(), + // Mutator is run on ingress and makes changes to the input object + Mutator: NewMutator(), + }, + { + Kind: examplev1alpha1.ExampleKind(), + // We only want the reconciler on one version of our kind, and it's usually best to use the latest + // We'll receive events for every example object, regardless of version used in the API, + // it will convert them to the version used for the reconciler. + Reconciler: reconciler, + // By default, reconcilers for ManagedKinds are wrapped in + ReconcileOptions: simple.BasicReconcileOptions{ + // Namespace is the namespace your reconciler will watch. + // It defaults to all, so this isn't necessary to specify the way we do here. + Namespace: resource.NamespaceAll, + // We can optionally filter our reconciler to only get events for Example resources which + // satisfy the following label filters + // LabelFilters: []string{"foo=bar"}, + // By default, reconcilers for ManagedKinds are wrapped in the app-sdk's OpinionatedReconciler. + // To turn this functionality off, you can set UsePlain to false + // UsePlain: true, + }, + // Validator is run on ingress and is it returns an error the request is rejected + Validator: NewValidator(), + // Mutator is run on ingress and makes changes to the input object + Mutator: NewMutator(), + // We defined this route in our CUE, but we need to actually define the HTTP handler for it. + CustomRoutes: simple.AppCustomRouteHandlers{ + { + Path: "foo", + Method: "GET", + }: ExampleGetFooHandler, + }, + }, + }, + // Conversion for kinds is defined for all versions of a kind at once. + // This interface may change in the future, see https://github.com/grafana/grafana-app-sdk/issues/617 + Converters: map[schema.GroupKind]simple.Converter{ + { + Group: cfg.ManifestData.Group, + Kind: examplev0alpha1.ExampleKind().Kind(), + }: NewExampleConverter(), + }, + // VersionedCustomRoutes are the custom route handlers for routes defined at the version level of the manifest + // instead of for a specific kind. This are sometimes referred to as "resource routes" + // (as opposed to "subresource routes" which are attached to kinds). + VersionedCustomRoutes: map[string]simple.AppVersionRouteHandlers{ + "v1alpha1": { + { + Namespaced: true, + Path: "something", + Method: "GET", + }: GetSomethingHandler, + { + Namespaced: false, + Path: "other", + Method: "GET", + }: GetOtherHandler, + }, + }, + } + + a, err := simple.NewApp(simpleConfig) + if err != nil { + return nil, err + } + + // This makes it easier to catch problems at startup, rather than when something doesn't behave as expected. + // ValidateManifest will ensure that the capabilities you define in your simple.AppConfig + // match the capabilities described in the AppManifest. + err = a.ValidateManifest(cfg.ManifestData) + if err != nil { + return nil, err + } + + return a, nil +} + +func GetKinds() map[schema.GroupVersion][]resource.Kind { + gv := schema.GroupVersion{ + Group: examplev1alpha1.ExampleKind().Group(), + Version: examplev1alpha1.ExampleKind().Version(), + } + return map[schema.GroupVersion][]resource.Kind{ + gv: {examplev1alpha1.ExampleKind()}, + } +} diff --git a/apps/example/pkg/app/authorizer.go b/apps/example/pkg/app/authorizer.go new file mode 100644 index 00000000000..1848d47898b --- /dev/null +++ b/apps/example/pkg/app/authorizer.go @@ -0,0 +1,55 @@ +package app + +import ( + "context" + "fmt" + "regexp" + + "k8s.io/apiserver/pkg/authorization/authorizer" + + "github.com/grafana/grafana/apps/example/pkg/apis/example/v1alpha1" + "github.com/grafana/grafana/pkg/apimachinery/identity" +) + +var namespacedSomethingRouteMatcher = regexp.MustCompile(fmt.Sprintf(`^/apis/%s/%s/namespaces/([^\/]+)/something$`, v1alpha1.APIGroup, v1alpha1.APIVersion)) + +// GetAuthorizer returns an authorizer for all kinds managed by the example app. +// It must be added to the installer in pkg/registry/apps/example/register.go to be used +func GetAuthorizer() authorizer.Authorizer { + return authorizer.AuthorizerFunc( + func(ctx context.Context, attr authorizer.Attributes) (authorizer.Decision, string, error) { + if !attr.IsResourceRequest() { + return authorizer.DecisionNoOpinion, "", nil + } + + // require a user + u, err := identity.GetRequester(ctx) + if err != nil { + return authorizer.DecisionDeny, "valid user is required", err + } + + // check if is admin + if u.GetIsGrafanaAdmin() { + return authorizer.DecisionAllow, "", nil + } + + // Only allow admins to call the custom subresource + if attr.GetSubresource() == "custom" { + return authorizer.DecisionDeny, "forbidden", nil + } + + // Only allow admins to call the namespaced and cluster routes + // There's no easy way to check that from attrs like with GetSubresource(), + // so we look at the full path and check + if namespacedSomethingRouteMatcher.MatchString(attr.GetPath()) { + return authorizer.DecisionDeny, "forbidden", nil + } + if attr.GetPath() == fmt.Sprintf("/apis/%s/%s/other", v1alpha1.APIGroup, v1alpha1.APIVersion) { + return authorizer.DecisionDeny, "forbidden", nil + } + + // Otherwise, allow + return authorizer.DecisionAllow, "", nil + }, + ) +} diff --git a/apps/example/pkg/app/config.go b/apps/example/pkg/app/config.go new file mode 100644 index 00000000000..bbbedf54202 --- /dev/null +++ b/apps/example/pkg/app/config.go @@ -0,0 +1,7 @@ +package app + +// ExampleConfig is an example app-specific config type +type ExampleConfig struct { + EnableReconciler bool + EnableSomeFeature bool +} diff --git a/apps/example/pkg/app/conversion.go b/apps/example/pkg/app/conversion.go new file mode 100644 index 00000000000..1bd7f6addd9 --- /dev/null +++ b/apps/example/pkg/app/conversion.go @@ -0,0 +1,126 @@ +package app + +import ( + "bytes" + "errors" + "fmt" + "strconv" + + "github.com/grafana/grafana-app-sdk/k8s" + "github.com/grafana/grafana-app-sdk/resource" + "github.com/grafana/grafana-app-sdk/simple" + "github.com/grafana/grafana/apps/example/pkg/apis/example/v0alpha1" + "github.com/grafana/grafana/apps/example/pkg/apis/example/v1alpha1" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +var _ simple.Converter = NewExampleConverter() + +type ExampleConverter struct{} + +func NewExampleConverter() *ExampleConverter { + return &ExampleConverter{} +} + +// Convert converts an object from an arbitrary input version slice of bytes +// to a target version, and returns the JSON bytes of that version. +func (e *ExampleConverter) Convert(obj k8s.RawKind, targetAPIVersion string) ([]byte, error) { + srcGVK := schema.FromAPIVersionAndKind(obj.APIVersion, obj.Kind) + dstGVK := schema.FromAPIVersionAndKind(targetAPIVersion, v1alpha1.ExampleKind().Kind()) + if srcGVK.Group != v1alpha1.APIGroup { + // This should never happen, but check just in case + return nil, fmt.Errorf("wrong group to convert example.grafana.app, got %s", srcGVK.Group) + } + if srcGVK.Kind != v1alpha1.ExampleKind().Kind() { + // This should also never happen, but check just in case + return nil, fmt.Errorf("wrong kind to convert Example, got %s", srcGVK.Kind) + } + if srcGVK == dstGVK { + // This should never happen, but if it does no conversion is necessary, we can return the input + return obj.Raw, nil + } + + // Check source version + switch srcGVK.Version { + case v0alpha1.APIVersion: + srcKind := v0alpha1.ExampleKind() + uncastSrcObj, err := srcKind.Read(bytes.NewReader(obj.Raw), resource.KindEncodingJSON) + if err != nil { + return nil, fmt.Errorf("unable to parse JSON bytes into %s: %w", srcGVK.String(), err) + } + srcObj, ok := uncastSrcObj.(*v0alpha1.Example) + if !ok { + return nil, errors.New("read object was not of type *v0alpha1.Example") + } + switch dstGVK.Version { + case v1alpha1.APIVersion: + dstObj := &v1alpha1.Example{} + // Set Type metadata + dstObj.SetGroupVersionKind(dstGVK) + // Copy Object metadata + srcObj.ObjectMeta.DeepCopyInto(&dstObj.ObjectMeta) + // Copy spec and status + dstObj.Spec.FirstField = strconv.Itoa(int(srcObj.Spec.FirstField)) + dstObj.Status.LastObservedGeneration = srcObj.Status.LastObservedGeneration + dstObj.Status.AdditionalFields = srcObj.Status.AdditionalFields + if srcObj.Status.OperatorStates != nil { + dstObj.Status.OperatorStates = make(map[string]v1alpha1.ExamplestatusOperatorState) + for k, v := range srcObj.Status.OperatorStates { + dstObj.Status.OperatorStates[k] = v1alpha1.ExamplestatusOperatorState{ + LastEvaluation: v.LastEvaluation, + State: v1alpha1.ExampleStatusOperatorStateState(v.State), + DescriptiveState: v.DescriptiveState, + Details: v.Details, + } + } + } + dstKind := v1alpha1.ExampleKind() + buf := &bytes.Buffer{} + err := dstKind.Write(dstObj, buf, resource.KindEncodingJSON) + return buf.Bytes(), err + default: + return nil, fmt.Errorf("unknown target version %s", dstGVK.Version) + } + case v1alpha1.APIVersion: + srcKind := v1alpha1.ExampleKind() + uncastSrcObj, err := srcKind.Read(bytes.NewReader(obj.Raw), resource.KindEncodingJSON) + if err != nil { + return nil, fmt.Errorf("unable to parse JSON bytes into %s: %w", srcGVK.String(), err) + } + srcObj, ok := uncastSrcObj.(*v1alpha1.Example) + if !ok { + return nil, errors.New("read object was not of type *v1alpha1.Example") + } + switch dstGVK.Version { + case v0alpha1.APIVersion: + dstObj := &v0alpha1.Example{} + // Set Type metadata + dstObj.SetGroupVersionKind(dstGVK) + // Copy Object metadata + srcObj.ObjectMeta.DeepCopyInto(&dstObj.ObjectMeta) + // Copy spec and status + castInt, _ := strconv.Atoi(srcObj.Spec.FirstField) // Lossy backwards conversion + dstObj.Spec.FirstField = int64(castInt) + dstObj.Status.LastObservedGeneration = srcObj.Status.LastObservedGeneration + dstObj.Status.AdditionalFields = srcObj.Status.AdditionalFields + if srcObj.Status.OperatorStates != nil { + dstObj.Status.OperatorStates = make(map[string]v0alpha1.ExamplestatusOperatorState) + for k, v := range srcObj.Status.OperatorStates { + dstObj.Status.OperatorStates[k] = v0alpha1.ExamplestatusOperatorState{ + LastEvaluation: v.LastEvaluation, + State: v0alpha1.ExampleStatusOperatorStateState(v.State), + DescriptiveState: v.DescriptiveState, + Details: v.Details, + } + } + } + dstKind := v0alpha1.ExampleKind() + buf := &bytes.Buffer{} + err := dstKind.Write(dstObj, buf, resource.KindEncodingJSON) + return buf.Bytes(), err + default: + return nil, fmt.Errorf("unknown target version %s", dstGVK.Version) + } + } + return nil, fmt.Errorf("unknown source version %s", srcGVK.Version) +} diff --git a/apps/example/pkg/app/mutation.go b/apps/example/pkg/app/mutation.go new file mode 100644 index 00000000000..a04c2b9f312 --- /dev/null +++ b/apps/example/pkg/app/mutation.go @@ -0,0 +1,31 @@ +package app + +import ( + "context" + + "github.com/grafana/grafana-app-sdk/app" + "github.com/grafana/grafana-app-sdk/simple" +) + +var _ simple.KindMutator = NewMutator() + +type Mutator struct{} + +func NewMutator() *Mutator { + return &Mutator{} +} + +// Mutate makes modifications to an input object from the API, and returns the changed object. +// This mutation will be done on every request, so it can be used to add or update things like labels +// or annotations. Here, we add an annotation noting the last resourceVersion this was called for. +func (m *Mutator) Mutate(ctx context.Context, req *app.AdmissionRequest) (*app.MutatingResponse, error) { + annotations := req.Object.GetAnnotations() + if annotations == nil { + annotations = make(map[string]string) + } + annotations["example.grafana.app/mutated"] = req.Object.GetResourceVersion() + req.Object.SetAnnotations(annotations) + return &app.MutatingResponse{ + UpdatedObject: req.Object, + }, nil +} diff --git a/apps/example/pkg/app/reconciler.go b/apps/example/pkg/app/reconciler.go new file mode 100644 index 00000000000..66399c62bf8 --- /dev/null +++ b/apps/example/pkg/app/reconciler.go @@ -0,0 +1,58 @@ +package app + +import ( + "context" + + "github.com/grafana/grafana-app-sdk/logging" + "github.com/grafana/grafana-app-sdk/operator" + "github.com/grafana/grafana-app-sdk/resource" + "github.com/grafana/grafana/apps/example/pkg/apis/example/v1alpha1" +) + +// ExampleReconciler wraps TypedReconciler to simplify some of our reconciliation logic, +// as TypedReconciler will handle type checking of the input object for us. +type ExampleReconciler struct { + operator.TypedReconciler[*v1alpha1.Example] + client resource.Client +} + +func NewExampleReconciler(client resource.Client) *ExampleReconciler { + reconciler := ExampleReconciler{ + TypedReconciler: operator.TypedReconciler[*v1alpha1.Example]{}, + client: client, + } + reconciler.ReconcileFunc = reconciler.doReconcile + return &reconciler +} + +// doReconcile is the main reconciliation loop for our app's Example reconciler. +// All it does is print a log message and then update the last observed generation in the status +// (if the request is a DELETE, it doesn't try to update the status, as the update would fail). +func (e *ExampleReconciler) doReconcile(ctx context.Context, req operator.TypedReconcileRequest[*v1alpha1.Example]) (operator.ReconcileResult, error) { + if req.Object.GetGeneration() == req.Object.Status.LastObservedGeneration { + // Skip if we've already processed this spec + return operator.ReconcileResult{}, nil + } + + logging.FromContext(ctx).Info("reconciling example", "name", req.Object.GetName(), "namespace", req.Object.GetNamespace(), "action", operator.ResourceActionFromReconcileAction(req.Action)) + + // If this is a delete, we don't need to do anything + if req.Action == operator.ReconcileActionDeleted { + return operator.ReconcileResult{}, nil + } + + // Update the status. + // We use resource.UpdateObject here to handle conflicts when doing the update, + // as it gets the current state, performs our update function, then pushes to the remote + _, err := resource.UpdateObject(ctx, e.client, req.Object.GetStaticMetadata().Identifier(), func(obj *v1alpha1.Example, _ bool) (*v1alpha1.Example, error) { + obj.Status.LastObservedGeneration = req.Object.GetGeneration() + return obj, nil + }, resource.UpdateOptions{ + Subresource: "status", + }) + if err != nil { + return operator.ReconcileResult{}, err + } + + return operator.ReconcileResult{}, nil +} diff --git a/apps/example/pkg/app/routes.go b/apps/example/pkg/app/routes.go new file mode 100644 index 00000000000..eb9206b0ce3 --- /dev/null +++ b/apps/example/pkg/app/routes.go @@ -0,0 +1,50 @@ +package app + +import ( + "context" + "encoding/json" + "fmt" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/grafana/grafana-app-sdk/app" + "github.com/grafana/grafana/apps/example/pkg/apis/example/v1alpha1" +) + +// ExampleGetFooHandler handles requests for the GET /foo subresource route +func ExampleGetFooHandler(ctx context.Context, writer app.CustomRouteResponseWriter, request *app.CustomRouteRequest) error { + message := "Hello, world!" + return json.NewEncoder(writer).Encode(v1alpha1.GetFoo{ + GetFooBody: v1alpha1.GetFooBody{ + Message: message, + }, + }) +} + +// GetSomethingHandler handles requests for the GET /something resource route +func GetSomethingHandler(ctx context.Context, writer app.CustomRouteResponseWriter, request *app.CustomRouteRequest) error { + message := "This is a namespaced route" + if request.URL.Query().Has("message") { + message = request.URL.Query().Get("message") + } + return json.NewEncoder(writer).Encode(v1alpha1.GetSomething{ + TypeMeta: metav1.TypeMeta{ + APIVersion: fmt.Sprintf("%s/%s", v1alpha1.APIGroup, v1alpha1.APIVersion), + }, + GetSomethingBody: v1alpha1.GetSomethingBody{ + Namespace: request.ResourceIdentifier.Namespace, + Message: message, + }, + }) +} + +// GetOtherHandler handles requests for the GET /other cluster-scoped resource route +func GetOtherHandler(ctx context.Context, writer app.CustomRouteResponseWriter, request *app.CustomRouteRequest) error { + message := "This is a cluster route" + if request.URL.Query().Has("message") { + message = request.URL.Query().Get("message") + } + return json.NewEncoder(writer).Encode(v1alpha1.GetOther{ + Message: message, + }) +} diff --git a/apps/example/pkg/app/validation.go b/apps/example/pkg/app/validation.go new file mode 100644 index 00000000000..74dad42f9ca --- /dev/null +++ b/apps/example/pkg/app/validation.go @@ -0,0 +1,28 @@ +package app + +import ( + "context" + "errors" + + "github.com/grafana/grafana-app-sdk/app" + "github.com/grafana/grafana-app-sdk/simple" +) + +var _ simple.KindValidator = NewValidator() + +// Validator implements simple.KindValidator +type Validator struct{} + +func NewValidator() *Validator { + return &Validator{} +} + +// Validate runs any kind of validation on incoming objects, +// and returns an error to reject the request. +// Here, we just reject any Example resource which is named "invalid" +func (v *Validator) Validate(ctx context.Context, req *app.AdmissionRequest) error { + if req.Object.GetName() == "invalid" { + return errors.New("example cannot be named 'invalid'") + } + return nil +} diff --git a/apps/example/plugin/src/generated/example/v0alpha1/example_object_gen.ts b/apps/example/plugin/src/generated/example/v0alpha1/example_object_gen.ts new file mode 100644 index 00000000000..dd344a9b8b2 --- /dev/null +++ b/apps/example/plugin/src/generated/example/v0alpha1/example_object_gen.ts @@ -0,0 +1,49 @@ +/* + * This file was generated by grafana-app-sdk. DO NOT EDIT. + */ +import { Spec } from './types.spec.gen'; +import { Status } from './types.status.gen'; + +export interface Metadata { + name: string; + namespace: string; + generateName?: string; + selfLink?: string; + uid?: string; + resourceVersion?: string; + generation?: number; + creationTimestamp?: string; + deletionTimestamp?: string; + deletionGracePeriodSeconds?: number; + labels?: Record; + annotations?: Record; + ownerReferences?: OwnerReference[]; + finalizers?: string[]; + managedFields?: ManagedFieldsEntry[]; +} + +export interface OwnerReference { + apiVersion: string; + kind: string; + name: string; + uid: string; + controller?: boolean; + blockOwnerDeletion?: boolean; +} + +export interface ManagedFieldsEntry { + manager?: string; + operation?: string; + apiVersion?: string; + time?: string; + fieldsType?: string; + subresource?: string; +} + +export interface Example { + kind: string; + apiVersion: string; + metadata: Metadata; + spec: Spec; + status: Status; +} diff --git a/apps/example/plugin/src/generated/example/v0alpha1/types.metadata.gen.ts b/apps/example/plugin/src/generated/example/v0alpha1/types.metadata.gen.ts new file mode 100644 index 00000000000..4377f3c1d08 --- /dev/null +++ b/apps/example/plugin/src/generated/example/v0alpha1/types.metadata.gen.ts @@ -0,0 +1,30 @@ +// Code generated - EDITING IS FUTILE. DO NOT EDIT. + +// metadata contains embedded CommonMetadata and can be extended with custom string fields +// TODO: use CommonMetadata instead of redefining here; currently needs to be defined here +// without external reference as using the CommonMetadata reference breaks thema codegen. +export interface Metadata { + updateTimestamp: string; + createdBy: string; + uid: string; + creationTimestamp: string; + deletionTimestamp?: string; + finalizers: string[]; + resourceVersion: string; + generation: number; + updatedBy: string; + labels: Record; +} + +export const defaultMetadata = (): Metadata => ({ + updateTimestamp: "", + createdBy: "", + uid: "", + creationTimestamp: "", + finalizers: [], + resourceVersion: "", + generation: 0, + updatedBy: "", + labels: {}, +}); + diff --git a/apps/example/plugin/src/generated/example/v0alpha1/types.spec.gen.ts b/apps/example/plugin/src/generated/example/v0alpha1/types.spec.gen.ts new file mode 100644 index 00000000000..aee6e7ddc96 --- /dev/null +++ b/apps/example/plugin/src/generated/example/v0alpha1/types.spec.gen.ts @@ -0,0 +1,11 @@ +// Code generated - EDITING IS FUTILE. DO NOT EDIT. + +// Spec is the schema of our resource. The spec should include all the user-editable information for the kind. +export interface Spec { + firstField: number; +} + +export const defaultSpec = (): Spec => ({ + firstField: 0, +}); + diff --git a/apps/example/plugin/src/generated/example/v0alpha1/types.status.gen.ts b/apps/example/plugin/src/generated/example/v0alpha1/types.status.gen.ts new file mode 100644 index 00000000000..2b1c7ecb645 --- /dev/null +++ b/apps/example/plugin/src/generated/example/v0alpha1/types.status.gen.ts @@ -0,0 +1,32 @@ +// Code generated - EDITING IS FUTILE. DO NOT EDIT. + +export interface OperatorState { + // lastEvaluation is the ResourceVersion last evaluated + lastEvaluation: string; + // state describes the state of the lastEvaluation. + // It is limited to three possible states for machine evaluation. + state: "success" | "in_progress" | "failed"; + // descriptiveState is an optional more descriptive state field which has no requirements on format + descriptiveState?: string; + // details contains any extra information that is operator-specific + details?: Record; +} + +export const defaultOperatorState = (): OperatorState => ({ + lastEvaluation: "", + state: "success", +}); + +export interface Status { + lastObservedGeneration: number; + // operatorStates is a map of operator ID to operator state evaluations. + // Any operator which consumes this kind SHOULD add its state evaluation information to this field. + operatorStates?: Record; + // additionalFields is reserved for future use + additionalFields?: Record; +} + +export const defaultStatus = (): Status => ({ + lastObservedGeneration: 0, +}); + diff --git a/apps/example/plugin/src/generated/example/v1alpha1/example_object_gen.ts b/apps/example/plugin/src/generated/example/v1alpha1/example_object_gen.ts new file mode 100644 index 00000000000..1d45847ce0f --- /dev/null +++ b/apps/example/plugin/src/generated/example/v1alpha1/example_object_gen.ts @@ -0,0 +1,51 @@ +/* + * This file was generated by grafana-app-sdk. DO NOT EDIT. + */ +import { Spec } from './types.spec.gen'; +import { Status } from './types.status.gen'; +import { Custom } from './types.custom.gen'; + +export interface Metadata { + name: string; + namespace: string; + generateName?: string; + selfLink?: string; + uid?: string; + resourceVersion?: string; + generation?: number; + creationTimestamp?: string; + deletionTimestamp?: string; + deletionGracePeriodSeconds?: number; + labels?: Record; + annotations?: Record; + ownerReferences?: OwnerReference[]; + finalizers?: string[]; + managedFields?: ManagedFieldsEntry[]; +} + +export interface OwnerReference { + apiVersion: string; + kind: string; + name: string; + uid: string; + controller?: boolean; + blockOwnerDeletion?: boolean; +} + +export interface ManagedFieldsEntry { + manager?: string; + operation?: string; + apiVersion?: string; + time?: string; + fieldsType?: string; + subresource?: string; +} + +export interface Example { + kind: string; + apiVersion: string; + metadata: Metadata; + spec: Spec; + status: Status; + custom: Custom; +} diff --git a/apps/example/plugin/src/generated/example/v1alpha1/types.custom.gen.ts b/apps/example/plugin/src/generated/example/v1alpha1/types.custom.gen.ts new file mode 100644 index 00000000000..5de21c36556 --- /dev/null +++ b/apps/example/plugin/src/generated/example/v1alpha1/types.custom.gen.ts @@ -0,0 +1,21 @@ +// Code generated - EDITING IS FUTILE. DO NOT EDIT. + +// Custom is a subresource that will be stored the same way status is stored, +// and requires using the /custom route to update. +// Its content is returned as part of a GET to the resource itself, just like with status. +// To route a subresource to an arbitrary handler, use the 'routes' field instead (see below). +// metadata if where kind- and schema-specific metadata goes. This is converted into typed annotations +// with getters and setters by the code generation. +// metadata: { +// kindSpecificField: string +// } +export interface Custom { + myField: string; + otherField: string; +} + +export const defaultCustom = (): Custom => ({ + myField: "", + otherField: "", +}); + diff --git a/apps/example/plugin/src/generated/example/v1alpha1/types.metadata.gen.ts b/apps/example/plugin/src/generated/example/v1alpha1/types.metadata.gen.ts new file mode 100644 index 00000000000..4377f3c1d08 --- /dev/null +++ b/apps/example/plugin/src/generated/example/v1alpha1/types.metadata.gen.ts @@ -0,0 +1,30 @@ +// Code generated - EDITING IS FUTILE. DO NOT EDIT. + +// metadata contains embedded CommonMetadata and can be extended with custom string fields +// TODO: use CommonMetadata instead of redefining here; currently needs to be defined here +// without external reference as using the CommonMetadata reference breaks thema codegen. +export interface Metadata { + updateTimestamp: string; + createdBy: string; + uid: string; + creationTimestamp: string; + deletionTimestamp?: string; + finalizers: string[]; + resourceVersion: string; + generation: number; + updatedBy: string; + labels: Record; +} + +export const defaultMetadata = (): Metadata => ({ + updateTimestamp: "", + createdBy: "", + uid: "", + creationTimestamp: "", + finalizers: [], + resourceVersion: "", + generation: 0, + updatedBy: "", + labels: {}, +}); + diff --git a/apps/example/plugin/src/generated/example/v1alpha1/types.routes.gen.ts b/apps/example/plugin/src/generated/example/v1alpha1/types.routes.gen.ts new file mode 100644 index 00000000000..145a7070c14 --- /dev/null +++ b/apps/example/plugin/src/generated/example/v1alpha1/types.routes.gen.ts @@ -0,0 +1,35 @@ +// Code generated - EDITING IS FUTILE. DO NOT EDIT. + +// routes contains subresource routes for the kind, which are exposed as HTTP handlers on `examples//`. +// This allows you to add additional non-storage-based handlers to your kind. +// These should only be used if the behavior cannot be accomplished by reconciliation on storage events. +export interface Routes { + // This will add a handler for /foo on the resource + foo: { + // GET request handler. A subresource route can have multiple methods attached to it. + // Allowed values are GET, POST, PUT, DELETE, PATCH, HEAD, and OPTIONS + GET: { + // The response type for the GET /foo method. + // This will generate a go type, and will also be used for the OpenAPI definition for the route. + response: { + message: string; + }; + request: { + message?: string; + }; + }; + }; +} + +export const defaultRoutes = (): Routes => ({ + foo: { + GET: { + response: { + message: "", +}, + request: { +}, +}, +}, +}); + diff --git a/apps/example/plugin/src/generated/example/v1alpha1/types.spec.gen.ts b/apps/example/plugin/src/generated/example/v1alpha1/types.spec.gen.ts new file mode 100644 index 00000000000..1a490c64cc7 --- /dev/null +++ b/apps/example/plugin/src/generated/example/v1alpha1/types.spec.gen.ts @@ -0,0 +1,30 @@ +// Code generated - EDITING IS FUTILE. DO NOT EDIT. + +// #DefinedType is a re-usable definition for us to use in our schema. +// Fields leading with # are definitions in CUE and won't be included in the generated types. +export interface DefinedType { + // Info is information about this entry. This comment, like all comments + // on fields or definitions, will be copied into the generated types as well. + info: string; + // Next is an optional next element in the DefinedType, allowing for a self-referential + // linked-list like structure. The ? in the field makes this optional. + next?: DefinedType; +} + +export const defaultDefinedType = (): DefinedType => ({ + info: "", +}); + +// Spec is the schema of our resource. The spec should include all the user-editable information for the kind. +export interface Spec { + // Example fields + firstField: string; + secondField: number; + list?: DefinedType; +} + +export const defaultSpec = (): Spec => ({ + firstField: "", + secondField: 0, +}); + diff --git a/apps/example/plugin/src/generated/example/v1alpha1/types.status.gen.ts b/apps/example/plugin/src/generated/example/v1alpha1/types.status.gen.ts new file mode 100644 index 00000000000..712de3d9076 --- /dev/null +++ b/apps/example/plugin/src/generated/example/v1alpha1/types.status.gen.ts @@ -0,0 +1,35 @@ +// Code generated - EDITING IS FUTILE. DO NOT EDIT. + +export interface OperatorState { + // lastEvaluation is the ResourceVersion last evaluated + lastEvaluation: string; + // state describes the state of the lastEvaluation. + // It is limited to three possible states for machine evaluation. + state: "success" | "in_progress" | "failed"; + // descriptiveState is an optional more descriptive state field which has no requirements on format + descriptiveState?: string; + // details contains any extra information that is operator-specific + details?: Record; +} + +export const defaultOperatorState = (): OperatorState => ({ + lastEvaluation: "", + state: "success", +}); + +// status is where state and status information which may be used or updated by the operator or back-end should be placed +// If you do not have any such information, you do not need to include this field, +// however, as mentioned above, certain fields will be added by the kind system regardless. +export interface Status { + lastObservedGeneration: number; + // operatorStates is a map of operator ID to operator state evaluations. + // Any operator which consumes this kind SHOULD add its state evaluation information to this field. + operatorStates?: Record; + // additionalFields is reserved for future use + additionalFields?: Record; +} + +export const defaultStatus = (): Status => ({ + lastObservedGeneration: 0, +}); + diff --git a/apps/example/plugin/src/generated/examplekind/v1alpha1/examplekind_object_gen.ts b/apps/example/plugin/src/generated/examplekind/v1alpha1/examplekind_object_gen.ts new file mode 100644 index 00000000000..c77f8842a68 --- /dev/null +++ b/apps/example/plugin/src/generated/examplekind/v1alpha1/examplekind_object_gen.ts @@ -0,0 +1,49 @@ +/* + * This file was generated by grafana-app-sdk. DO NOT EDIT. + */ +import { Spec } from './types.spec.gen'; +import { Status } from './types.status.gen'; + +export interface Metadata { + name: string; + namespace: string; + generateName?: string; + selfLink?: string; + uid?: string; + resourceVersion?: string; + generation?: number; + creationTimestamp?: string; + deletionTimestamp?: string; + deletionGracePeriodSeconds?: number; + labels?: Record; + annotations?: Record; + ownerReferences?: OwnerReference[]; + finalizers?: string[]; + managedFields?: ManagedFieldsEntry[]; +} + +export interface OwnerReference { + apiVersion: string; + kind: string; + name: string; + uid: string; + controller?: boolean; + blockOwnerDeletion?: boolean; +} + +export interface ManagedFieldsEntry { + manager?: string; + operation?: string; + apiVersion?: string; + time?: string; + fieldsType?: string; + subresource?: string; +} + +export interface ExampleKind { + kind: string; + apiVersion: string; + metadata: Metadata; + spec: Spec; + status: Status; +} diff --git a/apps/example/plugin/src/generated/examplekind/v1alpha1/types.metadata.gen.ts b/apps/example/plugin/src/generated/examplekind/v1alpha1/types.metadata.gen.ts new file mode 100644 index 00000000000..4377f3c1d08 --- /dev/null +++ b/apps/example/plugin/src/generated/examplekind/v1alpha1/types.metadata.gen.ts @@ -0,0 +1,30 @@ +// Code generated - EDITING IS FUTILE. DO NOT EDIT. + +// metadata contains embedded CommonMetadata and can be extended with custom string fields +// TODO: use CommonMetadata instead of redefining here; currently needs to be defined here +// without external reference as using the CommonMetadata reference breaks thema codegen. +export interface Metadata { + updateTimestamp: string; + createdBy: string; + uid: string; + creationTimestamp: string; + deletionTimestamp?: string; + finalizers: string[]; + resourceVersion: string; + generation: number; + updatedBy: string; + labels: Record; +} + +export const defaultMetadata = (): Metadata => ({ + updateTimestamp: "", + createdBy: "", + uid: "", + creationTimestamp: "", + finalizers: [], + resourceVersion: "", + generation: 0, + updatedBy: "", + labels: {}, +}); + diff --git a/apps/example/plugin/src/generated/examplekind/v1alpha1/types.spec.gen.ts b/apps/example/plugin/src/generated/examplekind/v1alpha1/types.spec.gen.ts new file mode 100644 index 00000000000..adc7830a1ac --- /dev/null +++ b/apps/example/plugin/src/generated/examplekind/v1alpha1/types.spec.gen.ts @@ -0,0 +1,25 @@ +// Code generated - EDITING IS FUTILE. DO NOT EDIT. + +// spec is the schema of our resource. The spec should include all the user-editable information for the kind. +// status is where state and status information which may be used or updated by the operator or back-end should be placed +// If you do not have any such information, you do not need to include this field, +// however, as mentioned above, certain fields will be added by the kind system regardless. +// status: { +// currentState: string +// } +// metadata if where kind- and schema-specific metadata goes. This is converted into typed annotations +// with getters and setters by the code generation. +// metadata: { +// kindSpecificField: string +// } +export interface Spec { + // Example fields + firstField: string; + secondField: number; +} + +export const defaultSpec = (): Spec => ({ + firstField: "", + secondField: 0, +}); + diff --git a/apps/example/plugin/src/generated/examplekind/v1alpha1/types.status.gen.ts b/apps/example/plugin/src/generated/examplekind/v1alpha1/types.status.gen.ts new file mode 100644 index 00000000000..01be8df7961 --- /dev/null +++ b/apps/example/plugin/src/generated/examplekind/v1alpha1/types.status.gen.ts @@ -0,0 +1,30 @@ +// Code generated - EDITING IS FUTILE. DO NOT EDIT. + +export interface OperatorState { + // lastEvaluation is the ResourceVersion last evaluated + lastEvaluation: string; + // state describes the state of the lastEvaluation. + // It is limited to three possible states for machine evaluation. + state: "success" | "in_progress" | "failed"; + // descriptiveState is an optional more descriptive state field which has no requirements on format + descriptiveState?: string; + // details contains any extra information that is operator-specific + details?: Record; +} + +export const defaultOperatorState = (): OperatorState => ({ + lastEvaluation: "", + state: "success", +}); + +export interface Status { + // operatorStates is a map of operator ID to operator state evaluations. + // Any operator which consumes this kind SHOULD add its state evaluation information to this field. + operatorStates?: Record; + // additionalFields is reserved for future use + additionalFields?: Record; +} + +export const defaultStatus = (): Status => ({ +}); + diff --git a/go.work b/go.work index 1b60b90eae9..3fa612c2fce 100644 --- a/go.work +++ b/go.work @@ -11,6 +11,7 @@ use ( ./apps/alerting/rules ./apps/correlations ./apps/dashboard + ./apps/example ./apps/folder ./apps/iam ./apps/investigations diff --git a/pkg/extensions/enterprise_imports.go b/pkg/extensions/enterprise_imports.go index 9c052688d8f..2dbdad4a9d6 100644 --- a/pkg/extensions/enterprise_imports.go +++ b/pkg/extensions/enterprise_imports.go @@ -57,5 +57,4 @@ import ( _ "github.com/grafana/tempo/pkg/traceql" _ "github.com/grafana/grafana/apps/alerting/alertenrichment/pkg/apis/alertenrichment/v1beta1" - _ "github.com/grafana/grafana/apps/scope/pkg/apis/scope/v0alpha1" ) diff --git a/pkg/registry/apps/apps.go b/pkg/registry/apps/apps.go index ad28e417e4a..6b48f15d708 100644 --- a/pkg/registry/apps/apps.go +++ b/pkg/registry/apps/apps.go @@ -15,6 +15,7 @@ import ( "github.com/grafana/grafana/pkg/registry/apps/alerting/notifications" "github.com/grafana/grafana/pkg/registry/apps/alerting/rules" "github.com/grafana/grafana/pkg/registry/apps/correlations" + "github.com/grafana/grafana/pkg/registry/apps/example" "github.com/grafana/grafana/pkg/registry/apps/investigations" "github.com/grafana/grafana/pkg/registry/apps/logsdrilldown" "github.com/grafana/grafana/pkg/registry/apps/playlist" @@ -38,10 +39,12 @@ func ProvideAppInstallers( correlationsAppInstaller *correlations.AppInstaller, alertingNotificationAppInstaller *notifications.AlertingNotificationsAppInstaller, logsdrilldownAppInstaller *logsdrilldown.LogsDrilldownAppInstaller, + exampleAppInstaller *example.ExampleAppInstaller, ) []appsdkapiserver.AppInstaller { installers := []appsdkapiserver.AppInstaller{ playlistAppInstaller, pluginsApplInstaller, + exampleAppInstaller, } //nolint:staticcheck // not yet migrated to OpenFeature if features.IsEnabledGlobally(featuremgmt.FlagKubernetesShortURLs) { diff --git a/pkg/registry/apps/apps_test.go b/pkg/registry/apps/apps_test.go index 83c337636c0..a27819b726b 100644 --- a/pkg/registry/apps/apps_test.go +++ b/pkg/registry/apps/apps_test.go @@ -8,6 +8,7 @@ import ( "github.com/grafana/grafana/pkg/registry/apps/alerting/notifications" "github.com/grafana/grafana/pkg/registry/apps/alerting/rules" "github.com/grafana/grafana/pkg/registry/apps/correlations" + "github.com/grafana/grafana/pkg/registry/apps/example" "github.com/grafana/grafana/pkg/registry/apps/playlist" "github.com/grafana/grafana/pkg/registry/apps/plugins" "github.com/grafana/grafana/pkg/services/featuremgmt" @@ -19,6 +20,7 @@ func TestProvideAppInstallers_Table(t *testing.T) { rulesInstaller := &rules.AlertingRulesAppInstaller{} correlationsAppInstaller := &correlations.AppInstaller{} notificationsAppInstaller := ¬ifications.AlertingNotificationsAppInstaller{} + exampleAppInstaller := &example.ExampleAppInstaller{} tests := []struct { name string @@ -35,7 +37,7 @@ func TestProvideAppInstallers_Table(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { features := featuremgmt.WithFeatures(tt.flags...) - got := ProvideAppInstallers(features, playlistInstaller, pluginsInstaller, nil, tt.rulesInst, correlationsAppInstaller, notificationsAppInstaller, nil) + got := ProvideAppInstallers(features, playlistInstaller, pluginsInstaller, nil, tt.rulesInst, correlationsAppInstaller, notificationsAppInstaller, nil, exampleAppInstaller) if tt.expectRulesApp { require.Contains(t, got, tt.rulesInst) } else { diff --git a/pkg/registry/apps/example/register.go b/pkg/registry/apps/example/register.go new file mode 100644 index 00000000000..1839d97b307 --- /dev/null +++ b/pkg/registry/apps/example/register.go @@ -0,0 +1,80 @@ +package example + +import ( + "fmt" + "strings" + + "k8s.io/apiserver/pkg/authorization/authorizer" + restclient "k8s.io/client-go/rest" + + "github.com/grafana/grafana-app-sdk/app" + appsdkapiserver "github.com/grafana/grafana-app-sdk/k8s/apiserver" + "github.com/grafana/grafana-app-sdk/simple" + "github.com/grafana/grafana/apps/example/pkg/apis" + "github.com/grafana/grafana/apps/example/pkg/apis/example/v1alpha1" + exampleapp "github.com/grafana/grafana/apps/example/pkg/app" + "github.com/grafana/grafana/pkg/services/featuremgmt" + "github.com/grafana/grafana/pkg/setting" +) + +var ( + _ appsdkapiserver.AppInstaller = (*ExampleAppInstaller)(nil) +) + +type ExampleAppInstaller struct { + appsdkapiserver.AppInstaller + cfg *setting.Cfg +} + +func (e ExampleAppInstaller) GetAuthorizer() authorizer.Authorizer { + return exampleapp.GetAuthorizer() +} + +func RegisterAppInstaller( + cfg *setting.Cfg, + features featuremgmt.FeatureToggles, +) (*ExampleAppInstaller, error) { + installer := &ExampleAppInstaller{ + cfg: cfg, + } + // Config specific to the app. This can pull from feature flags or setting.Cfg. + specificConfig := &exampleapp.ExampleConfig{ + EnableSomeFeature: true, + } + + // Set specificConfig.EnableReconciler to true IFF the v1alpha1 API is enabled in the runtime config. + // This is example-app-specific, as the version the reconciler uses is not served by default and must be enabled via an override. + apiserverRuntimeCfg := cfg.SectionWithEnvOverrides("grafana-apiserver").Key("runtime_config").String() + for _, s := range strings.Split(apiserverRuntimeCfg, ",") { + if len(s) == 0 { + continue + } + arr := strings.SplitN(s, "=", 2) + if len(arr) == 2 { + if arr[0] == fmt.Sprintf("%s/%s", v1alpha1.APIGroup, v1alpha1.APIVersion) { + specificConfig.EnableReconciler = strings.EqualFold("true", arr[1]) + break + } + } + } + + // Provider is the app provider, which contains the AppManifest, app-specific-config, and the New function for the app + provider := simple.NewAppProvider(apis.LocalManifest(), specificConfig, exampleapp.New) + + // appConfig is used alongside the provider for registrion. + // Most of the data is redunant, this may be more optimized in the future. + appConfig := app.Config{ + KubeConfig: restclient.Config{}, // this will be overridden by the installer's InitializeApp method + ManifestData: *apis.LocalManifest().ManifestData, + SpecificConfig: specificConfig, + } + // NewDefaultInstaller gets us the installer we need to underly the ExampleAppInstaller type. + // It does all the hard work of installing our app to the grafana API server + i, err := appsdkapiserver.NewDefaultAppInstaller(provider, appConfig, apis.NewGoTypeAssociator()) + if err != nil { + return nil, err + } + installer.AppInstaller = i + + return installer, nil +} diff --git a/pkg/registry/apps/wireset.go b/pkg/registry/apps/wireset.go index b1bedf15ad2..5961b0caf85 100644 --- a/pkg/registry/apps/wireset.go +++ b/pkg/registry/apps/wireset.go @@ -7,6 +7,7 @@ import ( "github.com/grafana/grafana/pkg/registry/apps/alerting/notifications" "github.com/grafana/grafana/pkg/registry/apps/alerting/rules" "github.com/grafana/grafana/pkg/registry/apps/correlations" + "github.com/grafana/grafana/pkg/registry/apps/example" "github.com/grafana/grafana/pkg/registry/apps/investigations" "github.com/grafana/grafana/pkg/registry/apps/logsdrilldown" "github.com/grafana/grafana/pkg/registry/apps/playlist" @@ -26,4 +27,5 @@ var WireSet = wire.NewSet( rules.RegisterAppInstaller, notifications.RegisterAppInstaller, logsdrilldown.RegisterAppInstaller, + example.RegisterAppInstaller, ) diff --git a/pkg/server/wire_gen.go b/pkg/server/wire_gen.go index 62435221671..feed7394400 100644 --- a/pkg/server/wire_gen.go +++ b/pkg/server/wire_gen.go @@ -81,6 +81,7 @@ import ( notifications2 "github.com/grafana/grafana/pkg/registry/apps/alerting/notifications" "github.com/grafana/grafana/pkg/registry/apps/alerting/rules" correlations2 "github.com/grafana/grafana/pkg/registry/apps/correlations" + "github.com/grafana/grafana/pkg/registry/apps/example" "github.com/grafana/grafana/pkg/registry/apps/investigations" "github.com/grafana/grafana/pkg/registry/apps/logsdrilldown" "github.com/grafana/grafana/pkg/registry/apps/playlist" @@ -783,7 +784,11 @@ func Initialize(ctx context.Context, cfg *setting.Cfg, opts Options, apiOpts api if err != nil { return nil, err } - v2 := appregistry.ProvideAppInstallers(featureToggles, playlistAppInstaller, pluginsAppInstaller, shortURLAppInstaller, alertingRulesAppInstaller, appInstaller, alertingNotificationsAppInstaller, logsDrilldownAppInstaller) + exampleAppInstaller, err := example.RegisterAppInstaller(cfg, featureToggles) + if err != nil { + return nil, err + } + v2 := appregistry.ProvideAppInstallers(featureToggles, playlistAppInstaller, pluginsAppInstaller, shortURLAppInstaller, alertingRulesAppInstaller, appInstaller, alertingNotificationsAppInstaller, logsDrilldownAppInstaller, exampleAppInstaller) builderMetrics := builder.ProvideBuilderMetrics(registerer) apiserverService, err := apiserver.ProvideService(cfg, featureToggles, routeRegisterImpl, tracingService, serverLockService, sqlStore, kvStore, middlewareHandler, scopedPluginDatasourceProvider, plugincontextProvider, pluginstoreService, dualwriteService, resourceClient, inlineSecureValueSupport, eventualRestConfigProvider, v, eventualRestConfigProvider, registerer, aggregatorRunner, v2, builderMetrics) if err != nil { @@ -1400,7 +1405,11 @@ func InitializeForTest(ctx context.Context, t sqlutil.ITestDB, testingT interfac if err != nil { return nil, err } - v2 := appregistry.ProvideAppInstallers(featureToggles, playlistAppInstaller, pluginsAppInstaller, shortURLAppInstaller, alertingRulesAppInstaller, appInstaller, alertingNotificationsAppInstaller, logsDrilldownAppInstaller) + exampleAppInstaller, err := example.RegisterAppInstaller(cfg, featureToggles) + if err != nil { + return nil, err + } + v2 := appregistry.ProvideAppInstallers(featureToggles, playlistAppInstaller, pluginsAppInstaller, shortURLAppInstaller, alertingRulesAppInstaller, appInstaller, alertingNotificationsAppInstaller, logsDrilldownAppInstaller, exampleAppInstaller) builderMetrics := builder.ProvideBuilderMetrics(registerer) apiserverService, err := apiserver.ProvideService(cfg, featureToggles, routeRegisterImpl, tracingService, serverLockService, sqlStore, kvStore, middlewareHandler, scopedPluginDatasourceProvider, plugincontextProvider, pluginstoreService, dualwriteService, resourceClient, inlineSecureValueSupport, eventualRestConfigProvider, v, eventualRestConfigProvider, registerer, aggregatorRunner, v2, builderMetrics) if err != nil { diff --git a/pkg/services/apiserver/appinstaller/server.go b/pkg/services/apiserver/appinstaller/server.go index b6b32be48e9..2e5d46b2b3d 100644 --- a/pkg/services/apiserver/appinstaller/server.go +++ b/pkg/services/apiserver/appinstaller/server.go @@ -116,6 +116,13 @@ func (s *serverWrapper) configureStorage(gr schema.GroupResource, dualWriteSuppo return statusStore } + // if the storage is a subresource store, we need to extract the underlying generic registry store + if subresourceStore, ok := storage.(*appsdkapiserver.SubresourceREST); ok { + subresourceStore.Store.KeyFunc = grafanaregistry.NamespaceKeyFunc(gr) + subresourceStore.Store.KeyRootFunc = grafanaregistry.KeyRootFunc(gr) + return subresourceStore + } + return storage } From edef69fdc82b2ffe79823ec0823bd0179e9f2f7c Mon Sep 17 00:00:00 2001 From: Paul Marbach Date: Mon, 27 Oct 2025 12:24:26 -0400 Subject: [PATCH 031/378] Canvas: Allow non-icon bg image fields (#112308) * Canvas: Allow non-icon bg image fields * add tests --- .../app/features/dimensions/resource.test.ts | 45 +++++++++++++++++-- public/app/features/dimensions/resource.ts | 15 ++++--- 2 files changed, 51 insertions(+), 9 deletions(-) diff --git a/public/app/features/dimensions/resource.test.ts b/public/app/features/dimensions/resource.test.ts index 5afaa15727f..646bf297ff5 100644 --- a/public/app/features/dimensions/resource.test.ts +++ b/public/app/features/dimensions/resource.test.ts @@ -1,3 +1,4 @@ +import { createDataFrame } from '@grafana/data'; import { ResourceDimensionMode } from '@grafana/schema'; import { getResourceDimension } from './resource'; @@ -13,7 +14,7 @@ describe('getResourceDimension', () => { const fixedValue = 'img/icons/unicons/question-circle.svg'; const config = { mode: ResourceDimensionMode.Fixed, fixed: fixedValue }; - expect(getResourceDimension(frame, config).fixed).toEqual(`${publicPath}build/${fixedValue}`); + expect(getResourceDimension(frame, config).value()).toEqual(`${publicPath}build/${fixedValue}`); }); it('fixed full URL path', () => { @@ -21,8 +22,46 @@ describe('getResourceDimension', () => { const fixedUrlValue = 'https://3rdparty.fake/image.png'; const config = { mode: ResourceDimensionMode.Fixed, fixed: fixedUrlValue }; - expect(getResourceDimension(frame, config).fixed).toEqual(fixedUrlValue); + expect(getResourceDimension(frame, config).value()).toEqual(fixedUrlValue); }); - // TODO: write tests for field and mapping modes + it('field URL path', () => { + const frame = createDataFrame({ + fields: [ + { + name: 'image_field', + values: ['https://3rdparty.fake/icon.png'], + display: (v) => ({ + text: String(v), + numeric: NaN, + icon: undefined, + }), + }, + ], + }); + const config = { mode: ResourceDimensionMode.Field, field: 'image_field', fixed: '' }; + + expect(getResourceDimension(frame, config).value()).toEqual('https://3rdparty.fake/icon.png'); + }); + + it('icon url', () => { + const frame = createDataFrame({ + fields: [ + { + name: 'image_field', + values: ['img1'], + display: (v) => ({ + text: String(v), + numeric: NaN, + icon: v === 'img1' ? 'https://3rdparty.fake/field.png' : undefined, + }), + }, + ], + }); + const config = { mode: ResourceDimensionMode.Field, field: 'image_field', fixed: '' }; + + expect(getResourceDimension(frame, config).value()).toEqual('https://3rdparty.fake/field.png'); + }); + + // TODO: write tests for mapping modes }); diff --git a/public/app/features/dimensions/resource.ts b/public/app/features/dimensions/resource.ts index d8b85ae8a94..278469b6a45 100644 --- a/public/app/features/dimensions/resource.ts +++ b/public/app/features/dimensions/resource.ts @@ -55,18 +55,21 @@ export function getResourceDimension( } // mode === ResourceDimensionMode.Field case - const getIcon = (value: string): string => { + const getImageOrIcon = (value: string): string => { + let url = value; if (field && field.display) { - const icon = field.display(value).icon; - return getPublicOrAbsoluteUrl(icon ?? ''); + const displayValue = field.display(value); + if (displayValue.icon) { + url = displayValue.icon; + } } - return ''; + return getPublicOrAbsoluteUrl(url); }; return { field, - get: (index: number): string => getIcon(field.values[index]), - value: () => getIcon(getLastNotNullFieldValue(field)), + get: (index: number): string => getImageOrIcon(field.values[index]), + value: () => getImageOrIcon(getLastNotNullFieldValue(field)), }; } From d216d75fbb14cc9e3d0665f7e83e50c47380db5a Mon Sep 17 00:00:00 2001 From: Jo Date: Mon, 27 Oct 2025 18:20:59 +0100 Subject: [PATCH 032/378] Access: Add CoreRole/Role Delete/Update hooks for OpenFGA (#112839) * Add delete and update hooks for roles/core roles no need to capture non reference types small cleanup on vars * fix ticket priming in hooks * fix ticket priming in hooks * Revert "fix ticket priming in hooks" This reverts commit f8e953ca09cd0356f1822effdb3ccbe4ec6d2f6f. * use old testing blocks * protect runtime obj in go func * update test for correctness * separate files for test correctness. fix leaking goroutines in go tests * go workspace fixes * attribute owner * clean up go mod --- apps/iam/go.sum | 2 + go.mod | 1 + go.sum | 2 + pkg/extensions/enterprise_imports.go | 1 + pkg/registry/apis/iam/register.go | 8 +- ...{hooks.go => resource_permission_hooks.go} | 128 +-- ...t.go => resource_permission_hooks_test.go} | 380 +------ pkg/registry/apis/iam/role_hooks.go | 413 ++++++++ pkg/registry/apis/iam/role_hooks_test.go | 952 ++++++++++++++++++ 9 files changed, 1428 insertions(+), 459 deletions(-) rename pkg/registry/apis/iam/{hooks.go => resource_permission_hooks.go} (78%) rename pkg/registry/apis/iam/{hooks_test.go => resource_permission_hooks_test.go} (56%) create mode 100644 pkg/registry/apis/iam/role_hooks.go create mode 100644 pkg/registry/apis/iam/role_hooks_test.go diff --git a/apps/iam/go.sum b/apps/iam/go.sum index 156abe868d7..812bacc1933 100644 --- a/apps/iam/go.sum +++ b/apps/iam/go.sum @@ -860,6 +860,8 @@ github.com/grafana/grafana-openapi-client-go v0.0.0-20231213163343-bd475d63fb79 github.com/grafana/grafana-openapi-client-go v0.0.0-20231213163343-bd475d63fb79/go.mod h1:wc6Hbh3K2TgCUSfBC/BOzabItujtHMESZeFk5ZhdxhQ= github.com/grafana/grafana-plugin-sdk-go v0.281.0 h1:V8dGyatzcOLQeivFhBV2JWMwTSZH/clDnpfKG9p3dTA= github.com/grafana/grafana-plugin-sdk-go v0.281.0/go.mod h1:3I0g+v6jAwVmrt6BEjDUP4V6pkhGP5QKY5NkXY4Ayr4= +github.com/grafana/grafana/apps/example v0.0.0-20251027162426-edef69fdc82b h1:6Bo65etvjQ4tStkaA5+N3A3ENbO4UAWj53TxF6g2Hdk= +github.com/grafana/grafana/apps/example v0.0.0-20251027162426-edef69fdc82b/go.mod h1:6+wASOCN8LWt6FJ8dc0oODUBIEY5XHaE6ABi8g0mR+k= github.com/grafana/grafana/pkg/promlib v0.0.8 h1:VUWsqttdf0wMI4j9OX9oNrykguQpZcruudDAFpJJVw0= github.com/grafana/grafana/pkg/promlib v0.0.8/go.mod h1:U1ezG/MGaEPoThqsr3lymMPN5yIPdVTJnDZ+wcXT+ao= github.com/grafana/grafana/pkg/semconv v0.0.0-20250804150913-990f1c69ecc2 h1:A65jWgLk4Re28gIuZcpC0aTh71JZ0ey89hKGE9h543s= diff --git a/go.mod b/go.mod index 4d7ec58ef44..aa63907b29f 100644 --- a/go.mod +++ b/go.mod @@ -239,6 +239,7 @@ require ( github.com/grafana/grafana/apps/alerting/rules v0.0.0 // @grafana/alerting-backend github.com/grafana/grafana/apps/correlations v0.0.0 // @grafana/datapro github.com/grafana/grafana/apps/dashboard v0.0.0 // @grafana/grafana-app-platform-squad @grafana/dashboards-squad + github.com/grafana/grafana/apps/example v0.0.0-20251027162426-edef69fdc82b // @grafana/grafana-app-platform-squad github.com/grafana/grafana/apps/folder v0.0.0 // @grafana/grafana-search-and-storage github.com/grafana/grafana/apps/iam v0.0.0 // @grafana/identity-access-team github.com/grafana/grafana/apps/investigations v0.0.0 // @fcjack @matryer diff --git a/go.sum b/go.sum index ccf6b889d50..c37d8583801 100644 --- a/go.sum +++ b/go.sum @@ -1641,6 +1641,8 @@ github.com/grafana/grafana-openapi-client-go v0.0.0-20231213163343-bd475d63fb79 github.com/grafana/grafana-openapi-client-go v0.0.0-20231213163343-bd475d63fb79/go.mod h1:wc6Hbh3K2TgCUSfBC/BOzabItujtHMESZeFk5ZhdxhQ= github.com/grafana/grafana-plugin-sdk-go v0.281.0 h1:V8dGyatzcOLQeivFhBV2JWMwTSZH/clDnpfKG9p3dTA= github.com/grafana/grafana-plugin-sdk-go v0.281.0/go.mod h1:3I0g+v6jAwVmrt6BEjDUP4V6pkhGP5QKY5NkXY4Ayr4= +github.com/grafana/grafana/apps/example v0.0.0-20251027162426-edef69fdc82b h1:6Bo65etvjQ4tStkaA5+N3A3ENbO4UAWj53TxF6g2Hdk= +github.com/grafana/grafana/apps/example v0.0.0-20251027162426-edef69fdc82b/go.mod h1:6+wASOCN8LWt6FJ8dc0oODUBIEY5XHaE6ABi8g0mR+k= github.com/grafana/grafana/pkg/promlib v0.0.8 h1:VUWsqttdf0wMI4j9OX9oNrykguQpZcruudDAFpJJVw0= github.com/grafana/grafana/pkg/promlib v0.0.8/go.mod h1:U1ezG/MGaEPoThqsr3lymMPN5yIPdVTJnDZ+wcXT+ao= github.com/grafana/grafana/pkg/semconv v0.0.0-20250804150913-990f1c69ecc2 h1:A65jWgLk4Re28gIuZcpC0aTh71JZ0ey89hKGE9h543s= diff --git a/pkg/extensions/enterprise_imports.go b/pkg/extensions/enterprise_imports.go index 2dbdad4a9d6..9c052688d8f 100644 --- a/pkg/extensions/enterprise_imports.go +++ b/pkg/extensions/enterprise_imports.go @@ -57,4 +57,5 @@ import ( _ "github.com/grafana/tempo/pkg/traceql" _ "github.com/grafana/grafana/apps/alerting/alertenrichment/pkg/apis/alertenrichment/v1beta1" + _ "github.com/grafana/grafana/apps/scope/pkg/apis/scope/v0alpha1" ) diff --git a/pkg/registry/apis/iam/register.go b/pkg/registry/apis/iam/register.go index 1d1e74730f4..8c328e9963d 100644 --- a/pkg/registry/apis/iam/register.go +++ b/pkg/registry/apis/iam/register.go @@ -277,8 +277,10 @@ func (b *IdentityAccessManagementAPIBuilder) UpdateAPIGroupInfo(apiGroupInfo *ge return err } if enableZanzanaSync { - b.logger.Info("Enabling AfterCreate hook for CoreRole to sync to Zanzana") + b.logger.Info("Enabling hooks for CoreRole to sync to Zanzana") coreRoleStore.AfterCreate = b.AfterRoleCreate + coreRoleStore.AfterDelete = b.AfterRoleDelete + coreRoleStore.BeginUpdate = b.BeginRoleUpdate } storage[iamv0.CoreRoleInfo.StoragePath()] = coreRoleStore @@ -287,8 +289,10 @@ func (b *IdentityAccessManagementAPIBuilder) UpdateAPIGroupInfo(apiGroupInfo *ge return err } if enableZanzanaSync { - b.logger.Info("Enabling AfterCreate hook for Role to sync to Zanzana") + b.logger.Info("Enabling hooks for Role to sync to Zanzana") roleStore.AfterCreate = b.AfterRoleCreate + roleStore.AfterDelete = b.AfterRoleDelete + roleStore.BeginUpdate = b.BeginRoleUpdate } storage[iamv0.RoleInfo.StoragePath()] = roleStore diff --git a/pkg/registry/apis/iam/hooks.go b/pkg/registry/apis/iam/resource_permission_hooks.go similarity index 78% rename from pkg/registry/apis/iam/hooks.go rename to pkg/registry/apis/iam/resource_permission_hooks.go index 42b2ffe604b..1de5bb9f110 100644 --- a/pkg/registry/apis/iam/hooks.go +++ b/pkg/registry/apis/iam/resource_permission_hooks.go @@ -13,10 +13,8 @@ import ( "k8s.io/apiserver/pkg/registry/generic/registry" iamv0 "github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1" - "github.com/grafana/grafana/pkg/services/accesscontrol" v1 "github.com/grafana/grafana/pkg/services/authz/proto/v1" "github.com/grafana/grafana/pkg/services/authz/zanzana" - "github.com/grafana/grafana/pkg/services/authz/zanzana/common" ) var ( @@ -37,7 +35,7 @@ func toZanzanaSubject(kind iamv0.ResourcePermissionSpecPermissionKind, name stri case iamv0.ResourcePermissionSpecPermissionKindServiceAccount: return zanzana.NewTupleEntry(zanzana.TypeServiceAccount, name, ""), nil case iamv0.ResourcePermissionSpecPermissionKindTeam: - return zanzana.NewTupleEntry(zanzana.TypeTeam, name, ""), nil + return zanzana.NewTupleEntry(zanzana.TypeTeam, name, zanzana.RelationTeamMember), nil case iamv0.ResourcePermissionSpecPermissionKindBasicRole: basicRole := zanzana.TranslateBasicRole(name) if basicRole == "" { @@ -442,127 +440,3 @@ func (b *IdentityAccessManagementAPIBuilder) AfterResourcePermissionDelete(obj r } }(rp.DeepCopy()) // Pass a copy of the object } - -// convertRolePermissionsToTuples converts role permissions (action/scope) to v1 TupleKey format -// using the shared zanzana.ConvertRolePermissionsToTuples utility and common.ToAuthzExtTupleKeys -func convertRolePermissionsToTuples(roleUID string, permissions []iamv0.CoreRolespecPermission) ([]*v1.TupleKey, error) { - // Convert IAM permissions to zanzana.RolePermission format - rolePerms := make([]zanzana.RolePermission, 0, len(permissions)) - for _, perm := range permissions { - // Split the scope to get kind, attribute, identifier - kind, _, identifier := accesscontrol.SplitScope(perm.Scope) - rolePerms = append(rolePerms, zanzana.RolePermission{ - Action: perm.Action, - Kind: kind, - Identifier: identifier, - }) - } - - // Translate to Zanzana tuples - openfgaTuples, err := zanzana.ConvertRolePermissionsToTuples(roleUID, rolePerms) - if err != nil { - return nil, err - } - - // Convert directly to v1 tuples using common utility - v1Tuples := common.ToAuthzExtTupleKeys(openfgaTuples) - - return v1Tuples, nil -} - -// AfterRoleCreate is a post-create hook that writes the role permissions to Zanzana (openFGA) -// It handles both Role and CoreRole types -func (b *IdentityAccessManagementAPIBuilder) AfterRoleCreate(obj runtime.Object, _ *metav1.CreateOptions) { - if b.zClient == nil { - return - } - - // Extract permissions based on the object type - var roleUID, namespace string - var permissions []iamv0.CoreRolespecPermission - var roleType string - - // Try CoreRole first - if coreRole, ok := obj.(*iamv0.CoreRole); ok { - roleUID = coreRole.Name - namespace = coreRole.Namespace - // Deep copy permissions to avoid race conditions - permissions = make([]iamv0.CoreRolespecPermission, len(coreRole.Spec.Permissions)) - copy(permissions, coreRole.Spec.Permissions) - roleType = "core role" - } else if role, ok := obj.(*iamv0.Role); ok { - // Try Role - roleUID = role.Name - namespace = role.Namespace - - // Convert and copy permissions to avoid race conditions - permissions = make([]iamv0.CoreRolespecPermission, len(role.Spec.Permissions)) - for i, p := range role.Spec.Permissions { - permissions[i] = iamv0.CoreRolespecPermission(p) - } - roleType = "role" - } else { - // Not a supported role type - return - } - - wait := time.Now() - b.zTickets <- true - hooksWaitHistogram.WithLabelValues("role", "create").Observe(time.Since(wait).Seconds()) - - go func() { - defer func() { - <-b.zTickets - }() - - tuples, err := convertRolePermissionsToTuples(roleUID, permissions) - if err != nil { - b.logger.Error("failed to convert role permissions to tuples", - "namespace", namespace, - "roleUID", roleUID, - "roleType", roleType, - "err", err, - "permissionsCnt", len(permissions), - ) - return - } - - // Avoid writing if there are no valid tuples - if len(tuples) == 0 { - b.logger.Debug("no valid tuples to write for role", - "namespace", namespace, - "roleUID", roleUID, - "roleType", roleType, - "permissionsCnt", len(permissions), - ) - return - } - - b.logger.Debug("writing role permissions to zanzana", - "namespace", namespace, - "roleUID", roleUID, - "roleType", roleType, - "tuplesCnt", len(tuples), - "permissionsCnt", len(permissions), - ) - - ctx, cancel := context.WithTimeout(context.Background(), defaultWriteTimeout) - defer cancel() - - err = b.zClient.Write(ctx, &v1.WriteRequest{ - Namespace: namespace, - Writes: &v1.WriteRequestWrites{ - TupleKeys: tuples, - }, - }) - if err != nil { - b.logger.Error("failed to write role permissions to zanzana", - "err", err, - "namespace", namespace, - "roleUID", roleUID, - "roleType", roleType, - "tuplesCnt", len(tuples), - ) - } - }() -} diff --git a/pkg/registry/apis/iam/hooks_test.go b/pkg/registry/apis/iam/resource_permission_hooks_test.go similarity index 56% rename from pkg/registry/apis/iam/hooks_test.go rename to pkg/registry/apis/iam/resource_permission_hooks_test.go index c19e45ce0d9..ff696020fc1 100644 --- a/pkg/registry/apis/iam/hooks_test.go +++ b/pkg/registry/apis/iam/resource_permission_hooks_test.go @@ -2,6 +2,7 @@ package iam import ( "context" + "sync" "testing" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -19,11 +20,6 @@ type FakeZanzanaClient struct { readCallback func(context.Context, *v1.ReadRequest) (*v1.ReadResponse, error) } -// Write implements zanzana.Client. -func (f *FakeZanzanaClient) Write(ctx context.Context, req *v1.WriteRequest) error { - return f.writeCallback(ctx, req) -} - // Read implements zanzana.Client. func (f *FakeZanzanaClient) Read(ctx context.Context, req *v1.ReadRequest) (*v1.ReadResponse, error) { if f.readCallback != nil { @@ -32,6 +28,11 @@ func (f *FakeZanzanaClient) Read(ctx context.Context, req *v1.ReadRequest) (*v1. return &v1.ReadResponse{}, nil } +// Write implements zanzana.Client. +func (f *FakeZanzanaClient) Write(ctx context.Context, req *v1.WriteRequest) error { + return f.writeCallback(ctx, req) +} + func requireTuplesMatch(t *testing.T, actual []*v1.TupleKey, expected []*v1.TupleKey, msgAndArgs ...interface{}) { t.Helper() for _, exp := range expected { @@ -50,16 +51,32 @@ func requireTuplesMatch(t *testing.T, actual []*v1.TupleKey, expected []*v1.Tupl } } -func TestAfterResourcePermissionCreate(t *testing.T) { - t.Run("should create zanzana entries for folder resource permissions", func(t *testing.T) { - b := &IdentityAccessManagementAPIBuilder{ - logger: log.NewNopLogger(), - zTickets: make(chan bool, 1), +func requireDeleteTuplesMatch(t *testing.T, actual []*v1.TupleKeyWithoutCondition, expected []*v1.TupleKeyWithoutCondition, msgAndArgs ...interface{}) { + t.Helper() + for _, exp := range expected { + found := false + for _, act := range actual { + if act.User == exp.User && + act.Relation == exp.Relation && + act.Object == exp.Object { + found = true + break + } } - t.Cleanup(func() { - <-b.zTickets - }) + if !found { + require.Fail(t, "Expected delete tuple not found", "Tuple: %+v\n%v", exp, msgAndArgs) + } + } +} +func TestAfterResourcePermissionCreate(t *testing.T) { + var wg sync.WaitGroup + b := &IdentityAccessManagementAPIBuilder{ + logger: log.NewNopLogger(), + zTickets: make(chan bool, 1), + } + t.Run("should create zanzana entries for folder resource permissions", func(t *testing.T) { + wg.Add(1) folderPerm := iamv0.ResourcePermission{ ObjectMeta: metav1.ObjectMeta{ Namespace: "org-2", @@ -76,6 +93,7 @@ func TestAfterResourcePermissionCreate(t *testing.T) { } testFolderEntries := func(ctx context.Context, req *v1.WriteRequest) error { + defer wg.Done() require.NotNil(t, req) require.NotNil(t, req.Writes) require.Len(t, req.Writes.TupleKeys, 2) @@ -92,17 +110,11 @@ func TestAfterResourcePermissionCreate(t *testing.T) { b.zClient = &FakeZanzanaClient{writeCallback: testFolderEntries} b.AfterResourcePermissionCreate(&folderPerm, nil) + wg.Wait() }) t.Run("should create zanzana entries for dashboard resource permissions", func(t *testing.T) { - b := &IdentityAccessManagementAPIBuilder{ - logger: log.NewNopLogger(), - zTickets: make(chan bool, 1), - } - t.Cleanup(func() { - <-b.zTickets - }) - + wg.Add(1) dashPerm := iamv0.ResourcePermission{ ObjectMeta: metav1.ObjectMeta{ Namespace: "default", @@ -119,6 +131,7 @@ func TestAfterResourcePermissionCreate(t *testing.T) { } testDashEntries := func(ctx context.Context, req *v1.WriteRequest) error { + defer wg.Done() object := "resource:dashboard.grafana.app/dashboards/dash1" require.NotNil(t, req) @@ -134,7 +147,7 @@ func TestAfterResourcePermissionCreate(t *testing.T) { expectedTuples := []*v1.TupleKey{ {User: "service-account:sa1", Relation: "view", Object: object}, - {User: "team:team1", Relation: "edit", Object: object}, + {User: "team:team1#member", Relation: "edit", Object: object}, } requireTuplesMatch(t, req.Writes.TupleKeys, expectedTuples) @@ -144,15 +157,17 @@ func TestAfterResourcePermissionCreate(t *testing.T) { b.zClient = &FakeZanzanaClient{writeCallback: testDashEntries} b.AfterResourcePermissionCreate(&dashPerm, nil) }) + wg.Wait() } func TestBeginResourcePermissionUpdate(t *testing.T) { + var wg sync.WaitGroup b := &IdentityAccessManagementAPIBuilder{ logger: log.NewNopLogger(), zTickets: make(chan bool, 1), } - t.Run("should update zanzana entries for folder resource permissions", func(t *testing.T) { + wg.Add(1) oldFolderPerm := iamv0.ResourcePermission{ ObjectMeta: metav1.ObjectMeta{ Namespace: "org-2", @@ -183,6 +198,7 @@ func TestBeginResourcePermissionUpdate(t *testing.T) { } testFolderWrite := func(ctx context.Context, req *v1.WriteRequest) error { + defer wg.Done() require.NotNil(t, req) require.Equal(t, "org-2", req.Namespace) @@ -218,10 +234,9 @@ func TestBeginResourcePermissionUpdate(t *testing.T) { finishFunc(context.Background(), true) }) - // Wait for the ticket to be released - <-b.zTickets - + wg.Wait() t.Run("should update zanzana entries for dashboard resource permissions", func(t *testing.T) { + wg.Add(1) oldDashPerm := iamv0.ResourcePermission{ ObjectMeta: metav1.ObjectMeta{ Namespace: "default", @@ -253,6 +268,7 @@ func TestBeginResourcePermissionUpdate(t *testing.T) { object := "resource:dashboard.grafana.app/dashboards/dash1" testDashWrite := func(ctx context.Context, req *v1.WriteRequest) error { + defer wg.Done() require.NotNil(t, req) require.Equal(t, "default", req.Namespace) @@ -291,16 +307,18 @@ func TestBeginResourcePermissionUpdate(t *testing.T) { // Call the finish function with success=true to trigger the zanzana write finishFunc(context.Background(), true) + wg.Wait() }) } func TestAfterResourcePermissionDelete(t *testing.T) { + var wg sync.WaitGroup b := &IdentityAccessManagementAPIBuilder{ logger: log.NewNopLogger(), zTickets: make(chan bool, 1), } - t.Run("should delete zanzana entries for folder resource permissions", func(t *testing.T) { + wg.Add(1) folderPerm := iamv0.ResourcePermission{ ObjectMeta: metav1.ObjectMeta{ Namespace: "org-2", @@ -317,6 +335,7 @@ func TestAfterResourcePermissionDelete(t *testing.T) { } testFolderDelete := func(ctx context.Context, req *v1.WriteRequest) error { + defer wg.Done() require.NotNil(t, req) require.Equal(t, "org-2", req.Namespace) @@ -340,12 +359,11 @@ func TestAfterResourcePermissionDelete(t *testing.T) { b.zClient = &FakeZanzanaClient{writeCallback: testFolderDelete} b.AfterResourcePermissionDelete(&folderPerm, nil) + wg.Wait() }) - // Wait for the ticket to be released - <-b.zTickets - t.Run("should delete zanzana entries for dashboard resource permissions", func(t *testing.T) { + wg.Add(1) dashPerm := iamv0.ResourcePermission{ ObjectMeta: metav1.ObjectMeta{ Namespace: "default", @@ -362,6 +380,7 @@ func TestAfterResourcePermissionDelete(t *testing.T) { } testDashDelete := func(ctx context.Context, req *v1.WriteRequest) error { + defer wg.Done() object := "resource:dashboard.grafana.app/dashboards/dash1" require.NotNil(t, req) @@ -388,305 +407,6 @@ func TestAfterResourcePermissionDelete(t *testing.T) { b.zClient = &FakeZanzanaClient{writeCallback: testDashDelete} b.AfterResourcePermissionDelete(&dashPerm, nil) - }) - - // Wait for the ticket to be released - <-b.zTickets -} - -func TestAfterCoreRoleCreate(t *testing.T) { - t.Run("should create zanzana entries for core role with folder permissions", func(t *testing.T) { - b := &IdentityAccessManagementAPIBuilder{ - logger: log.NewNopLogger(), - zTickets: make(chan bool, 1), - } - t.Cleanup(func() { - <-b.zTickets - }) - - coreRole := iamv0.CoreRole{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-role-uid", - Namespace: "org-1", - }, - Spec: iamv0.CoreRoleSpec{ - Title: "Test Role", - Description: "Test role for folders", - Permissions: []iamv0.CoreRolespecPermission{ - {Action: "folders:read", Scope: "folders:uid:folder1"}, - {Action: "folders:write", Scope: "folders:uid:folder1"}, - }, - }, - } - - testCoreRoleEntries := func(ctx context.Context, req *v1.WriteRequest) error { - require.NotNil(t, req) - require.NotNil(t, req.Writes) - require.Len(t, req.Writes.TupleKeys, 2) - require.Equal(t, "org-1", req.Namespace) - - expectedTuples := []*v1.TupleKey{ - {User: "role:test-role-uid#assignee", Relation: "get", Object: "folder:folder1"}, - {User: "role:test-role-uid#assignee", Relation: "update", Object: "folder:folder1"}, - } - - requireTuplesMatch(t, req.Writes.TupleKeys, expectedTuples) - return nil - } - - b.zClient = &FakeZanzanaClient{writeCallback: testCoreRoleEntries} - b.AfterRoleCreate(&coreRole, nil) - }) - - t.Run("should create zanzana entries for core role with dashboard permissions", func(t *testing.T) { - b := &IdentityAccessManagementAPIBuilder{ - logger: log.NewNopLogger(), - zTickets: make(chan bool, 1), - } - t.Cleanup(func() { - <-b.zTickets - }) - - coreRole := iamv0.CoreRole{ - ObjectMeta: metav1.ObjectMeta{ - Name: "dashboard-role-uid", - Namespace: "default", - }, - Spec: iamv0.CoreRoleSpec{ - Title: "Dashboard Role", - Description: "Test role for dashboards", - Permissions: []iamv0.CoreRolespecPermission{ - {Action: "dashboards:read", Scope: "dashboards:uid:dash1"}, - {Action: "dashboards:write", Scope: "dashboards:uid:dash1"}, - }, - }, - } - - testDashboardRoleEntries := func(ctx context.Context, req *v1.WriteRequest) error { - require.NotNil(t, req) - require.NotNil(t, req.Writes) - require.Len(t, req.Writes.TupleKeys, 2) - require.Equal(t, "default", req.Namespace) - - // Check subject is role with assignee relation - for _, tuple := range req.Writes.TupleKeys { - require.Equal(t, "role:dashboard-role-uid#assignee", tuple.User) - require.Contains(t, tuple.Object, "resource:") - require.Contains(t, tuple.Object, "dashboard") - } - - return nil - } - - b.zClient = &FakeZanzanaClient{writeCallback: testDashboardRoleEntries} - b.AfterRoleCreate(&coreRole, nil) - }) - - t.Run("should handle wildcard scopes", func(t *testing.T) { - b := &IdentityAccessManagementAPIBuilder{ - logger: log.NewNopLogger(), - zTickets: make(chan bool, 1), - } - t.Cleanup(func() { - <-b.zTickets - }) - - coreRole := iamv0.CoreRole{ - ObjectMeta: metav1.ObjectMeta{ - Name: "wildcard-role-uid", - Namespace: "org-2", - }, - Spec: iamv0.CoreRoleSpec{ - Title: "Wildcard Role", - Permissions: []iamv0.CoreRolespecPermission{ - {Action: "folders:read", Scope: "folders:*"}, - }, - }, - } - - testWildcardEntries := func(ctx context.Context, req *v1.WriteRequest) error { - require.NotNil(t, req) - require.NotNil(t, req.Writes) - require.Len(t, req.Writes.TupleKeys, 1) - - tuple := req.Writes.TupleKeys[0] - require.Equal(t, "role:wildcard-role-uid#assignee", tuple.User) - // Wildcard should create a group_resource tuple - require.Contains(t, tuple.Object, "group_resource:") - - return nil - } - - b.zClient = &FakeZanzanaClient{writeCallback: testWildcardEntries} - b.AfterRoleCreate(&coreRole, nil) - }) - - t.Run("should skip untranslatable permissions", func(t *testing.T) { - b := &IdentityAccessManagementAPIBuilder{ - logger: log.NewNopLogger(), - zTickets: make(chan bool, 1), - } - t.Cleanup(func() { - <-b.zTickets - }) - - coreRole := iamv0.CoreRole{ - ObjectMeta: metav1.ObjectMeta{ - Name: "mixed-role-uid", - Namespace: "org-1", - }, - Spec: iamv0.CoreRoleSpec{ - Title: "Mixed Role", - Permissions: []iamv0.CoreRolespecPermission{ - {Action: "folders:read", Scope: "folders:uid:folder1"}, - {Action: "unknown:action", Scope: "unknown:scope"}, // This should be skipped - }, - }, - } - - testMixedEntries := func(ctx context.Context, req *v1.WriteRequest) error { - require.NotNil(t, req) - require.NotNil(t, req.Writes) - // Should only have 1 tuple (the untranslatable one should be skipped) - require.Len(t, req.Writes.TupleKeys, 1) - - tuple := req.Writes.TupleKeys[0] - require.Equal(t, "role:mixed-role-uid#assignee", tuple.User) - require.Equal(t, "folder:folder1", tuple.Object) - - return nil - } - - b.zClient = &FakeZanzanaClient{writeCallback: testMixedEntries} - b.AfterRoleCreate(&coreRole, nil) - }) -} - -func TestAfterRoleCreate(t *testing.T) { - t.Run("should create zanzana entries for role with folder permissions", func(t *testing.T) { - b := &IdentityAccessManagementAPIBuilder{ - logger: log.NewNopLogger(), - zTickets: make(chan bool, 1), - } - t.Cleanup(func() { - <-b.zTickets - }) - - role := iamv0.Role{ - ObjectMeta: metav1.ObjectMeta{ - Name: "custom-role-uid", - Namespace: "org-3", - }, - Spec: iamv0.RoleSpec{ - Title: "Custom Role", - Description: "Custom role for folders", - Permissions: []iamv0.RolespecPermission{ - {Action: "folders:read", Scope: "folders:uid:folder2"}, - {Action: "folders:delete", Scope: "folders:uid:folder2"}, - }, - }, - } - - testRoleEntries := func(ctx context.Context, req *v1.WriteRequest) error { - require.NotNil(t, req) - require.NotNil(t, req.Writes) - require.Len(t, req.Writes.TupleKeys, 2) - require.Equal(t, "org-3", req.Namespace) - - expectedTuples := []*v1.TupleKey{ - {User: "role:custom-role-uid#assignee", Relation: "get", Object: "folder:folder2"}, - {User: "role:custom-role-uid#assignee", Relation: "delete", Object: "folder:folder2"}, - } - - requireTuplesMatch(t, req.Writes.TupleKeys, expectedTuples) - return nil - } - - b.zClient = &FakeZanzanaClient{writeCallback: testRoleEntries} - b.AfterRoleCreate(&role, nil) - }) - - t.Run("should create zanzana entries for role with dashboard permissions", func(t *testing.T) { - b := &IdentityAccessManagementAPIBuilder{ - logger: log.NewNopLogger(), - zTickets: make(chan bool, 1), - } - t.Cleanup(func() { - <-b.zTickets - }) - - role := iamv0.Role{ - ObjectMeta: metav1.ObjectMeta{ - Name: "dash-role-uid", - Namespace: "default", - }, - Spec: iamv0.RoleSpec{ - Title: "Dashboard Custom Role", - Description: "Custom role for dashboards", - Permissions: []iamv0.RolespecPermission{ - {Action: "dashboards:read", Scope: "dashboards:uid:mydash"}, - {Action: "dashboards:delete", Scope: "dashboards:uid:mydash"}, - }, - }, - } - - testDashRoleEntries := func(ctx context.Context, req *v1.WriteRequest) error { - require.NotNil(t, req) - require.NotNil(t, req.Writes) - require.Len(t, req.Writes.TupleKeys, 2) - require.Equal(t, "default", req.Namespace) - - // Check subject is role with assignee relation - for _, tuple := range req.Writes.TupleKeys { - require.Equal(t, "role:dash-role-uid#assignee", tuple.User) - require.Contains(t, tuple.Object, "resource:") - } - - return nil - } - - b.zClient = &FakeZanzanaClient{writeCallback: testDashRoleEntries} - b.AfterRoleCreate(&role, nil) - }) - - t.Run("should merge folder resource tuples with same object and user", func(t *testing.T) { - b := &IdentityAccessManagementAPIBuilder{ - logger: log.NewNopLogger(), - zTickets: make(chan bool, 1), - } - t.Cleanup(func() { - <-b.zTickets - }) - - role := iamv0.Role{ - ObjectMeta: metav1.ObjectMeta{ - Name: "merge-role-uid", - Namespace: "org-1", - }, - Spec: iamv0.RoleSpec{ - Title: "Merge Test Role", - Permissions: []iamv0.RolespecPermission{ - // These should create folder resource tuples that get merged - {Action: "dashboards:read", Scope: "folders:uid:parent-folder"}, - {Action: "dashboards:write", Scope: "folders:uid:parent-folder"}, - }, - }, - } - - testMergedEntries := func(ctx context.Context, req *v1.WriteRequest) error { - require.NotNil(t, req) - require.NotNil(t, req.Writes) - // After merging, we should have tuples for the folder resource actions - require.Greater(t, len(req.Writes.TupleKeys), 0) - - for _, tuple := range req.Writes.TupleKeys { - require.Equal(t, "role:merge-role-uid#assignee", tuple.User) - } - - return nil - } - - b.zClient = &FakeZanzanaClient{writeCallback: testMergedEntries} - b.AfterRoleCreate(&role, nil) + wg.Wait() }) } diff --git a/pkg/registry/apis/iam/role_hooks.go b/pkg/registry/apis/iam/role_hooks.go new file mode 100644 index 00000000000..9c4271c94aa --- /dev/null +++ b/pkg/registry/apis/iam/role_hooks.go @@ -0,0 +1,413 @@ +package iam + +import ( + "context" + "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apiserver/pkg/registry/generic/registry" + + iamv0 "github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1" + "github.com/grafana/grafana/pkg/services/accesscontrol" + v1 "github.com/grafana/grafana/pkg/services/authz/proto/v1" + "github.com/grafana/grafana/pkg/services/authz/zanzana" + "github.com/grafana/grafana/pkg/services/authz/zanzana/common" +) + +// convertRolePermissionsToTuples converts role permissions (action/scope) to v1 TupleKey format +// using the shared zanzana.ConvertRolePermissionsToTuples utility and common.ToAuthzExtTupleKeys +func convertRolePermissionsToTuples(roleUID string, permissions []iamv0.CoreRolespecPermission) ([]*v1.TupleKey, error) { + // Convert IAM permissions to zanzana.RolePermission format + rolePerms := make([]zanzana.RolePermission, 0, len(permissions)) + for _, perm := range permissions { + // Split the scope to get kind, attribute, identifier + kind, _, identifier := accesscontrol.SplitScope(perm.Scope) + rolePerms = append(rolePerms, zanzana.RolePermission{ + Action: perm.Action, + Kind: kind, + Identifier: identifier, + }) + } + + // Translate to Zanzana tuples + openfgaTuples, err := zanzana.ConvertRolePermissionsToTuples(roleUID, rolePerms) + if err != nil { + return nil, err + } + + // Convert directly to v1 tuples using common utility + v1Tuples := common.ToAuthzExtTupleKeys(openfgaTuples) + + return v1Tuples, nil +} + +// AfterRoleCreate is a post-create hook that writes the role permissions to Zanzana (openFGA) +// It handles both Role and CoreRole types +func (b *IdentityAccessManagementAPIBuilder) AfterRoleCreate(obj runtime.Object, _ *metav1.CreateOptions) { + if b.zClient == nil { + return + } + + var rType string + var rt *iamv0.CoreRole + + if coreRole, ok := obj.(*iamv0.CoreRole); ok { + rt = coreRole.DeepCopy() + rType = "coreRole" + } else if regRole, ok := obj.(*iamv0.Role); ok { + regRolePermissions := make([]iamv0.CoreRolespecPermission, len(regRole.Spec.Permissions)) + for i, p := range regRole.Spec.Permissions { + regRolePermissions[i] = iamv0.CoreRolespecPermission(p) + } + rt = &iamv0.CoreRole{ + ObjectMeta: metav1.ObjectMeta{ + Name: regRole.Name, + Namespace: regRole.Namespace, + }, + Spec: iamv0.CoreRoleSpec{ + Permissions: regRolePermissions, + }, + } + rType = "role" + } else { + // Not a supported role type + return + } + + wait := time.Now() + b.zTickets <- true + hooksWaitHistogram.WithLabelValues(rType, "create").Observe(time.Since(wait).Seconds()) + + go func(role *iamv0.CoreRole, roleType string) { + start := time.Now() + status := "success" + defer func() { + <-b.zTickets + hooksDurationHistogram.WithLabelValues(rType, "create", status).Observe(time.Since(start).Seconds()) + hooksOperationCounter.WithLabelValues(rType, "create", status).Inc() + }() + + tuples, err := convertRolePermissionsToTuples(role.Name, role.Spec.Permissions) + if err != nil { + b.logger.Error("failed to convert role permissions to tuples", + "namespace", role.Namespace, + "roleUID", role.Name, + "roleType", roleType, + "err", err, + "permissionsCnt", len(role.Spec.Permissions), + ) + status = "failure" + return + } + + // Avoid writing if there are no valid tuples + if len(tuples) == 0 { + b.logger.Debug("no valid tuples to write for role", + "namespace", role.Namespace, + "roleUID", role.Name, + "roleType", roleType, + "permissionsCnt", len(role.Spec.Permissions), + ) + status = "failure" + return + } + + b.logger.Debug("writing role permissions to zanzana", + "namespace", role.Namespace, + "roleUID", role.Name, + "roleType", roleType, + "tuplesCnt", len(tuples), + "permissionsCnt", len(role.Spec.Permissions), + ) + + ctx, cancel := context.WithTimeout(context.Background(), defaultWriteTimeout) + defer cancel() + + err = b.zClient.Write(ctx, &v1.WriteRequest{ + Namespace: role.Namespace, + Writes: &v1.WriteRequestWrites{ + TupleKeys: tuples, + }, + }) + if err != nil { + b.logger.Error("failed to write role permissions to zanzana", + "err", err, + "namespace", role.Namespace, + "roleUID", role.Name, + "roleType", roleType, + "tuplesCnt", len(tuples), + ) + status = "failure" + return + } + + // Record successful tuple writes + hooksTuplesCounter.WithLabelValues(rType, "create", "write").Add(float64(len(tuples))) + }(rt.DeepCopy(), rType) +} + +// AfterRoleDelete is a post-delete hook that removes the role permissions from Zanzana (openFGA) +// It handles both Role and CoreRole types +func (b *IdentityAccessManagementAPIBuilder) AfterRoleDelete(obj runtime.Object, _ *metav1.DeleteOptions) { + if b.zClient == nil { + return + } + + var rType string + var rt *iamv0.CoreRole + + // Try CoreRole first + if coreRole, ok := obj.(*iamv0.CoreRole); ok { + rt = coreRole.DeepCopy() + rType = "coreRole" + } else if regRole, ok := obj.(*iamv0.Role); ok { + regRolePermissions := make([]iamv0.CoreRolespecPermission, len(regRole.Spec.Permissions)) + for i, p := range regRole.Spec.Permissions { + regRolePermissions[i] = iamv0.CoreRolespecPermission(p) + } + rt = &iamv0.CoreRole{ + ObjectMeta: metav1.ObjectMeta{ + Name: regRole.Name, + Namespace: regRole.Namespace, + }, + Spec: iamv0.CoreRoleSpec{ + Permissions: regRolePermissions, + }, + } + rType = "role" + } else { + // Not a supported role type + return + } + + wait := time.Now() + b.zTickets <- true + hooksWaitHistogram.WithLabelValues("role", "delete").Observe(time.Since(wait).Seconds()) // Record wait time + + go func(role *iamv0.CoreRole, roleType string) { + defer func() { + <-b.zTickets + }() + + b.logger.Debug("deleting role permissions from zanzana", + "namespace", role.Namespace, + "roleUID", role.Name, + "roleType", roleType, + "permissionsCnt", len(role.Spec.Permissions), + ) + + tuples, err := convertRolePermissionsToTuples(role.Name, role.Spec.Permissions) + if err != nil { + b.logger.Error("failed to convert role permissions to tuples for deletion", + "namespace", role.Namespace, + "roleUID", role.Name, + "roleType", roleType, + "err", err, + "permissionsCnt", len(role.Spec.Permissions), + ) + return + } + + // Avoid deleting if there are no valid tuples + if len(tuples) == 0 { + b.logger.Debug("no valid tuples to delete for role", + "namespace", role.Namespace, + "roleUID", role.Name, + "roleType", roleType, + "permissionsCnt", len(role.Spec.Permissions), + ) + return + } + + // Convert tuples to TupleKeyWithoutCondition for deletion + deleteTuples := toTupleKeysWithoutCondition(tuples) + + b.logger.Debug("deleting role permissions from zanzana", + "namespace", role.Namespace, + "roleUID", role.Name, + "roleType", roleType, + "tuplesCnt", len(deleteTuples), + "permissionsCnt", len(role.Spec.Permissions), + ) + + ctx, cancel := context.WithTimeout(context.Background(), defaultWriteTimeout) + defer cancel() + + err = b.zClient.Write(ctx, &v1.WriteRequest{ + Namespace: role.Namespace, + Deletes: &v1.WriteRequestDeletes{ + TupleKeys: deleteTuples, + }, + }) + if err != nil { + b.logger.Error("failed to delete role permissions from zanzana", + "err", err, + "namespace", role.Namespace, + "roleUID", role.Name, + "roleType", roleType, + "tuplesCnt", len(deleteTuples), + ) + } + }(rt.DeepCopy(), rType) +} + +// beginRoleUpdate is a pre-update hook that prepares zanzana updates +// It converts old and new permissions to tuples and performs the zanzana write after K8s update succeeds +// It handles both Role and CoreRole types +func (b *IdentityAccessManagementAPIBuilder) BeginRoleUpdate(ctx context.Context, obj, oldObj runtime.Object, options *metav1.UpdateOptions) (registry.FinishFunc, error) { + if b.zClient == nil { + return nil, nil + } + var oldRole, newRole *iamv0.CoreRole + var roleType string + + if oldCoreRole, ok := oldObj.(*iamv0.CoreRole); ok { // Try CoreRole first + oldRole = oldCoreRole.DeepCopy() + newCoreRole, ok := obj.(*iamv0.CoreRole) + if !ok { + return nil, nil + } + newRole = newCoreRole.DeepCopy() + roleType = "coreRole" + } else if oldRegRole, ok := oldObj.(*iamv0.Role); ok { // Try Role + oldRegRolePermissions := make([]iamv0.CoreRolespecPermission, len(oldRegRole.Spec.Permissions)) + for i, p := range oldRegRole.Spec.Permissions { + oldRegRolePermissions[i] = iamv0.CoreRolespecPermission(p) + } + oldRole = &iamv0.CoreRole{ + ObjectMeta: metav1.ObjectMeta{ + Name: oldRegRole.Name, + Namespace: oldRegRole.Namespace, + }, + Spec: iamv0.CoreRoleSpec{ + Permissions: oldRegRolePermissions, + }, + } + newRegRole, ok := obj.(*iamv0.Role) + if !ok { + return nil, nil + } + newRegRolePermissions := make([]iamv0.CoreRolespecPermission, len(newRegRole.Spec.Permissions)) + for i, p := range newRegRole.Spec.Permissions { + newRegRolePermissions[i] = iamv0.CoreRolespecPermission(p) + } + newRole = &iamv0.CoreRole{ + ObjectMeta: metav1.ObjectMeta{ + Name: newRegRole.Name, + Namespace: newRegRole.Namespace, + }, + Spec: iamv0.CoreRoleSpec{ + Permissions: newRegRolePermissions, + }, + } + roleType = "role" + } else { + // Not a supported role type + return nil, nil + } + + // Return a finish function that performs the zanzana write only on success + return func(ctx context.Context, success bool) { + if !success { + // Update failed, don't write to zanzana + return + } + + // Grab a ticket to write to Zanzana + wait := time.Now() + b.zTickets <- true + hooksWaitHistogram.WithLabelValues(roleType, "update").Observe(time.Since(wait).Seconds()) // Record wait time + + go func(old *iamv0.CoreRole, new *iamv0.CoreRole) { + defer func() { + <-b.zTickets + }() + roleUID, namespace := old.Name, old.Namespace + oldPermissions, newPermissions := old.Spec.Permissions, new.Spec.Permissions + + // Convert old permissions to tuples for deletion + var oldTuples []*v1.TupleKey + if len(oldPermissions) > 0 { + var err error + oldTuples, err = convertRolePermissionsToTuples(roleUID, oldPermissions) + if err != nil { + b.logger.Error("failed to convert old role permissions to tuples", + "namespace", namespace, + "roleUID", roleUID, + "roleType", roleType, + "err", err, + ) + } + } + + // Convert new permissions to tuples for writing + newTuples, err := convertRolePermissionsToTuples(roleUID, newPermissions) + if err != nil { + b.logger.Error("failed to convert new role permissions to tuples", + "namespace", namespace, + "roleUID", roleUID, + "roleType", roleType, + "err", err, + ) + return + } + + b.logger.Debug("updating role permissions in zanzana", + "namespace", namespace, + "roleUID", roleUID, + "roleType", roleType, + "oldPermissionsCnt", len(oldPermissions), + "newPermissionsCnt", len(newPermissions), + ) + + ctx, cancel := context.WithTimeout(context.Background(), defaultWriteTimeout) + defer cancel() + + // Prepare write request + req := &v1.WriteRequest{ + Namespace: namespace, + } + + // Add deletes for old tuples + if len(oldTuples) > 0 { + deleteTuples := toTupleKeysWithoutCondition(oldTuples) + req.Deletes = &v1.WriteRequestDeletes{ + TupleKeys: deleteTuples, + } + b.logger.Debug("deleting existing role permissions from zanzana", + "namespace", namespace, + "roleUID", roleUID, + "roleType", roleType, + "tuplesCnt", len(deleteTuples), + ) + } + + // Add writes for new tuples + if len(newTuples) > 0 { + req.Writes = &v1.WriteRequestWrites{ + TupleKeys: newTuples, + } + b.logger.Debug("writing new role permissions to zanzana", + "namespace", namespace, + "roleUID", roleUID, + "roleType", roleType, + "tuplesCnt", len(newTuples), + ) + } + + // Only make the request if there are deletes or writes + if req.Deletes != nil || req.Writes != nil { + err = b.zClient.Write(ctx, req) + if err != nil { + b.logger.Error("failed to update role permissions in zanzana", + "err", err, + "namespace", namespace, + "roleUID", roleUID, + "roleType", roleType, + ) + } + } + }(oldRole.DeepCopy(), newRole.DeepCopy()) + }, nil +} diff --git a/pkg/registry/apis/iam/role_hooks_test.go b/pkg/registry/apis/iam/role_hooks_test.go new file mode 100644 index 00000000000..282576b6ec7 --- /dev/null +++ b/pkg/registry/apis/iam/role_hooks_test.go @@ -0,0 +1,952 @@ +package iam + +import ( + "context" + "sync" + "testing" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + iamv0 "github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1" + "github.com/grafana/grafana/pkg/infra/log" + v1 "github.com/grafana/grafana/pkg/services/authz/proto/v1" + "github.com/stretchr/testify/require" +) + +func TestAfterCoreRoleCreate(t *testing.T) { + var wg sync.WaitGroup + + b := &IdentityAccessManagementAPIBuilder{ + logger: log.NewNopLogger(), + zTickets: make(chan bool, 1), + } + t.Run("should create zanzana entries for core role with folder permissions", func(t *testing.T) { + wg.Add(1) + coreRole := iamv0.CoreRole{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-role-uid", + Namespace: "org-1", + }, + Spec: iamv0.CoreRoleSpec{ + Title: "Test Role", + Description: "Test role for folders", + Permissions: []iamv0.CoreRolespecPermission{ + {Action: "folders:read", Scope: "folders:uid:folder1"}, + {Action: "folders:write", Scope: "folders:uid:folder1"}, + }, + }, + } + + testCoreRoleEntries := func(ctx context.Context, req *v1.WriteRequest) error { + defer wg.Done() + require.NotNil(t, req) + require.NotNil(t, req.Writes) + require.Len(t, req.Writes.TupleKeys, 2) + require.Equal(t, "org-1", req.Namespace) + + expectedTuples := []*v1.TupleKey{ + {User: "role:test-role-uid#assignee", Relation: "get", Object: "folder:folder1"}, + {User: "role:test-role-uid#assignee", Relation: "update", Object: "folder:folder1"}, + } + + requireTuplesMatch(t, req.Writes.TupleKeys, expectedTuples) + return nil + } + + b.zClient = &FakeZanzanaClient{writeCallback: testCoreRoleEntries} + b.AfterRoleCreate(&coreRole, nil) + wg.Wait() + }) + + t.Run("should create zanzana entries for core role with dashboard permissions", func(t *testing.T) { + wg.Add(1) + coreRole := iamv0.CoreRole{ + ObjectMeta: metav1.ObjectMeta{ + Name: "dashboard-role-uid", + Namespace: "default", + }, + Spec: iamv0.CoreRoleSpec{ + Title: "Dashboard Role", + Description: "Test role for dashboards", + Permissions: []iamv0.CoreRolespecPermission{ + {Action: "dashboards:read", Scope: "dashboards:uid:dash1"}, + {Action: "dashboards:write", Scope: "dashboards:uid:dash1"}, + }, + }, + } + + testDashboardRoleEntries := func(ctx context.Context, req *v1.WriteRequest) error { + defer wg.Done() + require.NotNil(t, req) + require.NotNil(t, req.Writes) + require.Len(t, req.Writes.TupleKeys, 2) + require.Equal(t, "default", req.Namespace) + + // Check subject is role with assignee relation + for _, tuple := range req.Writes.TupleKeys { + require.Equal(t, "role:dashboard-role-uid#assignee", tuple.User) + require.Contains(t, tuple.Object, "resource:") + require.Contains(t, tuple.Object, "dashboard") + } + + return nil + } + + b.zClient = &FakeZanzanaClient{writeCallback: testDashboardRoleEntries} + b.AfterRoleCreate(&coreRole, nil) + wg.Wait() + }) + + t.Run("should handle wildcard scopes", func(t *testing.T) { + wg.Add(1) + coreRole := iamv0.CoreRole{ + ObjectMeta: metav1.ObjectMeta{ + Name: "wildcard-role-uid", + Namespace: "org-2", + }, + Spec: iamv0.CoreRoleSpec{ + Title: "Wildcard Role", + Permissions: []iamv0.CoreRolespecPermission{ + {Action: "folders:read", Scope: "folders:*"}, + }, + }, + } + + testWildcardEntries := func(ctx context.Context, req *v1.WriteRequest) error { + defer wg.Done() + require.NotNil(t, req) + require.NotNil(t, req.Writes) + require.Len(t, req.Writes.TupleKeys, 1) + + tuple := req.Writes.TupleKeys[0] + require.Equal(t, "role:wildcard-role-uid#assignee", tuple.User) + // Wildcard should create a group_resource tuple + require.Contains(t, tuple.Object, "group_resource:") + + return nil + } + + b.zClient = &FakeZanzanaClient{writeCallback: testWildcardEntries} + b.AfterRoleCreate(&coreRole, nil) + wg.Wait() + }) + + t.Run("should skip untranslatable permissions", func(t *testing.T) { + wg.Add(1) + coreRole := iamv0.CoreRole{ + ObjectMeta: metav1.ObjectMeta{ + Name: "mixed-role-uid", + Namespace: "org-1", + }, + Spec: iamv0.CoreRoleSpec{ + Title: "Mixed Role", + Permissions: []iamv0.CoreRolespecPermission{ + {Action: "folders:read", Scope: "folders:uid:folder1"}, + {Action: "unknown:action", Scope: "unknown:scope"}, // This should be skipped + }, + }, + } + + testMixedEntries := func(ctx context.Context, req *v1.WriteRequest) error { + defer wg.Done() + require.NotNil(t, req) + require.NotNil(t, req.Writes) + // Should only have 1 tuple (the untranslatable one should be skipped) + require.Len(t, req.Writes.TupleKeys, 1) + + tuple := req.Writes.TupleKeys[0] + require.Equal(t, "role:mixed-role-uid#assignee", tuple.User) + require.Equal(t, "folder:folder1", tuple.Object) + + return nil + } + + b.zClient = &FakeZanzanaClient{writeCallback: testMixedEntries} + b.AfterRoleCreate(&coreRole, nil) + wg.Wait() + }) +} + +func TestAfterRoleCreate(t *testing.T) { + var wg sync.WaitGroup + b := &IdentityAccessManagementAPIBuilder{ + logger: log.NewNopLogger(), + zTickets: make(chan bool, 1), + } + t.Run("should create zanzana entries for role with folder permissions", func(t *testing.T) { + wg.Add(1) + role := iamv0.Role{ + ObjectMeta: metav1.ObjectMeta{ + Name: "custom-role-uid", + Namespace: "org-3", + }, + Spec: iamv0.RoleSpec{ + Title: "Custom Role", + Description: "Custom role for folders", + Permissions: []iamv0.RolespecPermission{ + {Action: "folders:read", Scope: "folders:uid:folder2"}, + {Action: "folders:delete", Scope: "folders:uid:folder2"}, + }, + }, + } + + testRoleEntries := func(ctx context.Context, req *v1.WriteRequest) error { + defer wg.Done() + require.NotNil(t, req) + require.NotNil(t, req.Writes) + require.Len(t, req.Writes.TupleKeys, 2) + require.Equal(t, "org-3", req.Namespace) + + expectedTuples := []*v1.TupleKey{ + {User: "role:custom-role-uid#assignee", Relation: "get", Object: "folder:folder2"}, + {User: "role:custom-role-uid#assignee", Relation: "delete", Object: "folder:folder2"}, + } + + requireTuplesMatch(t, req.Writes.TupleKeys, expectedTuples) + return nil + } + + b.zClient = &FakeZanzanaClient{writeCallback: testRoleEntries} + b.AfterRoleCreate(&role, nil) + wg.Wait() + }) + + t.Run("should create zanzana entries for role with dashboard permissions", func(t *testing.T) { + wg.Add(1) + role := iamv0.Role{ + ObjectMeta: metav1.ObjectMeta{ + Name: "dash-role-uid", + Namespace: "default", + }, + Spec: iamv0.RoleSpec{ + Title: "Dashboard Custom Role", + Description: "Custom role for dashboards", + Permissions: []iamv0.RolespecPermission{ + {Action: "dashboards:read", Scope: "dashboards:uid:mydash"}, + {Action: "dashboards:delete", Scope: "dashboards:uid:mydash"}, + }, + }, + } + + testDashRoleEntries := func(ctx context.Context, req *v1.WriteRequest) error { + defer wg.Done() + require.NotNil(t, req) + require.NotNil(t, req.Writes) + require.Len(t, req.Writes.TupleKeys, 2) + require.Equal(t, "default", req.Namespace) + + // Check subject is role with assignee relation + for _, tuple := range req.Writes.TupleKeys { + require.Equal(t, "role:dash-role-uid#assignee", tuple.User) + require.Contains(t, tuple.Object, "resource:") + } + + return nil + } + + b.zClient = &FakeZanzanaClient{writeCallback: testDashRoleEntries} + b.AfterRoleCreate(&role, nil) + wg.Wait() + }) + + t.Run("should merge folder resource tuples with same object and user", func(t *testing.T) { + wg.Add(1) + role := iamv0.Role{ + ObjectMeta: metav1.ObjectMeta{ + Name: "merge-role-uid", + Namespace: "org-1", + }, + Spec: iamv0.RoleSpec{ + Title: "Merge Test Role", + Permissions: []iamv0.RolespecPermission{ + // These should create folder resource tuples that get merged + {Action: "dashboards:read", Scope: "folders:uid:parent-folder"}, + {Action: "dashboards:write", Scope: "folders:uid:parent-folder"}, + }, + }, + } + + testMergedEntries := func(ctx context.Context, req *v1.WriteRequest) error { + defer wg.Done() + require.NotNil(t, req) + require.NotNil(t, req.Writes) + // After merging, we should have tuples for the folder resource actions + require.Greater(t, len(req.Writes.TupleKeys), 0) + + for _, tuple := range req.Writes.TupleKeys { + require.Equal(t, "role:merge-role-uid#assignee", tuple.User) + } + + return nil + } + + b.zClient = &FakeZanzanaClient{writeCallback: testMergedEntries} + b.AfterRoleCreate(&role, nil) + wg.Wait() + }) +} + +func TestBeginCoreRoleUpdate(t *testing.T) { + var wg sync.WaitGroup + b := &IdentityAccessManagementAPIBuilder{ + logger: log.NewNopLogger(), + zTickets: make(chan bool, 1), + } + t.Run("should update zanzana entries when permissions change", func(t *testing.T) { + wg.Add(1) + oldRole := iamv0.CoreRole{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-role-uid", + Namespace: "org-1", + }, + Spec: iamv0.CoreRoleSpec{ + Title: "Test Role", + Permissions: []iamv0.CoreRolespecPermission{ + {Action: "folders:read", Scope: "folders:uid:folder1"}, + {Action: "folders:write", Scope: "folders:uid:folder1"}, + }, + }, + } + + newRole := iamv0.CoreRole{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-role-uid", + Namespace: "org-1", + }, + Spec: iamv0.CoreRoleSpec{ + Title: "Test Role Updated", + Permissions: []iamv0.CoreRolespecPermission{ + {Action: "folders:read", Scope: "folders:uid:folder2"}, + {Action: "folders:delete", Scope: "folders:uid:folder2"}, + }, + }, + } + + testUpdate := func(ctx context.Context, req *v1.WriteRequest) error { + defer wg.Done() + require.NotNil(t, req) + require.Equal(t, "org-1", req.Namespace) + + // Verify deletes (old permissions) + require.NotNil(t, req.Deletes) + require.Len(t, req.Deletes.TupleKeys, 2) + + expectedDeletes := []*v1.TupleKeyWithoutCondition{ + {User: "role:test-role-uid#assignee", Relation: "get", Object: "folder:folder1"}, + {User: "role:test-role-uid#assignee", Relation: "update", Object: "folder:folder1"}, + } + requireDeleteTuplesMatch(t, req.Deletes.TupleKeys, expectedDeletes) + + // Verify writes (new permissions) + require.NotNil(t, req.Writes) + require.Len(t, req.Writes.TupleKeys, 2) + + expectedWrites := []*v1.TupleKey{ + {User: "role:test-role-uid#assignee", Relation: "get", Object: "folder:folder2"}, + {User: "role:test-role-uid#assignee", Relation: "delete", Object: "folder:folder2"}, + } + requireTuplesMatch(t, req.Writes.TupleKeys, expectedWrites) + + return nil + } + + b.zClient = &FakeZanzanaClient{writeCallback: testUpdate} + + // Call BeginUpdate which does all the work + finishFunc, err := b.BeginRoleUpdate(context.Background(), &newRole, &oldRole, nil) + require.NoError(t, err) + require.NotNil(t, finishFunc) + + // Call the finish function with success=true to trigger the zanzana write + finishFunc(context.Background(), true) + wg.Wait() + }) + + t.Run("should handle adding new permissions", func(t *testing.T) { + wg.Add(1) + oldRole := iamv0.CoreRole{ + ObjectMeta: metav1.ObjectMeta{ + Name: "expand-role-uid", + Namespace: "org-2", + }, + Spec: iamv0.CoreRoleSpec{ + Title: "Expand Role", + Permissions: []iamv0.CoreRolespecPermission{ + {Action: "folders:read", Scope: "folders:uid:folder1"}, + }, + }, + } + + newRole := iamv0.CoreRole{ + ObjectMeta: metav1.ObjectMeta{ + Name: "expand-role-uid", + Namespace: "org-2", + }, + Spec: iamv0.CoreRoleSpec{ + Title: "Expand Role", + Permissions: []iamv0.CoreRolespecPermission{ + {Action: "folders:read", Scope: "folders:uid:folder1"}, + {Action: "folders:write", Scope: "folders:uid:folder1"}, + {Action: "folders:delete", Scope: "folders:uid:folder1"}, + }, + }, + } + + testExpand := func(ctx context.Context, req *v1.WriteRequest) error { + defer wg.Done() + require.NotNil(t, req) + require.Equal(t, "org-2", req.Namespace) + + // Should delete old permission + require.NotNil(t, req.Deletes) + require.Len(t, req.Deletes.TupleKeys, 1) + + // Should write all new permissions + require.NotNil(t, req.Writes) + require.Len(t, req.Writes.TupleKeys, 3) + + return nil + } + + b.zClient = &FakeZanzanaClient{writeCallback: testExpand} + + // Call BeginUpdate which does all the work + finishFunc, err := b.BeginRoleUpdate(context.Background(), &newRole, &oldRole, nil) + require.NoError(t, err) + require.NotNil(t, finishFunc) + + // Call the finish function with success=true to trigger the zanzana write + finishFunc(context.Background(), true) + wg.Wait() + }) + + t.Run("should handle removing all permissions", func(t *testing.T) { + wg.Add(1) + oldRole := iamv0.CoreRole{ + ObjectMeta: metav1.ObjectMeta{ + Name: "clear-role-uid", + Namespace: "org-3", + }, + Spec: iamv0.CoreRoleSpec{ + Title: "Clear Role", + Permissions: []iamv0.CoreRolespecPermission{ + {Action: "folders:read", Scope: "folders:uid:folder1"}, + {Action: "folders:write", Scope: "folders:uid:folder1"}, + }, + }, + } + + newRole := iamv0.CoreRole{ + ObjectMeta: metav1.ObjectMeta{ + Name: "clear-role-uid", + Namespace: "org-3", + }, + Spec: iamv0.CoreRoleSpec{ + Title: "Clear Role", + Permissions: []iamv0.CoreRolespecPermission{}, + }, + } + + testClear := func(ctx context.Context, req *v1.WriteRequest) error { + defer wg.Done() + require.NotNil(t, req) + require.Equal(t, "org-3", req.Namespace) + + // Should delete old permissions + require.NotNil(t, req.Deletes) + require.Len(t, req.Deletes.TupleKeys, 2) + + // Should have no writes + require.Nil(t, req.Writes) + + return nil + } + + b.zClient = &FakeZanzanaClient{writeCallback: testClear} + + // Call BeginUpdate which does all the work + finishFunc, err := b.BeginRoleUpdate(context.Background(), &newRole, &oldRole, nil) + require.NoError(t, err) + require.NotNil(t, finishFunc) + + // Call the finish function with success=true to trigger the zanzana write + finishFunc(context.Background(), true) + wg.Wait() + }) +} + +func TestBeginRoleUpdate(t *testing.T) { + var wg sync.WaitGroup + b := &IdentityAccessManagementAPIBuilder{ + logger: log.NewNopLogger(), + zTickets: make(chan bool, 1), + } + t.Run("should update zanzana entries when permissions change", func(t *testing.T) { + wg.Add(1) + oldRole := iamv0.Role{ + ObjectMeta: metav1.ObjectMeta{ + Name: "custom-role-uid", + Namespace: "org-1", + }, + Spec: iamv0.RoleSpec{ + Title: "Custom Role", + Permissions: []iamv0.RolespecPermission{ + {Action: "folders:read", Scope: "folders:uid:folder1"}, + {Action: "folders:write", Scope: "folders:uid:folder1"}, + }, + }, + } + + newRole := iamv0.Role{ + ObjectMeta: metav1.ObjectMeta{ + Name: "custom-role-uid", + Namespace: "org-1", + }, + Spec: iamv0.RoleSpec{ + Title: "Custom Role Updated", + Permissions: []iamv0.RolespecPermission{ + {Action: "dashboards:read", Scope: "dashboards:uid:dash1"}, + {Action: "dashboards:write", Scope: "dashboards:uid:dash1"}, + }, + }, + } + + testUpdate := func(ctx context.Context, req *v1.WriteRequest) error { + defer wg.Done() + require.NotNil(t, req) + require.Equal(t, "org-1", req.Namespace) + + // Verify deletes (old permissions) + require.NotNil(t, req.Deletes) + require.Len(t, req.Deletes.TupleKeys, 2) + + expectedDeletes := []*v1.TupleKeyWithoutCondition{ + {User: "role:custom-role-uid#assignee", Relation: "get", Object: "folder:folder1"}, + {User: "role:custom-role-uid#assignee", Relation: "update", Object: "folder:folder1"}, + } + requireDeleteTuplesMatch(t, req.Deletes.TupleKeys, expectedDeletes) + + // Verify writes (new permissions) - dashboards use resource type + require.NotNil(t, req.Writes) + require.Len(t, req.Writes.TupleKeys, 2) + + // All writes should be for dashboards + for _, tuple := range req.Writes.TupleKeys { + require.Equal(t, "role:custom-role-uid#assignee", tuple.User) + require.Contains(t, tuple.Object, "resource:") + require.Contains(t, tuple.Object, "dashboard") + } + + return nil + } + + b.zClient = &FakeZanzanaClient{writeCallback: testUpdate} + + // Call BeginUpdate which does all the work + finishFunc, err := b.BeginRoleUpdate(context.Background(), &newRole, &oldRole, nil) + require.NoError(t, err) + require.NotNil(t, finishFunc) + + // Call the finish function with success=true to trigger the zanzana write + finishFunc(context.Background(), true) + wg.Wait() + }) + + t.Run("should handle completely new permission set", func(t *testing.T) { + wg.Add(1) + oldRole := iamv0.Role{ + ObjectMeta: metav1.ObjectMeta{ + Name: "swap-role-uid", + Namespace: "default", + }, + Spec: iamv0.RoleSpec{ + Title: "Swap Role", + Permissions: []iamv0.RolespecPermission{ + {Action: "folders:read", Scope: "folders:uid:folder1"}, + }, + }, + } + + newRole := iamv0.Role{ + ObjectMeta: metav1.ObjectMeta{ + Name: "swap-role-uid", + Namespace: "default", + }, + Spec: iamv0.RoleSpec{ + Title: "Swap Role", + Permissions: []iamv0.RolespecPermission{ + {Action: "folders:write", Scope: "folders:uid:folder2"}, + {Action: "folders:delete", Scope: "folders:uid:folder2"}, + }, + }, + } + + testSwap := func(ctx context.Context, req *v1.WriteRequest) error { + defer wg.Done() + require.NotNil(t, req) + require.Equal(t, "default", req.Namespace) + + // Should delete old permission + require.NotNil(t, req.Deletes) + require.Len(t, req.Deletes.TupleKeys, 1) + require.Equal(t, "role:swap-role-uid#assignee", req.Deletes.TupleKeys[0].User) + require.Equal(t, "folder:folder1", req.Deletes.TupleKeys[0].Object) + + // Should write new permissions + require.NotNil(t, req.Writes) + require.Len(t, req.Writes.TupleKeys, 2) + for _, tuple := range req.Writes.TupleKeys { + require.Equal(t, "role:swap-role-uid#assignee", tuple.User) + require.Equal(t, "folder:folder2", tuple.Object) + } + + return nil + } + + b.zClient = &FakeZanzanaClient{writeCallback: testSwap} + + // Call BeginUpdate which does all the work + finishFunc, err := b.BeginRoleUpdate(context.Background(), &newRole, &oldRole, nil) + require.NoError(t, err) + require.NotNil(t, finishFunc) + + // Call the finish function with success=true to trigger the zanzana write + finishFunc(context.Background(), true) + wg.Wait() + }) + + t.Run("should handle adding permissions to empty role", func(t *testing.T) { + wg.Add(1) + oldRole := iamv0.Role{ + ObjectMeta: metav1.ObjectMeta{ + Name: "empty-role-uid", + Namespace: "org-2", + }, + Spec: iamv0.RoleSpec{ + Title: "Empty Role", + Permissions: []iamv0.RolespecPermission{}, + }, + } + + newRole := iamv0.Role{ + ObjectMeta: metav1.ObjectMeta{ + Name: "empty-role-uid", + Namespace: "org-2", + }, + Spec: iamv0.RoleSpec{ + Title: "Empty Role", + Permissions: []iamv0.RolespecPermission{ + {Action: "folders:read", Scope: "folders:uid:folder1"}, + }, + }, + } + + testAddToEmpty := func(ctx context.Context, req *v1.WriteRequest) error { + defer wg.Done() + require.NotNil(t, req) + require.Equal(t, "org-2", req.Namespace) + + // Should have no deletes + require.Nil(t, req.Deletes) + + // Should write new permission + require.NotNil(t, req.Writes) + require.Len(t, req.Writes.TupleKeys, 1) + require.Equal(t, "role:empty-role-uid#assignee", req.Writes.TupleKeys[0].User) + require.Equal(t, "folder:folder1", req.Writes.TupleKeys[0].Object) + + return nil + } + + b.zClient = &FakeZanzanaClient{writeCallback: testAddToEmpty} + + // Call BeginUpdate which does all the work + finishFunc, err := b.BeginRoleUpdate(context.Background(), &newRole, &oldRole, nil) + require.NoError(t, err) + require.NotNil(t, finishFunc) + + // Call the finish function with success=true to trigger the zanzana write + finishFunc(context.Background(), true) + wg.Wait() + }) +} + +func TestAfterCoreRoleDelete(t *testing.T) { + var wg sync.WaitGroup + b := &IdentityAccessManagementAPIBuilder{ + logger: log.NewNopLogger(), + zTickets: make(chan bool, 1), + } + t.Run("should delete zanzana entries for core role with folder permissions", func(t *testing.T) { + wg.Add(1) + coreRole := iamv0.CoreRole{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-role-uid", + Namespace: "org-1", + }, + Spec: iamv0.CoreRoleSpec{ + Title: "Test Role", + Description: "Test role for folders", + Permissions: []iamv0.CoreRolespecPermission{ + {Action: "folders:read", Scope: "folders:uid:folder1"}, + {Action: "folders:write", Scope: "folders:uid:folder1"}, + }, + }, + } + + testCoreRoleDeletes := func(ctx context.Context, req *v1.WriteRequest) error { + defer wg.Done() + require.NotNil(t, req) + require.NotNil(t, req.Deletes) + require.Len(t, req.Deletes.TupleKeys, 2) + require.Equal(t, "org-1", req.Namespace) + + expectedDeletes := []*v1.TupleKeyWithoutCondition{ + {User: "role:test-role-uid#assignee", Relation: "get", Object: "folder:folder1"}, + {User: "role:test-role-uid#assignee", Relation: "update", Object: "folder:folder1"}, + } + + requireDeleteTuplesMatch(t, req.Deletes.TupleKeys, expectedDeletes) + return nil + } + + b.zClient = &FakeZanzanaClient{writeCallback: testCoreRoleDeletes} + b.AfterRoleDelete(&coreRole, nil) + wg.Wait() + }) + + t.Run("should delete zanzana entries for core role with dashboard permissions", func(t *testing.T) { + wg.Add(1) + coreRole := iamv0.CoreRole{ + ObjectMeta: metav1.ObjectMeta{ + Name: "dashboard-role-uid", + Namespace: "default", + }, + Spec: iamv0.CoreRoleSpec{ + Title: "Dashboard Role", + Description: "Test role for dashboards", + Permissions: []iamv0.CoreRolespecPermission{ + {Action: "dashboards:read", Scope: "dashboards:uid:dash1"}, + {Action: "dashboards:write", Scope: "dashboards:uid:dash1"}, + }, + }, + } + + testDashboardRoleDeletes := func(ctx context.Context, req *v1.WriteRequest) error { + defer wg.Done() + require.NotNil(t, req) + require.NotNil(t, req.Deletes) + require.Len(t, req.Deletes.TupleKeys, 2) + require.Equal(t, "default", req.Namespace) + + // Check all deletes have the correct subject + for _, tuple := range req.Deletes.TupleKeys { + require.Equal(t, "role:dashboard-role-uid#assignee", tuple.User) + require.Contains(t, tuple.Object, "resource:") + } + + return nil + } + + b.zClient = &FakeZanzanaClient{writeCallback: testDashboardRoleDeletes} + b.AfterRoleDelete(&coreRole, nil) + wg.Wait() + }) + + t.Run("should handle wildcard scopes on delete", func(t *testing.T) { + wg.Add(1) + coreRole := iamv0.CoreRole{ + ObjectMeta: metav1.ObjectMeta{ + Name: "wildcard-role-uid", + Namespace: "org-2", + }, + Spec: iamv0.CoreRoleSpec{ + Title: "Wildcard Role", + Permissions: []iamv0.CoreRolespecPermission{ + {Action: "folders:read", Scope: "folders:*"}, + }, + }, + } + + testWildcardDeletes := func(ctx context.Context, req *v1.WriteRequest) error { + defer wg.Done() + require.NotNil(t, req) + require.NotNil(t, req.Deletes) + require.Len(t, req.Deletes.TupleKeys, 1) + + tuple := req.Deletes.TupleKeys[0] + require.Equal(t, "role:wildcard-role-uid#assignee", tuple.User) + require.Contains(t, tuple.Object, "group_resource:") + + return nil + } + + b.zClient = &FakeZanzanaClient{writeCallback: testWildcardDeletes} + b.AfterRoleDelete(&coreRole, nil) + wg.Wait() + }) + + t.Run("should skip untranslatable permissions on delete", func(t *testing.T) { + wg.Add(1) + coreRole := iamv0.CoreRole{ + ObjectMeta: metav1.ObjectMeta{ + Name: "mixed-role-uid", + Namespace: "org-1", + }, + Spec: iamv0.CoreRoleSpec{ + Title: "Mixed Role", + Permissions: []iamv0.CoreRolespecPermission{ + {Action: "folders:read", Scope: "folders:uid:folder1"}, + {Action: "unknown:action", Scope: "unknown:scope"}, // This should be skipped + }, + }, + } + + testMixedDeletes := func(ctx context.Context, req *v1.WriteRequest) error { + defer wg.Done() + require.NotNil(t, req) + require.NotNil(t, req.Deletes) + // Should only delete 1 tuple (the untranslatable one should be skipped) + require.Len(t, req.Deletes.TupleKeys, 1) + + tuple := req.Deletes.TupleKeys[0] + require.Equal(t, "role:mixed-role-uid#assignee", tuple.User) + require.Equal(t, "folder:folder1", tuple.Object) + + return nil + } + + b.zClient = &FakeZanzanaClient{writeCallback: testMixedDeletes} + b.AfterRoleDelete(&coreRole, nil) + wg.Wait() + }) +} + +func TestAfterRoleDelete(t *testing.T) { + var wg sync.WaitGroup + b := &IdentityAccessManagementAPIBuilder{ + logger: log.NewNopLogger(), + zTickets: make(chan bool, 1), + } + t.Run("should delete zanzana entries for role with folder permissions", func(t *testing.T) { + wg.Add(1) + role := iamv0.Role{ + ObjectMeta: metav1.ObjectMeta{ + Name: "custom-role-uid", + Namespace: "org-3", + }, + Spec: iamv0.RoleSpec{ + Title: "Custom Role", + Description: "Custom role for folders", + Permissions: []iamv0.RolespecPermission{ + {Action: "folders:read", Scope: "folders:uid:folder2"}, + {Action: "folders:delete", Scope: "folders:uid:folder2"}, + }, + }, + } + + testRoleDeletes := func(ctx context.Context, req *v1.WriteRequest) error { + defer wg.Done() + require.NotNil(t, req) + require.NotNil(t, req.Deletes) + require.Len(t, req.Deletes.TupleKeys, 2) + require.Equal(t, "org-3", req.Namespace) + + expectedDeletes := []*v1.TupleKeyWithoutCondition{ + {User: "role:custom-role-uid#assignee", Relation: "get", Object: "folder:folder2"}, + {User: "role:custom-role-uid#assignee", Relation: "delete", Object: "folder:folder2"}, + } + + requireDeleteTuplesMatch(t, req.Deletes.TupleKeys, expectedDeletes) + return nil + } + + b.zClient = &FakeZanzanaClient{writeCallback: testRoleDeletes} + b.AfterRoleDelete(&role, nil) + wg.Wait() + }) + + t.Run("should delete zanzana entries for role with dashboard permissions", func(t *testing.T) { + wg.Add(1) + role := iamv0.Role{ + ObjectMeta: metav1.ObjectMeta{ + Name: "dash-role-uid", + Namespace: "default", + }, + Spec: iamv0.RoleSpec{ + Title: "Dashboard Custom Role", + Description: "Custom role for dashboards", + Permissions: []iamv0.RolespecPermission{ + {Action: "dashboards:read", Scope: "dashboards:uid:mydash"}, + {Action: "dashboards:delete", Scope: "dashboards:uid:mydash"}, + }, + }, + } + + testDashRoleDeletes := func(ctx context.Context, req *v1.WriteRequest) error { + defer wg.Done() + require.NotNil(t, req) + require.NotNil(t, req.Deletes) + require.Len(t, req.Deletes.TupleKeys, 2) + require.Equal(t, "default", req.Namespace) + + // Check all deletes have the correct subject + for _, tuple := range req.Deletes.TupleKeys { + require.Equal(t, "role:dash-role-uid#assignee", tuple.User) + require.Contains(t, tuple.Object, "resource:") + } + + return nil + } + + b.zClient = &FakeZanzanaClient{writeCallback: testDashRoleDeletes} + b.AfterRoleDelete(&role, nil) + wg.Wait() + }) + + t.Run("should handle multiple permissions on delete", func(t *testing.T) { + wg.Add(1) + role := iamv0.Role{ + ObjectMeta: metav1.ObjectMeta{ + Name: "multi-role-uid", + Namespace: "org-1", + }, + Spec: iamv0.RoleSpec{ + Title: "Multi Permission Role", + Permissions: []iamv0.RolespecPermission{ + {Action: "folders:read", Scope: "folders:uid:folder1"}, + {Action: "folders:write", Scope: "folders:uid:folder1"}, + {Action: "folders:delete", Scope: "folders:uid:folder1"}, + }, + }, + } + + testMultiDeletes := func(ctx context.Context, req *v1.WriteRequest) error { + defer wg.Done() + require.NotNil(t, req) + require.NotNil(t, req.Deletes) + require.Len(t, req.Deletes.TupleKeys, 3) + + // All should be for the same role and folder + for _, tuple := range req.Deletes.TupleKeys { + require.Equal(t, "role:multi-role-uid#assignee", tuple.User) + require.Equal(t, "folder:folder1", tuple.Object) + } + + // Check all expected relations are present + relations := make(map[string]bool) + for _, tuple := range req.Deletes.TupleKeys { + relations[tuple.Relation] = true + } + require.True(t, relations["get"], "Expected 'get' relation") + require.True(t, relations["update"], "Expected 'update' relation") + require.True(t, relations["delete"], "Expected 'delete' relation") + + return nil + } + + b.zClient = &FakeZanzanaClient{writeCallback: testMultiDeletes} + b.AfterRoleDelete(&role, nil) + wg.Wait() + }) +} From 555deb5d28b780e2f850c6fa73a0070795705e27 Mon Sep 17 00:00:00 2001 From: Matias Chomicki Date: Mon, 27 Oct 2025 18:34:14 +0100 Subject: [PATCH 033/378] Logs panel: Respect selected fields for downloading logs (#111753) * txt: download selected fields * csv: download selected fields * json: download selected fields * Address lint issues * Update tests * Update tests * Update suppressions --- eslint-suppressions.json | 8 --- .../features/inspector/utils/download.test.ts | 50 +++++++++---- .../app/features/inspector/utils/download.ts | 5 +- .../logs/components/panel/LogListContext.tsx | 4 +- .../components/panel/LogListControls.test.tsx | 4 +- public/app/features/logs/utils.test.ts | 70 +++++++++++++++++++ public/app/features/logs/utils.ts | 64 +++++++++++------ 7 files changed, 159 insertions(+), 46 deletions(-) diff --git a/eslint-suppressions.json b/eslint-suppressions.json index 364c4e1b646..09e46121320 100644 --- a/eslint-suppressions.json +++ b/eslint-suppressions.json @@ -3168,14 +3168,6 @@ "count": 1 } }, - "public/app/features/logs/utils.ts": { - "@typescript-eslint/consistent-type-assertions": { - "count": 1 - }, - "no-restricted-syntax": { - "count": 6 - } - }, "public/app/features/manage-dashboards/DashboardImportPage.tsx": { "no-restricted-syntax": { "count": 2 diff --git a/public/app/features/inspector/utils/download.test.ts b/public/app/features/inspector/utils/download.test.ts index b2e76a29c89..1b1b69fc9eb 100644 --- a/public/app/features/inspector/utils/download.test.ts +++ b/public/app/features/inspector/utils/download.test.ts @@ -1,6 +1,7 @@ import saveAs from 'file-saver'; import { dataFrameFromJSON, DataFrameJSON, dateTimeFormat, FieldType, LogRowModel, LogsMetaKind } from '@grafana/data'; +import { createLogRow } from 'app/features/logs/components/mocks/logRow'; import { downloadAsJson, downloadDataFrameAsCsv, downloadLogsModelAsTxt } from './download'; @@ -33,13 +34,13 @@ describe('inspector download', () => { 'should, when logsModel is %s and title is %s, resolve in %s', async (dataFrame, title, expected) => { downloadDataFrameAsCsv(dataFrame, title); - const call = (saveAs as unknown as jest.Mock).mock.calls[0]; + const call = jest.mocked(saveAs).mock.calls[0]; const blob = call[0]; const filename = call[1]; - const text = await blob.text(); + const text = typeof blob === 'string' ? blob : await blob.text(); // By default the BOM character should not be included - expect(await getBomType(blob)).toBeUndefined(); + expect(blob instanceof Blob ? await getBomType(blob) : undefined).toBeUndefined(); expect(text).toEqual(expected); expect(filename).toEqual(`${title}-data-${dateTimeFormat(1400000000000)}.csv`); } @@ -48,15 +49,18 @@ describe('inspector download', () => { it('should use \t as the delimiter and the file should be utf16le if excelCompatibilityMode is true', async () => { downloadDataFrameAsCsv(dataFrameFromJSON(json), 'test', undefined, undefined, true); - const call = (saveAs as unknown as jest.Mock).mock.calls[0]; + const call = jest.mocked(saveAs).mock.calls[0]; const blob = call[0]; const filename = call[1]; - const text = await blob.text(); + const text = typeof blob === 'string' ? blob : await blob.text(); - expect(await getBomType(blob)).toBe('utf-16le'); - expect(blob.type).toBe('text/csv;charset=utf-16le'); + if (blob instanceof Blob) { + expect(await getBomType(blob)).toBe('utf-16le'); + expect(blob.type).toBe('text/csv;charset=utf-16le'); + } expect(text).toEqual('"time"\t"name"\t"value"\r\n100\tÅäö中文العربية\t1'); expect(filename).toEqual(`test-data-${dateTimeFormat(1400000000000)}.csv`); + expect.assertions(4); }); }); @@ -67,10 +71,10 @@ describe('inspector download', () => { [{ foo: 'bar' }, 'test', '{"foo":"bar"}'], ])('should, when logsModel is %s and title is %s, resolve in %s', async (logsModel, title, expected) => { downloadAsJson(logsModel, title); - const call = (saveAs as unknown as jest.Mock).mock.calls[0]; + const call = jest.mocked(saveAs).mock.calls[0]; const blob = call[0]; const filename = call[1]; - const text = await blob.text(); + const text = typeof blob === 'string' ? blob : await blob.text(); expect(text).toEqual(expected); expect(filename).toEqual(`${title}-${dateTimeFormat(1400000000000)}.json`); @@ -110,10 +114,10 @@ describe('inspector download', () => { ], ])('should, when logsModel is %s and title is %s, resolve in %s', async (logsModel, title, expected) => { downloadLogsModelAsTxt(logsModel, title); - const call = (saveAs as unknown as jest.Mock).mock.calls[0]; + const call = jest.mocked(saveAs).mock.calls[0]; const blob = call[0]; const filename = call[1]; - const text = await blob.text(); + const text = typeof blob === 'string' ? blob : await blob.text(); expect(text).toEqual(expected); expect(filename).toEqual(`${title}-logs-${dateTimeFormat(1400000000000)}.txt`); @@ -121,10 +125,32 @@ describe('inspector download', () => { it('should, when title is empty, resolve in %s', async () => { downloadLogsModelAsTxt({ meta: [], rows: [] }); - const call = (saveAs as unknown as jest.Mock).mock.calls[0]; + const call = jest.mocked(saveAs).mock.calls[0]; const filename = call[1]; expect(filename).toEqual(`Logs-${dateTimeFormat(1400000000000)}.txt`); }); + + it('should, when title is empty, resolve in %s', async () => { + downloadLogsModelAsTxt({ meta: [], rows: [] }); + const call = jest.mocked(saveAs).mock.calls[0]; + const filename = call[1]; + expect(filename).toEqual(`Logs-${dateTimeFormat(1400000000000)}.txt`); + }); + + it('should should download selected fields', async () => { + const logsModel = { + meta: [], + rows: [ + createLogRow({ timeEpochMs: 100, entry: 'testEntry', labels: { label: 'value', otherLabel: 'other value' } }), + ], + }; + downloadLogsModelAsTxt(logsModel, undefined, ['label', 'otherLabel']); + const call = jest.mocked(saveAs).mock.calls[0]; + const blob = call[0]; + const text = typeof blob === 'string' ? blob : await blob.text(); + + expect(text).toContain('value other value'); + }); }); }); diff --git a/public/app/features/inspector/utils/download.ts b/public/app/features/inspector/utils/download.ts index 1332180acf2..3a6c05c0f71 100644 --- a/public/app/features/inspector/utils/download.ts +++ b/public/app/features/inspector/utils/download.ts @@ -21,7 +21,7 @@ import { transformToZipkin } from '../../../plugins/datasource/zipkin/utils/tran * @param {(Pick)} logsModel * @param {string} title */ -export function downloadLogsModelAsTxt(logsModel: Pick, title = '') { +export function downloadLogsModelAsTxt(logsModel: Pick, title = '', fields: string[] = []) { let textToDownload = ''; logsModel.meta?.forEach((metaItem) => { @@ -31,7 +31,8 @@ export function downloadLogsModelAsTxt(logsModel: Pick { - const newRow = row.timeEpochMs + '\t' + dateTime(row.timeEpochMs).toISOString() + '\t' + row.entry + '\n'; + const entry = !fields.length ? row.entry : fields.map((field) => row.labels[field] ?? '').join(' '); + const newRow = row.timeEpochMs + '\t' + dateTime(row.timeEpochMs).toISOString() + '\t' + entry + '\n'; textToDownload = textToDownload + newRow; }); diff --git a/public/app/features/logs/components/panel/LogListContext.tsx b/public/app/features/logs/components/panel/LogListContext.tsx index efa4dfcda8a..0539743fb02 100644 --- a/public/app/features/logs/components/panel/LogListContext.tsx +++ b/public/app/features/logs/components/panel/LogListContext.tsx @@ -559,9 +559,9 @@ export const LogListContextProvider = ({ logListState.filterLevels.length === 0 ? logs : logs.filter((log) => logListState.filterLevels.includes(log.logLevel)); - download(format, filteredLogs, logsMeta); + download(format, filteredLogs, logsMeta, displayedFields); }, - [logListState.filterLevels, logs, logsMeta] + [displayedFields, logListState.filterLevels, logs, logsMeta] ); const closeDetails = useCallback(() => { diff --git a/public/app/features/logs/components/panel/LogListControls.test.tsx b/public/app/features/logs/components/panel/LogListControls.test.tsx index 29955c8d46d..f5325d21108 100644 --- a/public/app/features/logs/components/panel/LogListControls.test.tsx +++ b/public/app/features/logs/components/panel/LogListControls.test.tsx @@ -448,7 +448,7 @@ describe('LogListControls', () => { await userEvent.click(screen.getByLabelText(DOWNLOAD_LOGS_LABEL_COPY)); await userEvent.click(await screen.findByText(label)); expect(downloadLogs).toHaveBeenCalledTimes(1); - expect(downloadLogs).toHaveBeenCalledWith(format, [], undefined); + expect(downloadLogs).toHaveBeenCalledWith(format, [], undefined, []); }); test('Allows to download logs filtered logs', async () => { @@ -465,7 +465,7 @@ describe('LogListControls', () => { ); await userEvent.click(screen.getByLabelText(DOWNLOAD_LOGS_LABEL_COPY)); await userEvent.click(await screen.findByText('txt')); - expect(downloadLogs).toHaveBeenCalledWith('text', filteredLogs, undefined); + expect(downloadLogs).toHaveBeenCalledWith('text', filteredLogs, undefined, []); }); test('Controls new lines', async () => { diff --git a/public/app/features/logs/utils.test.ts b/public/app/features/logs/utils.test.ts index f23a8ae9069..2ae39fbeb10 100644 --- a/public/app/features/logs/utils.test.ts +++ b/public/app/features/logs/utils.test.ts @@ -1,3 +1,5 @@ +import saveAs from 'file-saver'; + import { AbsoluteTimeRange, FieldType, @@ -11,6 +13,7 @@ import { } from '@grafana/data'; import { getMockFrames } from 'app/plugins/datasource/loki/mocks/frames'; +import { createLogRow } from './components/mocks/logRow'; import { logSeriesToLogsModel } from './logsModel'; import { calculateLogsLabelStats, @@ -25,8 +28,12 @@ import { mergeLogsVolumeDataFrames, sortLogsResult, checkLogsSampled, + downloadLogs, + DownloadFormat, } from './utils'; +jest.mock('file-saver', () => jest.fn()); + describe('getLoglevel()', () => { it('returns no log level on empty line', () => { expect(getLogLevel('')).toBe(LogLevel.unknown); @@ -588,3 +595,66 @@ describe('findMatchingRow', () => { } }); }); + +describe('downloadLogs', () => { + const logs = [ + createLogRow({ timeEpochMs: 100, entry: 'test entry', labels: { label: 'value', otherLabel: 'other value' } }), + ]; + describe('Text format', () => { + beforeEach(() => { + jest.mocked(saveAs).mockClear(); + }); + + it('Downloads logs in txt format', async () => { + downloadLogs(DownloadFormat.Text, logs); + + const blob = jest.mocked(saveAs).mock.calls[0][0]; + const text = typeof blob === 'string' ? blob : await blob.text(); + + expect(text).toContain('test entry'); + }); + + it('Downloads selected fields in txt format', async () => { + downloadLogs(DownloadFormat.Text, logs, [], ['label', 'otherLabel']); + + const blob = jest.mocked(saveAs).mock.calls[0][0]; + const text = typeof blob === 'string' ? blob : await blob.text(); + + expect(text).toContain('value other value'); + }); + }); + + describe('JSON format', () => { + beforeEach(() => { + jest.mocked(saveAs).mockClear(); + }); + + it('Downloads logs in JSON format', async () => { + downloadLogs(DownloadFormat.Json, logs); + + const blob = jest.mocked(saveAs).mock.calls[0][0]; + const text = typeof blob === 'string' ? blob : await blob.text(); + + expect(JSON.parse(text)[0]).toEqual( + expect.objectContaining({ + line: 'test entry', + fields: { label: 'value', otherLabel: 'other value' }, + }) + ); + }); + + it('Downloads selected fields in JSON format', async () => { + downloadLogs(DownloadFormat.Json, logs, [], ['otherLabel']); + + const blob = jest.mocked(saveAs).mock.calls[0][0]; + const text = typeof blob === 'string' ? blob : await blob.text(); + + expect(JSON.parse(text)[0]).toEqual( + expect.objectContaining({ + line: 'test entry', + fields: { otherLabel: 'other value' }, + }) + ); + }); + }); +}); diff --git a/public/app/features/logs/utils.ts b/public/app/features/logs/utils.ts index 0d16732ba7d..61f428745a5 100644 --- a/public/app/features/logs/utils.ts +++ b/public/app/features/logs/utils.ts @@ -29,6 +29,7 @@ import { getTimeField, Field, LogsMetaItem, + store, } from '@grafana/data'; import { t } from '@grafana/i18n'; import { getConfig } from 'app/core/config'; @@ -67,6 +68,7 @@ export function getLogLevel(line: string): LogLevel { } export function getLogLevelFromKey(key: string | number): LogLevel { + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions const level = LogLevel[key.toString().toLowerCase() as keyof typeof LogLevel]; if (level) { return level; @@ -179,7 +181,7 @@ export const checkLogsSampled = (logRow: LogRowModel): string | undefined => { export const escapeUnescapedString = (string: string) => string.replace(/\\r\\n|\\n|\\t|\\r/g, (match: string) => (match.slice(1) === 't' ? '\t' : '\n')); -export function logRowsToReadableJson(logs: LogRowModel[]) { +export function logRowsToReadableJson(logs: LogRowModel[], pickFields: string[] = []) { return logs.map((log) => { const fields = getDataframeFields(log).reduce>((acc, field) => { const key = field.keys[0]; @@ -187,14 +189,20 @@ export function logRowsToReadableJson(logs: LogRowModel[]) { return acc; }, {}); + let logFields = { + ...fields, + ...log.labels, + }; + + if (pickFields.length) { + logFields = Object.fromEntries(Object.entries(logFields).filter(([key]) => pickFields.includes(key))); + } + return { line: log.entry, timestamp: log.timeEpochNs, date: dateTime(log.timeEpochMs).toISOString(), - fields: { - ...fields, - ...log.labels, - }, + fields: logFields, }; }); } @@ -423,15 +431,15 @@ function getDataSourceLabelType(labelType: string, datasourceType: string, plura const POPOVER_STORAGE_KEY = 'logs.popover.disabled'; export function disablePopoverMenu() { - localStorage.setItem(POPOVER_STORAGE_KEY, 'true'); + store.set(POPOVER_STORAGE_KEY, 'true'); } export function enablePopoverMenu() { - localStorage.removeItem(POPOVER_STORAGE_KEY); + store.delete(POPOVER_STORAGE_KEY); } export function isPopoverMenuDisabled() { - return Boolean(localStorage.getItem(POPOVER_STORAGE_KEY)); + return Boolean(store.get(POPOVER_STORAGE_KEY)); } export enum DownloadFormat { @@ -440,13 +448,18 @@ export enum DownloadFormat { CSV = 'csv', } -export const downloadLogs = async (format: DownloadFormat, logRows: LogRowModel[], meta?: LogsMetaItem[]) => { +export const downloadLogs = async ( + format: DownloadFormat, + logRows: LogRowModel[], + meta?: LogsMetaItem[], + fields: string[] = [] +) => { switch (format) { case DownloadFormat.Text: - downloadLogsModelAsTxt({ meta, rows: logRows }); + downloadLogsModelAsTxt({ meta, rows: logRows }, '', fields); break; case DownloadFormat.Json: - const jsonLogs = logRowsToReadableJson(logRows); + const jsonLogs = logRowsToReadableJson(logRows, fields); const blob = new Blob([JSON.stringify(jsonLogs)], { type: 'application/json;charset=utf-8', }); @@ -462,18 +475,29 @@ export const downloadLogs = async (format: DownloadFormat, logRows: LogRowModel[ }); dataFrameMap.forEach(async (dataFrame) => { const transforms: Array = getLogsExtractFields(dataFrame); - transforms.push( - { - id: 'organize', + if (fields.length) { + transforms.push(addISODateTransformation, { + id: 'filterFieldsByName', options: { - excludeByName: { - ['labels']: true, - ['labelTypes']: true, + include: { + names: ['Date', ...fields], }, }, - }, - addISODateTransformation - ); + }); + } else { + transforms.push( + { + id: 'organize', + options: { + excludeByName: { + ['labels']: true, + ['labelTypes']: true, + }, + }, + }, + addISODateTransformation + ); + } const transformedDataFrame = await lastValueFrom(transformDataFrame(transforms, [dataFrame])); downloadDataFrameAsCsv(transformedDataFrame[0], `Logs-${dataFrame.refId}`); }); From ce246936c41da1df64c12f6e012ba3bb1eaa01c4 Mon Sep 17 00:00:00 2001 From: Moustafa Baiou Date: Tue, 21 Oct 2025 16:12:35 -0400 Subject: [PATCH 034/378] Alerting: Surface remote AM silence creation errors properly When creating silences in remote Alertmanager instances, all 4xx errors were treated as 500s. This change ensures that 4xx errors are properly surfaced as bad payload errors, allowing callers to handle them appropriately. --- pkg/services/ngalert/remote/alertmanager.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/pkg/services/ngalert/remote/alertmanager.go b/pkg/services/ngalert/remote/alertmanager.go index 81e3ef40181..81175e14766 100644 --- a/pkg/services/ngalert/remote/alertmanager.go +++ b/pkg/services/ngalert/remote/alertmanager.go @@ -4,6 +4,7 @@ import ( "context" "encoding/base64" "encoding/json" + "errors" "fmt" "hash/fnv" "maps" @@ -13,6 +14,7 @@ import ( "strings" "time" + openapiRuntime "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" @@ -465,6 +467,18 @@ func (am *Alertmanager) CreateSilence(ctx context.Context, silence *apimodels.Po params := amsilence.NewPostSilencesParamsWithContext(ctx).WithSilence(silence) res, err := am.amClient.Silence.PostSilences(params) if err != nil { + // Translate downstream 4xx errors into a well-known bad payload error so callers can surface HTTP 400. + // The swagger client returns typed errors and/or an *openapiRuntime.APIError with a Code field. + var badReq *amsilence.PostSilencesBadRequest + if errors.As(err, &badReq) { + return "", fmt.Errorf("%w: %v", alertingNotify.ErrCreateSilenceBadPayload, err) + } + var apiErr *openapiRuntime.APIError + if errors.As(err, &apiErr) { + if apiErr.Code >= http.StatusBadRequest && apiErr.Code < http.StatusInternalServerError { + return "", fmt.Errorf("%w: %v", alertingNotify.ErrCreateSilenceBadPayload, err) + } + } return "", err } From 3dd4493d5042b3ebb4e47596c30582c92b01de4f Mon Sep 17 00:00:00 2001 From: Erik Sundell Date: Tue, 28 Oct 2025 07:32:35 +0100 Subject: [PATCH 035/378] Plugin Details Page: Fix tabs not loading on hard refresh (#112915) * don't show nav children while plugin config is loading * add tests --- .../admin/hooks/usePluginDetailsTabs.test.tsx | 124 ++++++++++++++++++ .../admin/hooks/usePluginDetailsTabs.tsx | 5 +- 2 files changed, 127 insertions(+), 2 deletions(-) create mode 100644 public/app/features/plugins/admin/hooks/usePluginDetailsTabs.test.tsx diff --git a/public/app/features/plugins/admin/hooks/usePluginDetailsTabs.test.tsx b/public/app/features/plugins/admin/hooks/usePluginDetailsTabs.test.tsx new file mode 100644 index 00000000000..83a148a2647 --- /dev/null +++ b/public/app/features/plugins/admin/hooks/usePluginDetailsTabs.test.tsx @@ -0,0 +1,124 @@ +import { renderHook } from '@testing-library/react'; + +import { PluginSignatureStatus, PluginSignatureType, PluginType } from '@grafana/data'; +import { config } from '@grafana/runtime'; + +import { CatalogPlugin } from '../types'; + +import { usePluginDetailsTabs } from './usePluginDetailsTabs'; + +jest.mock('react-router-dom-v5-compat', () => ({ + useLocation: () => ({ pathname: '/plugins/test-plugin' }), +})); + +jest.mock('./usePluginConfig'); + +jest.mock('app/core/core', () => ({ + contextSrv: { + hasPermissionInMetadata: jest.fn(() => true), + }, +})); + +const mockUsePluginConfig = jest.requireMock('./usePluginConfig').usePluginConfig; + +const mockPlugin: CatalogPlugin = { + id: 'test-plugin', + name: 'Test Plugin', + description: 'Test plugin description', + type: PluginType.app, + isPublished: true, + isInstalled: true, + isCore: false, + isDev: false, + isDisabled: false, + isDeprecated: false, + isEnterprise: false, + isFullyInstalled: true, + isManaged: false, + isPreinstalled: { found: false, withVersion: false }, + hasUpdate: false, + info: { + logos: { small: '', large: '' }, + keywords: [], + }, + orgName: 'Test', + signature: PluginSignatureStatus.valid, + signatureType: PluginSignatureType.grafana, + signatureOrg: 'Grafana', + popularity: 1, + downloads: 100, + updatedAt: '2023-01-01', + publishedAt: '2023-01-01', + angularDetected: false, + accessControl: {}, +}; + +const mockPluginConfig = { + meta: { + id: 'test-plugin', + name: 'Test Plugin', + type: PluginType.app, + module: 'test', + baseUrl: '', + info: { + author: { name: 'Test' }, + description: 'Test plugin', + logos: { small: '', large: '' }, + links: [], + screenshots: [], + updated: '2023-01-01', + version: '1.0.0', + keywords: [], + }, + }, + configPages: [ + { + id: 'config-page-1', + title: 'Configuration', + icon: 'cog', + body: () => null, + }, + ], +}; + +describe('usePluginDetailsTabs', () => { + beforeEach(() => { + jest.clearAllMocks(); + config.featureToggles.externalServiceAccounts = false; + }); + + it('should not include config-specific tabs while plugin config is loading', () => { + // simulate the race condition: plugin is loaded but config is still loading + mockUsePluginConfig.mockReturnValue({ + loading: true, + error: undefined, + value: null, + }); + + const { result } = renderHook(() => usePluginDetailsTabs(mockPlugin, undefined, false)); + + // should NOT include config page tabs while loading + const configTab = result.current.navModel.children?.find((tab) => tab.id === 'config-page-1'); + expect(configTab).toBeUndefined(); + + // should include basic tabs + const overviewTab = result.current.navModel.children?.find((tab) => tab.id === 'overview'); + expect(overviewTab).toBeDefined(); + }); + + it('should include config-specific tabs when plugin config is loaded', () => { + // simulate config loaded successfully + mockUsePluginConfig.mockReturnValue({ + loading: false, + error: undefined, + value: mockPluginConfig, + }); + + const { result } = renderHook(() => usePluginDetailsTabs(mockPlugin, undefined, false)); + + // should NOW include config page tabs + const configTab = result.current.navModel.children?.find((tab) => tab.id === 'config-page-1'); + expect(configTab).toBeDefined(); + expect(configTab?.text).toBe('Configuration'); + }); +}); diff --git a/public/app/features/plugins/admin/hooks/usePluginDetailsTabs.tsx b/public/app/features/plugins/admin/hooks/usePluginDetailsTabs.tsx index 6f0f076d54b..77ea7115922 100644 --- a/public/app/features/plugins/admin/hooks/usePluginDetailsTabs.tsx +++ b/public/app/features/plugins/admin/hooks/usePluginDetailsTabs.tsx @@ -85,7 +85,8 @@ export const usePluginDetailsTabs = ( } // Not extending the tabs with the config pages if the plugin is not installed - if (!pluginConfig) { + // also wait if the plugin config is still loading to avoid showing default tabs prematurely + if (!pluginConfig || loading) { return navModelChildren; } @@ -151,7 +152,7 @@ export const usePluginDetailsTabs = ( } return navModelChildren; - }, [plugin, pluginConfig, pathname, isPublished, currentPageId, isNarrowScreen]); + }, [plugin, pluginConfig, pathname, isPublished, currentPageId, isNarrowScreen, loading]); const navModel: NavModelItem = { text: plugin?.name ?? '', From b77a99214abedc93daf8b7e2394afb6cb652f559 Mon Sep 17 00:00:00 2001 From: Anna Urbiztondo Date: Tue, 28 Oct 2025 07:45:32 +0100 Subject: [PATCH 036/378] Docs: Admin tweaks - Edits, weights (#113031) * Edits, weights * WIP * Weights * prettier --- .../announcement-banner/_index.md | 1 + .../administration/back-up-grafana/index.md | 2 +- docs/sources/administration/cli.md | 37 ++++++++++--------- .../administration/correlations/_index.md | 2 +- .../data-source-management/_index.md | 2 +- .../enterprise-licensing/_index.md | 2 +- .../administration/grafana-advisor/_index.md | 2 +- .../administration/migration-guide/_index.md | 1 + .../organization-management/index.md | 2 +- .../organization-preferences/index.md | 2 +- .../administration/provisioning/index.md | 3 +- .../administration/recorded-queries/index.md | 7 ++-- .../roles-and-permissions/_index.md | 2 +- docs/sources/administration/search/_index.md | 1 + .../administration/service-accounts/_index.md | 2 +- .../administration/stats-and-license/index.md | 3 +- .../administration/team-management/_index.md | 6 +-- .../administration/user-management/_index.md | 4 +- 18 files changed, 45 insertions(+), 36 deletions(-) diff --git a/docs/sources/administration/announcement-banner/_index.md b/docs/sources/administration/announcement-banner/_index.md index b67e0d7ca1d..020ca45c877 100644 --- a/docs/sources/administration/announcement-banner/_index.md +++ b/docs/sources/administration/announcement-banner/_index.md @@ -9,6 +9,7 @@ labels: menuTitle: Announcement banner title: Create and configure announcement banner description: How to create an announcement banner to show important updates and information at the top of every Grafana page. +weight: 5500 --- # Create an announcement banner diff --git a/docs/sources/administration/back-up-grafana/index.md b/docs/sources/administration/back-up-grafana/index.md index 2c9286f0b0e..0ceb0b4e5fc 100644 --- a/docs/sources/administration/back-up-grafana/index.md +++ b/docs/sources/administration/back-up-grafana/index.md @@ -8,7 +8,7 @@ labels: - enterprise - oss title: Back up Grafana -weight: 80 +weight: 100 menuTitle: Back up Grafana --- diff --git a/docs/sources/administration/cli.md b/docs/sources/administration/cli.md index 0e8e6e611e0..416b1c24335 100644 --- a/docs/sources/administration/cli.md +++ b/docs/sources/administration/cli.md @@ -1,45 +1,43 @@ --- aliases: - ../cli/ # /docs/grafana/latest/cli/ -description: Guide to using grafana server cli +description: Guide to using the Grafana server CLI keywords: - grafana - cli - grafana cli - command line interface + - admin labels: products: - enterprise - oss title: Grafana server CLI -weight: 1100 +menuTitle: Admin with Grafana server CLI +weight: 4000 --- -# Grafana server CLI +# Administer Grafana with the Grafana server CLI -Grafana server CLI is a small executable that's bundled with Grafana server. -You can run it on the same machine Grafana server is running on. -Grafana server CLI has `plugins` and `admin` commands, as well as global options. +You can administer your Grafana instance with the Grafana server CLI, a small executable bundled with Grafana server. -To list all commands and options: +The Grafana server CLI has `plugins` and `admin` commands, as well as global options. To list them, run: ``` grafana cli -h ``` -## Run Grafana server CLI +For more details read on. -To run Grafana server CLI, add the path to the Grafana binaries in your `PATH` environment variable. -Alternately, if your current directory is the `bin` directory, run `./grafana cli`. -Otherwise, you can specify full path to the binary. -For example, on Linux `/usr/share/grafana/bin/grafana` and on Windows `C:\Program Files\GrafanaLabs\grafana\bin\grafana.exe`, and run it with `grafana cli`. +## Run the Grafana server CLI -{{< admonition type="note" >}} -Some commands, such as installing or removing plugins, require `sudo` on Linux. -If you're on Windows, run Windows PowerShell as Administrator. -{{< /admonition >}} +You can run the Grafana server CLI on the same machine Grafana server is running on. -## Grafana CLI command syntax +To run the CLI you have the following options: + +- Add the path to the Grafana binaries in your `PATH` environment variable. +- If your current directory is the `bin` directory, run `./grafana cli`. +- Otherwise, you can specify full path to the binary. For example, `/usr/share/grafana/bin/grafana` on Linux and `C:\Program Files\GrafanaLabs\grafana\bin\grafana.exe` on Windows. The general syntax for commands in Grafana server CLI is: @@ -47,6 +45,11 @@ The general syntax for commands in Grafana server CLI is: grafana cli [global options] command [command options] [arguments...] ``` +{{< admonition type="note" >}} +Some commands, such as installing or removing plugins, require `sudo` on Linux. +If you're on Windows, run Windows PowerShell as Administrator. +{{< /admonition >}} + ## Global options Grafana server CLI allows you to temporarily override certain Grafana default settings. Except for `--help` and `--version`, most global options are only used by developers. diff --git a/docs/sources/administration/correlations/_index.md b/docs/sources/administration/correlations/_index.md index 36e0badf5f5..7d449ce88b9 100644 --- a/docs/sources/administration/correlations/_index.md +++ b/docs/sources/administration/correlations/_index.md @@ -7,7 +7,7 @@ labels: - enterprise - oss title: Correlations -weight: 900 +weight: 6000 --- # Correlations diff --git a/docs/sources/administration/data-source-management/_index.md b/docs/sources/administration/data-source-management/_index.md index 1a28b0001c3..8cb0d57d30e 100644 --- a/docs/sources/administration/data-source-management/_index.md +++ b/docs/sources/administration/data-source-management/_index.md @@ -12,7 +12,7 @@ labels: - enterprise - cloud title: Data source management -weight: 100 +weight: 500 --- # Data source management diff --git a/docs/sources/administration/enterprise-licensing/_index.md b/docs/sources/administration/enterprise-licensing/_index.md index 11619aa43e7..759431ebad7 100644 --- a/docs/sources/administration/enterprise-licensing/_index.md +++ b/docs/sources/administration/enterprise-licensing/_index.md @@ -18,7 +18,7 @@ labels: - enterprise - oss title: Grafana Enterprise license -weight: 500 +weight: 5500 --- # Grafana Enterprise license diff --git a/docs/sources/administration/grafana-advisor/_index.md b/docs/sources/administration/grafana-advisor/_index.md index 38673e9e121..6292a13fd6b 100644 --- a/docs/sources/administration/grafana-advisor/_index.md +++ b/docs/sources/administration/grafana-advisor/_index.md @@ -1,7 +1,7 @@ --- title: Grafana Advisor description: Learn more about Grafana Advisor, the app to monitor the health of your Grafana instance -weight: 300 +weight: 700 labels: products: - oss diff --git a/docs/sources/administration/migration-guide/_index.md b/docs/sources/administration/migration-guide/_index.md index 94576db65c0..d601b95d331 100644 --- a/docs/sources/administration/migration-guide/_index.md +++ b/docs/sources/administration/migration-guide/_index.md @@ -9,6 +9,7 @@ keywords: - Grafana OSS menuTitle: Migrate from Grafana OSS/Enterprise to Grafana Cloud title: Migrate from Grafana OSS/Enterprise to Grafana Cloud +weight: 7000 --- # Migrate from Grafana OSS/Enterprise to Grafana Cloud diff --git a/docs/sources/administration/organization-management/index.md b/docs/sources/administration/organization-management/index.md index 7eef5d45424..621374d4884 100644 --- a/docs/sources/administration/organization-management/index.md +++ b/docs/sources/administration/organization-management/index.md @@ -14,7 +14,7 @@ labels: - oss menuTitle: Manage organizations title: Manage organizations -weight: 200 +weight: 3500 --- # Manage organizations diff --git a/docs/sources/administration/organization-preferences/index.md b/docs/sources/administration/organization-preferences/index.md index bc54894a3ab..0df51d324c7 100644 --- a/docs/sources/administration/organization-preferences/index.md +++ b/docs/sources/administration/organization-preferences/index.md @@ -11,7 +11,7 @@ labels: - enterprise - oss title: Organization preferences -weight: 500 +weight: 3600 --- # Organization preferences diff --git a/docs/sources/administration/provisioning/index.md b/docs/sources/administration/provisioning/index.md index 8874448224f..51fd1f4c604 100644 --- a/docs/sources/administration/provisioning/index.md +++ b/docs/sources/administration/provisioning/index.md @@ -11,7 +11,8 @@ labels: - enterprise - oss title: Provision Grafana -weight: 600 +menuTitle: Provision Grafana +weight: 4100 --- # Provision Grafana diff --git a/docs/sources/administration/recorded-queries/index.md b/docs/sources/administration/recorded-queries/index.md index 425ff2bbf7c..e76021ae8d7 100644 --- a/docs/sources/administration/recorded-queries/index.md +++ b/docs/sources/administration/recorded-queries/index.md @@ -11,11 +11,12 @@ labels: products: - cloud - enterprise -title: Recorded queries -weight: 300 +title: Recorded queries (deprecated) +menuTitle: Recorded queries (deprecated) +weight: 9000 --- -# DEPRECATED Recorded queries +# Recorded queries (deprecated) {{< admonition type="warning" >}} Recorded queries are deprecated. Please use the new [Grafana-managed recording rules](/docs/grafana/latest/alerting/alerting-rules/create-recording-rules/create-grafana-managed-recording-rules) instead. diff --git a/docs/sources/administration/roles-and-permissions/_index.md b/docs/sources/administration/roles-and-permissions/_index.md index d6cca1b7eb9..c8135836fa1 100644 --- a/docs/sources/administration/roles-and-permissions/_index.md +++ b/docs/sources/administration/roles-and-permissions/_index.md @@ -12,7 +12,7 @@ labels: - oss - cloud title: Roles and permissions -weight: 300 +weight: 3100 --- # Roles and permissions diff --git a/docs/sources/administration/search/_index.md b/docs/sources/administration/search/_index.md index 5bd777e9f01..7e41f995ad3 100644 --- a/docs/sources/administration/search/_index.md +++ b/docs/sources/administration/search/_index.md @@ -15,6 +15,7 @@ labels: - oss menutitle: Search title: Search +weight: 8000 --- # Grafana search diff --git a/docs/sources/administration/service-accounts/_index.md b/docs/sources/administration/service-accounts/_index.md index 5eb48e324b6..34bbd916610 100644 --- a/docs/sources/administration/service-accounts/_index.md +++ b/docs/sources/administration/service-accounts/_index.md @@ -15,7 +15,7 @@ labels: - cloud menuTitle: Service accounts title: Service accounts -weight: 800 +weight: 4200 refs: service-accounts: - pattern: /docs/grafana/ diff --git a/docs/sources/administration/stats-and-license/index.md b/docs/sources/administration/stats-and-license/index.md index ec926f73c2f..c8fe61fe47d 100644 --- a/docs/sources/administration/stats-and-license/index.md +++ b/docs/sources/administration/stats-and-license/index.md @@ -16,7 +16,8 @@ labels: - cloud - enterprise title: View server statistics and license -weight: 400 +menutitle: Server stats and license +weight: 5000 --- # View server statistics and license diff --git a/docs/sources/administration/team-management/_index.md b/docs/sources/administration/team-management/_index.md index 0a35b764cb7..5fff00428f3 100644 --- a/docs/sources/administration/team-management/_index.md +++ b/docs/sources/administration/team-management/_index.md @@ -15,11 +15,11 @@ keywords: - microservices - architecture menuTitle: Grafana Teams -title: Grafana Teams -weight: 100 +title: Manage teams with Grafana Teams +weight: 2000 --- -# Grafana Teams +# Manage teams with Grafana Teams Grafana Teams makes it easy to organize and administer groups of users in your enterprise. Teams allows you to grant permissions to a group of users instead of granting permissions to individual users one at a time. diff --git a/docs/sources/administration/user-management/_index.md b/docs/sources/administration/user-management/_index.md index ad3be03f7cb..3b6ff208903 100644 --- a/docs/sources/administration/user-management/_index.md +++ b/docs/sources/administration/user-management/_index.md @@ -5,8 +5,8 @@ labels: products: - enterprise - oss -title: User management -weight: 200 +title: Manage users +weight: 3000 --- # User management From 4bb91a7846fc9b12583d378b9c5219fee0bc189f Mon Sep 17 00:00:00 2001 From: Kyle Brandt Date: Tue, 28 Oct 2025 02:48:57 -0400 Subject: [PATCH 037/378] =?UTF-8?q?Revert=20"SQL=20Expressions:=20(Chore)?= =?UTF-8?q?=20Update=20GMS=20(go-mysql-server)=20depende=E2=80=A6=20(#1130?= =?UTF-8?q?50)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/backend-unit-tests.yml | 4 ++-- .github/workflows/pr-test-integration.yml | 8 ++++---- Makefile | 10 ---------- apps/iam/go.mod | 7 ++++--- apps/iam/go.sum | 14 ++++++++------ .../query-transform-data/sql-expressions/index.md | 10 ---------- go.mod | 7 ++++--- go.sum | 14 ++++++++------ go.work.sum | 11 ----------- pkg/build/daggerbuild/flags/packages.go | 1 - pkg/expr/sql/db_test.go | 12 ++++++++++++ 11 files changed, 42 insertions(+), 56 deletions(-) diff --git a/.github/workflows/backend-unit-tests.yml b/.github/workflows/backend-unit-tests.yml index 628dd44ef1f..3dd179c5c87 100644 --- a/.github/workflows/backend-unit-tests.yml +++ b/.github/workflows/backend-unit-tests.yml @@ -68,7 +68,7 @@ jobs: run: | set -euo pipefail readarray -t PACKAGES <<< "$(./scripts/ci/backend-tests/shard.sh -N"$SHARD")" - CGO_ENABLED=0 go test -tags=gms_pure_go -short -timeout=30m "${PACKAGES[@]}" + CGO_ENABLED=0 go test -short -timeout=30m "${PACKAGES[@]}" grafana-enterprise: # Run this workflow for non-PR events (like pushes to `main` or `release-*`) OR for internal PRs (PRs not from forks) @@ -118,7 +118,7 @@ jobs: readarray -t PACKAGES <<< "$(./scripts/ci/backend-tests/shard.sh -N"$SHARD")" # This tee requires pipefail to be set, otherwise `go test`'s exit code is thrown away. # That means having no `-o pipefail` => failing tests => exit code 0, which is wrong. - CGO_ENABLED=0 go test -tags=gms_pure_go -short -timeout=30m "${PACKAGES[@]}" + CGO_ENABLED=0 go test -short -timeout=30m "${PACKAGES[@]}" # This is the job that is actually required by rulesets. # We need to require EITHER the OSS or the Enterprise job to pass. diff --git a/.github/workflows/pr-test-integration.yml b/.github/workflows/pr-test-integration.yml index ef601303e3e..7e7545bead0 100644 --- a/.github/workflows/pr-test-integration.yml +++ b/.github/workflows/pr-test-integration.yml @@ -68,7 +68,7 @@ jobs: run: | set -euo pipefail readarray -t PACKAGES <<< "$(./scripts/ci/backend-tests/pkgs-with-tests-named.sh -b TestIntegration | ./scripts/ci/backend-tests/shard.sh -N"$SHARD" -d-)" - go test -tags=sqlite,gms_pure_go -timeout=8m -run '^TestIntegration' "${PACKAGES[@]}" + go test -tags=sqlite -timeout=8m -run '^TestIntegration' "${PACKAGES[@]}" sqlite_nocgo: needs: detect-changes @@ -102,7 +102,7 @@ jobs: set -euo pipefail readarray -t PACKAGES <<< "$(./scripts/ci/backend-tests/pkgs-with-tests-named.sh -b TestIntegration | ./scripts/ci/backend-tests/shard.sh -N"$SHARD" -d-)" # ionice since tests are IO intensive - CGO_ENABLED=0 ionice -c2 -n7 go test -p=4 -tags=sqlite,gms_pure_go -timeout=8m -run '^TestIntegration' "${PACKAGES[@]}" + CGO_ENABLED=0 ionice -c2 -n7 go test -p=4 -tags=sqlite -timeout=8m -run '^TestIntegration' "${PACKAGES[@]}" mysql: needs: detect-changes if: needs.detect-changes.outputs.changed == 'true' @@ -152,7 +152,7 @@ jobs: run: | set -euo pipefail readarray -t PACKAGES <<< "$(./scripts/ci/backend-tests/pkgs-with-tests-named.sh -b TestIntegration | ./scripts/ci/backend-tests/shard.sh -N"$SHARD" -d-)" - CGO_ENABLED=0 go test -p=1 -tags=mysql,gms_pure_go -timeout=8m -run '^TestIntegration' "${PACKAGES[@]}" + CGO_ENABLED=0 go test -p=1 -tags=mysql -timeout=8m -run '^TestIntegration' "${PACKAGES[@]}" postgres: needs: detect-changes if: needs.detect-changes.outputs.changed == 'true' @@ -201,7 +201,7 @@ jobs: run: | set -euo pipefail readarray -t PACKAGES <<< "$(./scripts/ci/backend-tests/pkgs-with-tests-named.sh -b TestIntegration | ./scripts/ci/backend-tests/shard.sh -N"$SHARD" -d-)" - CGO_ENABLED=0 go test -p=1 -tags=postgres,gms_pure_go -timeout=8m -run '^TestIntegration' "${PACKAGES[@]}" + CGO_ENABLED=0 go test -p=1 -tags=postgres -timeout=8m -run '^TestIntegration' "${PACKAGES[@]}" # This is the job that is actually required by rulesets. # We want to only require one job instead of all the individual tests and shards. diff --git a/Makefile b/Makefile index e5713db14b1..5bf0150e047 100644 --- a/Makefile +++ b/Makefile @@ -14,16 +14,6 @@ GO_TEST_FILES ?= $(shell ./scripts/go-workspace/test-includes.sh) SH_FILES ?= $(shell find ./scripts -name *.sh) GO_RACE := $(shell [ -n "$(GO_RACE)" -o -e ".go-race-enabled-locally" ] && echo 1 ) GO_RACE_FLAG := $(if $(GO_RACE),-race) - -## Always include gms_pure_go for go-mysql-server dependency -ifneq (,$(findstring gms_pure_go,$(GO_BUILD_TAGS))) - GO_BUILD_TAGS := $(GO_BUILD_TAGS) -else ifneq (,$(strip $(GO_BUILD_TAGS))) - GO_BUILD_TAGS := $(GO_BUILD_TAGS),gms_pure_go -else - GO_BUILD_TAGS := gms_pure_go -endif - GO_BUILD_FLAGS += $(if $(GO_BUILD_DEV),-dev) GO_BUILD_FLAGS += $(if $(GO_BUILD_TAGS),-build-tags=$(GO_BUILD_TAGS)) GO_BUILD_FLAGS += $(GO_RACE_FLAG) diff --git a/apps/iam/go.mod b/apps/iam/go.mod index cb946d8d694..63dae42947a 100644 --- a/apps/iam/go.mod +++ b/apps/iam/go.mod @@ -162,10 +162,10 @@ require ( github.com/dlmiddlecote/sqlstats v1.0.2 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/dolthub/flatbuffers/v23 v23.3.3-dh.2 // indirect - github.com/dolthub/go-icu-regex v0.0.0-20250916051405-78a38d478790 // indirect - github.com/dolthub/go-mysql-server v0.20.1-0.20251009205227-b4366f30538c // indirect + github.com/dolthub/go-icu-regex v0.0.0-20250327004329-6799764f2dad // indirect + github.com/dolthub/go-mysql-server v0.19.1-0.20250410182021-5632d67cd46e // indirect github.com/dolthub/jsonpath v0.0.2-0.20240227200619-19675ab05c71 // indirect - github.com/dolthub/vitess v0.0.0-20250930230441-70c2c6a98e33 // indirect + github.com/dolthub/vitess v0.0.0-20250410090211-143e6b272ad4 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/emicklei/go-restful/v3 v3.13.0 // indirect github.com/emirpasic/gods v1.18.1 // indirect @@ -381,6 +381,7 @@ require ( github.com/stretchr/objx v0.5.2 // indirect github.com/stretchr/testify v1.11.1 // indirect github.com/subosito/gotenv v1.6.0 // indirect + github.com/tetratelabs/wazero v1.8.2 // indirect github.com/thomaspoignant/go-feature-flag v1.42.0 // indirect github.com/tjhop/slog-gokit v0.1.3 // indirect github.com/uber/jaeger-client-go v2.30.0+incompatible // indirect diff --git a/apps/iam/go.sum b/apps/iam/go.sum index 812bacc1933..8709ea21e9e 100644 --- a/apps/iam/go.sum +++ b/apps/iam/go.sum @@ -489,16 +489,16 @@ github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4 github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/dolthub/flatbuffers/v23 v23.3.3-dh.2 h1:u3PMzfF8RkKd3lB9pZ2bfn0qEG+1Gms9599cr0REMww= github.com/dolthub/flatbuffers/v23 v23.3.3-dh.2/go.mod h1:mIEZOHnFx4ZMQeawhw9rhsj+0zwQj7adVsnBX7t+eKY= -github.com/dolthub/go-icu-regex v0.0.0-20250916051405-78a38d478790 h1:zxMsH7RLiG+dlZ/y0LgJHTV26XoiSJcuWq+em6t6VVc= -github.com/dolthub/go-icu-regex v0.0.0-20250916051405-78a38d478790/go.mod h1:F3cnm+vMRK1HaU6+rNqQrOCyR03HHhR1GWG2gnPOqaE= -github.com/dolthub/go-mysql-server v0.20.1-0.20251009205227-b4366f30538c h1:vElww7wlYrlu1dldciCcYOvVuh73gw8i6mkcTUvH6nQ= -github.com/dolthub/go-mysql-server v0.20.1-0.20251009205227-b4366f30538c/go.mod h1:EeYR0apo+8j2Dyxmn2ghkPlirO2S5mT1xHBrA+Efys8= +github.com/dolthub/go-icu-regex v0.0.0-20250327004329-6799764f2dad h1:66ZPawHszNu37VPQckdhX1BPPVzREsGgNxQeefnlm3g= +github.com/dolthub/go-icu-regex v0.0.0-20250327004329-6799764f2dad/go.mod h1:ylU4XjUpsMcvl/BKeRRMXSH7e7WBrPXdSLvnRJYrxEA= +github.com/dolthub/go-mysql-server v0.19.1-0.20250410182021-5632d67cd46e h1:7pAttAqWaudUAsM9iHASi/4eFBK+qn4qeaNto7g8bK4= +github.com/dolthub/go-mysql-server v0.19.1-0.20250410182021-5632d67cd46e/go.mod h1:KZyoO3jngyZCLyCf100FEQTrwAHj33AIMj4Zv4u3MNE= github.com/dolthub/jsonpath v0.0.2-0.20240227200619-19675ab05c71 h1:bMGS25NWAGTEtT5tOBsCuCrlYnLRKpbJVJkDbrTRhwQ= github.com/dolthub/jsonpath v0.0.2-0.20240227200619-19675ab05c71/go.mod h1:2/2zjLQ/JOOSbbSboojeg+cAwcRV0fDLzIiWch/lhqI= github.com/dolthub/maphash v0.1.0 h1:bsQ7JsF4FkkWyrP3oCnFJgrCUAFbFf3kOl4L/QxPDyQ= github.com/dolthub/maphash v0.1.0/go.mod h1:gkg4Ch4CdCDu5h6PMriVLawB7koZ+5ijb9puGMV50a4= -github.com/dolthub/vitess v0.0.0-20250930230441-70c2c6a98e33 h1:ScHTwNbcVC6JH1OSyXzj8S4w67BIpRXwTSjrac3/PSw= -github.com/dolthub/vitess v0.0.0-20250930230441-70c2c6a98e33/go.mod h1:8pvvk5OLaLN9LLxghyczUapn/97l+mBgIb10qC1LG84= +github.com/dolthub/vitess v0.0.0-20250410090211-143e6b272ad4 h1:LGTt2LtYX8vaai32d+c9L0sMcP+Dg9w1kO6+lbsxxYg= +github.com/dolthub/vitess v0.0.0-20250410090211-143e6b272ad4/go.mod h1:1gQZs/byeHLMSul3Lvl3MzioMtOW1je79QYGyi2fd70= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= 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= @@ -1498,6 +1498,8 @@ github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= +github.com/tetratelabs/wazero v1.8.2 h1:yIgLR/b2bN31bjxwXHD8a3d+BogigR952csSDdLYEv4= +github.com/tetratelabs/wazero v1.8.2/go.mod h1:yAI0XTsMBhREkM/YDAK/zNou3GoiAce1P6+rp/wQhjs= github.com/thejerf/slogassert v0.3.4 h1:VoTsXixRbXMrRSSxDjYTiEDCM4VWbsYPW5rB/hX24kM= github.com/thejerf/slogassert v0.3.4/go.mod h1:0zn9ISLVKo1aPMTqcGfG1o6dWwt+Rk574GlUxHD4rs8= github.com/thomaspoignant/go-feature-flag v1.42.0 h1:C7embmOTzaLyRki+OoU2RvtVjJE9IrvgBA2C1mRN1lc= diff --git a/docs/sources/visualizations/panels-visualizations/query-transform-data/sql-expressions/index.md b/docs/sources/visualizations/panels-visualizations/query-transform-data/sql-expressions/index.md index 992bc7611b5..7cb91aaeb7f 100644 --- a/docs/sources/visualizations/panels-visualizations/query-transform-data/sql-expressions/index.md +++ b/docs/sources/visualizations/panels-visualizations/query-transform-data/sql-expressions/index.md @@ -307,16 +307,6 @@ FULL OUTER JOIN ( This approach ensures that a schema exists even when one query returns no data. -### Regular Expressions - -Regular expressions are not fully compatible with MySQL standards. SQL expressions that use regular expression functions will have limitations such as: - -- Lack of back-references -- No before/after text matching -- Differences in handling CR ('\r') - -There may be other minor differences as well. - ## SQL expressions examples 1. Create the following Prometheus query: diff --git a/go.mod b/go.mod index aa63907b29f..f909171526f 100644 --- a/go.mod +++ b/go.mod @@ -52,8 +52,8 @@ require ( github.com/crewjam/saml v0.4.14 // @grafana/identity-access-team github.com/dgraph-io/badger/v4 v4.7.0 // @grafana/grafana-search-and-storage github.com/dlmiddlecote/sqlstats v1.0.2 // @grafana/grafana-backend-group - github.com/dolthub/go-mysql-server v0.20.1-0.20251009205227-b4366f30538c // @grafana/grafana-datasources-core-services - github.com/dolthub/vitess v0.0.0-20250930230441-70c2c6a98e33 // @grafana/grafana-datasources-core-services + github.com/dolthub/go-mysql-server v0.19.1-0.20250410182021-5632d67cd46e // @grafana/grafana-datasources-core-services + github.com/dolthub/vitess v0.0.0-20250410090211-143e6b272ad4 // @grafana/grafana-datasources-core-services github.com/dustin/go-humanize v1.0.1 // @grafana/observability-traces-and-profiling github.com/emicklei/go-restful/v3 v3.13.0 // @grafana/grafana-app-platform-squad github.com/fatih/color v1.18.0 // @grafana/grafana-backend-group @@ -404,7 +404,7 @@ require ( github.com/docker/go-connections v0.6.0 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/dolthub/flatbuffers/v23 v23.3.3-dh.2 // indirect - github.com/dolthub/go-icu-regex v0.0.0-20250916051405-78a38d478790 // indirect + github.com/dolthub/go-icu-regex v0.0.0-20250327004329-6799764f2dad // indirect github.com/dolthub/jsonpath v0.0.2-0.20240227200619-19675ab05c71 // indirect github.com/dolthub/maphash v0.1.0 // indirect github.com/edsrzf/mmap-go v1.2.0 // indirect @@ -585,6 +585,7 @@ require ( github.com/stoewer/go-strcase v1.3.1 // indirect github.com/stretchr/objx v0.5.2 // indirect github.com/subosito/gotenv v1.6.0 // indirect + github.com/tetratelabs/wazero v1.8.2 // indirect github.com/uber/jaeger-client-go v2.30.0+incompatible // indirect github.com/uber/jaeger-lib v2.4.1+incompatible // indirect github.com/unknwon/bra v0.0.0-20200517080246-1e3013ecaff8 // indirect diff --git a/go.sum b/go.sum index c37d8583801..a19b3327237 100644 --- a/go.sum +++ b/go.sum @@ -1118,16 +1118,16 @@ github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZ github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/dolthub/flatbuffers/v23 v23.3.3-dh.2 h1:u3PMzfF8RkKd3lB9pZ2bfn0qEG+1Gms9599cr0REMww= github.com/dolthub/flatbuffers/v23 v23.3.3-dh.2/go.mod h1:mIEZOHnFx4ZMQeawhw9rhsj+0zwQj7adVsnBX7t+eKY= -github.com/dolthub/go-icu-regex v0.0.0-20250916051405-78a38d478790 h1:zxMsH7RLiG+dlZ/y0LgJHTV26XoiSJcuWq+em6t6VVc= -github.com/dolthub/go-icu-regex v0.0.0-20250916051405-78a38d478790/go.mod h1:F3cnm+vMRK1HaU6+rNqQrOCyR03HHhR1GWG2gnPOqaE= -github.com/dolthub/go-mysql-server v0.20.1-0.20251009205227-b4366f30538c h1:vElww7wlYrlu1dldciCcYOvVuh73gw8i6mkcTUvH6nQ= -github.com/dolthub/go-mysql-server v0.20.1-0.20251009205227-b4366f30538c/go.mod h1:EeYR0apo+8j2Dyxmn2ghkPlirO2S5mT1xHBrA+Efys8= +github.com/dolthub/go-icu-regex v0.0.0-20250327004329-6799764f2dad h1:66ZPawHszNu37VPQckdhX1BPPVzREsGgNxQeefnlm3g= +github.com/dolthub/go-icu-regex v0.0.0-20250327004329-6799764f2dad/go.mod h1:ylU4XjUpsMcvl/BKeRRMXSH7e7WBrPXdSLvnRJYrxEA= +github.com/dolthub/go-mysql-server v0.19.1-0.20250410182021-5632d67cd46e h1:7pAttAqWaudUAsM9iHASi/4eFBK+qn4qeaNto7g8bK4= +github.com/dolthub/go-mysql-server v0.19.1-0.20250410182021-5632d67cd46e/go.mod h1:KZyoO3jngyZCLyCf100FEQTrwAHj33AIMj4Zv4u3MNE= github.com/dolthub/jsonpath v0.0.2-0.20240227200619-19675ab05c71 h1:bMGS25NWAGTEtT5tOBsCuCrlYnLRKpbJVJkDbrTRhwQ= github.com/dolthub/jsonpath v0.0.2-0.20240227200619-19675ab05c71/go.mod h1:2/2zjLQ/JOOSbbSboojeg+cAwcRV0fDLzIiWch/lhqI= github.com/dolthub/maphash v0.1.0 h1:bsQ7JsF4FkkWyrP3oCnFJgrCUAFbFf3kOl4L/QxPDyQ= github.com/dolthub/maphash v0.1.0/go.mod h1:gkg4Ch4CdCDu5h6PMriVLawB7koZ+5ijb9puGMV50a4= -github.com/dolthub/vitess v0.0.0-20250930230441-70c2c6a98e33 h1:ScHTwNbcVC6JH1OSyXzj8S4w67BIpRXwTSjrac3/PSw= -github.com/dolthub/vitess v0.0.0-20250930230441-70c2c6a98e33/go.mod h1:8pvvk5OLaLN9LLxghyczUapn/97l+mBgIb10qC1LG84= +github.com/dolthub/vitess v0.0.0-20250410090211-143e6b272ad4 h1:LGTt2LtYX8vaai32d+c9L0sMcP+Dg9w1kO6+lbsxxYg= +github.com/dolthub/vitess v0.0.0-20250410090211-143e6b272ad4/go.mod h1:1gQZs/byeHLMSul3Lvl3MzioMtOW1je79QYGyi2fd70= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= 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= @@ -2463,6 +2463,8 @@ github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= +github.com/tetratelabs/wazero v1.8.2 h1:yIgLR/b2bN31bjxwXHD8a3d+BogigR952csSDdLYEv4= +github.com/tetratelabs/wazero v1.8.2/go.mod h1:yAI0XTsMBhREkM/YDAK/zNou3GoiAce1P6+rp/wQhjs= github.com/thanos-io/objstore v0.0.0-20240818203309-0363dadfdfb1 h1:z0v9BB/p7s4J6R//+0a5M3wCld8KzNjrGRLIwXfrAZk= github.com/thanos-io/objstore v0.0.0-20240818203309-0363dadfdfb1/go.mod h1:3ukSkG4rIRUGkKM4oIz+BSuUx2e3RlQVVv3Cc3W+Tv4= github.com/thejerf/slogassert v0.3.4 h1:VoTsXixRbXMrRSSxDjYTiEDCM4VWbsYPW5rB/hX24kM= diff --git a/go.work.sum b/go.work.sum index 3b88b54f3dd..d26aabd35b9 100644 --- a/go.work.sum +++ b/go.work.sum @@ -550,7 +550,6 @@ github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53 h1:sR+/8Yb4s github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53/go.mod h1:+3IMCy2vIlbG1XG/0ggNQv0SvxCAIpPM5b1nCz56Xno= github.com/CloudyKit/jet/v6 v6.2.0 h1:EpcZ6SR9n28BUGtNJSvlBqf90IpjeFr36Tizxhn/oME= github.com/CloudyKit/jet/v6 v6.2.0/go.mod h1:d3ypHeIRNo2+XyqnGA8s+aphtcVpjP5hPwP/Lzo7Ro4= -github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= github.com/DataDog/datadog-go v3.2.0+incompatible h1:qSG2N4FghB1He/r2mFrWKCaL7dXCilEuNEeAn20fdD4= github.com/DataDog/sketches-go v1.4.6 h1:acd5fb+QdUzGrosfNLwrIhqyrbMORpvBy7mE+vHlT3I= github.com/DataDog/sketches-go v1.4.6/go.mod h1:7Y8GN8Jf66DLyDhc94zuWA3uHEt/7ttt8jHOBWWrSOg= @@ -829,8 +828,6 @@ github.com/dchest/siphash v1.2.3/go.mod h1:0NvQU092bT0ipiFN++/rXm69QG9tVxLAlQHIX github.com/dchest/uniuri v1.2.0 h1:koIcOUdrTIivZgSLhHQvKgqdWZq5d7KdMEWF1Ud6+5g= github.com/dchest/uniuri v1.2.0/go.mod h1:fSzm4SLHzNZvWLvWJew423PhAzkpNQYq+uNLq4kxhkY= github.com/denisenkom/go-mssqldb v0.0.0-20190515213511-eb9f6a1743f3 h1:tkum0XDgfR0jcVVXuTsYv/erY2NnEDqwRojbxR1rBYA= -github.com/denisenkom/go-mssqldb v0.10.0 h1:QykgLZBorFE95+gO3u9esLd0BmbvpWp0/waNNZfHBM8= -github.com/denisenkom/go-mssqldb v0.10.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= github.com/dgryski/go-ddmin v0.0.0-20210904190556-96a6d69f1034 h1:BuCyszxPxUjBrYW2HNVrimC0rBUs2U27jCJGVh0IKTM= github.com/dgryski/go-ddmin v0.0.0-20210904190556-96a6d69f1034/go.mod h1:zz4KxBkcXUWKjIcrc+uphJ1gPh/t18ymGm3PmQ+VGTk= github.com/dgryski/go-sip13 v0.0.0-20190329191031-25c5027a8c7b h1:Yqiad0+sloMPdd/0Fg22actpFx0dekpzt1xJmVNVkU0= @@ -994,7 +991,6 @@ github.com/gogo/status v1.1.0/go.mod h1:BFv9nrluPLmrS0EmGVvLaPNmRosr9KapBYd5/hpY github.com/golang-jwt/jwt v3.2.1+incompatible h1:73Z+4BJcrTC+KczS6WvTPvRGOp1WmfEP4Q1lOd9Z/+c= github.com/golang-jwt/jwt v3.2.1+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= -github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g= github.com/gomarkdown/markdown v0.0.0-20230716120725-531d2d74bc12 h1:uK3X/2mt4tbSGoHvbLBHUny7CKiuwUip3MArtukol4E= github.com/gomarkdown/markdown v0.0.0-20230716120725-531d2d74bc12/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA= @@ -1208,7 +1204,6 @@ github.com/jedib0t/go-pretty/v6 v6.6.7/go.mod h1:YwC5CE4fJ1HFUDeivSV1r//AmANFHyq github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jhump/gopoet v0.1.0 h1:gYjOPnzHd2nzB37xYQZxj4EIQNpBrBskRqQQ3q4ZgSg= github.com/jhump/goprotoc v0.5.0 h1:Y1UgUX+txUznfqcGdDef8ZOVlyQvnV0pKWZH08RmZuo= -github.com/jmoiron/sqlx v1.3.4/go.mod h1:2BljVx/86SuTyjE+aPYlHCTNvZrnJXghYGpNiXLBMCQ= github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901 h1:rp+c0RAYOWj8l6qbCUTSiRLG/iKnW3K3/QfPPuSsBt4= github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901/go.mod h1:Z86h9688Y0wesXCyonoVr47MasHilkuLMqGhRZ4Hpak= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= @@ -1298,7 +1293,6 @@ github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= github.com/leodido/ragel-machinery v0.0.0-20190525184631-5f46317e436b h1:11UHH39z1RhZ5dc4y4r/4koJo6IYFgTRMe/LlwRTEw0= github.com/leodido/ragel-machinery v0.0.0-20190525184631-5f46317e436b/go.mod h1:WZxr2/6a/Ar9bMDc2rN/LJrE/hF6bXE4LPyDSIxwAfg= -github.com/lib/pq v1.10.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lightstep/go-expohisto v1.0.0 h1:UPtTS1rGdtehbbAF7o/dhkWLTDI73UifG8LbfQI7cA4= github.com/lightstep/go-expohisto v1.0.0/go.mod h1:xDXD0++Mu2FOaItXtdDfksfgxfV0z1TMPa+e/EUd0cs= github.com/lithammer/fuzzysearch v1.1.8 h1:/HIuJnjHuXS8bKaiTMeeDlW2/AyIWk2brx1V8LFgLN4= @@ -1323,7 +1317,6 @@ github.com/matryer/moq v0.5.2/go.mod h1:W/k5PLfou4f+bzke9VPXTbfJljxoeR1tLHigsmbs github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= -github.com/mattn/go-sqlite3 v1.14.7/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg= github.com/maxbrunsfeld/counterfeiter/v6 v6.11.2 h1:yVCLo4+ACVroOEr4iFU1iH46Ldlzz2rTuu18Ra7M8sU= github.com/maxbrunsfeld/counterfeiter/v6 v6.11.2/go.mod h1:VzB2VoMh1Y32/QqDfg9ZJYHj99oM4LiGtqPZydTiQSQ= @@ -1571,7 +1564,6 @@ github.com/shirou/gopsutil/v4 v4.25.5 h1:rtd9piuSMGeU8g1RMXjZs9y9luK5BwtnG7dZaQU github.com/shirou/gopsutil/v4 v4.25.5/go.mod h1:PfybzyydfZcN+JMMjkF6Zb8Mq1A/VcogFFg7hj50W9c= github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= -github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shurcooL/go v0.0.0-20200502201357-93f07166e636 h1:aSISeOcal5irEhJd1M+IrApc0PdcN7e7Aj4yuEnOrfQ= github.com/shurcooL/go v0.0.0-20200502201357-93f07166e636/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= @@ -2124,7 +2116,6 @@ google.golang.org/api v0.229.0/go.mod h1:wyDfmq5g1wYJWn29O22FDWN48P7Xcz0xz+LBppt google.golang.org/api v0.232.0/go.mod h1:p9QCfBWZk1IJETUdbTKloR5ToFdKbYh2fkjsUL6vNoY= google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= -google.golang.org/genproto v0.0.0-20190926190326-7ee9db18f195/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d/go.mod h1:yZTlhN0tQnXo3h00fuXNCxJdLdIdnVFVBaRJ5LWBbw4= google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80/go.mod h1:cc8bqMqtv9gMOr0zHg2Vzff5ULhhL2IXP4sbcn32Dro= google.golang.org/genproto v0.0.0-20241118233622-e639e219e697/go.mod h1:JJrvXBWRZaFMxBufik1a4RpFw4HhgVtBBWQeQgUj2cc= @@ -2196,7 +2187,6 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5/go. google.golang.org/genproto/googleapis/rpc v0.0.0-20250826171959-ef028d996bc1/go.mod h1:GmFNa4BdJZ2a8G+wCe9Bg3wwThLrJun751XstdJt5Og= google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090/go.mod h1:GmFNa4BdJZ2a8G+wCe9Bg3wwThLrJun751XstdJt5Og= google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= google.golang.org/grpc v1.61.0/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs= google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= @@ -2231,7 +2221,6 @@ google.golang.org/protobuf v1.36.7/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/ google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU= google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU= gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc= -gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0 h1:0vLT13EuvQ0hNvakwLuFZ/jYrLp5F3kcWHXdRggjCE8= gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/go-jose/go-jose.v2 v2.6.3 h1:nt80fvSDlhKWQgSWyHyy5CfmlQr+asih51R8PTWNKKs= diff --git a/pkg/build/daggerbuild/flags/packages.go b/pkg/build/daggerbuild/flags/packages.go index dcc9011949d..897364b6f07 100644 --- a/pkg/build/daggerbuild/flags/packages.go +++ b/pkg/build/daggerbuild/flags/packages.go @@ -8,7 +8,6 @@ import ( var DefaultTags = []string{ "osusergo", "timetzdata", - "gms_pure_go", } const ( diff --git a/pkg/expr/sql/db_test.go b/pkg/expr/sql/db_test.go index c67c23b32b9..ff5ecac022f 100644 --- a/pkg/expr/sql/db_test.go +++ b/pkg/expr/sql/db_test.go @@ -278,6 +278,18 @@ func TestNaNBecomesNull(t *testing.T) { require.NoError(t, err) } +func TestErrorsFromGoMySQLServerAreFlagged(t *testing.T) { + const GmsNotImplemented = "TRUNCATE" // not implemented in go-mysql-server as of 2025-04-11 + + db := DB{} + + query := `SELECT ` + GmsNotImplemented + `(123.456, 2);` + + _, err := db.QueryFrames(context.Background(), &testTracer{}, "sqlExpressionRefId", query, nil) + require.Error(t, err) + require.Contains(t, err.Error(), "error from the sql expression engine") +} + func TestFrameToSQLAndBack_JSONRoundtrip(t *testing.T) { expectedFrame := &data.Frame{ RefID: "json_test", From bee486be231b6f6fbaa5421a50ebf2eb243c0a54 Mon Sep 17 00:00:00 2001 From: Andres Martinez Gotor Date: Tue, 28 Oct 2025 09:24:44 +0100 Subject: [PATCH 038/378] Advisor: update app-sdk and deps (#112937) --- apps/advisor/Makefile | 8 +- apps/advisor/go.mod | 237 +++--- apps/advisor/go.sum | 688 +++++++++--------- apps/advisor/kinds/check.cue | 84 +-- apps/advisor/kinds/checktype.cue | 36 +- apps/advisor/kinds/manifest.cue | 20 +- .../apis/advisor/v0alpha1/check_client_gen.go | 99 +++ .../advisor/v0alpha1/checktype_client_gen.go | 99 +++ apps/advisor/pkg/apis/advisor_manifest.go | 57 +- go.work.sum | 4 +- 10 files changed, 809 insertions(+), 523 deletions(-) create mode 100644 apps/advisor/pkg/apis/advisor/v0alpha1/check_client_gen.go create mode 100644 apps/advisor/pkg/apis/advisor/v0alpha1/checktype_client_gen.go diff --git a/apps/advisor/Makefile b/apps/advisor/Makefile index aaac06377ca..fdffcfd4fbf 100644 --- a/apps/advisor/Makefile +++ b/apps/advisor/Makefile @@ -1,5 +1,9 @@ include ../sdk.mk -.PHONY: generate +.PHONY: generate # Run Grafana App SDK code generation generate: install-app-sdk update-app-sdk - @$(APP_SDK_BIN) generate -g ./pkg/apis --grouping=group --postprocess --defencoding=none --useoldmanifestkinds + @$(APP_SDK_BIN) generate \ + --source=./kinds/ \ + --gogenpath=./pkg/apis \ + --grouping=group \ + --defencoding=none diff --git a/apps/advisor/go.mod b/apps/advisor/go.mod index 29fd3c33281..a45fa8d0423 100644 --- a/apps/advisor/go.mod +++ b/apps/advisor/go.mod @@ -4,34 +4,53 @@ go 1.25.3 require ( github.com/Masterminds/semver/v3 v3.4.0 + github.com/google/go-cmp v0.7.0 github.com/google/go-github/v70 v70.0.0 - github.com/grafana/authlib/types v0.0.0-20250710201142-9542f2f28d43 + github.com/grafana/authlib/types v0.0.0-20250926065801-df98203cff37 github.com/grafana/grafana v0.0.0-00010101000000-000000000000 - github.com/grafana/grafana-app-sdk v0.40.2 - github.com/grafana/grafana-app-sdk/logging v0.40.2 - github.com/grafana/grafana-plugin-sdk-go v0.278.0 - github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250804150913-990f1c69ecc2 - github.com/stretchr/testify v1.10.0 - k8s.io/apimachinery v0.33.3 - k8s.io/apiserver v0.33.3 - k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff + github.com/grafana/grafana-app-sdk v0.48.1 + github.com/grafana/grafana-app-sdk/logging v0.48.1 + github.com/grafana/grafana-plugin-sdk-go v0.281.0 + github.com/grafana/grafana/pkg/apimachinery v0.0.0 + github.com/stretchr/testify v1.11.1 + k8s.io/apimachinery v0.34.1 + k8s.io/apiserver v0.34.1 + k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 ) // transitive dependencies that need replaced // TODO: stop depending on grafana core replace github.com/grafana/grafana => ../.. -replace github.com/prometheus/alertmanager => github.com/grafana/prometheus-alertmanager v0.25.1-0.20250620093340-be61a673dee6 +replace github.com/grafana/grafana/apps/provisioning => ../provisioning + +replace github.com/grafana/grafana/pkg/apimachinery => ../../pkg/apimachinery + +replace github.com/grafana/grafana/pkg/apiserver => ../../pkg/apiserver + +replace github.com/grafana/grafana/apps/dashboard => ../dashboard + +replace github.com/grafana/grafana/pkg/aggregator => ../../pkg/aggregator + +replace github.com/grafana/grafana/apps/folder => ../folder + +replace github.com/grafana/grafana/apps/secret => ../secret + +replace github.com/grafana/grafana/apps/iam => ../iam + +replace github.com/grafana/grafana/apps/plugins => ../plugins + +replace github.com/prometheus/alertmanager => github.com/grafana/prometheus-alertmanager v0.25.1-0.20250911094103-5456b6e45604 require ( cloud.google.com/go/compute/metadata v0.7.0 // indirect dario.cat/mergo v1.0.2 // indirect filippo.io/edwards25519 v1.1.0 // indirect - github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.1 // indirect - github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.10.1 // indirect - github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1 // indirect + github.com/Azure/azure-sdk-for-go/sdk/azcore v1.19.1 // indirect + github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.12.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2 // indirect github.com/Azure/go-ntlmssp v0.0.0-20220621081337-cb9428e4ac1e // indirect - github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2 // indirect + github.com/AzureAD/microsoft-authentication-library-for-go v1.5.0 // indirect github.com/BurntSushi/toml v1.5.0 // indirect github.com/Masterminds/goutils v1.1.1 // indirect github.com/Masterminds/semver v1.5.0 // indirect @@ -40,19 +59,19 @@ require ( github.com/VividCortex/mysqlerr v0.0.0-20170204212430-6c6b55f8796f // indirect github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b // indirect github.com/antlr4-go/antlr/v4 v4.13.1 // indirect - github.com/apache/arrow-go/v18 v18.3.0 // indirect + github.com/apache/arrow-go/v18 v18.4.1 // indirect github.com/armon/go-metrics v0.4.1 // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/at-wat/mqtt-go v0.19.4 // indirect github.com/aws/aws-sdk-go v1.55.7 // indirect - github.com/aws/aws-sdk-go-v2 v1.36.5 // indirect - github.com/aws/aws-sdk-go-v2/credentials v1.17.70 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.36 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.36 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.4 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.17 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.34.0 // indirect - github.com/aws/smithy-go v1.22.4 // indirect + github.com/aws/aws-sdk-go-v2 v1.38.1 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.18.6 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.4 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.4 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.0 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.4 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.38.0 // indirect + github.com/aws/smithy-go v1.23.1 // indirect github.com/barkimedes/go-deepcopy v0.0.0-20220514131651-17c30cfc62df // indirect github.com/benbjohnson/clock v1.3.5 // indirect github.com/beorn7/perks v1.0.1 // indirect @@ -62,13 +81,12 @@ require ( github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874 // indirect github.com/bwmarrin/snowflake v0.3.0 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect - github.com/cenkalti/backoff/v5 v5.0.2 // indirect + github.com/cenkalti/backoff/v5 v5.0.3 // 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-20250429231605-6ed5b53462d4 // indirect github.com/cloudflare/circl v1.6.1 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect - github.com/cpuguy83/go-md2man/v2 v2.0.6 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/diegoholiveira/jsonlogic/v3 v3.7.4 // indirect @@ -80,78 +98,83 @@ require ( github.com/dolthub/jsonpath v0.0.2-0.20240227200619-19675ab05c71 // indirect github.com/dolthub/vitess v0.0.0-20250410090211-143e6b272ad4 // indirect github.com/dustin/go-humanize v1.0.1 // indirect - github.com/elazarl/goproxy v1.7.2 // indirect - github.com/emicklei/go-restful/v3 v3.12.1 // indirect - github.com/evanphx/json-patch v5.6.0+incompatible // indirect + github.com/emicklei/go-restful/v3 v3.13.0 // indirect github.com/fatih/color v1.18.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect - github.com/fxamacker/cbor/v2 v2.7.0 // indirect + github.com/fxamacker/cbor/v2 v2.9.0 // indirect github.com/gchaincl/sqlhooks v1.3.0 // indirect - github.com/getkin/kin-openapi v0.132.0 // indirect + github.com/getkin/kin-openapi v0.133.0 // indirect github.com/go-asn1-ber/asn1-ber v1.5.4 // indirect - github.com/go-jose/go-jose/v3 v3.0.4 // indirect + github.com/go-jose/go-jose/v4 v4.1.2 // indirect github.com/go-kit/log v0.2.1 // indirect github.com/go-ldap/ldap/v3 v3.4.4 // indirect github.com/go-logfmt/logfmt v0.6.0 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect - github.com/go-openapi/analysis v0.23.0 // indirect - github.com/go-openapi/errors v0.22.0 // indirect - github.com/go-openapi/jsonpointer v0.21.0 // indirect - github.com/go-openapi/jsonreference v0.21.0 // indirect - github.com/go-openapi/loads v0.22.0 // indirect + github.com/go-openapi/analysis v0.24.0 // indirect + github.com/go-openapi/errors v0.22.3 // indirect + github.com/go-openapi/jsonpointer v0.22.1 // indirect + github.com/go-openapi/jsonreference v0.21.2 // indirect + github.com/go-openapi/loads v0.23.1 // indirect github.com/go-openapi/runtime v0.28.0 // indirect - github.com/go-openapi/spec v0.21.0 // indirect - github.com/go-openapi/strfmt v0.23.0 // indirect + github.com/go-openapi/spec v0.22.0 // indirect + github.com/go-openapi/strfmt v0.24.0 // indirect github.com/go-openapi/swag v0.23.0 // indirect - github.com/go-openapi/validate v0.24.0 // indirect - github.com/go-redis/redis/v8 v8.11.5 // indirect + github.com/go-openapi/swag/conv v0.25.1 // indirect + github.com/go-openapi/swag/fileutils v0.25.1 // indirect + github.com/go-openapi/swag/jsonname v0.25.1 // indirect + github.com/go-openapi/swag/jsonutils v0.25.1 // indirect + github.com/go-openapi/swag/loading v0.25.1 // indirect + github.com/go-openapi/swag/mangling v0.25.1 // indirect + github.com/go-openapi/swag/stringutils v0.25.1 // indirect + github.com/go-openapi/swag/typeutils v0.25.1 // indirect + github.com/go-openapi/swag/yamlutils v0.25.1 // indirect + github.com/go-openapi/validate v0.25.0 // indirect github.com/go-sql-driver/mysql v1.9.3 // indirect github.com/go-stack/stack v1.8.1 // indirect + github.com/go-viper/mapstructure/v2 v2.4.0 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/goccy/go-json v0.10.5 // indirect github.com/gofrs/uuid v4.4.0+incompatible // indirect github.com/gogo/googleapis v1.4.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang-jwt/jwt/v4 v4.5.2 // indirect - github.com/golang-jwt/jwt/v5 v5.2.3 // indirect + github.com/golang-jwt/jwt/v5 v5.3.0 // indirect github.com/golang-migrate/migrate/v4 v4.7.0 // indirect - github.com/golang/mock v1.7.0-rc.1 // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/google/btree v1.1.3 // indirect github.com/google/flatbuffers v25.2.10+incompatible // indirect - github.com/google/gnostic-models v0.6.9 // indirect - github.com/google/go-cmp v0.7.0 // indirect + github.com/google/gnostic-models v0.7.0 // indirect github.com/google/go-querystring v1.1.0 // indirect github.com/google/uuid v1.6.0 // indirect - github.com/google/wire v0.6.0 // indirect - github.com/gorilla/mux v1.8.1 // indirect - github.com/grafana/alerting v0.0.0-20250729175202-b4b881b7b263 // indirect - github.com/grafana/authlib v0.0.0-20250710201142-9542f2f28d43 // indirect + github.com/google/wire v0.7.0 // indirect + github.com/grafana/alerting v0.0.0-20251009192429-9427c24835ae // indirect + github.com/grafana/authlib v0.0.0-20250930082137-a40e2c2b094f // indirect github.com/grafana/dataplane/sdata v0.0.9 // indirect - github.com/grafana/dskit v0.0.0-20250611075409-46f51e1ce914 // indirect - github.com/grafana/grafana-aws-sdk v1.1.0 // indirect - github.com/grafana/grafana-azure-sdk-go/v2 v2.2.0 // indirect - github.com/grafana/grafana/apps/provisioning v0.0.0-20250804150913-990f1c69ecc2 // indirect - github.com/grafana/grafana/pkg/apiserver v0.0.0-20250804150913-990f1c69ecc2 // indirect + github.com/grafana/dskit v0.0.0-20250908063411-6b6da59b5cc4 // indirect + github.com/grafana/grafana-aws-sdk v1.2.0 // indirect + github.com/grafana/grafana-azure-sdk-go/v2 v2.3.1 // indirect + github.com/grafana/grafana/apps/plugins v0.0.0 // indirect + github.com/grafana/grafana/apps/provisioning v0.0.0 // indirect + github.com/grafana/grafana/pkg/apiserver v0.0.0 // indirect github.com/grafana/otel-profiling-go v0.5.1 // indirect - github.com/grafana/pyroscope-go/godeltaprof v0.1.8 // indirect - github.com/grafana/sqlds/v4 v4.2.4 // indirect + github.com/grafana/pyroscope-go/godeltaprof v0.1.9 // indirect + github.com/grafana/sqlds/v4 v4.2.7 // indirect github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0 // indirect github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.2 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-hclog v1.6.3 // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect github.com/hashicorp/go-metrics v0.5.4 // indirect github.com/hashicorp/go-msgpack/v2 v2.1.2 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect - github.com/hashicorp/go-plugin v1.6.3 // indirect + github.com/hashicorp/go-plugin v1.7.0 // indirect github.com/hashicorp/go-sockaddr v1.0.7 // indirect github.com/hashicorp/golang-lru v1.0.2 // indirect github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect github.com/hashicorp/memberlist v0.5.2 // indirect - github.com/hashicorp/yamux v0.1.1 // indirect + github.com/hashicorp/yamux v0.1.2 // indirect github.com/huandu/xstrings v1.5.0 // indirect github.com/jaegertracing/jaeger-idl v0.5.0 // indirect github.com/jessevdk/go-flags v1.6.1 // indirect @@ -163,7 +186,7 @@ require ( 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.18.0 // indirect - github.com/klauspost/cpuid/v2 v2.2.10 // indirect + github.com/klauspost/cpuid/v2 v2.3.0 // indirect github.com/kylelemons/godebug v1.1.0 // indirect github.com/lestrrat-go/strftime v1.0.4 // indirect github.com/lib/pq v1.10.9 // indirect @@ -173,7 +196,7 @@ require ( github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.16 // indirect - github.com/mattn/go-sqlite3 v1.14.22 // indirect + github.com/mattn/go-sqlite3 v1.14.32 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/mdlayher/socket v0.4.1 // indirect github.com/mdlayher/vsock v1.2.1 // indirect @@ -188,7 +211,7 @@ require ( github.com/mithrandie/go-text v1.6.0 // indirect github.com/mithrandie/ternary v1.1.1 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect - github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect @@ -199,9 +222,9 @@ require ( github.com/oklog/run v1.1.0 // indirect github.com/oklog/ulid v1.3.1 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect - github.com/open-feature/go-sdk v1.14.1 // indirect - github.com/open-feature/go-sdk-contrib/providers/go-feature-flag v0.2.3 // indirect - github.com/open-feature/go-sdk-contrib/providers/ofrep v0.1.5 // indirect + github.com/open-feature/go-sdk v1.16.0 // indirect + github.com/open-feature/go-sdk-contrib/providers/go-feature-flag v0.2.6 // indirect + github.com/open-feature/go-sdk-contrib/providers/ofrep v0.1.6 // indirect github.com/patrickmn/go-cache v2.1.0+incompatible // indirect github.com/perimeterx/marshmallow v1.1.5 // indirect github.com/pierrec/lz4/v4 v4.1.22 // indirect @@ -209,13 +232,14 @@ require ( github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/alertmanager v0.28.0 // indirect - github.com/prometheus/client_golang v1.22.0 // indirect + github.com/prometheus/client_golang v1.23.2 // indirect github.com/prometheus/client_model v0.6.2 // indirect - github.com/prometheus/common v0.65.0 // indirect + github.com/prometheus/common v0.67.1 // indirect github.com/prometheus/common/sigv4 v0.1.0 // indirect github.com/prometheus/exporter-toolkit v0.14.0 // indirect github.com/prometheus/procfs v0.16.1 // indirect github.com/puzpuzpuz/xsync/v2 v2.5.1 // indirect + github.com/redis/go-redis/v9 v9.14.0 // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/rivo/uniseg v0.4.7 // indirect github.com/rs/cors v1.11.1 // indirect @@ -223,10 +247,10 @@ require ( github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 // indirect github.com/shopspring/decimal v1.4.0 // indirect github.com/shurcooL/httpfs v0.0.0-20230704072500-f1e31cf0ba5c // indirect - github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546 // indirect + github.com/shurcooL/vfsgen v0.0.0-20230704071429-0000e147ea92 // indirect github.com/sirupsen/logrus v1.9.3 // indirect - github.com/spf13/cast v1.7.1 // indirect - github.com/spf13/pflag v1.0.7 // indirect + github.com/spf13/cast v1.10.0 // indirect + github.com/spf13/pflag v1.0.10 // indirect github.com/stretchr/objx v0.5.2 // indirect github.com/tetratelabs/wazero v1.8.2 // indirect github.com/thomaspoignant/go-feature-flag v1.42.0 // indirect @@ -234,16 +258,17 @@ require ( github.com/unknwon/bra v0.0.0-20200517080246-1e3013ecaff8 // indirect github.com/unknwon/com v1.0.1 // indirect github.com/unknwon/log v0.0.0-20200308114134-929b1006e34a // indirect - github.com/urfave/cli v1.22.16 // indirect + github.com/urfave/cli v1.22.17 // indirect + github.com/woodsbury/decimal128 v1.3.0 // indirect github.com/x448/float16 v0.8.4 // indirect github.com/zeebo/xxh3 v1.0.2 // indirect - go.mongodb.org/mongo-driver v1.17.3 // indirect + go.mongodb.org/mongo-driver v1.17.4 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.61.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 // indirect - go.opentelemetry.io/contrib/propagators/jaeger v1.36.0 // indirect - go.opentelemetry.io/contrib/samplers/jaegerremote v0.30.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.63.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0 // indirect + go.opentelemetry.io/contrib/propagators/jaeger v1.38.0 // indirect + go.opentelemetry.io/contrib/samplers/jaegerremote v0.32.0 // indirect go.opentelemetry.io/otel v1.38.0 // indirect go.opentelemetry.io/otel/exporters/jaeger v1.17.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 // indirect @@ -252,48 +277,52 @@ require ( go.opentelemetry.io/otel/metric v1.38.0 // indirect go.opentelemetry.io/otel/sdk v1.38.0 // indirect go.opentelemetry.io/otel/trace v1.38.0 // indirect - go.opentelemetry.io/proto/otlp v1.7.0 // indirect + go.opentelemetry.io/proto/otlp v1.7.1 // indirect go.uber.org/atomic v1.11.0 // indirect - go.yaml.in/yaml/v2 v2.4.2 // indirect - golang.org/x/crypto v0.40.0 // indirect - golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 // indirect - golang.org/x/mod v0.26.0 // indirect - golang.org/x/net v0.42.0 // indirect - golang.org/x/oauth2 v0.30.0 // indirect - golang.org/x/sync v0.16.0 // indirect - golang.org/x/sys v0.34.0 // indirect - golang.org/x/term v0.33.0 // indirect - golang.org/x/text v0.27.0 // indirect - golang.org/x/time v0.11.0 // indirect - golang.org/x/tools v0.35.0 // indirect + go.uber.org/mock v0.6.0 // indirect + go.yaml.in/yaml/v2 v2.4.3 // indirect + go.yaml.in/yaml/v3 v3.0.4 // indirect + golang.org/x/crypto v0.43.0 // indirect + golang.org/x/exp v0.0.0-20251002181428-27f1f14c8bb9 // indirect + golang.org/x/mod v0.29.0 // indirect + golang.org/x/net v0.46.0 // indirect + golang.org/x/oauth2 v0.32.0 // indirect + golang.org/x/sync v0.17.0 // indirect + golang.org/x/sys v0.37.0 // indirect + golang.org/x/telemetry v0.0.0-20251008203120-078029d740a8 // indirect + golang.org/x/term v0.36.0 // indirect + golang.org/x/text v0.30.0 // indirect + golang.org/x/time v0.14.0 // indirect + golang.org/x/tools v0.38.0 // indirect golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect gonum.org/v1/gonum v0.16.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 // indirect - google.golang.org/grpc v1.74.2 // indirect - google.golang.org/protobuf v1.36.6 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20250908214217-97024824d090 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20251002232023-7c0ddcbb5797 // indirect + google.golang.org/grpc v1.76.0 // indirect + google.golang.org/protobuf v1.36.10 // indirect gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect gopkg.in/fsnotify/fsnotify.v1 v1.4.7 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/mail.v2 v2.3.1 // indirect gopkg.in/src-d/go-errors.v1 v1.0.0 // indirect - gopkg.in/telebot.v3 v3.2.1 // indirect + gopkg.in/telebot.v3 v3.3.8 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/api v0.33.3 // indirect - k8s.io/apiextensions-apiserver v0.33.3 // indirect - k8s.io/client-go v0.33.3 // indirect - k8s.io/component-base v0.33.3 // indirect + k8s.io/api v0.34.1 // indirect + k8s.io/apiextensions-apiserver v0.34.1 // indirect + k8s.io/client-go v0.34.1 // indirect + k8s.io/component-base v0.34.1 // indirect k8s.io/klog/v2 v2.130.1 // indirect - k8s.io/utils v0.0.0-20241210054802-24370beab758 // indirect - modernc.org/libc v1.65.0 // indirect + k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 // indirect + modernc.org/libc v1.66.10 // indirect modernc.org/mathutil v1.7.1 // indirect - modernc.org/memory v1.10.0 // indirect - modernc.org/sqlite v1.38.0 // indirect + modernc.org/memory v1.11.0 // indirect + modernc.org/sqlite v1.39.1 // indirect sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect sigs.k8s.io/randfill v1.0.0 // indirect - sigs.k8s.io/yaml v1.5.0 // indirect + sigs.k8s.io/structured-merge-diff/v6 v6.3.0 // indirect + sigs.k8s.io/yaml v1.6.0 // indirect xorm.io/builder v0.3.6 // indirect ) diff --git a/apps/advisor/go.sum b/apps/advisor/go.sum index 982588e1749..340f046aed0 100644 --- a/apps/advisor/go.sum +++ b/apps/advisor/go.sum @@ -78,14 +78,14 @@ dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7 filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= github.com/Azure/azure-sdk-for-go v68.0.0+incompatible h1:fcYLmCpyNYRnvJbPerq7U0hS+6+I79yEDJBqVNcqUzU= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.1 h1:Wc1ml6QlJs2BHQ/9Bqu1jiyggbsSjramq2oUmp5WeIo= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.1/go.mod h1:Ot/6aikWnKWi4l9QB7qVSwa8iMphQNqkWALMoNT3rzM= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.10.1 h1:B+blDbyVIG3WaikNxPnhPiJ1MThR03b3vKGtER95TP4= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.10.1/go.mod h1:JdM5psgjfBf5fo2uWOZhflPWyDBZ/O/CNAH9CtsuZE4= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.19.1 h1:5YTBM8QDVIBN3sxBil89WfdAAqDZbyJTgh688DSxX5w= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.19.1/go.mod h1:YD5h/ldMsG0XiIw7PdyNhLxaM317eFh5yNLccNfGdyw= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.12.0 h1:wL5IEG5zb7BVv1Kv0Xm92orq+5hB5Nipn3B5tn4Rqfk= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.12.0/go.mod h1:J7MUC/wtRpfGVbQ5sIItY5/FuVWmvzlY21WAOfQnq/I= github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2 h1:yz1bePFlP5Vws5+8ez6T3HWXPmwOK7Yvq8QxDBD3SKY= github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2/go.mod h1:Pa9ZNPuoNu/GztvBSKk9J1cDJW6vk/n0zLtV4mgd8N8= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1 h1:FPKJS1T+clwv+OLGt13a8UjqeRuh0O4SJ3lUriThc+4= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1/go.mod h1:j2chePtV91HrC22tGoRX3sGY42uF13WzmmV80/OdVAA= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2 h1:9iefClla7iYpfYWdzPCRDozdmndjTm8DXdpCzPajMgA= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2/go.mod h1:XtLgD3ZD34DAaVIIAyG3objl5DynM3CQ/vMcbBNJZGI= github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.1 h1:lhZdRq7TIx0GJQvSyX2Si406vrYsov2FXGp/RnSEtcs= github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.1/go.mod h1:8cl44BDmi+effbARHMQjgOKA2AYvcohNm7KEt42mSV8= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= @@ -98,16 +98,15 @@ github.com/Azure/go-ntlmssp v0.0.0-20220621081337-cb9428e4ac1e h1:NeAW1fUYUEWhft github.com/Azure/go-ntlmssp v0.0.0-20220621081337-cb9428e4ac1e/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1 h1:WJTmL004Abzc5wDB5VtZG2PJk5ndYDgVacGqfirKxjM= github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1/go.mod h1:tCcJZ0uHAmvjsVYzEFivsRTN00oz5BEsRgQHu5JZ9WE= -github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2 h1:oygO0locgZJe7PpYPXT5A29ZkwJaPqcva7BVeemZOZs= -github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= +github.com/AzureAD/microsoft-authentication-library-for-go v1.5.0 h1:XkkQbfMyuH2jTSjQjSoihryI8GINRcs4xp8lNawg0FI= +github.com/AzureAD/microsoft-authentication-library-for-go v1.5.0/go.mod h1:HKpQxkWaGLJ+D/5H8QRpyQXA1eKjxkFlOMwck5+33Jk= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg= github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= -github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.27.0 h1:ErKg/3iS1AKcTkf3yixlZ54f9U1rljCkQyEXWUnIUxc= -github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.27.0/go.mod h1:yAZHSGnqScoU556rBOVkwLze6WP5N+U11RHuWaGVxwY= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.29.0 h1:UQUsRi8WTzhZntp5313l+CHIAT95ojUI2lpP/ExlZa4= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.29.0/go.mod h1:Cz6ft6Dkn3Et6l2v2a9/RpN7epQ1GtDlO6lj8bEcOvw= github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.51.0 h1:fYE9p3esPxA/C0rQ0AHhP0drtPXDRhaWiwg1DPqO7IU= github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.51.0/go.mod h1:BnBReJLvVYx2CS/UHOgVz2BXKXD9wsQPxZug20nZhd0= github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.51.0 h1:6/0iUd0xrnX7qt+mLNRwg5c0PGv8wpE8K90ryANQwMI= @@ -120,6 +119,8 @@ github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1 github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= github.com/Masterminds/sprig/v3 v3.3.0 h1:mQh0Yrg1XPo6vjYXgtf5OtijNAKJRNcTdOOGZe3tPhs= github.com/Masterminds/sprig/v3 v3.3.0/go.mod h1:Zy1iXRYNqNLUolqCpL4uhk6SHUMAOSCzdgBfDb35Lz0= +github.com/Masterminds/squirrel v1.5.4 h1:uUcX/aBc8O7Fg9kaISIUsHXdKuqehiXAMQTYX8afzqM= +github.com/Masterminds/squirrel v1.5.4/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10= github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I= github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= @@ -135,6 +136,8 @@ github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWX github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/VividCortex/mysqlerr v0.0.0-20170204212430-6c6b55f8796f h1:HR5nRmUQgXrwqZOwZ2DAc/aCi3Bu3xENpspW935vxu0= github.com/VividCortex/mysqlerr v0.0.0-20170204212430-6c6b55f8796f/go.mod h1:f3HiCrHjHBdcm6E83vGaXh1KomZMA2P6aeo3hKx/wg0= +github.com/Yiling-J/theine-go v0.6.2 h1:1GeoXeQ0O0AUkiwj2S9Jc0Mzx+hpqzmqsJ4kIC4M9AY= +github.com/Yiling-J/theine-go v0.6.2/go.mod h1:08QpMa5JZ2pKN+UJCRrCasWYO1IKCdl54Xa836rpmDU= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= @@ -142,16 +145,16 @@ github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRF github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b h1:mimo19zliBX/vSQ6PWWSL9lK8qwHozUj03+zLoEB8O0= github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b/go.mod h1:fvzegU4vN3H1qMT+8wDmzjAcDONcgo2/SZ/TyfdUOFs= -github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA= -github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA= +github.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwToPjQ= +github.com/andybalholm/brotli v1.2.0/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= 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/v18 v18.3.0 h1:Xq4A6dZj9Nu33sqZibzn012LNnewkTUlfKVUFD/RX/I= -github.com/apache/arrow-go/v18 v18.3.0/go.mod h1:eEM1DnUTHhgGAjf/ChvOAQbUQ+EPohtDrArffvUjPg8= +github.com/apache/arrow-go/v18 v18.4.1 h1:q/jVkBWCJOB9reDgaIZIdruLQUb1kbkvOnOFezVH1C4= +github.com/apache/arrow-go/v18 v18.4.1/go.mod h1:tLyFubsAl17bvFdUAy24bsSvA/6ww95Iqi67fTpGu3E= github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= -github.com/apache/thrift v0.21.0 h1:tdPmh/ptjE1IJnhbhrcl2++TauVjy242rkV/UzJChnE= -github.com/apache/thrift v0.21.0/go.mod h1:W1H8aR/QRtYNvrPeFXBtobyRkd0/YVhTc6i07XIAgDw= +github.com/apache/thrift v0.22.0 h1:r7mTJdj51TMDe6RtcmNdQxgn9XcyfGDOzegMDRg47uc= +github.com/apache/thrift v0.22.0/go.mod h1:1e7J/O1Ae6ZQMTYdy9xa3w9k+XHWPfRvdPyJeynQ+/g= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-metrics v0.3.10/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= @@ -168,44 +171,44 @@ github.com/aws/aws-sdk-go v1.17.7/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN github.com/aws/aws-sdk-go v1.38.35/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= github.com/aws/aws-sdk-go v1.55.7 h1:UJrkFq7es5CShfBwlWAC8DA077vp8PyVbQd3lqLiztE= github.com/aws/aws-sdk-go v1.55.7/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU= -github.com/aws/aws-sdk-go-v2 v1.36.5 h1:0OF9RiEMEdDdZEMqF9MRjevyxAQcf6gY+E7vwBILFj0= -github.com/aws/aws-sdk-go-v2 v1.36.5/go.mod h1:EYrzvCCN9CMUTa5+6lf6MM4tq3Zjp8UhSGR/cBsjai0= +github.com/aws/aws-sdk-go-v2 v1.38.1 h1:j7sc33amE74Rz0M/PoCpsZQ6OunLqys/m5antM0J+Z8= +github.com/aws/aws-sdk-go-v2 v1.38.1/go.mod h1:9Q0OoGQoboYIAJyslFyF1f5K1Ryddop8gqMhWx/n4Wg= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.11 h1:12SpdwU8Djs+YGklkinSSlcrPyj3H4VifVsKf78KbwA= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.11/go.mod h1:dd+Lkp6YmMryke+qxW/VnKyhMBDTYP41Q2Bb+6gNZgY= -github.com/aws/aws-sdk-go-v2/config v1.29.17 h1:jSuiQ5jEe4SAMH6lLRMY9OVC+TqJLP5655pBGjmnjr0= -github.com/aws/aws-sdk-go-v2/config v1.29.17/go.mod h1:9P4wwACpbeXs9Pm9w1QTh6BwWwJjwYvJ1iCt5QbCXh8= -github.com/aws/aws-sdk-go-v2/credentials v1.17.70 h1:ONnH5CM16RTXRkS8Z1qg7/s2eDOhHhaXVd72mmyv4/0= -github.com/aws/aws-sdk-go-v2/credentials v1.17.70/go.mod h1:M+lWhhmomVGgtuPOhO85u4pEa3SmssPTdcYpP/5J/xc= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.32 h1:KAXP9JSHO1vKGCr5f4O6WmlVKLFFXgWYAGoJosorxzU= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.32/go.mod h1:h4Sg6FQdexC1yYG9RDnOvLbW1a/P986++/Y/a+GyEM8= +github.com/aws/aws-sdk-go-v2/config v1.31.2 h1:NOaSZpVGEH2Np/c1toSeW0jooNl+9ALmsUTZ8YvkJR0= +github.com/aws/aws-sdk-go-v2/config v1.31.2/go.mod h1:17ft42Yb2lF6OigqSYiDAiUcX4RIkEMY6XxEMJsrAes= +github.com/aws/aws-sdk-go-v2/credentials v1.18.6 h1:AmmvNEYrru7sYNJnp3pf57lGbiarX4T9qU/6AZ9SucU= +github.com/aws/aws-sdk-go-v2/credentials v1.18.6/go.mod h1:/jdQkh1iVPa01xndfECInp1v1Wnp70v3K4MvtlLGVEc= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.4 h1:lpdMwTzmuDLkgW7086jE94HweHCqG+uOJwHf3LZs7T0= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.4/go.mod h1:9xzb8/SV62W6gHQGC/8rrvgNXU6ZoYM3sAIJCIrXJxY= github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.69 h1:6VFPH/Zi9xYFMJKPQOX5URYkQoXRWeJ7V/7Y6ZDYoms= github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.69/go.mod h1:GJj8mmO6YT6EqgduWocwhMoxTLFitkhIrK+owzrYL2I= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.36 h1:SsytQyTMHMDPspp+spo7XwXTP44aJZZAC7fBV2C5+5s= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.36/go.mod h1:Q1lnJArKRXkenyog6+Y+zr7WDpk4e6XlR6gs20bbeNo= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.36 h1:i2vNHQiXUvKhs3quBR6aqlgJaiaexz/aNvdCktW/kAM= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.36/go.mod h1:UdyGa7Q91id/sdyHPwth+043HhmP6yP9MBHgbZM0xo8= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.4 h1:IdCLsiiIj5YJ3AFevsewURCPV+YWUlOW8JiPhoAy8vg= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.4/go.mod h1:l4bdfCD7XyyZA9BolKBo1eLqgaJxl0/x91PL4Yqe0ao= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.4 h1:j7vjtr1YIssWQOMeOWRbh3z8g2oY/xPjnZH2gLY4sGw= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.4/go.mod h1:yDmJgqOiH4EA8Hndnv4KwAo8jCGTSnM5ASG1nBI+toA= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 h1:bIqFDwgGXXN1Kpp99pDOdKMTTb5d2KyU5X/BZxjOkRo= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3/go.mod h1:H5O/EsxDWyU+LP/V8i5sm8cxoZgc2fdNR9bxlOFrQTo= github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.34 h1:ZNTqv4nIdE/DiBfUUfXcLZ/Spcuz+RjeziUtNJackkM= github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.34/go.mod h1:zf7Vcd1ViW7cPqYWEHLHJkS50X0JS2IKz9Cgaj6ugrs= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.4 h1:CXV68E2dNqhuynZJPB80bhPQwAKqBWVer887figW6Jc= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.4/go.mod h1:/xFi9KtvBXP97ppCz1TAEvU1Uf66qvid89rbem3wCzQ= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.0 h1:6+lZi2JeGKtCraAj1rpoZfKqnQ9SptseRZioejfUOLM= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.0/go.mod h1:eb3gfbVIxIoGgJsi9pGne19dhCBpK6opTYpQqAmdy44= github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.7.0 h1:lguz0bmOoGzozP9XfRJR1QIayEYo+2vP/No3OfLF0pU= github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.7.0/go.mod h1:iu6FSzgt+M2/x3Dk8zhycdIcHjEFb36IS8HVUVFoMg0= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.17 h1:t0E6FzREdtCsiLIoLCWsYliNsRBgyGD/MCK571qk4MI= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.17/go.mod h1:ygpklyoaypuyDvOM5ujWGrYWpAK3h7ugnmKCU/76Ys4= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.4 h1:ueB2Te0NacDMnaC+68za9jLwkjzxGWm0KB5HTUHjLTI= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.4/go.mod h1:nLEfLnVMmLvyIG58/6gsSA03F1voKGaCfHV7+lR8S7s= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.15 h1:moLQUoVq91LiqT1nbvzDukyqAlCv89ZmwaHw/ZFlFZg= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.15/go.mod h1:ZH34PJUc8ApjBIfgQCFvkWcUDBtl/WTD+uiYHjd8igA= github.com/aws/aws-sdk-go-v2/service/s3 v1.78.2 h1:jIiopHEV22b4yQP2q36Y0OmwLbsxNWdWwfZRR5QRRO4= github.com/aws/aws-sdk-go-v2/service/s3 v1.78.2/go.mod h1:U5SNqwhXB3Xe6F47kXvWihPl/ilGaEDe8HD/50Z9wxc= -github.com/aws/aws-sdk-go-v2/service/sso v1.25.5 h1:AIRJ3lfb2w/1/8wOOSqYb9fUKGwQbtysJ2H1MofRUPg= -github.com/aws/aws-sdk-go-v2/service/sso v1.25.5/go.mod h1:b7SiVprpU+iGazDUqvRSLf5XmCdn+JtT1on7uNL6Ipc= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.3 h1:BpOxT3yhLwSJ77qIY3DoHAQjZsc4HEGfMCE4NGy3uFg= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.3/go.mod h1:vq/GQR1gOFLquZMSrxUK/cpvKCNVYibNyJ1m7JrU88E= -github.com/aws/aws-sdk-go-v2/service/sts v1.34.0 h1:NFOJ/NXEGV4Rq//71Hs1jC/NvPs1ezajK+yQmkwnPV0= -github.com/aws/aws-sdk-go-v2/service/sts v1.34.0/go.mod h1:7ph2tGpfQvwzgistp2+zga9f+bCjlQJPkPUmMgDSD7w= -github.com/aws/smithy-go v1.22.4 h1:uqXzVZNuNexwc/xrh6Tb56u89WDlJY6HS+KC0S4QSjw= -github.com/aws/smithy-go v1.22.4/go.mod h1:t1ufH5HMublsJYulve2RKmHDC15xu1f26kHCp/HgceI= +github.com/aws/aws-sdk-go-v2/service/sso v1.28.2 h1:ve9dYBB8CfJGTFqcQ3ZLAAb/KXWgYlgu/2R2TZL2Ko0= +github.com/aws/aws-sdk-go-v2/service/sso v1.28.2/go.mod h1:n9bTZFZcBa9hGGqVz3i/a6+NG0zmZgtkB9qVVFDqPA8= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.33.2 h1:pd9G9HQaM6UZAZh19pYOkpKSQkyQQ9ftnl/LttQOcGI= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.33.2/go.mod h1:eknndR9rU8UpE/OmFpqU78V1EcXPKFTTm5l/buZYgvM= +github.com/aws/aws-sdk-go-v2/service/sts v1.38.0 h1:iV1Ko4Em/lkJIsoKyGfc0nQySi+v0Udxr6Igq+y9JZc= +github.com/aws/aws-sdk-go-v2/service/sts v1.38.0/go.mod h1:bEPcjW7IbolPfK67G1nilqWyoxYMSPrDiIQ3RdIdKgo= +github.com/aws/smithy-go v1.23.1 h1:sLvcH6dfAFwGkHLZ7dGiYF7aK6mg4CgKA/iDKjLDt9M= +github.com/aws/smithy-go v1.23.1/go.mod h1:LEj2LM3rBRQJxPZTB4KuzZkaZYnZPnvgIhb4pu07mx0= github.com/axiomhq/hyperloglog v0.0.0-20240507144631-af9851f82b27 h1:60m4tnanN1ctzIu4V3bfCNJ39BiOPSm1gHFlFjTkRE0= github.com/axiomhq/hyperloglog v0.0.0-20240507144631-af9851f82b27/go.mod h1:k08r+Yj1PRAmuayFiRK6MYuR5Ve4IuZtTfxErMIh0+c= github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk= @@ -275,8 +278,12 @@ github.com/blugelabs/ice/v2 v2.0.1/go.mod h1:QxAWSPNwZwsIqS25c3lbIPFQrVvT1sphf5x github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874 h1:N7oVaKyGp8bttX0bfZGmcGkjz7DLQXhAn3DNd3T0ous= github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874/go.mod h1:r5xuitiExdLAJ09PR7vBVENGvp4ZuTBeWTGtxuX3K+c= -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/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs= +github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c= +github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= +github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= +github.com/bufbuild/protocompile v0.14.1 h1:iA73zAf/fyljNjQKwYzUHD6AD4R8KMasmwa/FBatYVw= +github.com/bufbuild/protocompile v0.14.1/go.mod h1:ppVdAIhbr2H8asPk6k4pY7t9zB1OU5DoEw9xY/FUi1c= 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/bwmarrin/snowflake v0.3.0 h1:xm67bEhkKh6ij1790JB83OujPR5CzNe8QuQqAgISZN0= @@ -285,8 +292,8 @@ github.com/caio/go-tdigest v3.1.0+incompatible h1:uoVMJ3Q5lXmVLCCqaMGHLBWnbGoN6L github.com/caio/go-tdigest v3.1.0+incompatible/go.mod h1:sHQM/ubZStBUmF1WbB8FAm8q9GjDajLC5T7ydxE3JHI= 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/cenkalti/backoff/v5 v5.0.2 h1:rIfFVxEf1QsI7E1ZHfp/B4DF/6QBAUhmgkxc0H7Zss8= -github.com/cenkalti/backoff/v5 v5.0.2/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= +github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= +github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= @@ -294,8 +301,6 @@ 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-20250429231605-6ed5b53462d4 h1:UZdrvid2JFwnvPlUSEFlE794XZL4Jmrj8fuxfcLECJE= -github.com/chromedp/cdproto v0.0.0-20250429231605-6ed5b53462d4/go.mod h1:NItd7aLkcfOA/dcMXvl8p1u+lQqioRMq/SqDp71Pb/k= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= @@ -328,9 +333,8 @@ github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSV github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= 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.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/cpuguy83/go-md2man/v2 v2.0.6 h1:XJtiaUW6dEEqVuZiMTn1ldk455QWwEIsMIJlo5vtkx0= -github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= +github.com/cpuguy83/go-md2man/v2 v2.0.7 h1:zbFlGlXEAKlwXpmvle3d8Oe3YnkKIK4xSRTd3sHPnBo= +github.com/cpuguy83/go-md2man/v2 v2.0.7/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/cznic/b v0.0.0-20180115125044-35e9bbe41f07/go.mod h1:URriBxXwVq5ijiJ12C7iIZqlA69nTlI+LgI6/pwftG8= github.com/cznic/fileutil v0.0.0-20180108211300-6a051e75936f/go.mod h1:8S58EK26zhXSxzv7NQFpnliaOQsmDUxvoQO3rt154Vg= @@ -386,10 +390,10 @@ github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5m github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= -github.com/elazarl/goproxy v1.7.2 h1:Y2o6urb7Eule09PjlhQRGNsqRfPmYI3KKQLFpCAV3+o= -github.com/elazarl/goproxy v1.7.2/go.mod h1:82vkLNir0ALaW14Rc399OTTjyNREgmdL2cVoIbS6XaE= -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/emicklei/go-restful/v3 v3.13.0 h1:C4Bl2xDndpU6nJ4bc1jXd+uTmYPVUwkD6bFY/oTyCes= +github.com/emicklei/go-restful/v3 v3.13.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= +github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= 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= @@ -405,8 +409,8 @@ github.com/envoyproxy/go-control-plane/envoy v1.32.4/go.mod h1:Gzjc5k8JcJswLjAx1 github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v1.2.1 h1:DEo3O99U8j4hBFwbJfrz9VtgcDfUKS7KJ7spH3d86P8= github.com/envoyproxy/protoc-gen-validate v1.2.1/go.mod h1:d/C80l/jxXLdfEIhX1W2TmLfsJ31lvEjwamM4DxlWXU= -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/evanphx/json-patch v5.9.11+incompatible h1:ixHHqfcGvxhWkniF1tWxBHA0yb4Z+d1UQi45df52xW8= +github.com/evanphx/json-patch v5.9.11+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= @@ -425,22 +429,20 @@ github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8 github.com/fsouza/fake-gcs-server v1.7.0/go.mod h1:5XIRs4YvwNbNoz+1JF8j6KLAyDh7RHGAyAK3EP2EsNk= github.com/fullstorydev/grpchan v1.1.1 h1:heQqIJlAv5Cnks9a70GRL2EJke6QQoUB25VGR6TZQas= github.com/fullstorydev/grpchan v1.1.1/go.mod h1:f4HpiV8V6htfY/K44GWV1ESQzHBTq7DinhzqQ95lpgc= -github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= -github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= +github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM= +github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= github.com/gchaincl/sqlhooks v1.3.0 h1:yKPXxW9a5CjXaVf2HkQn6wn7TZARvbAOAelr3H8vK2Y= github.com/gchaincl/sqlhooks v1.3.0/go.mod h1:9BypXnereMT0+Ys8WGWHqzgkkOfHIhyeUCqXC24ra34= -github.com/getkin/kin-openapi v0.132.0 h1:3ISeLMsQzcb5v26yeJrBcdTCEQTag36ZjaGk7MIRUwk= -github.com/getkin/kin-openapi v0.132.0/go.mod h1:3OlG51PCYNsPByuiMB0t4fjnNlIDnaEDsjiKUV8nL58= +github.com/getkin/kin-openapi v0.133.0 h1:pJdmNohVIJ97r4AUFtEXRXwESr8b0bD721u/Tz6k8PQ= +github.com/getkin/kin-openapi v0.133.0/go.mod h1:boAciF6cXk5FhPqe/NQeBTeenbjqU4LhWBf09ILVvWE= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-asn1-ber/asn1-ber v1.5.4 h1:vXT6d/FNDiELJnLb6hGNa309LMsrCoYFvpwHDF0+Y1A= github.com/go-asn1-ber/asn1-ber v1.5.4/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-jose/go-jose/v3 v3.0.4 h1:Wp5HA7bLQcKnf6YYao/4kpRpVMp/yf6+pJKV8WFSaNY= -github.com/go-jose/go-jose/v3 v3.0.4/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ= -github.com/go-jose/go-jose/v4 v4.1.0 h1:cYSYxd3pw5zd2FSXk2vGdn9igQU2PS8MuxrCOCl0FdY= -github.com/go-jose/go-jose/v4 v4.1.0/go.mod h1:GG/vqmYm3Von2nYiB2vGTXzdoNKE5tix5tuc6iAd+sw= +github.com/go-jose/go-jose/v4 v4.1.2 h1:TK/7NqRQZfgAh+Td8AlsrvtPoUyiHh0LqVvokh+1vHI= +github.com/go-jose/go-jose/v4 v4.1.2/go.mod h1:22cg9HWM1pOlnRiY+9cQYJ9XHmya1bYW8OeDM6Ku6Oo= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= @@ -459,32 +461,50 @@ github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= 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/analysis v0.23.0 h1:aGday7OWupfMs+LbmLZG4k0MYXIANxcuBTYUC03zFCU= -github.com/go-openapi/analysis v0.23.0/go.mod h1:9mz9ZWaSlV8TvjQHLl2mUW2PbZtemkE8yA5v22ohupo= -github.com/go-openapi/errors v0.22.0 h1:c4xY/OLxUBSTiepAg3j/MHuAv5mJhnf53LLMWFB+u/w= -github.com/go-openapi/errors v0.22.0/go.mod h1:J3DmZScxCDufmIMsdOuDHxJbdOGC0xtUynjIx092vXE= -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.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= -github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= -github.com/go-openapi/loads v0.22.0 h1:ECPGd4jX1U6NApCGG1We+uEozOAvXvJSF4nnwHZ8Aco= -github.com/go-openapi/loads v0.22.0/go.mod h1:yLsaTCS92mnSAZX5WWoxszLj0u+Ojl+Zs5Stn1oF+rs= +github.com/go-openapi/analysis v0.24.0 h1:vE/VFFkICKyYuTWYnplQ+aVr45vlG6NcZKC7BdIXhsA= +github.com/go-openapi/analysis v0.24.0/go.mod h1:GLyoJA+bvmGGaHgpfeDh8ldpGo69fAJg7eeMDMRCIrw= +github.com/go-openapi/errors v0.22.3 h1:k6Hxa5Jg1TUyZnOwV2Lh81j8ayNw5VVYLvKrp4zFKFs= +github.com/go-openapi/errors v0.22.3/go.mod h1:+WvbaBBULWCOna//9B9TbLNGSFOfF8lY9dw4hGiEiKQ= +github.com/go-openapi/jsonpointer v0.22.1 h1:sHYI1He3b9NqJ4wXLoJDKmUmHkWy/L7rtEo92JUxBNk= +github.com/go-openapi/jsonpointer v0.22.1/go.mod h1:pQT9OsLkfz1yWoMgYFy4x3U5GY5nUlsOn1qSBH5MkCM= +github.com/go-openapi/jsonreference v0.21.2 h1:Wxjda4M/BBQllegefXrY/9aq1fxBA8sI5M/lFU6tSWU= +github.com/go-openapi/jsonreference v0.21.2/go.mod h1:pp3PEjIsJ9CZDGCNOyXIQxsNuroxm8FAJ/+quA0yKzQ= +github.com/go-openapi/loads v0.23.1 h1:H8A0dX2KDHxDzc797h0+uiCZ5kwE2+VojaQVaTlXvS0= +github.com/go-openapi/loads v0.23.1/go.mod h1:hZSXkyACCWzWPQqizAv/Ye0yhi2zzHwMmoXQ6YQml44= github.com/go-openapi/runtime v0.28.0 h1:gpPPmWSNGo214l6n8hzdXYhPuJcGtziTOgUpvsFWGIQ= github.com/go-openapi/runtime v0.28.0/go.mod h1:QN7OzcS+XuYmkQLw05akXk0jRH/eZ3kb18+1KwW9gyc= -github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9ZY= -github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk= -github.com/go-openapi/strfmt v0.23.0 h1:nlUS6BCqcnAk0pyhi9Y+kdDVZdZMHfEKQiS4HaMgO/c= -github.com/go-openapi/strfmt v0.23.0/go.mod h1:NrtIpfKtWIygRkKVsxh7XQMDQW5HKQl6S5ik2elW+K4= +github.com/go-openapi/spec v0.22.0 h1:xT/EsX4frL3U09QviRIZXvkh80yibxQmtoEvyqug0Tw= +github.com/go-openapi/spec v0.22.0/go.mod h1:K0FhKxkez8YNS94XzF8YKEMULbFrRw4m15i2YUht4L0= +github.com/go-openapi/strfmt v0.24.0 h1:dDsopqbI3wrrlIzeXRbqMihRNnjzGC+ez4NQaAAJLuc= +github.com/go-openapi/strfmt v0.24.0/go.mod h1:Lnn1Bk9rZjXxU9VMADbEEOo7D7CDyKGLsSKekhFr7s4= 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-openapi/validate v0.24.0 h1:LdfDKwNbpB6Vn40xhTdNZAnfLECL81w+VX3BumrGD58= -github.com/go-openapi/validate v0.24.0/go.mod h1:iyeX1sEufmv3nPbBdX3ieNviWnOZaJ1+zquzJEf2BAQ= +github.com/go-openapi/swag/conv v0.25.1 h1:+9o8YUg6QuqqBM5X6rYL/p1dpWeZRhoIt9x7CCP+he0= +github.com/go-openapi/swag/conv v0.25.1/go.mod h1:Z1mFEGPfyIKPu0806khI3zF+/EUXde+fdeksUl2NiDs= +github.com/go-openapi/swag/fileutils v0.25.1 h1:rSRXapjQequt7kqalKXdcpIegIShhTPXx7yw0kek2uU= +github.com/go-openapi/swag/fileutils v0.25.1/go.mod h1:+NXtt5xNZZqmpIpjqcujqojGFek9/w55b3ecmOdtg8M= +github.com/go-openapi/swag/jsonname v0.25.1 h1:Sgx+qbwa4ej6AomWC6pEfXrA6uP2RkaNjA9BR8a1RJU= +github.com/go-openapi/swag/jsonname v0.25.1/go.mod h1:71Tekow6UOLBD3wS7XhdT98g5J5GR13NOTQ9/6Q11Zo= +github.com/go-openapi/swag/jsonutils v0.25.1 h1:AihLHaD0brrkJoMqEZOBNzTLnk81Kg9cWr+SPtxtgl8= +github.com/go-openapi/swag/jsonutils v0.25.1/go.mod h1:JpEkAjxQXpiaHmRO04N1zE4qbUEg3b7Udll7AMGTNOo= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.1 h1:DSQGcdB6G0N9c/KhtpYc71PzzGEIc/fZ1no35x4/XBY= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.1/go.mod h1:kjmweouyPwRUEYMSrbAidoLMGeJ5p6zdHi9BgZiqmsg= +github.com/go-openapi/swag/loading v0.25.1 h1:6OruqzjWoJyanZOim58iG2vj934TysYVptyaoXS24kw= +github.com/go-openapi/swag/loading v0.25.1/go.mod h1:xoIe2EG32NOYYbqxvXgPzne989bWvSNoWoyQVWEZicc= +github.com/go-openapi/swag/mangling v0.25.1 h1:XzILnLzhZPZNtmxKaz/2xIGPQsBsvmCjrJOWGNz/ync= +github.com/go-openapi/swag/mangling v0.25.1/go.mod h1:CdiMQ6pnfAgyQGSOIYnZkXvqhnnwOn997uXZMAd/7mQ= +github.com/go-openapi/swag/stringutils v0.25.1 h1:Xasqgjvk30eUe8VKdmyzKtjkVjeiXx1Iz0zDfMNpPbw= +github.com/go-openapi/swag/stringutils v0.25.1/go.mod h1:JLdSAq5169HaiDUbTvArA2yQxmgn4D6h4A+4HqVvAYg= +github.com/go-openapi/swag/typeutils v0.25.1 h1:rD/9HsEQieewNt6/k+JBwkxuAHktFtH3I3ysiFZqukA= +github.com/go-openapi/swag/typeutils v0.25.1/go.mod h1:9McMC/oCdS4BKwk2shEB7x17P6HmMmA6dQRtAkSnNb8= +github.com/go-openapi/swag/yamlutils v0.25.1 h1:mry5ez8joJwzvMbaTGLhw8pXUnhDK91oSJLDPF1bmGk= +github.com/go-openapi/swag/yamlutils v0.25.1/go.mod h1:cm9ywbzncy3y6uPm/97ysW8+wZ09qsks+9RS8fLWKqg= +github.com/go-openapi/validate v0.25.0 h1:JD9eGX81hDTjoY3WOzh6WqxVBVl7xjsLnvDo1GL5WPU= +github.com/go-openapi/validate v0.25.0/go.mod h1:SUY7vKrN5FiwK6LyvSwKjDfLNirSfWwHNgxd2l29Mmw= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= -github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= -github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-sql-driver/mysql v1.9.3 h1:U/N249h2WzJ3Ukj8SowVFjdtZKfu9vlLZxjPXV1aweo= @@ -496,6 +516,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.1.1 h1:0r/53hagsehfO4bzD2Pgr/+RgHqhmf+k1Bpse2cTu1U= github.com/go-test/deep v1.1.1/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= +github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= +github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= 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/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= @@ -518,8 +540,8 @@ github.com/gogo/status v1.1.1 h1:DuHXlSFHNKqTQ+/ACf5Vs6r4X/dH2EgIzR9Vr+H65kg= github.com/gogo/status v1.1.1/go.mod h1:jpG3dM5QPcqu19Hg8lkUhBFBa3TcLs1DG7+2Jqci7oU= github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI= github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= -github.com/golang-jwt/jwt/v5 v5.2.3 h1:kkGXqQOBSDDWRhWNXTFpqGSCMyh/PLnqUvMGJPDJDs0= -github.com/golang-jwt/jwt/v5 v5.2.3/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= +github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo= +github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= github.com/golang-migrate/migrate/v4 v4.7.0 h1:gONcHxHApDTKXDyLH/H97gEHmpu1zcnnbAaq2zgrPrs= github.com/golang-migrate/migrate/v4 v4.7.0/go.mod h1:Qvut3N4xKWjoH3sokBccML6WyHSnggXm/DvMMnTsQIc= github.com/golang/geo v0.0.0-20210211234256-740aa86cb551 h1:gtexQ/VGyN+VVFRXSFiguSNcXmS6rkKT+X7FdIrTtfo= @@ -540,8 +562,6 @@ github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= -github.com/golang/mock v1.7.0-rc.1 h1:YojYx61/OLFsiv6Rw1Z96LpldJIy31o+UHmwAUMJ6/U= -github.com/golang/mock v1.7.0-rc.1/go.mod h1:s42URUywIqd+OcERslBJvOjepvNymP31m3q8d/GkuRs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -571,12 +591,12 @@ github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Z github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 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.25.0 h1:jsFw9Fhn+3y2kBbltZR4VEz5xKkcIFRPDnuEzAGv5GY= -github.com/google/cel-go v0.25.0/go.mod h1:hjEb6r5SuOSlhCHmFoLzu8HGCERvIsDAbxDAyNU/MmI= +github.com/google/cel-go v0.26.1 h1:iPbVVEdkhTX++hpe3lzSk7D3G3QSYqLGoHOcEio+UXQ= +github.com/google/cel-go v0.26.1/go.mod h1:A9O8OU9rdvrK5MQyrqfIxo1a0u4g3sF8KB6PUIaryMM= github.com/google/flatbuffers v25.2.10+incompatible h1:F3vclr7C3HpB1k9mxCGRMXq6FdUalZ6H/pNX4FP1v0Q= github.com/google/flatbuffers v25.2.10+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= -github.com/google/gnostic-models v0.6.9 h1:MU/8wDLif2qCXZmzncUQ/BOfxWfthHi63KqpoNbWqVw= -github.com/google/gnostic-models v0.6.9/go.mod h1:CiWsm0s6BSQd1hRn8/QmxqB6BesYcbSZxsz9b0KuDBw= +github.com/google/gnostic-models v0.7.0 h1:qwTtogB15McXDaNqTZdzPJRHvaVJlAl+HVQnLmJEJxo= +github.com/google/gnostic-models v0.7.0/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -591,7 +611,6 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= @@ -626,12 +645,11 @@ github.com/google/pprof v0.0.0-20250403155104-27863c87afa6/go.mod h1:boTsfXsheKC github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0= github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM= -github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 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/google/wire v0.6.0 h1:HBkoIh4BdSxoyo9PveV8giw7ZsaBOvzWKfcg/6MrVwI= -github.com/google/wire v0.6.0/go.mod h1:F4QhpQ9EDIdJ1Mbop/NZBRB+5yrR6qg3BnctaoUk6NA= +github.com/google/wire v0.7.0 h1:JxUKI6+CVBgCO2WToKy/nQk0sS+amI9z9EjVmdaocj4= +github.com/google/wire v0.7.0/go.mod h1:n6YbUQD9cPKTnHXEBN2DXlOp/mVADhVErcMFb0v3J18= github.com/googleapis/enterprise-certificate-proxy v0.3.6 h1:GW/XbdyBFQ8Qe+YAmFU9uHLo7OnF5tL52HFAgMmyrf4= github.com/googleapis/enterprise-certificate-proxy v0.3.6/go.mod h1:MkHOF77EYAE7qfSuSS9PU6g4Nt4e11cnsDUowfwewLA= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= @@ -644,63 +662,52 @@ github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK github.com/googleapis/gax-go/v2 v2.14.2 h1:eBLnkZ9635krYIPD+ag1USrOAI0Nr0QYF3+/3GqO0k0= github.com/googleapis/gax-go/v2 v2.14.2/go.mod h1:ON64QhlJkhVtSqp4v1uaK92VyZ2gmvDQsweuyLV+8+w= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= -github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e h1:JKmoR8x90Iww1ks85zJ1lfDGgIiMDuIptTOhJq+zKyg= github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g= +github.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfreZ6J5gM2i+k= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.1/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= -github.com/grafana/alerting v0.0.0-20250729175202-b4b881b7b263 h1:hcr/AmPB0KL4H+gCEFIdKUnkihTxGAkAOiZA7GDYoL8= -github.com/grafana/alerting v0.0.0-20250729175202-b4b881b7b263/go.mod h1:VKxaR93Gff0ZlO2sPcdPVob1a/UzArFEW5zx3Bpyhls= -github.com/grafana/authlib v0.0.0-20250710201142-9542f2f28d43 h1:vVPT0i5Y1vI6qzecYStV2yk7cHKrC3Pc7AgvwT5KydQ= -github.com/grafana/authlib v0.0.0-20250710201142-9542f2f28d43/go.mod h1:1fWkOiL+m32NBgRHZtlZGz2ji868tPZACYbqP3nBRJI= -github.com/grafana/authlib/types v0.0.0-20250710201142-9542f2f28d43 h1:NlkGMnVi/oUn6Cr90QbJYpQJ4FnjyAIG9Ex5GtTZIzw= -github.com/grafana/authlib/types v0.0.0-20250710201142-9542f2f28d43/go.mod h1:qeWYbnWzaYGl88JlL9+DsP1GT2Cudm58rLtx13fKZdw= +github.com/grafana/alerting v0.0.0-20251009192429-9427c24835ae h1:NLPwY3tIP0lg0g9wTRiMcypm6VRXW6W+MOLBsq8JSVA= +github.com/grafana/alerting v0.0.0-20251009192429-9427c24835ae/go.mod h1:VGjS5gDwWEADPP6pF/drqLxEImgeuHlEW5u8E5EfIrM= +github.com/grafana/authlib v0.0.0-20250930082137-a40e2c2b094f h1:Cbm6OKkOcJ+7CSZsGsEJzktC/SIa5bxVeYKQLuYK86o= +github.com/grafana/authlib v0.0.0-20250930082137-a40e2c2b094f/go.mod h1:axY0cdOg3q0TZHwpHnIz5x16xZ8ZBxJHShsSHHXcHQg= +github.com/grafana/authlib/types v0.0.0-20250926065801-df98203cff37 h1:qEwZ+7MbPjzRvTi31iT9w7NBhKIpKwZrFbYmOZLqkwA= +github.com/grafana/authlib/types v0.0.0-20250926065801-df98203cff37/go.mod h1:qeWYbnWzaYGl88JlL9+DsP1GT2Cudm58rLtx13fKZdw= github.com/grafana/dataplane/examples v0.0.1 h1:K9M5glueWyLoL4//H+EtTQq16lXuHLmOhb6DjSCahzA= github.com/grafana/dataplane/examples v0.0.1/go.mod h1:h5YwY8s407/17XF5/dS8XrUtsTVV2RnuW8+m1Mp46mg= github.com/grafana/dataplane/sdata v0.0.9 h1:AGL1LZnCUG4MnQtnWpBPbQ8ZpptaZs14w6kE/MWfg7s= github.com/grafana/dataplane/sdata v0.0.9/go.mod h1:Jvs5ddpGmn6vcxT7tCTWAZ1mgi4sbcdFt9utQx5uMAU= -github.com/grafana/dskit v0.0.0-20250611075409-46f51e1ce914 h1:qcSGhr691f1mmPHwg2svGyO40Ex92G02aOyHzP6XHCE= -github.com/grafana/dskit v0.0.0-20250611075409-46f51e1ce914/go.mod h1:OiN4P4aC6LwLzLbEupH3Ue83VfQoNMfG48rsna8jI/E= -github.com/grafana/grafana-app-sdk v0.40.2 h1:j2ftFuqhX+exYUipfEjeWDs3i7oiJkweTF8gFLL7wWU= -github.com/grafana/grafana-app-sdk v0.40.2/go.mod h1:BbNXPNki3mtbkWxYqJsyA1Cj9AShSyaY33z8WkyfVv0= -github.com/grafana/grafana-app-sdk/logging v0.40.2 h1:HQ1+y9Od92iMbWWB54QxiYpNtCvYGUVpyxvxZ7ywB1k= -github.com/grafana/grafana-app-sdk/logging v0.40.2/go.mod h1:otUD9XpJD7A5sCLb8mcs9hIXGdeV6lnhzVwe747g4RU= -github.com/grafana/grafana-aws-sdk v1.1.0 h1:G0fvwbQmHw14c5RXPd7Gnw9ZQcgzl139LtMDoe0KhmE= -github.com/grafana/grafana-aws-sdk v1.1.0/go.mod h1:7e+47EdHynteYWGoT5Ere9KeOXQObsk8F0vkOLQ1tz8= -github.com/grafana/grafana-azure-sdk-go/v2 v2.2.0 h1:0TYrkzAc3u0HX+9GK86cGrLTUAcmQfl3/LEB3tL+SOA= -github.com/grafana/grafana-azure-sdk-go/v2 v2.2.0/go.mod h1:H9sVh9A4yg5egMGZeh0mifxT1Q/uqwKe1LBjBJU6pN8= -github.com/grafana/grafana-plugin-sdk-go v0.278.0 h1:5/rIYparLi02pofdaag8wnjspMMVNCi8cZhC4cdC3Ho= -github.com/grafana/grafana-plugin-sdk-go v0.278.0/go.mod h1:+8NXT/XUJ/89GV6FxGQ366NZ3nU+cAXDMd0OUESF9H4= -github.com/grafana/grafana/apps/dashboard v0.0.0-20250804150913-990f1c69ecc2 h1:M5kMQVRjcjtnGuw0RM9/iab5VpmJyBwpEDbSfS6IQV4= -github.com/grafana/grafana/apps/dashboard v0.0.0-20250804150913-990f1c69ecc2/go.mod h1:Ik6PLuCNceqTeOesGeQLn4hVL5wCbfscuAEhBEdq8js= -github.com/grafana/grafana/apps/folder v0.0.0-20250804150913-990f1c69ecc2 h1:tubqrwcZaJzS3DM2bLJxK6OCUsmBK0Vs95HiBuhCQcU= -github.com/grafana/grafana/apps/folder v0.0.0-20250804150913-990f1c69ecc2/go.mod h1:la6q+Qvy0JGzBu/yyjC+e7xPefPM7CEfEgD574R2QMU= -github.com/grafana/grafana/apps/provisioning v0.0.0-20250804150913-990f1c69ecc2 h1:83OGBndFNYijNjgQpSf4y1bSNlscVDq8ru97Q6PyU6o= -github.com/grafana/grafana/apps/provisioning v0.0.0-20250804150913-990f1c69ecc2/go.mod h1:qzFUVwLI1b5UIbVFxFydUYAsnOK27AgtA5so3EW8jM0= -github.com/grafana/grafana/apps/secret v0.0.0-20250804150913-990f1c69ecc2 h1:r5oGyvRVxljzKHTQYHtpmK2Et+BVhWQVw7aXo+FUygk= -github.com/grafana/grafana/apps/secret v0.0.0-20250804150913-990f1c69ecc2/go.mod h1:pS2M5ILsHx9VNTM96glLtCjCVXHWyfGcT34WHvbbMtM= -github.com/grafana/grafana/pkg/aggregator v0.0.0-20250804150913-990f1c69ecc2 h1:1AdHE94bYfEG7cuFb92wFlBaVPeexF21l9zCFmN8im0= -github.com/grafana/grafana/pkg/aggregator v0.0.0-20250804150913-990f1c69ecc2/go.mod h1:wU4CoDIHuOOL7ZnchyvfER5UAcEz94A+ZkY+Xt+Ks/8= -github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250804150913-990f1c69ecc2 h1:X0cnaFdR+iz+sDSuoZmkryFSjOirchHe2MdKSRwBWgM= -github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250804150913-990f1c69ecc2/go.mod h1:RRvSjHH12/PnQaXraMO65jUhVu8n59mzvhfIMBETnV4= -github.com/grafana/grafana/pkg/apiserver v0.0.0-20250804150913-990f1c69ecc2 h1:oUINBBiA25EwjOFXJVa4rmU8jHlOGn5EdPCmqpIqy4Q= -github.com/grafana/grafana/pkg/apiserver v0.0.0-20250804150913-990f1c69ecc2/go.mod h1:BA9Rvm6co9tbrZ0lS8ScqLFvAnDQ4lZOyplJgB+yMQQ= +github.com/grafana/dskit v0.0.0-20250908063411-6b6da59b5cc4 h1:jSojuc7njleS3UOz223WDlXOinmuLAIPI0z2vtq8EgI= +github.com/grafana/dskit v0.0.0-20250908063411-6b6da59b5cc4/go.mod h1:VahT+GtfQIM+o8ht2StR6J9g+Ef+C2Vokh5uuSmOD/4= +github.com/grafana/grafana-app-sdk v0.48.1 h1:bKJadWH18WCpJ+Zk8AezRFXCcZgGredRv+fRS+8zkek= +github.com/grafana/grafana-app-sdk v0.48.1/go.mod h1:5LljCz+wvmGfkQ8ZKTOfserhtXNEF0cSFthoWShvN6c= +github.com/grafana/grafana-app-sdk/logging v0.48.1 h1:veM0X5LAPyN3KsDLglWjIofndbGuf7MqnrDuDN+F/Ng= +github.com/grafana/grafana-app-sdk/logging v0.48.1/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA= +github.com/grafana/grafana-aws-sdk v1.2.0 h1:LLR4/g91WBuCRwm2cbWfCREq565+GxIFe08nqqIcIuw= +github.com/grafana/grafana-aws-sdk v1.2.0/go.mod h1:bBo7qOmM3f61vO+2JxTolNUph1l2TmtzmWcU9/Im+8A= +github.com/grafana/grafana-azure-sdk-go/v2 v2.3.1 h1:FFcEA01tW+SmuJIuDbHOdgUBL+d7DPrZ2N4zwzPhfGk= +github.com/grafana/grafana-azure-sdk-go/v2 v2.3.1/go.mod h1:Oi4anANlCuTCc66jCyqIzfVbgLXFll8Wja+Y4vfANlc= +github.com/grafana/grafana-plugin-sdk-go v0.281.0 h1:V8dGyatzcOLQeivFhBV2JWMwTSZH/clDnpfKG9p3dTA= +github.com/grafana/grafana-plugin-sdk-go v0.281.0/go.mod h1:3I0g+v6jAwVmrt6BEjDUP4V6pkhGP5QKY5NkXY4Ayr4= github.com/grafana/grafana/pkg/promlib v0.0.8 h1:VUWsqttdf0wMI4j9OX9oNrykguQpZcruudDAFpJJVw0= github.com/grafana/grafana/pkg/promlib v0.0.8/go.mod h1:U1ezG/MGaEPoThqsr3lymMPN5yIPdVTJnDZ+wcXT+ao= github.com/grafana/grafana/pkg/semconv v0.0.0-20250804150913-990f1c69ecc2 h1:A65jWgLk4Re28gIuZcpC0aTh71JZ0ey89hKGE9h543s= github.com/grafana/grafana/pkg/semconv v0.0.0-20250804150913-990f1c69ecc2/go.mod h1:2HRzUK/xQEYc+8d5If/XSusMcaYq9IptnBSHACiQcOQ= 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/prometheus-alertmanager v0.25.1-0.20250620093340-be61a673dee6 h1:oJnbhG6ZNy10AjsgNeAtAKeGHogIGOMfAsBH6fYYa5M= -github.com/grafana/prometheus-alertmanager v0.25.1-0.20250620093340-be61a673dee6/go.mod h1:O/QP1BCm0HHIzbKvgMzqb5sSyH88rzkFk84F4TfJjBU= -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/prometheus-alertmanager v0.25.1-0.20250911094103-5456b6e45604 h1:aXfUhVN/Ewfpbko2CCtL65cIiGgwStOo4lWH2b6gw2U= +github.com/grafana/prometheus-alertmanager v0.25.1-0.20250911094103-5456b6e45604/go.mod h1:O/QP1BCm0HHIzbKvgMzqb5sSyH88rzkFk84F4TfJjBU= +github.com/grafana/pyroscope-go/godeltaprof v0.1.9 h1:c1Us8i6eSmkW+Ez05d3co8kasnuOY813tbMN8i/a3Og= +github.com/grafana/pyroscope-go/godeltaprof v0.1.9/go.mod h1:2+l7K7twW49Ct4wFluZD3tZ6e0SjanjcUUBPVD/UuGU= 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/grafana/sqlds/v4 v4.2.4 h1:Xlxy1udWqDK0dlbuJ1qXL7K3EYaf+aKMl38zhd3VbQY= -github.com/grafana/sqlds/v4 v4.2.4/go.mod h1:BQRjUG8rOqrBI4NAaeoWrIMuoNgfi8bdhCJ+5cgEfLU= +github.com/grafana/sqlds/v4 v4.2.7 h1:sFQhsS7DBakNMdxa++yOfJ9BVvkZwFJ0B95o57K0/XA= +github.com/grafana/sqlds/v4 v4.2.7/go.mod h1:BQRjUG8rOqrBI4NAaeoWrIMuoNgfi8bdhCJ+5cgEfLU= +github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI= +github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8= github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0 h1:QGLs/O40yoNK9vmy4rhUGBVyMf1lISBGtXRpsu/Qu/o= github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0/go.mod h1:hM2alZsMUni80N33RBe6J0e423LB+odMj7d3EMP9l20= github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.2 h1:sGm2vDRFUrQJO/Veii4h4zG2vvqG6uWNkBHSTqXOZk0= @@ -709,8 +716,8 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgf github.com/grpc-ecosystem/go-grpc-prometheus v1.2.1-0.20191002090509-6af20e3a5340 h1:uGoIog/wiQHI9GAxXO5TJbT0wWKH3O9HhOJW1F9c3fY= 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/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1 h1:X5VWvz21y3gzm9Nw/kaUeku/1+uBhcekkmy4IkffJww= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1/go.mod h1:Zanoh4+gvIgluNqcfMVTJueD4wSS5hT7zTt4Mrutd90= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 h1:8Tjv8EJ+pM1xP8mK6egEbD1OgnVTyacbefKhmbLhIhU= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2/go.mod h1:pkJQ2tZHJ0aFOVEEot6oZmaVEZcRme73eIFmhiVuRWs= github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4= github.com/hashicorp/consul/api v1.12.0/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0= github.com/hashicorp/consul/api v1.31.2 h1:NicObVJHcCmyOIl7Z9iHPvvFrocgTYo9cITSGg0/7pw= @@ -739,8 +746,8 @@ github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHh github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= -github.com/hashicorp/go-plugin v1.6.3 h1:xgHB+ZUSYeuJi96WtxEjzi23uh7YQpznjGh0U0UUrwg= -github.com/hashicorp/go-plugin v1.6.3/go.mod h1:MRobyh+Wc/nYy1V4KAXUiYfzxoYhs7V1mlH1Z7iY2h0= +github.com/hashicorp/go-plugin v1.7.0 h1:YghfQH/0QmPNc/AZMTFE3ac8fipZyZECHdDPshfk+mA= +github.com/hashicorp/go-plugin v1.7.0/go.mod h1:BExt6KEaIYx804z8k4gRzRLEvxKVb+kn0NMcihqOqb8= github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= @@ -769,8 +776,8 @@ github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpT github.com/hashicorp/serf v0.9.7/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= github.com/hashicorp/serf v0.10.2 h1:m5IORhuNSjaxeljg5DeQVDlQyVkhRIjJDimbkCa8aAc= github.com/hashicorp/serf v0.10.2/go.mod h1:T1CmSGfSeGfnfNy/w0odXQUR1rfECGd2Qdsp84DjOiY= -github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE= -github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/hashicorp/yamux v0.1.2 h1:XtB8kyFOyHXYVFnwT5C3+Bdo8gArse7j2AQ0DA0Uey8= +github.com/hashicorp/yamux v0.1.2/go.mod h1:C+zze2n6e/7wshOZep2A70/aQU6QBRWJO/G6FT1wIns= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI= github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= @@ -781,13 +788,22 @@ github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLf github.com/invopop/jsonschema v0.13.0 h1:KvpoAJWEjR3uD9Kbm2HWJmqsEaHt8lBUpd0qHcIi21E= github.com/invopop/jsonschema v0.13.0/go.mod h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uON45H2qjYt+0= github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ= +github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgx v3.2.0+incompatible h1:0Vihzu20St42/UDsvZGdNE6jak7oi/UOeMzwMPHkgFY= github.com/jackc/pgx v3.2.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I= +github.com/jackc/pgx/v5 v5.7.6 h1:rWQc5FwZSPX58r1OQmkuaNicxdmExaEz5A2DO2hUuTk= +github.com/jackc/pgx/v5 v5.7.6/go.mod h1:aruU7o91Tc2q2cFp5h4uP3f6ztExVpyVv88Xl/8Vl8M= +github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= +github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= github.com/jaegertracing/jaeger-idl v0.5.0 h1:zFXR5NL3Utu7MhPg8ZorxtCBjHrL3ReM1VoB65FOFGE= github.com/jaegertracing/jaeger-idl v0.5.0/go.mod h1:ON90zFo9eoyXrt9F/KN8YeF3zxcnujaisMweFY/rg5k= github.com/jessevdk/go-flags v1.6.1 h1:Cvu5U8UGrLay1rZfv/zP7iLpSHGUZ/Ou68T0iX1bBK4= github.com/jessevdk/go-flags v1.6.1/go.mod h1:Mk8T1hIAWpOiJiHa9rJASDK2UGWji0EuPGBnNLMooyc= -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.17.0 h1:qOEr613fac2lOuTgWN4tPAtLL7fUSbuJL5X5XumQh94= +github.com/jhump/protoreflect v1.17.0/go.mod h1:h9+vUUL38jiBzck8ck+6G/aeMX8Z4QUY/NiJPwPNi+8= github.com/jmespath-community/go-jmespath v1.1.1 h1:bFikPhsi/FdmlZhVgSCd2jj1e7G/rw+zyQfyg5UF+L4= github.com/jmespath-community/go-jmespath v1.1.1/go.mod h1:4gOyFJsR/Gk+05RgTKYrifT7tBPWD8Lubtb5jRrfy9I= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= @@ -827,8 +843,8 @@ github.com/klauspost/asmfmt v1.3.2 h1:4Ri7ox3EwapiOjCki+hw14RyKk201CN4rzyCJRFLpK github.com/klauspost/asmfmt v1.3.2/go.mod h1:AG8TuvYojzulgDAMCnYn50l/5QV3Bs/tp6j0HLHbNSE= github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= -github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE= -github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= +github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y= +github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -846,6 +862,10 @@ github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kshvakov/clickhouse v1.3.5/go.mod h1:DMzX7FxRymoNkVgizH0DWAL8Cur7wHLgx3MUnGwJqpE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 h1:SOEGU9fKiNWd/HOJuq6+3iTQz8KNCLtVX6idSoTLdUw= +github.com/lann/builder v0.0.0-20180802200727-47ae307949d0/go.mod h1:dXGbAdH5GtBTC4WfIxhKZfyBF/HBFgRZSWwZ9g/He9o= +github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 h1:P6pPBnrTSX3DEVR4fDembhRWSsG5rVo6hYhAB/ADZrk= +github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc h1:RKf14vYWi2ttpEmkA4aQ3j4u9dStX2t4M8UM6qqNsG8= github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc/go.mod h1:kopuH9ugFRkIXf3YoqHKyrJ9YfUFsckUU9S7B+XP+is= @@ -855,6 +875,8 @@ github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/madflojo/testcerts v1.4.0 h1:I09gN0C1ly9IgeVNcAqKk8RAKIJTe3QnFrrPBDyvzN4= +github.com/madflojo/testcerts v1.4.0/go.mod h1:MW8sh39gLnkKh4K0Nc55AyHEDl9l/FBLDUsQhpmkuo0= github.com/magefile/mage v1.15.0 h1:BvGheCMAsG3bWUDbZ8AyXXpCNwU9u5CB6sM+HNb9HYg= github.com/magefile/mage v1.15.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A= github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= @@ -885,8 +907,8 @@ github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6T github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= -github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= -github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= +github.com/mattn/go-sqlite3 v1.14.32 h1:JD12Ag3oLy1zQA+BNn74xRgaBbdhbNIDYvQUEuuErjs= +github.com/mattn/go-sqlite3 v1.14.32/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= @@ -894,6 +916,8 @@ github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA= github.com/mdlayher/vsock v1.2.1 h1:pC1mTJTvjo1r9n9fbm7S1j04rCgCzhCOS5DY0zqHlnQ= github.com/mdlayher/vsock v1.2.1/go.mod h1:NRfCibel++DgeMD8z/hP+PPTjlNJsdPOmxcnENvE+SE= +github.com/mfridman/interpolate v0.0.2 h1:pnuTK7MQIxxFz1Gr+rjSIx9u7qVjf5VOoM/u6BbAxPY= +github.com/mfridman/interpolate v0.0.2/go.mod h1:p+7uk6oE07mpE/Ik1b8EckO0O4ZXiGAfshKBWLUM9Xg= github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= github.com/miekg/dns v1.1.63 h1:8M5aAw6OMZfFXTT7K5V0Eu5YiiL8l7nUAkyN6C9YwaY= @@ -926,15 +950,16 @@ github.com/mithrandie/go-text v1.6.0 h1:8gOXTMPbMY8DJbKMTv8kHhADcJlDWXqS/YQH4SyW github.com/mithrandie/go-text v1.6.0/go.mod h1:xCgj1xiNbI/d4xA9sLVvXkjh5B2tNx2ZT2/3rpmh8to= github.com/mithrandie/ternary v1.1.1 h1:k/joD6UGVYxHixYmSR8EGgDFNONBMqyD373xT4QRdC4= github.com/mithrandie/ternary v1.1.1/go.mod h1:0D9Ba3+09K2TdSZO7/bFCC0GjSXetCvYuYq0u8FY/1g= -github.com/mocktools/go-smtp-mock/v2 v2.3.1 h1:wq75NDSsOy5oHo/gEQQT0fRRaYKRqr1IdkjhIPXxagM= -github.com/mocktools/go-smtp-mock/v2 v2.3.1/go.mod h1:h9AOf/IXLSU2m/1u4zsjtOM/WddPwdOUBz56dV9f81M= +github.com/mocktools/go-smtp-mock/v2 v2.5.1 h1:QcMJMChSgG1olVj4o6xxQFdrWzRjYNrcq660HAjd0wA= +github.com/mocktools/go-smtp-mock/v2 v2.5.1/go.mod h1:Rr8M2njlxx//l5INl2+uESnsL2lDsL24teEykCrGfmE= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= +github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= @@ -946,12 +971,12 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/nakagami/firebirdsql v0.0.0-20190310045651-3c02a58cfed8/go.mod h1:86wM1zFnC6/uDBfZGNwB65O+pR2OFi5q/YQaEUid1qA= +github.com/natefinch/wrap v0.2.0 h1:IXzc/pw5KqxJv55gV0lSOcKHYuEZPGbQrOOXr/bamRk= +github.com/natefinch/wrap v0.2.0/go.mod h1:6gMHlAl12DwYEfKP3TkuykYUfLSEAvHw67itm4/KAS8= github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4= github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= github.com/nikunjy/rules v1.5.0 h1:KJDSLOsFhwt7kcXUyZqwkgrQg5YoUwj+TVu6ItCQShw= github.com/nikunjy/rules v1.5.0/go.mod h1:TlZtZdBChrkqi8Lr2AXocme8Z7EsbxtFdDoKeI6neBQ= -github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= -github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 h1:G7ERwszslrBzRxj//JalHPu/3yz+De2J+4aLtSRlHiY= github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037/go.mod h1:2bpvgLBZEtENV5scfDFEtB/5+1M4hkQhDQrccEJ/qGw= github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 h1:bQx3WeLcUWy+RletIKwUIt4x3t8n2SxavmoclizMb8c= @@ -960,25 +985,32 @@ github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/oklog/ulid/v2 v2.1.1 h1:suPZ4ARWLOJLegGFiZZ1dFAkqzhMjL3J1TzI+5wHz8s= +github.com/oklog/ulid/v2 v2.1.1/go.mod h1:rcEKHmBBKfef9DhnvX7y1HZBYxjXb0cP5ExxNsTT1QQ= github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= -github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/ginkgo/v2 v2.22.2 h1:/3X8Panh8/WwhU/3Ssa6rCKqPLuAkVY2I0RoyDLySlU= github.com/onsi/ginkgo/v2 v2.22.2/go.mod h1:oeMosUL+8LtarXBHu/c0bx2D/K9zyQ6uX3cTyztHwsk= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.36.2 h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8= github.com/onsi/gomega v1.36.2/go.mod h1:DdwyADRjrc825LhMEkD76cHR5+pUnjhUN8GlHlRPHzY= -github.com/open-feature/go-sdk v1.14.1 h1:jcxjCIG5Up3XkgYwWN5Y/WWfc6XobOhqrIwjyDBsoQo= -github.com/open-feature/go-sdk v1.14.1/go.mod h1:t337k0VB/t/YxJ9S0prT30ISUHwYmUd/jhUZgFcOvGg= -github.com/open-feature/go-sdk-contrib/providers/go-feature-flag v0.2.3 h1:6jpO63NCEZv4xunJj+aNlDuFVuRkVBPMcIuxvFPYRWQ= -github.com/open-feature/go-sdk-contrib/providers/go-feature-flag v0.2.3/go.mod h1:dPUHjAIFzg+ci/wt6XxlNiiMkOh5Yw4SGyeRY0AFT0g= -github.com/open-feature/go-sdk-contrib/providers/ofrep v0.1.5 h1:ZdqlGnNwhWf3luhBQlIpbglvcCzjkcuEgOEhYhr5Emc= -github.com/open-feature/go-sdk-contrib/providers/ofrep v0.1.5/go.mod h1:jrD4UG3ZCzuwImKHlyuIN2iWeYjlOX5+zJ/sX45efuE= +github.com/open-feature/go-sdk v1.16.0 h1:5NCHYv5slvNBIZhYXAzAufo0OI59OACZ5tczVqSE+Tg= +github.com/open-feature/go-sdk v1.16.0/go.mod h1:EIF40QcoYT1VbQkMPy2ZJH4kvZeY+qGUXAorzSWgKSo= +github.com/open-feature/go-sdk-contrib/providers/go-feature-flag v0.2.6 h1:megzzlQGjsRVWDX8oJnLaa5eEcsAHekiL4Uvl3jSAcY= +github.com/open-feature/go-sdk-contrib/providers/go-feature-flag v0.2.6/go.mod h1:K1gDKvt76CGFLSUMHUydd5ba2V5Cv69gQZsdbnXhAm8= +github.com/open-feature/go-sdk-contrib/providers/ofrep v0.1.6 h1:WinefYxeVx5rV0uQmuWbxQf8iACu/JiRubo5w0saToc= +github.com/open-feature/go-sdk-contrib/providers/ofrep v0.1.6/go.mod h1:Dwcaoma6lZVqYwyfVlY7eB6RXbG+Ju3b9cnpTlUN+Hc= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/openfga/api/proto v0.0.0-20250909172242-b4b2a12f5c67 h1:58mhO5nqkdka2Mpg5mijuZOHScX7reowhzRciwjFCU8= +github.com/openfga/api/proto v0.0.0-20250909172242-b4b2a12f5c67/go.mod h1:XDX4qYNBUM2Rsa2AbKPh+oocZc2zgme+EF2fFC6amVU= +github.com/openfga/language/pkg/go v0.2.0-beta.2.0.20250428093642-7aeebe78bbfe h1:X1g0rBUMvvzMudsak/jmoEZ1NhSsp6yR0VGxWHnGMzs= +github.com/openfga/language/pkg/go v0.2.0-beta.2.0.20250428093642-7aeebe78bbfe/go.mod h1:5Z0pbTT7Jz/oQFLfadb+C5t5NwHrduAO7j7L07Ec1GM= +github.com/openfga/openfga v1.10.0 h1:Ieq4fjJeT3KrxRiekgCnp9VCoXXnBvYITcTR35SPlYY= +github.com/openfga/openfga v1.10.0/go.mod h1:6/m4GTwQsqECsGYQVD3t5sCX97rh3smnmxbMa3YAtJk= github.com/opentracing-contrib/go-stdlib v1.0.0 h1:TBS7YuVotp8myLon4Pv7BtCBzOTo1DeZCld0Z63mW2w= github.com/opentracing-contrib/go-stdlib v1.0.0/go.mod h1:qtI1ogk+2JhVPIXVc6q+NHziSmy2W5GbdQZFUHADCBU= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= @@ -993,8 +1025,8 @@ github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTK github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas= -github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= -github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= +github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= +github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= github.com/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX50IvK2s= github.com/perimeterx/marshmallow v1.1.5/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= @@ -1014,6 +1046,8 @@ 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/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= +github.com/pressly/goose/v3 v3.25.0 h1:6WeYhMWGRCzpyd89SpODFnCBCKz41KrVbRT58nVjGng= +github.com/pressly/goose/v3 v3.25.0/go.mod h1:4hC1KrritdCxtuFsqgs1R4AU5bWtTAf+cnWvfhf2DNY= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= @@ -1022,8 +1056,8 @@ github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3O github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q= -github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0= +github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o= +github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= @@ -1039,8 +1073,8 @@ github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8b github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= github.com/prometheus/common v0.29.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= -github.com/prometheus/common v0.65.0 h1:QDwzd+G1twt//Kwj/Ww6E9FQq1iVMmODnILtW1t2VzE= -github.com/prometheus/common v0.65.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8= +github.com/prometheus/common v0.67.1 h1:OTSON1P4DNxzTg4hmKCc37o4ZAZDv0cfXLkOt0oEowI= +github.com/prometheus/common v0.67.1/go.mod h1:RpmT9v35q2Y+lsieQsdOh5sXZ6ajUGC8NjZAmr8vb0Q= 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/exporter-toolkit v0.14.0 h1:NMlswfibpcZZ+H0sZBiTjrA3/aBFHkNZqE+iCj5EmRg= @@ -1058,8 +1092,8 @@ github.com/prometheus/prometheus v0.303.1/go.mod h1:WEq2ogBPZoLjj9x5K67VEk7ECR0n github.com/puzpuzpuz/xsync/v2 v2.5.1 h1:mVGYAvzDSu52+zaGyNjC+24Xw2bQi3kTr4QJ6N9pIIU= github.com/puzpuzpuz/xsync/v2 v2.5.1/go.mod h1:gD2H2krq/w52MfPLE+Uy64TzJDVY7lP2znR9qmR35kU= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= -github.com/redis/go-redis/v9 v9.8.0 h1:q3nRvjrlge/6UD7eTu/DSg2uYiU2mCL0G/uzBWqhicI= -github.com/redis/go-redis/v9 v9.8.0/go.mod h1:huWgSWd8mW6+m0VPhJjSSQ+d6Nh1VICQ6Q5lHuCH/Iw= +github.com/redis/go-redis/v9 v9.14.0 h1:u4tNCjXOyzfgeLN+vAZaW1xUooqWDqVEsZN0U01jfAE= +github.com/redis/go-redis/v9 v9.14.0/go.mod h1:huWgSWd8mW6+m0VPhJjSSQ+d6Nh1VICQ6Q5lHuCH/Iw= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= @@ -1077,17 +1111,21 @@ github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/sagikazarmark/crypt v0.6.0/go.mod h1:U8+INwJo3nBv1m6A/8OBXAq7Jnpspk5AxSgDyEQcea8= +github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc= +github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/sethvargo/go-retry v0.3.0 h1:EEt31A35QhrcRZtrYFDTBg91cqZVnFL2navjDrah2SE= +github.com/sethvargo/go-retry v0.3.0/go.mod h1:mNX17F0C/HguQMyMyJxcnU471gOZGxCLyYaFyAZraas= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= github.com/shurcooL/httpfs v0.0.0-20230704072500-f1e31cf0ba5c h1:aqg5Vm5dwtvL+YgDpBcK1ITf3o96N/K7/wsRXQnUTEs= github.com/shurcooL/httpfs v0.0.0-20230704072500-f1e31cf0ba5c/go.mod h1:owqhoLW1qZoYLZzLnBw+QkPP9WZnjlSWihhxAJC1+/M= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= -github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546 h1:pXY9qYc/MP5zdvqWEUH6SjNiu7VhSjuVFTFiTcphaLU= -github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw= +github.com/shurcooL/vfsgen v0.0.0-20230704071429-0000e147ea92 h1:OfRzdxCzDhp+rsKWXuOO2I/quKMJ/+TQwVbIP/gltZg= +github.com/shurcooL/vfsgen v0.0.0-20230704071429-0000e147ea92/go.mod h1:7/OT02F6S6I7v6WXb+IjhMuZEYfH/RJ5RwEWnEo5BMg= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= @@ -1098,22 +1136,28 @@ github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304 h1:Jpy1PX github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c h1:Ho+uVpkel/udgjbwB5Lktg9BtvJSh2DT0Hi6LPSyI2w= github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s= +github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 h1:+jumHNA0Wrelhe64i8F6HNlS8pkoyMv5sreGx2Ry5Rw= +github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8/go.mod h1:3n1Cwaq1E1/1lhQhtRK2ts/ZwZEhjcQeJQ1RuC6Q/8U= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.8.2/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo= +github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I= +github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg= github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= -github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y= -github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= -github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo= -github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0= +github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY= +github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo= +github.com/spf13/cobra v1.10.1 h1:lJeBwCfmrnXthfAupyUTzJ/J4Nc1RsHC/mSRU2dll/s= +github.com/spf13/cobra v1.10.1/go.mod h1:7SmJGaTHFVBY0jW4NXGluQoLvhqFQM+6XSKD+P4XaB0= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/pflag v1.0.7 h1:vN6T9TfwStFPFM5XzjsvmzZkLuaLX+HS+0SeFLRgU6M= -github.com/spf13/pflag v1.0.7/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= +github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.13.0/go.mod h1:Icm2xNL3/8uyh/wFuB1jI7TiTNKp8632Nwegu+zgdYw= +github.com/spf13/viper v1.21.0 h1:x5S+0EU27Lbphp4UKm1C+1oQO+rKx36vfCoaVebLFSU= +github.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjbTCAY= github.com/spiffe/go-spiffe/v2 v2.5.0 h1:N2I01KCUkv1FAjZXJMwh95KK1ZIQLYbPfhaxw8WS0hE= github.com/spiffe/go-spiffe/v2 v2.5.0/go.mod h1:P+NxobPc6wXhVtINNtFjNWGBTreew1GBUCwT2wPmb7g= -github.com/stoewer/go-strcase v1.3.0 h1:g0eASXYtp+yvN9fK8sH94oCIk0fau9uV1/ZdJ0AVEzs= -github.com/stoewer/go-strcase v1.3.0/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo= +github.com/stoewer/go-strcase v1.3.1 h1:iS0MdW+kVTxgMoE1LAZyMiYJFKlOzLooE4MxjirtkAs= +github.com/stoewer/go-strcase v1.3.1/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= @@ -1132,9 +1176,12 @@ github.com/stretchr/testify v1.7.5/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= +github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= +github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/tetratelabs/wazero v1.8.2 h1:yIgLR/b2bN31bjxwXHD8a3d+BogigR952csSDdLYEv4= github.com/tetratelabs/wazero v1.8.2/go.mod h1:yAI0XTsMBhREkM/YDAK/zNou3GoiAce1P6+rp/wQhjs= github.com/thejerf/slogassert v0.3.4 h1:VoTsXixRbXMrRSSxDjYTiEDCM4VWbsYPW5rB/hX24kM= @@ -1159,11 +1206,13 @@ github.com/unknwon/log v0.0.0-20150304194804-e617c87089d3/go.mod h1:1xEUf2abjfP9 github.com/unknwon/log v0.0.0-20200308114134-929b1006e34a h1:vcrhXnj9g9PIE+cmZgaPSwOyJ8MAQTRmsgGrB0x5rF4= github.com/unknwon/log v0.0.0-20200308114134-929b1006e34a/go.mod h1:1xEUf2abjfP92w2GZTV+GgaRxXErwRXcClbUwrNJffU= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= -github.com/urfave/cli v1.22.16 h1:MH0k6uJxdwdeWQTwhSO42Pwr4YLrNLwBtg1MRgTqPdQ= -github.com/urfave/cli v1.22.16/go.mod h1:EeJR6BKodywf4zciqrdw6hpCPk68JO9z5LazXZMn5Po= +github.com/urfave/cli v1.22.17 h1:SYzXoiPfQjHBbkYxbew5prZHS1TOLT3ierW8SYLqtVQ= +github.com/urfave/cli v1.22.17/go.mod h1:b0ht0aqgH/6pBYzzxURyrM4xXNgsoT/n2ZzwQiEhNVo= github.com/wk8/go-ordered-map v1.0.0 h1:BV7z+2PaK8LTSd/mWgY12HyMAo5CEgkHqbkVq2thqr8= github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc= github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw= +github.com/woodsbury/decimal128 v1.3.0 h1:8pffMNWIlC0O5vbyHWFZAt5yWvWcrHA+3ovIIjVWss0= +github.com/woodsbury/decimal128 v1.3.0/go.mod h1:C5UTmyTjW3JftjUFzOVhC20BEQa2a4ZKOB5I6Zjb+ds= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xanzy/go-gitlab v0.15.0/go.mod h1:8zdQa/ri1dfn8eS3Ir1SyfvOKlw7WBJ8DVThkpGiXrs= @@ -1174,8 +1223,6 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= 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/errs v1.4.0 h1:XNdoD/RRMKP7HD0UhJnIzUy74ISdGGxURlYG8HSWSfM= @@ -1183,21 +1230,21 @@ github.com/zeebo/errs v1.4.0/go.mod h1:sgbWHsvVuTPHcqJJGQ1WhI5KbWlHYz+2+2C/LSEtC github.com/zeebo/xxh3 v1.0.2 h1:xZmwmqxHZA8AI603jOQ0tMqmBr9lPeFwGg6d+xy9DC0= github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA= gitlab.com/nyarla/go-crypt v0.0.0-20160106005555-d9a5dc2b789b/go.mod h1:T3BPAOm2cqquPa0MKWeNkmOM5RQsRhkrwMWonFMN7fE= -go.etcd.io/bbolt v1.4.0 h1:TU77id3TnN/zKr7CO/uk+fBCwF2jGcMuw2B/FMAzYIk= -go.etcd.io/bbolt v1.4.0/go.mod h1:AsD+OCi/qPN1giOX1aiLAha3o1U8rAz65bvN4j0sRuk= +go.etcd.io/bbolt v1.4.2 h1:IrUHp260R8c+zYx/Tm8QZr04CX+qWS5PGfPdevhdm1I= +go.etcd.io/bbolt v1.4.2/go.mod h1:Is8rSHO/b4f3XigBC0lL0+4FwAQv3HXEEIgFMuKHceM= go.etcd.io/etcd/api/v3 v3.5.4/go.mod h1:5GB2vv4A4AOn3yk7MftYGHkUfGtDHnEraIjym4dYz5A= -go.etcd.io/etcd/api/v3 v3.5.21 h1:A6O2/JDb3tvHhiIz3xf9nJ7REHvtEFJJ3veW3FbCnS8= -go.etcd.io/etcd/api/v3 v3.5.21/go.mod h1:c3aH5wcvXv/9dqIw2Y810LDXJfhSYdHQ0vxmP3CCHVY= +go.etcd.io/etcd/api/v3 v3.6.4 h1:7F6N7toCKcV72QmoUKa23yYLiiljMrT4xCeBL9BmXdo= +go.etcd.io/etcd/api/v3 v3.6.4/go.mod h1:eFhhvfR8Px1P6SEuLT600v+vrhdDTdcfMzmnxVXXSbk= go.etcd.io/etcd/client/pkg/v3 v3.5.4/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= -go.etcd.io/etcd/client/pkg/v3 v3.5.21 h1:lPBu71Y7osQmzlflM9OfeIV2JlmpBjqBNlLtcoBqUTc= -go.etcd.io/etcd/client/pkg/v3 v3.5.21/go.mod h1:BgqT/IXPjK9NkeSDjbzwsHySX3yIle2+ndz28nVsjUs= +go.etcd.io/etcd/client/pkg/v3 v3.6.4 h1:9HBYrjppeOfFjBjaMTRxT3R7xT0GLK8EJMVC4xg6ok0= +go.etcd.io/etcd/client/pkg/v3 v3.6.4/go.mod h1:sbdzr2cl3HzVmxNw//PH7aLGVtY4QySjQFuaCgcRFAI= go.etcd.io/etcd/client/v2 v2.305.4/go.mod h1:Ud+VUwIi9/uQHOMA+4ekToJ12lTxlv0zB/+DHwTGEbU= go.etcd.io/etcd/client/v3 v3.5.4/go.mod h1:ZaRkVgBZC+L+dLCjTcF1hRXpgZXQPOvnA/Ak/gq3kiY= -go.etcd.io/etcd/client/v3 v3.5.21 h1:T6b1Ow6fNjOLOtM0xSoKNQt1ASPCLWrF9XMHcH9pEyY= -go.etcd.io/etcd/client/v3 v3.5.21/go.mod h1:mFYy67IOqmbRf/kRUvsHixzo3iG+1OF2W2+jVIQRAnU= +go.etcd.io/etcd/client/v3 v3.6.4 h1:YOMrCfMhRzY8NgtzUsHl8hC2EBSnuqbR3dh84Uryl7A= +go.etcd.io/etcd/client/v3 v3.6.4/go.mod h1:jaNNHCyg2FdALyKWnd7hxZXZxZANb0+KGY+YQaEMISo= go.mongodb.org/mongo-driver v1.1.0/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= -go.mongodb.org/mongo-driver v1.17.3 h1:TQyXhnsWfWtgAhMtOgtYHMTkZIfBTpMTsMnd9ZBeHxQ= -go.mongodb.org/mongo-driver v1.17.3/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ= +go.mongodb.org/mongo-driver v1.17.4 h1:jUorfmVzljjr0FLzYQsGP8cgN/qzzxlY9Vh0C9KFXVw= +go.mongodb.org/mongo-driver v1.17.4/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ= go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= @@ -1216,76 +1263,78 @@ go.opentelemetry.io/contrib/detectors/gcp v1.36.0 h1:F7q2tNlCaHY9nMKHR6XH9/qkp8F go.opentelemetry.io/contrib/detectors/gcp v1.36.0/go.mod h1:IbBN8uAIIx734PTonTPxAxnjc2pQTxWNkwfstZ+6H2k= go.opentelemetry.io/contrib/exporters/autoexport v0.61.0 h1:XfzKtKSrbtYk9TNCF8dkO0Y9M7IOfb4idCwBOTwGBiI= go.opentelemetry.io/contrib/exporters/autoexport v0.61.0/go.mod h1:N6otC+qXTD5bAnbK2O1f/1SXq3cX+3KYSWrkBUqG0cw= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0 h1:x7wzEgXfnzJcHDwStJT+mxOz4etr2EcexjqhBvmoakw= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0/go.mod h1:rg+RlpR5dKwaS95IyyZqj5Wd4E13lk/msnTS0Xl9lJM= -go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.61.0 h1:lREC4C0ilyP4WibDhQ7Gg2ygAQFP8oR07Fst/5cafwI= -go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.61.0/go.mod h1:HfvuU0kW9HewH14VCOLImqKvUgONodURG7Alj/IrnGI= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 h1:Hf9xI/XLML9ElpiHVDNwvqI0hIFlzV8dgIr35kV1kRU= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0/go.mod h1:NfchwuyNoMcZ5MLHwPrODwUF1HWCXWrL31s8gSAdIKY= -go.opentelemetry.io/contrib/propagators/jaeger v1.36.0 h1:SoCgXYF4ISDtNyfLUzsGDaaudZVTx2yJhOyBO0+/GYk= -go.opentelemetry.io/contrib/propagators/jaeger v1.36.0/go.mod h1:VHu48l0YTRKSObdPQ+Sb8xMZvdnJlN7yhHuHoPgNqHM= -go.opentelemetry.io/contrib/samplers/jaegerremote v0.30.0 h1:bQ1Gvah4Sp8z7epSkgJaNTuZm7sutfA6Fji2/7cKFMc= -go.opentelemetry.io/contrib/samplers/jaegerremote v0.30.0/go.mod h1:9b8Q9rH52NgYH3ShiTFB5wf18Vt3RTH/VMB7LDcC1ug= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 h1:YH4g8lQroajqUwWbq/tr2QX1JFmEXaDLgG+ew9bLMWo= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0/go.mod h1:fvPi2qXDqFs8M4B4fmJhE92TyQs9Ydjlg3RvfUp+NbQ= +go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.63.0 h1:2pn7OzMewmYRiNtv1doZnLo3gONcnMHlFnmOR8Vgt+8= +go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.63.0/go.mod h1:rjbQTDEPQymPE0YnRQp9/NuPwwtL0sesz/fnqRW/v84= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0 h1:RbKq8BG0FI8OiXhBfcRtqqHcZcka+gU3cskNuf05R18= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0/go.mod h1:h06DGIukJOevXaj/xrNjhi/2098RZzcLTbc0jDAUbsg= +go.opentelemetry.io/contrib/propagators/jaeger v1.38.0 h1:nXGeLvT1QtCAhkASkP/ksjkTKZALIaQBIW+JSIw1KIc= +go.opentelemetry.io/contrib/propagators/jaeger v1.38.0/go.mod h1:oMvOXk78ZR3KEuPMBgp/ThAMDy9ku/eyUVztr+3G6Wo= +go.opentelemetry.io/contrib/samplers/jaegerremote v0.32.0 h1:oPW/SRFyHgIgxrvNhSBzqvZER2N5kRlci3/rGTOuyWo= +go.opentelemetry.io/contrib/samplers/jaegerremote v0.32.0/go.mod h1:B9Oka5QVD0bnmZNO6gBbBta6nohD/1Z+f9waH2oXyBs= go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= -go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ= -go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I= +go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= +go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= go.opentelemetry.io/otel/exporters/jaeger v1.17.0 h1:D7UpUy2Xc2wsi1Ras6V40q806WM07rqoCWzXu7Sqy+4= go.opentelemetry.io/otel/exporters/jaeger v1.17.0/go.mod h1:nPCqOnEH9rNLKqH/+rrUjiMzHJdV1BlpKcTwRTyKkKI= go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.12.2 h1:06ZeJRe5BnYXceSM9Vya83XXVaNGe3H1QqsvqRANQq8= go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.12.2/go.mod h1:DvPtKE63knkDVP88qpatBj81JxN+w1bqfVbsbCbj1WY= go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.12.2 h1:tPLwQlXbJ8NSOfZc4OkgU5h2A38M4c9kfHSVc4PFQGs= go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.12.2/go.mod h1:QTnxBwT/1rBIgAG1goq6xMydfYOBKU6KTiYF4fp5zL8= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.37.0 h1:zG8GlgXCJQd5BU98C0hZnBbElszTmUgCNCfYneaDL0A= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.37.0/go.mod h1:hOfBCz8kv/wuq73Mx2H2QnWokh/kHZxkh6SNF2bdKtw= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.37.0 h1:9PgnL3QNlj10uGxExowIDIZu66aVBwWhXmbOp1pa6RA= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.37.0/go.mod h1:0ineDcLELf6JmKfuo0wvvhAVMuxWFYvkTin2iV4ydPQ= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0 h1:Ahq7pZmv87yiyn3jeFz/LekZmPLLdKejuO3NcK9MssM= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0/go.mod h1:MJTqhM0im3mRLw1i8uGHnCvUEeS7VwRyxlLC78PA18M= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0 h1:EtFWSnwW9hGObjkIdmlnWSydO+Qs8OwzfzXLUPg4xOc= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0/go.mod h1:QjUEoiGCPkvFZ/MjK6ZZfNOS6mfVEVKYE99dFhuN2LI= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.37.0 h1:bDMKF3RUSxshZ5OjOTi8rsHGaPKsAt76FaqgvIUySLc= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.37.0/go.mod h1:dDT67G/IkA46Mr2l9Uj7HsQVwsjASyV9SjGofsiUZDA= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0 h1:vl9obrcoWVKp/lwl8tRE33853I8Xru9HFbw/skNeLs8= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0/go.mod h1:GAXRxmLJcVM3u22IjTg74zWBrRCKq8BnOqUVLodpcpw= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.38.0 h1:Oe2z/BCg5q7k4iXC3cqJxKYg0ieRiOqF0cecFYdPTwk= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.38.0/go.mod h1:ZQM5lAJpOsKnYagGg/zV2krVqTtaVdYdDkhMoX6Oalg= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 h1:GqRJVj7UmLjCVyVJ3ZFLdPRmhDUp2zFmQe3RHIOsw24= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0/go.mod h1:ri3aaHSmCTVYu2AWv44YMauwAQc0aqI9gHKIcSbI1pU= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 h1:lwI4Dc5leUqENgGuQImwLo4WnuXFPetmPpkLi2IrX54= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0/go.mod h1:Kz/oCE7z5wuyhPxsXDuaPteSWqjSBD5YaSdbxZYGbGk= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 h1:aTL7F04bJHUlztTsNGJ2l+6he8c+y/b//eR0jjjemT4= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0/go.mod h1:kldtb7jDTeol0l3ewcmd8SDvx3EmIE7lyvqbasU3QC4= go.opentelemetry.io/otel/exporters/prometheus v0.59.0 h1:HHf+wKS6o5++XZhS98wvILrLVgHxjA/AMjqHKes+uzo= go.opentelemetry.io/otel/exporters/prometheus v0.59.0/go.mod h1:R8GpRXTZrqvXHDEGVH5bF6+JqAZcK8PjJcZ5nGhEWiE= go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.12.2 h1:12vMqzLLNZtXuXbJhSENRg+Vvx+ynNilV8twBLBsXMY= go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.12.2/go.mod h1:ZccPZoPOoq8x3Trik/fCsba7DEYDUnN6yX79pgp2BUQ= go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.36.0 h1:rixTyDGXFxRy1xzhKrotaHy3/KXdPhlWARrCgK+eqUY= go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.36.0/go.mod h1:dowW6UsM9MKbJq5JTz2AMVp3/5iW5I/TStsk8S+CfHw= -go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.37.0 h1:SNhVp/9q4Go/XHBkQ1/d5u9P/U+L1yaGPoi0x+mStaI= -go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.37.0/go.mod h1:tx8OOlGH6R4kLV67YaYO44GFXloEjGPZuMjEkaaqIp4= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0 h1:kJxSDN4SgWWTjG/hPp3O7LCGLcHXFlvS2/FFOrwL+SE= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0/go.mod h1:mgIOzS7iZeKJdeB8/NYHrJ48fdGc71Llo5bJ1J4DWUE= go.opentelemetry.io/otel/log v0.12.2 h1:yob9JVHn2ZY24byZeaXpTVoPS6l+UrrxmxmPKohXTwc= go.opentelemetry.io/otel/log v0.12.2/go.mod h1:ShIItIxSYxufUMt+1H5a2wbckGli3/iCfuEbVZi/98E= go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM= -go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE= -go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E= +go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= +go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E= -go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI= -go.opentelemetry.io/otel/sdk v1.37.0/go.mod h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg= +go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= +go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= go.opentelemetry.io/otel/sdk/log v0.12.2 h1:yNoETvTByVKi7wHvYS6HMcZrN5hFLD7I++1xIZ/k6W0= go.opentelemetry.io/otel/sdk/log v0.12.2/go.mod h1:DcpdmUXHJgSqN/dh+XMWa7Vf89u9ap0/AAk/XGLnEzY= -go.opentelemetry.io/otel/sdk/metric v1.37.0 h1:90lI228XrB9jCMuSdA0673aubgRobVZFhbjxHHspCPc= -go.opentelemetry.io/otel/sdk/metric v1.37.0/go.mod h1:cNen4ZWfiD37l5NhS+Keb5RXVWZWpRE+9WyVCpbo5ps= +go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= +go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ= -go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4= -go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0= +go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= +go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.opentelemetry.io/proto/otlp v1.7.0 h1:jX1VolD6nHuFzOYso2E73H85i92Mv8JQYk0K9vz09os= -go.opentelemetry.io/proto/otlp v1.7.0/go.mod h1:fSKjH6YJ7HDlwzltzyMj036AJ3ejJLCgCSHGj4efDDo= +go.opentelemetry.io/proto/otlp v1.7.1 h1:gTOMpGDb0WTBOP8JaO72iL3auEZhVmAQg4ipjOVAtj4= +go.opentelemetry.io/proto/otlp v1.7.1/go.mod h1:b2rVh6rfI/s2pHWNlB7ILJcRALpcNDzKhACevjI+ZnE= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y= +go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= -go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI= -go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU= -go.yaml.in/yaml/v3 v3.0.3 h1:bXOww4E/J3f66rav3pX3m8w6jDE4knZjGOw8b5Y6iNE= -go.yaml.in/yaml/v3 v3.0.3/go.mod h1:tBHosrYAkRZjRAOREWbDnBXUf08JOwYq++0QNwQiWzI= +go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0= +go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8= +go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= +go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= gocloud.dev v0.42.0 h1:qzG+9ItUL3RPB62/Amugws28n+4vGZXEoJEAMfjutzw= gocloud.dev v0.42.0/go.mod h1:zkaYAapZfQisXOA4bzhsbA4ckiStGQ3Psvs9/OQ5dPM= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -1298,15 +1347,11 @@ golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3 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/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= -golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= -golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= -golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM= -golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY= +golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04= +golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -1317,8 +1362,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 h1:y5zboxd6LQAqYIhHnB48p0ByQ/GnQx2BE33L8BOHQkI= -golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6/go.mod h1:U6Lno4MTRCDY+Ba7aCcauB9T60gsv5s4ralQzP72ZoQ= +golang.org/x/exp v0.0.0-20251002181428-27f1f14c8bb9 h1:TQwNpfvNkxAVlItJf6Cr5JTsVZoC/Sj7K3OZv2Pc14A= +golang.org/x/exp v0.0.0-20251002181428-27f1f14c8bb9/go.mod h1:TwQYMMnGpvZyc+JpB/UAuTNIsVJifOlSkrZkhcvpVUk= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -1344,13 +1389,8 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/mod v0.26.0 h1:EGMPT//Ezu+ylkCijjPc+f4Aih7sZvaAr+O3EHBxvZg= -golang.org/x/mod v0.26.0/go.mod h1:/j6NAhSk8iQ723BGAUyoAcn7SlD7s15Dp9Nd/SfeaFQ= +golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA= +golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w= 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-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1397,7 +1437,6 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96b golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= @@ -1405,13 +1444,8 @@ golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= -golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= -golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs= -golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= +golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4= +golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1434,8 +1468,8 @@ golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= -golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= +golang.org/x/oauth2 v0.32.0 h1:jsCblLleRMDrxMN29H3z/k1KliIvpLgCkE6R8FXXNgY= +golang.org/x/oauth2 v0.32.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1448,12 +1482,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220513210516-0976fa681c29/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= -golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= -golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug= +golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1528,7 +1558,6 @@ golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1541,26 +1570,17 @@ golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= -golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= +golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/telemetry v0.0.0-20251008203120-078029d740a8 h1:LvzTn0GQhWuvKH/kVRS3R3bVAsdQWI7hvfLHGgh9+lU= +golang.org/x/telemetry v0.0.0-20251008203120-078029d740a8/go.mod h1:Pi4ztBfryZoJEkyFTI5/Ocsu2jXyDr6iSdgJiYE/uwE= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= -golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= -golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= -golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= -golang.org/x/term v0.33.0 h1:NuFncQrRcaRvVmgRkvM3j/F00gWIAlcmlB8ACEKmGIg= -golang.org/x/term v0.33.0/go.mod h1:s18+ql9tYWp1IfpV9DmCtQDDSRBUjKaw9M1eAv5UeF0= +golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q= +golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1570,17 +1590,13 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4= -golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU= +golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k= +golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0= -golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= +golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= +golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -1639,13 +1655,10 @@ golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= -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.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= -golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps= -golang.org/x/tools v0.35.0 h1:mBffYraMEf7aa0sB+NuKnuCy8qI/9Bughn8dC2Gu5r0= -golang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw= +golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ= +golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs= +golang.org/x/tools/godoc v0.1.0-deprecated h1:o+aZ1BOj6Hsx/GBdJO/s815sqftjSnrZZwyYTHODvtk= +golang.org/x/tools/godoc v0.1.0-deprecated/go.mod h1:qM63CriJ961IHWmnWa9CjZnBndniPt4a3CK0PVB9bIg= 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= @@ -1790,10 +1803,10 @@ google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= google.golang.org/genproto v0.0.0-20250603155806-513f23925822 h1:rHWScKit0gvAPuOnu87KpaYtjK5zBMLcULh7gxkCXu4= google.golang.org/genproto v0.0.0-20250603155806-513f23925822/go.mod h1:HubltRL7rMh0LfnQPkMH4NPDFEWp0jw3vixw7jEM53s= -google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 h1:oWVWY3NzT7KJppx2UKhKmzPq4SRe0LdCijVRwvGeikY= -google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822/go.mod h1:h3c4v36UTKzUiuaOKQ6gr3S+0hovBtUrXzTG/i3+XEc= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 h1:fc6jSaCT0vBduLYZHYrBBNY4dsWuvgyff9noRNDdBeE= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= +google.golang.org/genproto/googleapis/api v0.0.0-20250908214217-97024824d090 h1:d8Nakh1G+ur7+P3GcMjpRDEkoLUcLW2iU92XVqR+XMQ= +google.golang.org/genproto/googleapis/api v0.0.0-20250908214217-97024824d090/go.mod h1:U8EXRNSd8sUYyDfs/It7KVWodQr+Hf9xtxyxWudSwEw= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251002232023-7c0ddcbb5797 h1:CirRxTOwnRWVLKzDNrs0CXAaVozJoR4G9xvdRecrdpk= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251002232023-7c0ddcbb5797/go.mod h1:HSkG/KdJWusxU1F6CNrwNDjBMgisKxGnc5dAZfT0mjQ= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= @@ -1825,8 +1838,8 @@ google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ5 google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.74.2 h1:WoosgB65DlWVC9FqI82dGsZhWFNBSLjQ84bjROOpMu4= -google.golang.org/grpc v1.74.2/go.mod h1:CtQ+BGjaAIXHs/5YS3i473GqwBBa1zGQNevxdeBEXrM= +google.golang.org/grpc v1.76.0 h1:UnVkv1+uMLYXoIz6o7chp59WfQUYA2ex/BXQ9rHZu7A= +google.golang.org/grpc v1.76.0/go.mod h1:Ju12QI8M6iQJtbcsV+awF5a4hfJMLi4X0JLo94ULZ6c= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= 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= @@ -1842,8 +1855,8 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= -google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= +google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= +google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk= gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk= @@ -1868,9 +1881,8 @@ gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= gopkg.in/src-d/go-errors.v1 v1.0.0 h1:cooGdZnCjYbeS1zb1s6pVAAimTdKceRrpn7aKOnNIfc= gopkg.in/src-d/go-errors.v1 v1.0.0/go.mod h1:q1cBlomlw2FnDBDNGlnh6X0jPihy+QxZfMMNxPCbdYg= -gopkg.in/telebot.v3 v3.2.1 h1:3I4LohaAyJBiivGmkfB+CiVu7QFOWkuZ4+KHgO/G3rs= -gopkg.in/telebot.v3 v3.2.1/go.mod h1:GJKwwWqp9nSkIVN51eRKU78aB5f5OnQuWdwiIZfPbko= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/telebot.v3 v3.3.8 h1:uVDGjak9l824FN9YARWUHMsiNZnlohAVwUycw21k6t8= +gopkg.in/telebot.v3 v3.3.8/go.mod h1:1mlbqcLTVSfK9dx7fdp+Nb5HZsy4LLPtpZTKmwhwtzM= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -1894,46 +1906,48 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -k8s.io/api v0.33.3 h1:SRd5t//hhkI1buzxb288fy2xvjubstenEKL9K51KBI8= -k8s.io/api v0.33.3/go.mod h1:01Y/iLUjNBM3TAvypct7DIj0M0NIZc+PzAHCIo0CYGE= -k8s.io/apiextensions-apiserver v0.33.3 h1:qmOcAHN6DjfD0v9kxL5udB27SRP6SG/MTopmge3MwEs= -k8s.io/apiextensions-apiserver v0.33.3/go.mod h1:oROuctgo27mUsyp9+Obahos6CWcMISSAPzQ77CAQGz8= -k8s.io/apimachinery v0.33.3 h1:4ZSrmNa0c/ZpZJhAgRdcsFcZOw1PQU1bALVQ0B3I5LA= -k8s.io/apimachinery v0.33.3/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM= -k8s.io/apiserver v0.33.3 h1:Wv0hGc+QFdMJB4ZSiHrCgN3zL3QRatu56+rpccKC3J4= -k8s.io/apiserver v0.33.3/go.mod h1:05632ifFEe6TxwjdAIrwINHWE2hLwyADFk5mBsQa15E= -k8s.io/client-go v0.33.3 h1:M5AfDnKfYmVJif92ngN532gFqakcGi6RvaOF16efrpA= -k8s.io/client-go v0.33.3/go.mod h1:luqKBQggEf3shbxHY4uVENAxrDISLOarxpTKMiUuujg= -k8s.io/component-base v0.33.3 h1:mlAuyJqyPlKZM7FyaoM/LcunZaaY353RXiOd2+B5tGA= -k8s.io/component-base v0.33.3/go.mod h1:ktBVsBzkI3imDuxYXmVxZ2zxJnYTZ4HAsVj9iF09qp4= +k8s.io/api v0.34.1 h1:jC+153630BMdlFukegoEL8E/yT7aLyQkIVuwhmwDgJM= +k8s.io/api v0.34.1/go.mod h1:SB80FxFtXn5/gwzCoN6QCtPD7Vbu5w2n1S0J5gFfTYk= +k8s.io/apiextensions-apiserver v0.34.1 h1:NNPBva8FNAPt1iSVwIE0FsdrVriRXMsaWFMqJbII2CI= +k8s.io/apiextensions-apiserver v0.34.1/go.mod h1:hP9Rld3zF5Ay2Of3BeEpLAToP+l4s5UlxiHfqRaRcMc= +k8s.io/apimachinery v0.34.1 h1:dTlxFls/eikpJxmAC7MVE8oOeP1zryV7iRyIjB0gky4= +k8s.io/apimachinery v0.34.1/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= +k8s.io/apiserver v0.34.1 h1:U3JBGdgANK3dfFcyknWde1G6X1F4bg7PXuvlqt8lITA= +k8s.io/apiserver v0.34.1/go.mod h1:eOOc9nrVqlBI1AFCvVzsob0OxtPZUCPiUJL45JOTBG0= +k8s.io/client-go v0.34.1 h1:ZUPJKgXsnKwVwmKKdPfw4tB58+7/Ik3CrjOEhsiZ7mY= +k8s.io/client-go v0.34.1/go.mod h1:kA8v0FP+tk6sZA0yKLRG67LWjqufAoSHA2xVGKw9Of8= +k8s.io/component-base v0.34.1 h1:v7xFgG+ONhytZNFpIz5/kecwD+sUhVE6HU7qQUiRM4A= +k8s.io/component-base v0.34.1/go.mod h1:mknCpLlTSKHzAQJJnnHVKqjxR7gBeHRv0rPXA7gdtQ0= k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= -k8s.io/kms v0.33.3 h1:7cQWC+GSH211NgY8LRKjBXNtkzra5SkpYzeZrOt5D+8= -k8s.io/kms v0.33.3/go.mod h1:C1I8mjFFBNzfUZXYt9FZVJ8MJl7ynFbGgZFbBzkBJ3E= -k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff h1:/usPimJzUKKu+m+TE36gUyGcf03XZEP0ZIKgKj35LS4= -k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff/go.mod h1:5jIi+8yX4RIb8wk3XwBo5Pq2ccx4FP10ohkbSKCZoK8= -k8s.io/utils v0.0.0-20241210054802-24370beab758 h1:sdbE21q2nlQtFh65saZY+rRM6x6aJJI8IUa1AmH/qa0= -k8s.io/utils v0.0.0-20241210054802-24370beab758/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -modernc.org/cc/v4 v4.26.0 h1:QMYvbVduUGH0rrO+5mqF/PSPPRZNpRtg2CLELy7vUpA= -modernc.org/cc/v4 v4.26.0/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0= -modernc.org/ccgo/v4 v4.26.0 h1:gVzXaDzGeBYJ2uXTOpR8FR7OlksDOe9jxnjhIKCsiTc= -modernc.org/ccgo/v4 v4.26.0/go.mod h1:Sem8f7TFUtVXkG2fiaChQtyyfkqhJBg/zjEJBkmuAVY= -modernc.org/fileutil v1.3.1 h1:8vq5fe7jdtEvoCf3Zf9Nm0Q05sH6kGx0Op2CPx1wTC8= -modernc.org/fileutil v1.3.1/go.mod h1:HxmghZSZVAz/LXcMNwZPA/DRrQZEVP9VX0V4LQGQFOc= +k8s.io/kms v0.34.1 h1:iCFOvewDPzWM9fMTfyIPO+4MeuZ0tcZbugxLNSHFG4w= +k8s.io/kms v0.34.1/go.mod h1:s1CFkLG7w9eaTYvctOxosx88fl4spqmixnNpys0JAtM= +k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 h1:Y3gxNAuB0OBLImH611+UDZcmKS3g6CthxToOb37KgwE= +k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912/go.mod h1:kdmbQkyfwUagLfXIad1y2TdrjPFWp2Q89B3qkRwf/pQ= +k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 h1:hwvWFiBzdWw1FhfY1FooPn3kzWuJ8tmbZBHi4zVsl1Y= +k8s.io/utils v0.0.0-20250604170112-4c0f3b243397/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +modernc.org/cc/v4 v4.26.5 h1:xM3bX7Mve6G8K8b+T11ReenJOT+BmVqQj0FY5T4+5Y4= +modernc.org/cc/v4 v4.26.5/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0= +modernc.org/ccgo/v4 v4.28.1 h1:wPKYn5EC/mYTqBO373jKjvX2n+3+aK7+sICCv4Fjy1A= +modernc.org/ccgo/v4 v4.28.1/go.mod h1:uD+4RnfrVgE6ec9NGguUNdhqzNIeeomeXf6CL0GTE5Q= +modernc.org/fileutil v1.3.40 h1:ZGMswMNc9JOCrcrakF1HrvmergNLAmxOPjizirpfqBA= +modernc.org/fileutil v1.3.40/go.mod h1:HxmghZSZVAz/LXcMNwZPA/DRrQZEVP9VX0V4LQGQFOc= modernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI= modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito= -modernc.org/libc v1.65.0 h1:e183gLDnAp9VJh6gWKdTy0CThL9Pt7MfcR/0bgb7Y1Y= -modernc.org/libc v1.65.0/go.mod h1:7m9VzGq7APssBTydds2zBcxGREwvIGpuUBaKTXdm2Qs= +modernc.org/goabi0 v0.2.0 h1:HvEowk7LxcPd0eq6mVOAEMai46V+i7Jrj13t4AzuNks= +modernc.org/goabi0 v0.2.0/go.mod h1:CEFRnnJhKvWT1c1JTI3Avm+tgOWbkOu5oPA8eH8LnMI= +modernc.org/libc v1.66.10 h1:yZkb3YeLx4oynyR+iUsXsybsX4Ubx7MQlSYEw4yj59A= +modernc.org/libc v1.66.10/go.mod h1:8vGSEwvoUoltr4dlywvHqjtAqHBaw0j1jI7iFBTAr2I= modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU= modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg= -modernc.org/memory v1.10.0 h1:fzumd51yQ1DxcOxSO+S6X7+QTuVU+n8/Aj7swYjFfC4= -modernc.org/memory v1.10.0/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw= +modernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI= +modernc.org/memory v1.11.0/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw= modernc.org/opt v0.1.4 h1:2kNGMRiUjrp4LcaPuLY2PzUfqM/w9N23quVwhKt5Qm8= modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns= modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w= modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE= -modernc.org/sqlite v1.37.0 h1:s1TMe7T3Q3ovQiK2Ouz4Jwh7dw4ZDqbebSDTlSJdfjI= -modernc.org/sqlite v1.37.0/go.mod h1:5YiWv+YviqGMuGw4V+PNplcyaJ5v+vQd7TQOgkACoJM= +modernc.org/sqlite v1.39.1 h1:H+/wGFzuSCIEVCvXYVHX5RQglwhMOvtHSv+VtidL2r4= +modernc.org/sqlite v1.39.1/go.mod h1:9fjQZ0mB1LLP0GYrp39oOJXx/I2sxEnZtzCmEQIKvGE= modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0= modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A= modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= @@ -1945,14 +1959,12 @@ sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2 h1:jpcvIRr3GLoUo sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw= sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 h1:gBQPwqORJ8d8/YNZWEjoZs7npUVDpVXUUOFfW6CgAqE= sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= -sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= -sigs.k8s.io/structured-merge-diff/v4 v4.7.0 h1:qPeWmscJcXP0snki5IYF79Z8xrl8ETFxgMd7wez1XkI= -sigs.k8s.io/structured-merge-diff/v4 v4.7.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps= +sigs.k8s.io/structured-merge-diff/v6 v6.3.0 h1:jTijUJbW353oVOd9oTlifJqOGEkUw2jB/fXCbTiQEco= +sigs.k8s.io/structured-merge-diff/v6 v6.3.0/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= -sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= -sigs.k8s.io/yaml v1.5.0 h1:M10b2U7aEUY6hRtU870n2VTPgR5RZiL/I6Lcc2F4NUQ= -sigs.k8s.io/yaml v1.5.0/go.mod h1:wZs27Rbxoai4C0f8/9urLZtZtF3avA3gKvGyPdDqTO4= +sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= +sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= xorm.io/builder v0.3.6 h1:ha28mQ2M+TFx96Hxo+iq6tQgnkC9IZkM6D8w9sKHHF8= xorm.io/builder v0.3.6/go.mod h1:LEFAPISnRzG+zxaxj2vPicRwz67BdhFreKg8yv8/TgU= diff --git a/apps/advisor/kinds/check.cue b/apps/advisor/kinds/check.cue index 01982443ffc..bf227efbe53 100644 --- a/apps/advisor/kinds/check.cue +++ b/apps/advisor/kinds/check.cue @@ -1,57 +1,49 @@ package advisor -check: { - kind: "Check" - pluralName: "Checks" - current: "v0alpha1" +checkv0alpha1: { + kind: "Check" + plural: "checks" + scope: "Namespaced" validation: { operations: [ "CREATE", "UPDATE", ] } - versions: { - "v0alpha1": { - codegen: { - ts: {enabled: false} - go: {enabled: true} - } - schema: { - #Data: { - // Generic data input that a check can receive - data?: [string]: string - } - #ErrorLink: { - // URL to a page with more information about the error - url: string - // Human readable error message - message: string - } - #ReportFailure: { - // Severity of the failure - severity: "high" | "low" - // Step ID that the failure is associated with - stepID: string - // Human readable identifier of the item that failed - item: string - // ID of the item that failed - itemID: string - // Links to actions that can be taken to resolve the failure - links: [...#ErrorLink] - // More information about the failure, not meant to be displayed to the user. Used for LLM suggestions. - moreInfo?: string - } - #Report: { - // Number of elements analyzed - count: int - // List of failures - failures: [...#ReportFailure] - } - spec: #Data - status: { - report: #Report - } - } + schema: { + #Data: { + // Generic data input that a check can receive + data?: [string]: string + } + #ErrorLink: { + // URL to a page with more information about the error + url: string + // Human readable error message + message: string + } + #ReportFailure: { + // Severity of the failure + severity: "high" | "low" + // Step ID that the failure is associated with + stepID: string + // Human readable identifier of the item that failed + item: string + // ID of the item that failed + itemID: string + // Links to actions that can be taken to resolve the failure + links: [...#ErrorLink] + // More information about the failure, not meant to be displayed to the user. Used for LLM suggestions. + moreInfo?: string + } + #Report: { + // Number of elements analyzed + count: int + // List of failures + failures: [...#ReportFailure] + } + spec: #Data + status: { + report: #Report } } } diff --git a/apps/advisor/kinds/checktype.cue b/apps/advisor/kinds/checktype.cue index 315d231754d..25902d8265a 100644 --- a/apps/advisor/kinds/checktype.cue +++ b/apps/advisor/kinds/checktype.cue @@ -1,27 +1,19 @@ package advisor -checktype: { - kind: "CheckType" - pluralName: "CheckTypes" - current: "v0alpha1" - versions: { - "v0alpha1": { - codegen: { - ts: {enabled: false} - go: {enabled: true} - } - schema: { - #Step: { - title: string - description: string - stepID: string - resolution: string - } - spec: { - name: string - steps: [...#Step] - } - } +checktypev0alpha1: { + kind: "CheckType" + plural: "checktypes" + scope: "Namespaced" + schema: { + #Step: { + title: string + description: string + stepID: string + resolution: string + } + spec: { + name: string + steps: [...#Step] } } } diff --git a/apps/advisor/kinds/manifest.cue b/apps/advisor/kinds/manifest.cue index 75a0eee05ef..ca791996f13 100644 --- a/apps/advisor/kinds/manifest.cue +++ b/apps/advisor/kinds/manifest.cue @@ -1,10 +1,18 @@ package advisor manifest: { - appName: "advisor" - groupOverride: "advisor.grafana.app" - kinds: [ - check, - checktype, - ] + appName: "advisor" + groupOverride: "advisor.grafana.app" + versions: { + "v0alpha1": { + codegen: { + ts: {enabled: false} + go: {enabled: true} + } + kinds: [ + checkv0alpha1, + checktypev0alpha1, + ] + } + } } diff --git a/apps/advisor/pkg/apis/advisor/v0alpha1/check_client_gen.go b/apps/advisor/pkg/apis/advisor/v0alpha1/check_client_gen.go new file mode 100644 index 00000000000..b224a1d4478 --- /dev/null +++ b/apps/advisor/pkg/apis/advisor/v0alpha1/check_client_gen.go @@ -0,0 +1,99 @@ +package v0alpha1 + +import ( + "context" + + "github.com/grafana/grafana-app-sdk/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +type CheckClient struct { + client *resource.TypedClient[*Check, *CheckList] +} + +func NewCheckClient(client resource.Client) *CheckClient { + return &CheckClient{ + client: resource.NewTypedClient[*Check, *CheckList](client, CheckKind()), + } +} + +func NewCheckClientFromGenerator(generator resource.ClientGenerator) (*CheckClient, error) { + c, err := generator.ClientFor(CheckKind()) + if err != nil { + return nil, err + } + return NewCheckClient(c), nil +} + +func (c *CheckClient) Get(ctx context.Context, identifier resource.Identifier) (*Check, error) { + return c.client.Get(ctx, identifier) +} + +func (c *CheckClient) List(ctx context.Context, namespace string, opts resource.ListOptions) (*CheckList, error) { + return c.client.List(ctx, namespace, opts) +} + +func (c *CheckClient) ListAll(ctx context.Context, namespace string, opts resource.ListOptions) (*CheckList, error) { + resp, err := c.client.List(ctx, namespace, resource.ListOptions{ + ResourceVersion: opts.ResourceVersion, + Limit: opts.Limit, + LabelFilters: opts.LabelFilters, + FieldSelectors: opts.FieldSelectors, + }) + if err != nil { + return nil, err + } + for resp.GetContinue() != "" { + page, err := c.client.List(ctx, namespace, resource.ListOptions{ + Continue: resp.GetContinue(), + ResourceVersion: opts.ResourceVersion, + Limit: opts.Limit, + LabelFilters: opts.LabelFilters, + FieldSelectors: opts.FieldSelectors, + }) + if err != nil { + return nil, err + } + resp.SetContinue(page.GetContinue()) + resp.SetResourceVersion(page.GetResourceVersion()) + resp.SetItems(append(resp.GetItems(), page.GetItems()...)) + } + return resp, nil +} + +func (c *CheckClient) Create(ctx context.Context, obj *Check, opts resource.CreateOptions) (*Check, error) { + // Make sure apiVersion and kind are set + obj.APIVersion = GroupVersion.Identifier() + obj.Kind = CheckKind().Kind() + return c.client.Create(ctx, obj, opts) +} + +func (c *CheckClient) Update(ctx context.Context, obj *Check, opts resource.UpdateOptions) (*Check, error) { + return c.client.Update(ctx, obj, opts) +} + +func (c *CheckClient) Patch(ctx context.Context, identifier resource.Identifier, req resource.PatchRequest, opts resource.PatchOptions) (*Check, error) { + return c.client.Patch(ctx, identifier, req, opts) +} + +func (c *CheckClient) UpdateStatus(ctx context.Context, identifier resource.Identifier, newStatus CheckStatus, opts resource.UpdateOptions) (*Check, error) { + return c.client.Update(ctx, &Check{ + TypeMeta: metav1.TypeMeta{ + Kind: CheckKind().Kind(), + APIVersion: GroupVersion.Identifier(), + }, + ObjectMeta: metav1.ObjectMeta{ + ResourceVersion: opts.ResourceVersion, + Namespace: identifier.Namespace, + Name: identifier.Name, + }, + Status: newStatus, + }, resource.UpdateOptions{ + Subresource: "status", + ResourceVersion: opts.ResourceVersion, + }) +} + +func (c *CheckClient) Delete(ctx context.Context, identifier resource.Identifier, opts resource.DeleteOptions) error { + return c.client.Delete(ctx, identifier, opts) +} diff --git a/apps/advisor/pkg/apis/advisor/v0alpha1/checktype_client_gen.go b/apps/advisor/pkg/apis/advisor/v0alpha1/checktype_client_gen.go new file mode 100644 index 00000000000..2acf5bf5cfe --- /dev/null +++ b/apps/advisor/pkg/apis/advisor/v0alpha1/checktype_client_gen.go @@ -0,0 +1,99 @@ +package v0alpha1 + +import ( + "context" + + "github.com/grafana/grafana-app-sdk/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +type CheckTypeClient struct { + client *resource.TypedClient[*CheckType, *CheckTypeList] +} + +func NewCheckTypeClient(client resource.Client) *CheckTypeClient { + return &CheckTypeClient{ + client: resource.NewTypedClient[*CheckType, *CheckTypeList](client, CheckTypeKind()), + } +} + +func NewCheckTypeClientFromGenerator(generator resource.ClientGenerator) (*CheckTypeClient, error) { + c, err := generator.ClientFor(CheckTypeKind()) + if err != nil { + return nil, err + } + return NewCheckTypeClient(c), nil +} + +func (c *CheckTypeClient) Get(ctx context.Context, identifier resource.Identifier) (*CheckType, error) { + return c.client.Get(ctx, identifier) +} + +func (c *CheckTypeClient) List(ctx context.Context, namespace string, opts resource.ListOptions) (*CheckTypeList, error) { + return c.client.List(ctx, namespace, opts) +} + +func (c *CheckTypeClient) ListAll(ctx context.Context, namespace string, opts resource.ListOptions) (*CheckTypeList, error) { + resp, err := c.client.List(ctx, namespace, resource.ListOptions{ + ResourceVersion: opts.ResourceVersion, + Limit: opts.Limit, + LabelFilters: opts.LabelFilters, + FieldSelectors: opts.FieldSelectors, + }) + if err != nil { + return nil, err + } + for resp.GetContinue() != "" { + page, err := c.client.List(ctx, namespace, resource.ListOptions{ + Continue: resp.GetContinue(), + ResourceVersion: opts.ResourceVersion, + Limit: opts.Limit, + LabelFilters: opts.LabelFilters, + FieldSelectors: opts.FieldSelectors, + }) + if err != nil { + return nil, err + } + resp.SetContinue(page.GetContinue()) + resp.SetResourceVersion(page.GetResourceVersion()) + resp.SetItems(append(resp.GetItems(), page.GetItems()...)) + } + return resp, nil +} + +func (c *CheckTypeClient) Create(ctx context.Context, obj *CheckType, opts resource.CreateOptions) (*CheckType, error) { + // Make sure apiVersion and kind are set + obj.APIVersion = GroupVersion.Identifier() + obj.Kind = CheckTypeKind().Kind() + return c.client.Create(ctx, obj, opts) +} + +func (c *CheckTypeClient) Update(ctx context.Context, obj *CheckType, opts resource.UpdateOptions) (*CheckType, error) { + return c.client.Update(ctx, obj, opts) +} + +func (c *CheckTypeClient) Patch(ctx context.Context, identifier resource.Identifier, req resource.PatchRequest, opts resource.PatchOptions) (*CheckType, error) { + return c.client.Patch(ctx, identifier, req, opts) +} + +func (c *CheckTypeClient) UpdateStatus(ctx context.Context, identifier resource.Identifier, newStatus CheckTypeStatus, opts resource.UpdateOptions) (*CheckType, error) { + return c.client.Update(ctx, &CheckType{ + TypeMeta: metav1.TypeMeta{ + Kind: CheckTypeKind().Kind(), + APIVersion: GroupVersion.Identifier(), + }, + ObjectMeta: metav1.ObjectMeta{ + ResourceVersion: opts.ResourceVersion, + Namespace: identifier.Namespace, + Name: identifier.Name, + }, + Status: newStatus, + }, resource.UpdateOptions{ + Subresource: "status", + ResourceVersion: opts.ResourceVersion, + }) +} + +func (c *CheckTypeClient) Delete(ctx context.Context, identifier resource.Identifier, opts resource.DeleteOptions) error { + return c.client.Delete(ctx, identifier, opts) +} diff --git a/apps/advisor/pkg/apis/advisor_manifest.go b/apps/advisor/pkg/apis/advisor_manifest.go index a85ff8b904f..5c7b5896ee8 100644 --- a/apps/advisor/pkg/apis/advisor_manifest.go +++ b/apps/advisor/pkg/apis/advisor_manifest.go @@ -12,22 +12,26 @@ import ( "github.com/grafana/grafana-app-sdk/app" "github.com/grafana/grafana-app-sdk/resource" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/kube-openapi/pkg/spec3" + "k8s.io/kube-openapi/pkg/validation/spec" v0alpha1 "github.com/grafana/grafana/apps/advisor/pkg/apis/advisor/v0alpha1" ) var ( - rawSchemaCheckv0alpha1 = []byte(`{"spec":{"properties":{"data":{"additionalProperties":{"type":"string"},"description":"Generic data input that a check can receive","type":"object"}},"type":"object"},"status":{"properties":{"additionalFields":{"description":"additionalFields is reserved for future use","type":"object","x-kubernetes-preserve-unknown-fields":true},"operatorStates":{"additionalProperties":{"properties":{"descriptiveState":{"description":"descriptiveState is an optional more descriptive state field which has no requirements on format","type":"string"},"details":{"description":"details contains any extra information that is operator-specific","type":"object","x-kubernetes-preserve-unknown-fields":true},"lastEvaluation":{"description":"lastEvaluation is the ResourceVersion last evaluated","type":"string"},"state":{"description":"state describes the state of the lastEvaluation.\nIt is limited to three possible states for machine evaluation.","enum":["success","in_progress","failed"],"type":"string"}},"required":["lastEvaluation","state"],"type":"object"},"description":"operatorStates is a map of operator ID to operator state evaluations.\nAny operator which consumes this kind SHOULD add its state evaluation information to this field.","type":"object"},"report":{"properties":{"count":{"description":"Number of elements analyzed","type":"integer"},"failures":{"description":"List of failures","items":{"properties":{"item":{"description":"Human readable identifier of the item that failed","type":"string"},"itemID":{"description":"ID of the item that failed","type":"string"},"links":{"description":"Links to actions that can be taken to resolve the failure","items":{"properties":{"message":{"description":"Human readable error message","type":"string"},"url":{"description":"URL to a page with more information about the error","type":"string"}},"required":["url","message"],"type":"object"},"type":"array"},"moreInfo":{"description":"More information about the failure, not meant to be displayed to the user. Used for LLM suggestions.","type":"string"},"severity":{"description":"Severity of the failure","enum":["high","low"],"type":"string"},"stepID":{"description":"Step ID that the failure is associated with","type":"string"}},"required":["severity","stepID","item","itemID","links"],"type":"object"},"type":"array"}},"required":["count","failures"],"type":"object"}},"required":["report"],"type":"object"}}`) + rawSchemaCheckv0alpha1 = []byte(`{"Check":{"properties":{"spec":{"$ref":"#/components/schemas/spec"},"status":{"$ref":"#/components/schemas/status"}},"required":["spec"]},"ErrorLink":{"additionalProperties":false,"properties":{"message":{"description":"Human readable error message","type":"string"},"url":{"description":"URL to a page with more information about the error","type":"string"}},"required":["url","message"],"type":"object"},"OperatorState":{"additionalProperties":false,"properties":{"descriptiveState":{"description":"descriptiveState is an optional more descriptive state field which has no requirements on format","type":"string"},"details":{"additionalProperties":{"additionalProperties":{},"type":"object"},"description":"details contains any extra information that is operator-specific","type":"object"},"lastEvaluation":{"description":"lastEvaluation is the ResourceVersion last evaluated","type":"string"},"state":{"description":"state describes the state of the lastEvaluation.\nIt is limited to three possible states for machine evaluation.","enum":["success","in_progress","failed"],"type":"string"}},"required":["lastEvaluation","state"],"type":"object"},"Report":{"additionalProperties":false,"properties":{"count":{"description":"Number of elements analyzed","type":"integer"},"failures":{"description":"List of failures","items":{"$ref":"#/components/schemas/ReportFailure"},"type":"array"}},"required":["count","failures"],"type":"object"},"ReportFailure":{"additionalProperties":false,"properties":{"item":{"description":"Human readable identifier of the item that failed","type":"string"},"itemID":{"description":"ID of the item that failed","type":"string"},"links":{"description":"Links to actions that can be taken to resolve the failure","items":{"$ref":"#/components/schemas/ErrorLink"},"type":"array"},"moreInfo":{"description":"More information about the failure, not meant to be displayed to the user. Used for LLM suggestions.","type":"string"},"severity":{"description":"Severity of the failure","enum":["high","low"],"type":"string"},"stepID":{"description":"Step ID that the failure is associated with","type":"string"}},"required":["severity","stepID","item","itemID","links"],"type":"object"},"spec":{"additionalProperties":false,"properties":{"data":{"additionalProperties":{"type":"string"},"description":"Generic data input that a check can receive","type":"object"}},"type":"object"},"status":{"additionalProperties":false,"properties":{"additionalFields":{"additionalProperties":{"additionalProperties":{},"type":"object"},"description":"additionalFields is reserved for future use","type":"object"},"operatorStates":{"additionalProperties":{"$ref":"#/components/schemas/OperatorState"},"description":"operatorStates is a map of operator ID to operator state evaluations.\nAny operator which consumes this kind SHOULD add its state evaluation information to this field.","type":"object"},"report":{"$ref":"#/components/schemas/Report"}},"required":["report"],"type":"object"}}`) versionSchemaCheckv0alpha1 app.VersionSchema _ = json.Unmarshal(rawSchemaCheckv0alpha1, &versionSchemaCheckv0alpha1) - rawSchemaCheckTypev0alpha1 = []byte(`{"spec":{"properties":{"name":{"type":"string"},"steps":{"items":{"properties":{"description":{"type":"string"},"resolution":{"type":"string"},"stepID":{"type":"string"},"title":{"type":"string"}},"required":["title","description","stepID","resolution"],"type":"object"},"type":"array"}},"required":["name","steps"],"type":"object"},"status":{"properties":{"additionalFields":{"description":"additionalFields is reserved for future use","type":"object","x-kubernetes-preserve-unknown-fields":true},"operatorStates":{"additionalProperties":{"properties":{"descriptiveState":{"description":"descriptiveState is an optional more descriptive state field which has no requirements on format","type":"string"},"details":{"description":"details contains any extra information that is operator-specific","type":"object","x-kubernetes-preserve-unknown-fields":true},"lastEvaluation":{"description":"lastEvaluation is the ResourceVersion last evaluated","type":"string"},"state":{"description":"state describes the state of the lastEvaluation.\nIt is limited to three possible states for machine evaluation.","enum":["success","in_progress","failed"],"type":"string"}},"required":["lastEvaluation","state"],"type":"object"},"description":"operatorStates is a map of operator ID to operator state evaluations.\nAny operator which consumes this kind SHOULD add its state evaluation information to this field.","type":"object"}},"type":"object"}}`) + rawSchemaCheckTypev0alpha1 = []byte(`{"CheckType":{"properties":{"spec":{"$ref":"#/components/schemas/spec"},"status":{"$ref":"#/components/schemas/status"}},"required":["spec"]},"OperatorState":{"additionalProperties":false,"properties":{"descriptiveState":{"description":"descriptiveState is an optional more descriptive state field which has no requirements on format","type":"string"},"details":{"additionalProperties":{"additionalProperties":{},"type":"object"},"description":"details contains any extra information that is operator-specific","type":"object"},"lastEvaluation":{"description":"lastEvaluation is the ResourceVersion last evaluated","type":"string"},"state":{"description":"state describes the state of the lastEvaluation.\nIt is limited to three possible states for machine evaluation.","enum":["success","in_progress","failed"],"type":"string"}},"required":["lastEvaluation","state"],"type":"object"},"Step":{"additionalProperties":false,"properties":{"description":{"type":"string"},"resolution":{"type":"string"},"stepID":{"type":"string"},"title":{"type":"string"}},"required":["title","description","stepID","resolution"],"type":"object"},"spec":{"additionalProperties":false,"properties":{"name":{"type":"string"},"steps":{"items":{"$ref":"#/components/schemas/Step"},"type":"array"}},"required":["name","steps"],"type":"object"},"status":{"additionalProperties":false,"properties":{"additionalFields":{"additionalProperties":{"additionalProperties":{},"type":"object"},"description":"additionalFields is reserved for future use","type":"object"},"operatorStates":{"additionalProperties":{"$ref":"#/components/schemas/OperatorState"},"description":"operatorStates is a map of operator ID to operator state evaluations.\nAny operator which consumes this kind SHOULD add its state evaluation information to this field.","type":"object"}},"type":"object"}}`) versionSchemaCheckTypev0alpha1 app.VersionSchema _ = json.Unmarshal(rawSchemaCheckTypev0alpha1, &versionSchemaCheckTypev0alpha1) ) var appManifestData = app.ManifestData{ - AppName: "advisor", - Group: "advisor.grafana.app", + AppName: "advisor", + Group: "advisor.grafana.app", + PreferredVersion: "v0alpha1", Versions: []app.ManifestVersion{ { Name: "v0alpha1", @@ -57,6 +61,11 @@ var appManifestData = app.ManifestData{ Schema: &versionSchemaCheckTypev0alpha1, }, }, + Routes: app.ManifestVersionRoutes{ + Namespaced: map[string]spec3.PathProps{}, + Cluster: map[string]spec3.PathProps{}, + Schemas: map[string]spec.Schema{}, + }, }, }, } @@ -86,6 +95,7 @@ var customRouteToGoResponseType = map[string]any{} // ManifestCustomRouteResponsesAssociator returns the associated response go type for a given kind, version, custom route path, and method, if one exists. // kind may be empty for custom routes which are not kind subroutes. Leading slashes are removed from subroute paths. // If there is no association for the provided kind, version, custom route path, and method, exists will return false. +// Resource routes (those without a kind) should prefix their route with "/" if the route is namespaced (otherwise the route is assumed to be cluster-scope) func ManifestCustomRouteResponsesAssociator(kind, version, path, verb string) (goType any, exists bool) { if len(path) > 0 && path[0] == '/' { path = path[1:] @@ -93,3 +103,42 @@ func ManifestCustomRouteResponsesAssociator(kind, version, path, verb string) (g goType, exists = customRouteToGoResponseType[fmt.Sprintf("%s|%s|%s|%s", version, kind, path, strings.ToUpper(verb))] return goType, exists } + +var customRouteToGoParamsType = map[string]runtime.Object{} + +func ManifestCustomRouteQueryAssociator(kind, version, path, verb string) (goType runtime.Object, exists bool) { + if len(path) > 0 && path[0] == '/' { + path = path[1:] + } + goType, exists = customRouteToGoParamsType[fmt.Sprintf("%s|%s|%s|%s", version, kind, path, strings.ToUpper(verb))] + return goType, exists +} + +var customRouteToGoRequestBodyType = map[string]any{} + +func ManifestCustomRouteRequestBodyAssociator(kind, version, path, verb string) (goType any, exists bool) { + if len(path) > 0 && path[0] == '/' { + path = path[1:] + } + goType, exists = customRouteToGoRequestBodyType[fmt.Sprintf("%s|%s|%s|%s", version, kind, path, strings.ToUpper(verb))] + return goType, exists +} + +type GoTypeAssociator struct{} + +func NewGoTypeAssociator() *GoTypeAssociator { + return &GoTypeAssociator{} +} + +func (g *GoTypeAssociator) KindToGoType(kind, version string) (goType resource.Kind, exists bool) { + return ManifestGoTypeAssociator(kind, version) +} +func (g *GoTypeAssociator) CustomRouteReturnGoType(kind, version, path, verb string) (goType any, exists bool) { + return ManifestCustomRouteResponsesAssociator(kind, version, path, verb) +} +func (g *GoTypeAssociator) CustomRouteQueryGoType(kind, version, path, verb string) (goType runtime.Object, exists bool) { + return ManifestCustomRouteQueryAssociator(kind, version, path, verb) +} +func (g *GoTypeAssociator) CustomRouteRequestBodyGoType(kind, version, path, verb string) (goType any, exists bool) { + return ManifestCustomRouteRequestBodyAssociator(kind, version, path, verb) +} diff --git a/go.work.sum b/go.work.sum index d26aabd35b9..995365a4618 100644 --- a/go.work.sum +++ b/go.work.sum @@ -1196,7 +1196,6 @@ github.com/invopop/yaml v0.3.1/go.mod h1:PMOp3nn4/12yEZUFfmOuNHJsZToEEOwoWsT+D81 github.com/iris-contrib/schema v0.0.6 h1:CPSBLyx2e91H2yJzPuhGuifVRnZBBJ3pCOMbOvPZaTw= github.com/iris-contrib/schema v0.0.6/go.mod h1:iYszG0IOsuIsfzjymw1kMzTL8YQcCWlm65f3wX8J5iA= github.com/jackc/fake v0.0.0-20150926172116-812a484cc733 h1:vr3AYkKovP8uR8AvSGGUK1IDqRa5lAAvEkZG1LKaCRc= -github.com/jackc/pgx v3.2.0+incompatible h1:0Vihzu20St42/UDsvZGdNE6jak7oi/UOeMzwMPHkgFY= github.com/jackspirou/syscerts v0.0.0-20160531025014-b68f5469dff1 h1:9Xm8CKtMZIXgcopfdWk/qZ1rt0HjMgfMR9nxxSeK6vk= github.com/jackspirou/syscerts v0.0.0-20160531025014-b68f5469dff1/go.mod h1:zuHl3Hh+e9P6gmBPvcqR1HjkaWHC/csgyskg6IaFKFo= github.com/jedib0t/go-pretty/v6 v6.6.7 h1:m+LbHpm0aIAPLzLbMfn8dc3Ht8MW7lsSO4MPItz/Uuo= @@ -1719,6 +1718,7 @@ go.einride.tech/aip v0.68.1/go.mod h1:XaFtaj4HuA3Zwk9xoBtTWgNubZ0ZZXv9BZJCkuKuWb go.etcd.io/bbolt v1.3.11/go.mod h1:dksAq7YMXoljX0xu6VF5DMZGbhYYoLUalEiSySYAS4I= go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= +go.etcd.io/etcd/client/v2 v2.305.4 h1:Dcx3/MYyfKcPNLpR4VVQUP5KgYrBeJtktBwEKkw08Ao= go.etcd.io/etcd/client/v2 v2.305.21 h1:eLiFfexc2mE+pTLz9WwnoEsX5JTTpLCYVivKkmVXIRA= go.etcd.io/etcd/client/v2 v2.305.21/go.mod h1:OKkn4hlYNf43hpjEM3Ke3aRdUkhSl8xjKjSf8eCq2J8= go.etcd.io/etcd/client/v3 v3.5.0/go.mod h1:AIKXXVX/DQXtfTEqBryiLTUXwON+GuvO6Z7lLS/oTh0= @@ -2318,4 +2318,6 @@ sigs.k8s.io/controller-runtime v0.22.1/go.mod h1:FwiwRjkRPbiN+zp2QRp7wlTCzbUXxZ/ sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3/go.mod h1:18nIHnGi6636UCz6m8i4DhaJ65T6EruyzmoQqI2BVDo= sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e h1:4Z09Hglb792X0kfOBBJUPFEyvVfQWrYT/l8h5EKA6JQ= +sigs.k8s.io/structured-merge-diff/v4 v4.5.0 h1:nbCitCK2hfnhyiKo6uf2HxUPTCodY6Qaf85SbDIaMBk= +sigs.k8s.io/structured-merge-diff/v4 v4.5.0/go.mod h1:N8f93tFZh9U6vpxwRArLiikrE5/2tiu1w1AGfACIGE4= sigs.k8s.io/structured-merge-diff/v6 v6.2.0/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= From d4d8b2562e6576a8bf34c84e3d85f389ccd26a96 Mon Sep 17 00:00:00 2001 From: Ryan McKinley Date: Tue, 28 Oct 2025 12:10:37 +0300 Subject: [PATCH 039/378] Chore: Update gocloud.dev, removing opencensus (#113056) --- apps/advisor/go.mod | 4 +- apps/advisor/go.sum | 79 +- apps/iam/go.mod | 36 +- apps/iam/go.sum | 106 +- go.mod | 50 +- go.sum | 107 +- go.work.sum | 1205 ++-------------------- pkg/build/go.mod | 2 +- pkg/build/go.sum | 4 +- pkg/promlib/go.mod | 4 +- pkg/promlib/go.sum | 12 +- pkg/storage/unified/search/bleve_test.go | 1 - pkg/util/testutil/context_test.go | 2 - 13 files changed, 281 insertions(+), 1331 deletions(-) diff --git a/apps/advisor/go.mod b/apps/advisor/go.mod index a45fa8d0423..da70ceca234 100644 --- a/apps/advisor/go.mod +++ b/apps/advisor/go.mod @@ -180,7 +180,7 @@ require ( github.com/jessevdk/go-flags v1.6.1 // indirect github.com/jmespath-community/go-jmespath v1.1.1 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect - github.com/jmoiron/sqlx v1.3.5 // indirect + github.com/jmoiron/sqlx v1.4.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/jpillora/backoff v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect @@ -324,5 +324,5 @@ require ( sigs.k8s.io/randfill v1.0.0 // indirect sigs.k8s.io/structured-merge-diff/v6 v6.3.0 // indirect sigs.k8s.io/yaml v1.6.0 // indirect - xorm.io/builder v0.3.6 // indirect + xorm.io/builder v0.3.13 // indirect ) diff --git a/apps/advisor/go.sum b/apps/advisor/go.sum index 340f046aed0..89d9baaa4b4 100644 --- a/apps/advisor/go.sum +++ b/apps/advisor/go.sum @@ -32,10 +32,10 @@ cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A= -cloud.google.com/go v0.121.1 h1:S3kTQSydxmu1JfLRLpKtxRPA7rSrYPRPEUmL/PavVUw= -cloud.google.com/go v0.121.1/go.mod h1:nRFlrHq39MNVWu+zESP2PosMWA0ryJw8KUBZ2iZpxbw= -cloud.google.com/go/auth v0.16.1 h1:XrXauHMd30LhQYVRHLGvJiYeczweKQXZxsTbV9TiguU= -cloud.google.com/go/auth v0.16.1/go.mod h1:1howDHJ5IETh/LwYs3ZxvlkXF48aSqqJUM+5o02dNOI= +cloud.google.com/go v0.121.4 h1:cVvUiY0sX0xwyxPwdSU2KsF9knOVmtRyAMt8xou0iTs= +cloud.google.com/go v0.121.4/go.mod h1:XEBchUiHFJbz4lKBZwYBDHV/rSyfFktk737TLDU089s= +cloud.google.com/go/auth v0.16.3 h1:kabzoQ9/bobUmnseYnBO6qQG7q4a/CffFRlJSxv2wCc= +cloud.google.com/go/auth v0.16.3/go.mod h1:NucRGjaXfzP1ltpcQ7On/VTZ0H4kWB5Jy+Y9Dnm76fA= cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc= cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= @@ -77,6 +77,8 @@ dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= 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/Azure/azure-sdk-for-go v68.0.0+incompatible h1:fcYLmCpyNYRnvJbPerq7U0hS+6+I79yEDJBqVNcqUzU= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.19.1 h1:5YTBM8QDVIBN3sxBil89WfdAAqDZbyJTgh688DSxX5w= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.19.1/go.mod h1:YD5h/ldMsG0XiIw7PdyNhLxaM317eFh5yNLccNfGdyw= @@ -107,10 +109,10 @@ github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.29.0 h1:UQUsRi8WTzhZntp5313l+CHIAT95ojUI2lpP/ExlZa4= github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.29.0/go.mod h1:Cz6ft6Dkn3Et6l2v2a9/RpN7epQ1GtDlO6lj8bEcOvw= -github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.51.0 h1:fYE9p3esPxA/C0rQ0AHhP0drtPXDRhaWiwg1DPqO7IU= -github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.51.0/go.mod h1:BnBReJLvVYx2CS/UHOgVz2BXKXD9wsQPxZug20nZhd0= -github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.51.0 h1:6/0iUd0xrnX7qt+mLNRwg5c0PGv8wpE8K90ryANQwMI= -github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.51.0/go.mod h1:otE2jQekW/PqXk1Awf5lmfokJx4uwuqcj1ab5SpGeW0= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.53.0 h1:owcC2UnmsZycprQ5RfRgjydWhuoxg71LUfyiQdijZuM= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.53.0/go.mod h1:ZPpqegjbE99EPKsu3iUWV22A04wzGPcAY/ziSIQEEgs= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.53.0 h1:Ron4zCA/yk6U7WOBXhTJcDpsUBG9npumK6xw2auFltQ= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.53.0/go.mod h1:cSgYe11MCNYunTnRXrKiR/tHc0eoKjICUuWpNZoVCOo= github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= @@ -181,26 +183,26 @@ github.com/aws/aws-sdk-go-v2/credentials v1.18.6 h1:AmmvNEYrru7sYNJnp3pf57lGbiar github.com/aws/aws-sdk-go-v2/credentials v1.18.6/go.mod h1:/jdQkh1iVPa01xndfECInp1v1Wnp70v3K4MvtlLGVEc= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.4 h1:lpdMwTzmuDLkgW7086jE94HweHCqG+uOJwHf3LZs7T0= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.4/go.mod h1:9xzb8/SV62W6gHQGC/8rrvgNXU6ZoYM3sAIJCIrXJxY= -github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.69 h1:6VFPH/Zi9xYFMJKPQOX5URYkQoXRWeJ7V/7Y6ZDYoms= -github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.69/go.mod h1:GJj8mmO6YT6EqgduWocwhMoxTLFitkhIrK+owzrYL2I= +github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.84 h1:cTXRdLkpBanlDwISl+5chq5ui1d1YWg4PWMR9c3kXyw= +github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.84/go.mod h1:kwSy5X7tfIHN39uucmjQVs2LvDdXEjQucgQQEqCggEo= github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.4 h1:IdCLsiiIj5YJ3AFevsewURCPV+YWUlOW8JiPhoAy8vg= github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.4/go.mod h1:l4bdfCD7XyyZA9BolKBo1eLqgaJxl0/x91PL4Yqe0ao= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.4 h1:j7vjtr1YIssWQOMeOWRbh3z8g2oY/xPjnZH2gLY4sGw= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.4/go.mod h1:yDmJgqOiH4EA8Hndnv4KwAo8jCGTSnM5ASG1nBI+toA= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 h1:bIqFDwgGXXN1Kpp99pDOdKMTTb5d2KyU5X/BZxjOkRo= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3/go.mod h1:H5O/EsxDWyU+LP/V8i5sm8cxoZgc2fdNR9bxlOFrQTo= -github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.34 h1:ZNTqv4nIdE/DiBfUUfXcLZ/Spcuz+RjeziUtNJackkM= -github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.34/go.mod h1:zf7Vcd1ViW7cPqYWEHLHJkS50X0JS2IKz9Cgaj6ugrs= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.36 h1:GMYy2EOWfzdP3wfVAGXBNKY5vK4K8vMET4sYOYltmqs= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.36/go.mod h1:gDhdAV6wL3PmPqBhiPbnlS447GoWs8HTTOYef9/9Inw= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.0 h1:6+lZi2JeGKtCraAj1rpoZfKqnQ9SptseRZioejfUOLM= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.0/go.mod h1:eb3gfbVIxIoGgJsi9pGne19dhCBpK6opTYpQqAmdy44= -github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.7.0 h1:lguz0bmOoGzozP9XfRJR1QIayEYo+2vP/No3OfLF0pU= -github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.7.0/go.mod h1:iu6FSzgt+M2/x3Dk8zhycdIcHjEFb36IS8HVUVFoMg0= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.7.4 h1:nAP2GYbfh8dd2zGZqFRSMlq+/F6cMPBUuCsGAMkN074= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.7.4/go.mod h1:LT10DsiGjLWh4GbjInf9LQejkYEhBgBCjLG5+lvk4EE= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.4 h1:ueB2Te0NacDMnaC+68za9jLwkjzxGWm0KB5HTUHjLTI= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.4/go.mod h1:nLEfLnVMmLvyIG58/6gsSA03F1voKGaCfHV7+lR8S7s= -github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.15 h1:moLQUoVq91LiqT1nbvzDukyqAlCv89ZmwaHw/ZFlFZg= -github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.15/go.mod h1:ZH34PJUc8ApjBIfgQCFvkWcUDBtl/WTD+uiYHjd8igA= -github.com/aws/aws-sdk-go-v2/service/s3 v1.78.2 h1:jIiopHEV22b4yQP2q36Y0OmwLbsxNWdWwfZRR5QRRO4= -github.com/aws/aws-sdk-go-v2/service/s3 v1.78.2/go.mod h1:U5SNqwhXB3Xe6F47kXvWihPl/ilGaEDe8HD/50Z9wxc= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.17 h1:qcLWgdhq45sDM9na4cvXax9dyLitn8EYBRl8Ak4XtG4= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.17/go.mod h1:M+jkjBFZ2J6DJrjMv2+vkBbuht6kxJYtJiwoVgX4p4U= +github.com/aws/aws-sdk-go-v2/service/s3 v1.84.0 h1:0reDqfEN+tB+sozj2r92Bep8MEwBZgtAXTND1Kk9OXg= +github.com/aws/aws-sdk-go-v2/service/s3 v1.84.0/go.mod h1:kUklwasNoCn5YpyAqC/97r6dzTA1SRKJfKq16SXeoDU= github.com/aws/aws-sdk-go-v2/service/sso v1.28.2 h1:ve9dYBB8CfJGTFqcQ3ZLAAb/KXWgYlgu/2R2TZL2Ko0= github.com/aws/aws-sdk-go-v2/service/sso v1.28.2/go.mod h1:n9bTZFZcBa9hGGqVz3i/a6+NG0zmZgtkB9qVVFDqPA8= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.33.2 h1:pd9G9HQaM6UZAZh19pYOkpKSQkyQQ9ftnl/LttQOcGI= @@ -506,7 +508,7 @@ github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTM github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= -github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= github.com/go-sql-driver/mysql v1.9.3 h1:U/N249h2WzJ3Ukj8SowVFjdtZKfu9vlLZxjPXV1aweo= github.com/go-sql-driver/mysql v1.9.3/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= @@ -518,8 +520,6 @@ github.com/go-test/deep v1.1.1 h1:0r/53hagsehfO4bzD2Pgr/+RgHqhmf+k1Bpse2cTu1U= github.com/go-test/deep v1.1.1/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= -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/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= @@ -551,8 +551,6 @@ github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4er github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ= -github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= @@ -659,8 +657,8 @@ github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0 github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM= github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM= github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c= -github.com/googleapis/gax-go/v2 v2.14.2 h1:eBLnkZ9635krYIPD+ag1USrOAI0Nr0QYF3+/3GqO0k0= -github.com/googleapis/gax-go/v2 v2.14.2/go.mod h1:ON64QhlJkhVtSqp4v1uaK92VyZ2gmvDQsweuyLV+8+w= +github.com/googleapis/gax-go/v2 v2.15.0 h1:SyjDc1mGgZU5LncH8gimWo9lW1DtIfPibOG81vgd/bo= +github.com/googleapis/gax-go/v2 v2.15.0/go.mod h1:zVVkkxAQHa1RQpg9z2AUCMnKhi0Qld9rcmyfL1OZhoc= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g= @@ -811,8 +809,8 @@ github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9Y github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= -github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g= -github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ= +github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o= +github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY= 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/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= @@ -907,6 +905,7 @@ github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6T github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= +github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/mattn/go-sqlite3 v1.14.32 h1:JD12Ag3oLy1zQA+BNn74xRgaBbdhbNIDYvQUEuuErjs= github.com/mattn/go-sqlite3 v1.14.32/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= @@ -1253,14 +1252,12 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= -go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= -go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= go.opentelemetry.io/contrib/bridges/prometheus v0.61.0 h1:RyrtJzu5MAmIcbRrwg75b+w3RlZCP0vJByDVzcpAe3M= go.opentelemetry.io/contrib/bridges/prometheus v0.61.0/go.mod h1:tirr4p9NXbzjlbruiRGp53IzlYrDk5CO2fdHj0sSSaY= -go.opentelemetry.io/contrib/detectors/gcp v1.36.0 h1:F7q2tNlCaHY9nMKHR6XH9/qkp8FktLnIcy6jJNyOCQw= -go.opentelemetry.io/contrib/detectors/gcp v1.36.0/go.mod h1:IbBN8uAIIx734PTonTPxAxnjc2pQTxWNkwfstZ+6H2k= +go.opentelemetry.io/contrib/detectors/gcp v1.37.0 h1:B+WbN9RPsvobe6q4vP6KgM8/9plR/HNjgGBrfcOlweA= +go.opentelemetry.io/contrib/detectors/gcp v1.37.0/go.mod h1:K5zQ3TT7p2ru9Qkzk0bKtCql0RGkPj9pRjpXgZJZ+rU= go.opentelemetry.io/contrib/exporters/autoexport v0.61.0 h1:XfzKtKSrbtYk9TNCF8dkO0Y9M7IOfb4idCwBOTwGBiI= go.opentelemetry.io/contrib/exporters/autoexport v0.61.0/go.mod h1:N6otC+qXTD5bAnbK2O1f/1SXq3cX+3KYSWrkBUqG0cw= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 h1:YH4g8lQroajqUwWbq/tr2QX1JFmEXaDLgG+ew9bLMWo= @@ -1296,8 +1293,8 @@ go.opentelemetry.io/otel/exporters/prometheus v0.59.0 h1:HHf+wKS6o5++XZhS98wvILr go.opentelemetry.io/otel/exporters/prometheus v0.59.0/go.mod h1:R8GpRXTZrqvXHDEGVH5bF6+JqAZcK8PjJcZ5nGhEWiE= go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.12.2 h1:12vMqzLLNZtXuXbJhSENRg+Vvx+ynNilV8twBLBsXMY= go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.12.2/go.mod h1:ZccPZoPOoq8x3Trik/fCsba7DEYDUnN6yX79pgp2BUQ= -go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.36.0 h1:rixTyDGXFxRy1xzhKrotaHy3/KXdPhlWARrCgK+eqUY= -go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.36.0/go.mod h1:dowW6UsM9MKbJq5JTz2AMVp3/5iW5I/TStsk8S+CfHw= +go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.37.0 h1:6VjV6Et+1Hd2iLZEPtdV7vie80Yyqf7oikJLjQ/myi0= +go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.37.0/go.mod h1:u8hcp8ji5gaM/RfcOo8z9NMnf1pVLfVY7lBY2VOGuUU= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0 h1:kJxSDN4SgWWTjG/hPp3O7LCGLcHXFlvS2/FFOrwL+SE= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0/go.mod h1:mgIOzS7iZeKJdeB8/NYHrJ48fdGc71Llo5bJ1J4DWUE= go.opentelemetry.io/otel/log v0.12.2 h1:yob9JVHn2ZY24byZeaXpTVoPS6l+UrrxmxmPKohXTwc= @@ -1335,8 +1332,8 @@ go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0= go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= -gocloud.dev v0.42.0 h1:qzG+9ItUL3RPB62/Amugws28n+4vGZXEoJEAMfjutzw= -gocloud.dev v0.42.0/go.mod h1:zkaYAapZfQisXOA4bzhsbA4ckiStGQ3Psvs9/OQ5dPM= +gocloud.dev v0.43.0 h1:aW3eq4RMyehbJ54PMsh4hsp7iX8cO/98ZRzJJOzN/5M= +gocloud.dev v0.43.0/go.mod h1:eD8rkg7LhKUHrzkEdLTZ+Ty/vgPHPCd+yMQdfelQVu4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= @@ -1712,8 +1709,8 @@ google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRR google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw= google.golang.org/api v0.81.0/go.mod h1:FA6Mb/bZxj706H2j+j2d6mHEEaHBmbbWnkfvmorOCko= -google.golang.org/api v0.235.0 h1:C3MkpQSRxS1Jy6AkzTGKKrpSCOd2WOGrezZ+icKSkKo= -google.golang.org/api v0.235.0/go.mod h1:QpeJkemzkFKe5VCE/PMv7GsUfn9ZF+u+q1Q7w6ckxTg= +google.golang.org/api v0.242.0 h1:7Lnb1nfnpvbkCiZek6IXKdJ0MFuAZNAJKQfA1ws62xg= +google.golang.org/api v0.242.0/go.mod h1:cOVEm2TpdAGHL2z+UwyS+kmlGr3bVWQQ6sYEqkKje50= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -1801,8 +1798,8 @@ google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= -google.golang.org/genproto v0.0.0-20250603155806-513f23925822 h1:rHWScKit0gvAPuOnu87KpaYtjK5zBMLcULh7gxkCXu4= -google.golang.org/genproto v0.0.0-20250603155806-513f23925822/go.mod h1:HubltRL7rMh0LfnQPkMH4NPDFEWp0jw3vixw7jEM53s= +google.golang.org/genproto v0.0.0-20250715232539-7130f93afb79 h1:Nt6z9UHqSlIdIGJdz6KhTIs2VRx/iOsA5iE8bmQNcxs= +google.golang.org/genproto v0.0.0-20250715232539-7130f93afb79/go.mod h1:kTmlBHMPqR5uCZPBvwa2B18mvubkjyY3CRLI0c6fj0s= google.golang.org/genproto/googleapis/api v0.0.0-20250908214217-97024824d090 h1:d8Nakh1G+ur7+P3GcMjpRDEkoLUcLW2iU92XVqR+XMQ= google.golang.org/genproto/googleapis/api v0.0.0-20250908214217-97024824d090/go.mod h1:U8EXRNSd8sUYyDfs/It7KVWodQr+Hf9xtxyxWudSwEw= google.golang.org/genproto/googleapis/rpc v0.0.0-20251002232023-7c0ddcbb5797 h1:CirRxTOwnRWVLKzDNrs0CXAaVozJoR4G9xvdRecrdpk= @@ -1966,5 +1963,5 @@ sigs.k8s.io/structured-merge-diff/v6 v6.3.0/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099Yo sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= -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= diff --git a/apps/iam/go.mod b/apps/iam/go.mod index 63dae42947a..154a6bb0632 100644 --- a/apps/iam/go.mod +++ b/apps/iam/go.mod @@ -59,8 +59,8 @@ require ( require ( cel.dev/expr v0.24.0 // indirect - cloud.google.com/go v0.121.1 // indirect - cloud.google.com/go/auth v0.16.1 // indirect + cloud.google.com/go v0.121.4 // indirect + cloud.google.com/go/auth v0.16.3 // indirect cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect cloud.google.com/go/compute/metadata v0.7.0 // indirect cloud.google.com/go/iam v1.5.2 // indirect @@ -79,8 +79,8 @@ require ( github.com/AzureAD/microsoft-authentication-library-for-go v1.5.0 // indirect github.com/BurntSushi/toml v1.5.0 // indirect github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.29.0 // indirect - github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.51.0 // indirect - github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.51.0 // indirect + github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.53.0 // indirect + github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.53.0 // indirect github.com/HdrHistogram/hdrhistogram-go v1.1.2 // indirect github.com/Masterminds/goutils v1.1.1 // indirect github.com/Masterminds/semver v1.5.0 // indirect @@ -105,16 +105,16 @@ require ( github.com/aws/aws-sdk-go-v2/config v1.31.2 // indirect github.com/aws/aws-sdk-go-v2/credentials v1.18.6 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.4 // indirect - github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.69 // indirect + github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.84 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.4 // indirect github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.4 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 // indirect - github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.34 // indirect + github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.36 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.0 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.7.0 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.7.4 // indirect github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.4 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.15 // indirect - github.com/aws/aws-sdk-go-v2/service/s3 v1.78.2 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.17 // indirect + github.com/aws/aws-sdk-go-v2/service/s3 v1.84.0 // indirect github.com/aws/aws-sdk-go-v2/service/sso v1.28.2 // indirect github.com/aws/aws-sdk-go-v2/service/ssooidc v1.33.2 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.38.0 // indirect @@ -216,7 +216,6 @@ require ( github.com/golang-jwt/jwt/v4 v4.5.2 // indirect github.com/golang-jwt/jwt/v5 v5.3.0 // indirect github.com/golang-migrate/migrate/v4 v4.7.0 // indirect - github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/golang/snappy v1.0.0 // indirect github.com/google/btree v1.1.3 // indirect @@ -229,7 +228,7 @@ require ( github.com/google/uuid v1.6.0 // indirect github.com/google/wire v0.7.0 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect - github.com/googleapis/gax-go/v2 v2.14.2 // indirect + github.com/googleapis/gax-go/v2 v2.15.0 // indirect github.com/gorilla/mux v1.8.1 // indirect github.com/grafana/alerting v0.0.0-20251009192429-9427c24835ae // indirect github.com/grafana/authlib v0.0.0-20250930082137-a40e2c2b094f // indirect @@ -284,7 +283,7 @@ require ( github.com/jhump/protoreflect v1.17.0 // indirect github.com/jmespath-community/go-jmespath v1.1.1 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect - github.com/jmoiron/sqlx v1.3.5 // indirect + github.com/jmoiron/sqlx v1.4.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/jpillora/backoff v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect @@ -399,10 +398,9 @@ require ( go.etcd.io/etcd/client/pkg/v3 v3.6.4 // indirect go.etcd.io/etcd/client/v3 v3.6.4 // indirect go.mongodb.org/mongo-driver v1.17.4 // indirect - go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect go.opentelemetry.io/contrib/bridges/prometheus v0.61.0 // indirect - go.opentelemetry.io/contrib/detectors/gcp v1.36.0 // indirect + go.opentelemetry.io/contrib/detectors/gcp v1.37.0 // indirect go.opentelemetry.io/contrib/exporters/autoexport v0.61.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.63.0 // indirect @@ -419,7 +417,7 @@ require ( go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 // indirect go.opentelemetry.io/otel/exporters/prometheus v0.59.0 // indirect go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.12.2 // indirect - go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.36.0 // indirect + go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.37.0 // indirect go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0 // indirect go.opentelemetry.io/otel/log v0.12.2 // indirect go.opentelemetry.io/otel/metric v1.38.0 // indirect @@ -433,7 +431,7 @@ require ( go.uber.org/zap v1.27.0 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect - gocloud.dev v0.42.0 // indirect + gocloud.dev v0.43.0 // indirect golang.org/x/crypto v0.43.0 // indirect golang.org/x/exp v0.0.0-20251002181428-27f1f14c8bb9 // indirect golang.org/x/mod v0.29.0 // indirect @@ -449,8 +447,8 @@ require ( golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect gonum.org/v1/gonum v0.16.0 // indirect - google.golang.org/api v0.235.0 // indirect - google.golang.org/genproto v0.0.0-20250603155806-513f23925822 // indirect + google.golang.org/api v0.242.0 // indirect + google.golang.org/genproto v0.0.0-20250715232539-7130f93afb79 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250908214217-97024824d090 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20251002232023-7c0ddcbb5797 // indirect google.golang.org/grpc v1.76.0 // indirect @@ -483,5 +481,5 @@ require ( sigs.k8s.io/randfill v1.0.0 // indirect sigs.k8s.io/structured-merge-diff/v6 v6.3.0 // indirect sigs.k8s.io/yaml v1.6.0 // indirect - xorm.io/builder v0.3.6 // indirect + xorm.io/builder v0.3.13 // indirect ) diff --git a/apps/iam/go.sum b/apps/iam/go.sum index 8709ea21e9e..ad77e3a1a30 100644 --- a/apps/iam/go.sum +++ b/apps/iam/go.sum @@ -36,10 +36,10 @@ cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A= -cloud.google.com/go v0.121.1 h1:S3kTQSydxmu1JfLRLpKtxRPA7rSrYPRPEUmL/PavVUw= -cloud.google.com/go v0.121.1/go.mod h1:nRFlrHq39MNVWu+zESP2PosMWA0ryJw8KUBZ2iZpxbw= -cloud.google.com/go/auth v0.16.1 h1:XrXauHMd30LhQYVRHLGvJiYeczweKQXZxsTbV9TiguU= -cloud.google.com/go/auth v0.16.1/go.mod h1:1howDHJ5IETh/LwYs3ZxvlkXF48aSqqJUM+5o02dNOI= +cloud.google.com/go v0.121.4 h1:cVvUiY0sX0xwyxPwdSU2KsF9knOVmtRyAMt8xou0iTs= +cloud.google.com/go v0.121.4/go.mod h1:XEBchUiHFJbz4lKBZwYBDHV/rSyfFktk737TLDU089s= +cloud.google.com/go/auth v0.16.3 h1:kabzoQ9/bobUmnseYnBO6qQG7q4a/CffFRlJSxv2wCc= +cloud.google.com/go/auth v0.16.3/go.mod h1:NucRGjaXfzP1ltpcQ7On/VTZ0H4kWB5Jy+Y9Dnm76fA= cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc= cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= @@ -95,6 +95,8 @@ filippo.io/age v1.2.1 h1:X0TZjehAZylOIj4DubWYU1vWQxv9bJpo+Uu2/LGhi1o= filippo.io/age v1.2.1/go.mod h1:JL9ew2lTN+Pyft4RiNGguFfOpewKwSHm5ayKD/A4004= 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/1NCE-GmbH/grpc-go-pool v0.0.0-20231117122434-2a5bb974daa2 h1:qFYgLH2zZe3WHpQgUrzeazC+ebDebwAQqS9yE1cP5Bs= github.com/1NCE-GmbH/grpc-go-pool v0.0.0-20231117122434-2a5bb974daa2/go.mod h1:09/ALd1AXCTCOfcJYD8+jIYKmFmi6PVCkTsipC18F7E= github.com/Azure/azure-pipeline-go v0.2.3 h1:7U9HBg1JFK3jHl5qmo4CTZKFTVgMwdFHMVtCdfBE21U= @@ -151,12 +153,12 @@ github.com/FZambia/eagle v0.2.0 h1:1kQaZpJvbkvAXFRE/9K2ucBMuVqo+E29EMLYB74hIis= github.com/FZambia/eagle v0.2.0/go.mod h1:LKMYBwGYhao5sJI0TppvQ4SvvldFj9gITxrl8NvGwG0= github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.29.0 h1:UQUsRi8WTzhZntp5313l+CHIAT95ojUI2lpP/ExlZa4= github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.29.0/go.mod h1:Cz6ft6Dkn3Et6l2v2a9/RpN7epQ1GtDlO6lj8bEcOvw= -github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.51.0 h1:fYE9p3esPxA/C0rQ0AHhP0drtPXDRhaWiwg1DPqO7IU= -github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.51.0/go.mod h1:BnBReJLvVYx2CS/UHOgVz2BXKXD9wsQPxZug20nZhd0= -github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.51.0 h1:OqVGm6Ei3x5+yZmSJG1Mh2NwHvpVmZ08CB5qJhT9Nuk= -github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.51.0/go.mod h1:SZiPHWGOOk3bl8tkevxkoiwPgsIl6CwrWcbwjfHZpdM= -github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.51.0 h1:6/0iUd0xrnX7qt+mLNRwg5c0PGv8wpE8K90ryANQwMI= -github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.51.0/go.mod h1:otE2jQekW/PqXk1Awf5lmfokJx4uwuqcj1ab5SpGeW0= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.53.0 h1:owcC2UnmsZycprQ5RfRgjydWhuoxg71LUfyiQdijZuM= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.53.0/go.mod h1:ZPpqegjbE99EPKsu3iUWV22A04wzGPcAY/ziSIQEEgs= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.53.0 h1:4LP6hvB4I5ouTbGgWtixJhgED6xdf67twf9PoY96Tbg= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.53.0/go.mod h1:jUZ5LYlw40WMd07qxcQJD5M40aUxrfwqQX1g7zxYnrQ= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.53.0 h1:Ron4zCA/yk6U7WOBXhTJcDpsUBG9npumK6xw2auFltQ= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.53.0/go.mod h1:cSgYe11MCNYunTnRXrKiR/tHc0eoKjICUuWpNZoVCOo= github.com/HdrHistogram/hdrhistogram-go v1.1.2 h1:5IcZpTvzydCQeHzK4Ef/D5rrSqwxob0t8PQPMybUNFM= github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo= github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= @@ -243,16 +245,16 @@ github.com/aws/aws-sdk-go-v2/credentials v1.18.6 h1:AmmvNEYrru7sYNJnp3pf57lGbiar github.com/aws/aws-sdk-go-v2/credentials v1.18.6/go.mod h1:/jdQkh1iVPa01xndfECInp1v1Wnp70v3K4MvtlLGVEc= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.4 h1:lpdMwTzmuDLkgW7086jE94HweHCqG+uOJwHf3LZs7T0= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.4/go.mod h1:9xzb8/SV62W6gHQGC/8rrvgNXU6ZoYM3sAIJCIrXJxY= -github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.69 h1:6VFPH/Zi9xYFMJKPQOX5URYkQoXRWeJ7V/7Y6ZDYoms= -github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.69/go.mod h1:GJj8mmO6YT6EqgduWocwhMoxTLFitkhIrK+owzrYL2I= +github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.84 h1:cTXRdLkpBanlDwISl+5chq5ui1d1YWg4PWMR9c3kXyw= +github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.84/go.mod h1:kwSy5X7tfIHN39uucmjQVs2LvDdXEjQucgQQEqCggEo= github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.4 h1:IdCLsiiIj5YJ3AFevsewURCPV+YWUlOW8JiPhoAy8vg= github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.4/go.mod h1:l4bdfCD7XyyZA9BolKBo1eLqgaJxl0/x91PL4Yqe0ao= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.4 h1:j7vjtr1YIssWQOMeOWRbh3z8g2oY/xPjnZH2gLY4sGw= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.4/go.mod h1:yDmJgqOiH4EA8Hndnv4KwAo8jCGTSnM5ASG1nBI+toA= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 h1:bIqFDwgGXXN1Kpp99pDOdKMTTb5d2KyU5X/BZxjOkRo= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3/go.mod h1:H5O/EsxDWyU+LP/V8i5sm8cxoZgc2fdNR9bxlOFrQTo= -github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.34 h1:ZNTqv4nIdE/DiBfUUfXcLZ/Spcuz+RjeziUtNJackkM= -github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.34/go.mod h1:zf7Vcd1ViW7cPqYWEHLHJkS50X0JS2IKz9Cgaj6ugrs= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.36 h1:GMYy2EOWfzdP3wfVAGXBNKY5vK4K8vMET4sYOYltmqs= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.36/go.mod h1:gDhdAV6wL3PmPqBhiPbnlS447GoWs8HTTOYef9/9Inw= github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.45.3 h1:Nn3qce+OHZuMj/edx4its32uxedAmquCDxtZkrdeiD4= github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.45.3/go.mod h1:aqsLGsPs+rJfwDBwWHLcIV8F7AFcikFTPLwUD4RwORQ= github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs v1.51.0 h1:e5cbPZYTIY2nUEFieZUfVdINOiCTvChOMPfdLnmiLzs= @@ -261,20 +263,20 @@ github.com/aws/aws-sdk-go-v2/service/ec2 v1.225.2 h1:IfMb3Ar8xEaWjgH/zeVHYD8izwJ github.com/aws/aws-sdk-go-v2/service/ec2 v1.225.2/go.mod h1:35jGWx7ECvCwTsApqicFYzZ7JFEnBc6oHUuOQ3xIS54= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.0 h1:6+lZi2JeGKtCraAj1rpoZfKqnQ9SptseRZioejfUOLM= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.0/go.mod h1:eb3gfbVIxIoGgJsi9pGne19dhCBpK6opTYpQqAmdy44= -github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.7.0 h1:lguz0bmOoGzozP9XfRJR1QIayEYo+2vP/No3OfLF0pU= -github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.7.0/go.mod h1:iu6FSzgt+M2/x3Dk8zhycdIcHjEFb36IS8HVUVFoMg0= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.7.4 h1:nAP2GYbfh8dd2zGZqFRSMlq+/F6cMPBUuCsGAMkN074= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.7.4/go.mod h1:LT10DsiGjLWh4GbjInf9LQejkYEhBgBCjLG5+lvk4EE= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.4 h1:ueB2Te0NacDMnaC+68za9jLwkjzxGWm0KB5HTUHjLTI= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.4/go.mod h1:nLEfLnVMmLvyIG58/6gsSA03F1voKGaCfHV7+lR8S7s= -github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.15 h1:moLQUoVq91LiqT1nbvzDukyqAlCv89ZmwaHw/ZFlFZg= -github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.15/go.mod h1:ZH34PJUc8ApjBIfgQCFvkWcUDBtl/WTD+uiYHjd8igA= -github.com/aws/aws-sdk-go-v2/service/kms v1.38.1 h1:tecq7+mAav5byF+Mr+iONJnCBf4B4gon8RSp4BrweSc= -github.com/aws/aws-sdk-go-v2/service/kms v1.38.1/go.mod h1:cQn6tAF77Di6m4huxovNM7NVAozWTZLsDRp9t8Z/WYk= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.17 h1:qcLWgdhq45sDM9na4cvXax9dyLitn8EYBRl8Ak4XtG4= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.17/go.mod h1:M+jkjBFZ2J6DJrjMv2+vkBbuht6kxJYtJiwoVgX4p4U= +github.com/aws/aws-sdk-go-v2/service/kms v1.41.2 h1:zJeUxFP7+XP52u23vrp4zMcVhShTWbNO8dHV6xCSvFo= +github.com/aws/aws-sdk-go-v2/service/kms v1.41.2/go.mod h1:Pqd9k4TuespkireN206cK2QBsaBTL6X+VPAez5Qcijk= github.com/aws/aws-sdk-go-v2/service/oam v1.18.3 h1:teOWtElLARLOhpYWwupjLbY9j5I/yZ/H1I8jg41An78= github.com/aws/aws-sdk-go-v2/service/oam v1.18.3/go.mod h1:wGhpdyftHX6/1U4egowHkYdypwBMjpb+KjAAprv6z20= github.com/aws/aws-sdk-go-v2/service/resourcegroupstaggingapi v1.26.6 h1:PwbxovpcJvb25k019bkibvJfCpCmIANOFrXZIFPmRzk= github.com/aws/aws-sdk-go-v2/service/resourcegroupstaggingapi v1.26.6/go.mod h1:Z4xLt5mXspLKjBV92i165wAJ/3T6TIv4n7RtIS8pWV0= -github.com/aws/aws-sdk-go-v2/service/s3 v1.78.2 h1:jIiopHEV22b4yQP2q36Y0OmwLbsxNWdWwfZRR5QRRO4= -github.com/aws/aws-sdk-go-v2/service/s3 v1.78.2/go.mod h1:U5SNqwhXB3Xe6F47kXvWihPl/ilGaEDe8HD/50Z9wxc= +github.com/aws/aws-sdk-go-v2/service/s3 v1.84.0 h1:0reDqfEN+tB+sozj2r92Bep8MEwBZgtAXTND1Kk9OXg= +github.com/aws/aws-sdk-go-v2/service/s3 v1.84.0/go.mod h1:kUklwasNoCn5YpyAqC/97r6dzTA1SRKJfKq16SXeoDU= github.com/aws/aws-sdk-go-v2/service/sso v1.28.2 h1:ve9dYBB8CfJGTFqcQ3ZLAAb/KXWgYlgu/2R2TZL2Ko0= github.com/aws/aws-sdk-go-v2/service/sso v1.28.2/go.mod h1:n9bTZFZcBa9hGGqVz3i/a6+NG0zmZgtkB9qVVFDqPA8= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.33.2 h1:pd9G9HQaM6UZAZh19pYOkpKSQkyQQ9ftnl/LttQOcGI= @@ -644,7 +646,7 @@ github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq github.com/go-sourcemap/sourcemap v2.1.4+incompatible h1:a+iTbH5auLKxaNwQFg0B+TCYl6lbukKPc7b5x0n1s6Q= github.com/go-sourcemap/sourcemap v2.1.4+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= -github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= github.com/go-sql-driver/mysql v1.9.3 h1:U/N249h2WzJ3Ukj8SowVFjdtZKfu9vlLZxjPXV1aweo= github.com/go-sql-driver/mysql v1.9.3/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= @@ -656,8 +658,6 @@ github.com/go-test/deep v1.1.1 h1:0r/53hagsehfO4bzD2Pgr/+RgHqhmf+k1Bpse2cTu1U= github.com/go-test/deep v1.1.1/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= -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/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= @@ -695,8 +695,6 @@ github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4er github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ= -github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= @@ -813,8 +811,8 @@ github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0 github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM= github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM= github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c= -github.com/googleapis/gax-go/v2 v2.14.2 h1:eBLnkZ9635krYIPD+ag1USrOAI0Nr0QYF3+/3GqO0k0= -github.com/googleapis/gax-go/v2 v2.14.2/go.mod h1:ON64QhlJkhVtSqp4v1uaK92VyZ2gmvDQsweuyLV+8+w= +github.com/googleapis/gax-go/v2 v2.15.0 h1:SyjDc1mGgZU5LncH8gimWo9lW1DtIfPibOG81vgd/bo= +github.com/googleapis/gax-go/v2 v2.15.0/go.mod h1:zVVkkxAQHa1RQpg9z2AUCMnKhi0Qld9rcmyfL1OZhoc= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g= @@ -960,8 +958,9 @@ github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iP github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= -github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/hcl v1.0.1-vault-7 h1:ag5OxFVy3QYTFTJODRzTKVZ6xvdfLLCA1cy/Y6xGI0I= +github.com/hashicorp/hcl v1.0.1-vault-7/go.mod h1:XYhtn6ijBSAj6n4YqAaf7RBPS4I06AItNorpy+MoQNM= github.com/hashicorp/hcl/v2 v2.24.0 h1:2QJdZ454DSsYGoaE6QheQZjtKZSUs9Nh2izTWiwQxvE= github.com/hashicorp/hcl/v2 v2.24.0/go.mod h1:oGoO1FIQYfn/AgyOhlg9qLC6/nOJPX3qGbkZpYAcqfM= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= @@ -973,8 +972,8 @@ github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpT github.com/hashicorp/serf v0.9.7/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= github.com/hashicorp/serf v0.10.2 h1:m5IORhuNSjaxeljg5DeQVDlQyVkhRIjJDimbkCa8aAc= github.com/hashicorp/serf v0.10.2/go.mod h1:T1CmSGfSeGfnfNy/w0odXQUR1rfECGd2Qdsp84DjOiY= -github.com/hashicorp/vault/api v1.16.0 h1:nbEYGJiAPGzT9U4oWgaaB0g+Rj8E59QuHKyA5LhwQN4= -github.com/hashicorp/vault/api v1.16.0/go.mod h1:KhuUhzOD8lDSk29AtzNjgAu2kxRA9jL9NAbkFlqvkBA= +github.com/hashicorp/vault/api v1.20.0 h1:KQMHElgudOsr+IbJgmbjHnCTxEpKs9LnozA1D3nozU4= +github.com/hashicorp/vault/api v1.20.0/go.mod h1:GZ4pcjfzoOWpkJ3ijHNpEoAxKEsBJnVljyTe3jM2Sms= github.com/hashicorp/yamux v0.1.2 h1:XtB8kyFOyHXYVFnwT5C3+Bdo8gArse7j2AQ0DA0Uey8= github.com/hashicorp/yamux v0.1.2/go.mod h1:C+zze2n6e/7wshOZep2A70/aQU6QBRWJO/G6FT1wIns= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= @@ -1035,8 +1034,8 @@ github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9Y github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= -github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g= -github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ= +github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o= +github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY= github.com/jonboulle/clockwork v0.5.0 h1:Hyh9A8u51kptdkR+cqRpT1EebBwTn1oK9YfGYbdFz6I= github.com/jonboulle/clockwork v0.5.0/go.mod h1:3mZlmanh0g2NDKO5TWZVJAfofYk64M7XN3SzBPjZF60= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= @@ -1146,6 +1145,7 @@ github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6T github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= +github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/mattn/go-sqlite3 v1.14.32 h1:JD12Ag3oLy1zQA+BNn74xRgaBbdhbNIDYvQUEuuErjs= github.com/mattn/go-sqlite3 v1.14.32/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= @@ -1600,20 +1600,18 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= -go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= -go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= -go.opentelemetry.io/collector/featuregate v1.43.0 h1:Aq8UR5qv1zNlbbkTyqv8kLJtnoQMq/sG1/jS9o1cCJI= -go.opentelemetry.io/collector/featuregate v1.43.0/go.mod h1:d0tiRzVYrytB6LkcYgz2ESFTv7OktRPQe0QEQcPt1L4= -go.opentelemetry.io/collector/pdata v1.43.0 h1:zVkj2hcjiMLwX+QDDNwb7iTh3LBjNXKv2qPSgj1Rzb4= -go.opentelemetry.io/collector/pdata v1.43.0/go.mod h1:KsJzdDG9e5BaHlmYr0sqdSEKeEiSfKzoF+rdWU7J//w= +go.opentelemetry.io/collector/featuregate v1.44.0 h1:/GeGhTD8f+FNWS7C4w1Dj0Ui9Jp4v2WAdlXyW1p3uG8= +go.opentelemetry.io/collector/featuregate v1.44.0/go.mod h1:d0tiRzVYrytB6LkcYgz2ESFTv7OktRPQe0QEQcPt1L4= +go.opentelemetry.io/collector/pdata v1.44.0 h1:q/EfWDDKrSaf4hjTIzyPeg1ZcCRg1Uj7VTFnGfNVdk8= +go.opentelemetry.io/collector/pdata v1.44.0/go.mod h1:LnsjYysFc3AwMVh6KGNlkGKJUF2ReuWxtD9Hb3lSMZk= go.opentelemetry.io/collector/semconv v0.124.0 h1:YTdo3UFwNyDQCh9DiSm2rbzAgBuwn/9dNZ0rv454goA= go.opentelemetry.io/collector/semconv v0.124.0/go.mod h1:te6VQ4zZJO5Lp8dM2XIhDxDiL45mwX0YAQQWRQ0Qr9U= go.opentelemetry.io/contrib/bridges/prometheus v0.61.0 h1:RyrtJzu5MAmIcbRrwg75b+w3RlZCP0vJByDVzcpAe3M= go.opentelemetry.io/contrib/bridges/prometheus v0.61.0/go.mod h1:tirr4p9NXbzjlbruiRGp53IzlYrDk5CO2fdHj0sSSaY= -go.opentelemetry.io/contrib/detectors/gcp v1.36.0 h1:F7q2tNlCaHY9nMKHR6XH9/qkp8FktLnIcy6jJNyOCQw= -go.opentelemetry.io/contrib/detectors/gcp v1.36.0/go.mod h1:IbBN8uAIIx734PTonTPxAxnjc2pQTxWNkwfstZ+6H2k= +go.opentelemetry.io/contrib/detectors/gcp v1.37.0 h1:B+WbN9RPsvobe6q4vP6KgM8/9plR/HNjgGBrfcOlweA= +go.opentelemetry.io/contrib/detectors/gcp v1.37.0/go.mod h1:K5zQ3TT7p2ru9Qkzk0bKtCql0RGkPj9pRjpXgZJZ+rU= go.opentelemetry.io/contrib/exporters/autoexport v0.61.0 h1:XfzKtKSrbtYk9TNCF8dkO0Y9M7IOfb4idCwBOTwGBiI= go.opentelemetry.io/contrib/exporters/autoexport v0.61.0/go.mod h1:N6otC+qXTD5bAnbK2O1f/1SXq3cX+3KYSWrkBUqG0cw= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 h1:YH4g8lQroajqUwWbq/tr2QX1JFmEXaDLgG+ew9bLMWo= @@ -1649,8 +1647,8 @@ go.opentelemetry.io/otel/exporters/prometheus v0.59.0 h1:HHf+wKS6o5++XZhS98wvILr go.opentelemetry.io/otel/exporters/prometheus v0.59.0/go.mod h1:R8GpRXTZrqvXHDEGVH5bF6+JqAZcK8PjJcZ5nGhEWiE= go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.12.2 h1:12vMqzLLNZtXuXbJhSENRg+Vvx+ynNilV8twBLBsXMY= go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.12.2/go.mod h1:ZccPZoPOoq8x3Trik/fCsba7DEYDUnN6yX79pgp2BUQ= -go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.36.0 h1:rixTyDGXFxRy1xzhKrotaHy3/KXdPhlWARrCgK+eqUY= -go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.36.0/go.mod h1:dowW6UsM9MKbJq5JTz2AMVp3/5iW5I/TStsk8S+CfHw= +go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.37.0 h1:6VjV6Et+1Hd2iLZEPtdV7vie80Yyqf7oikJLjQ/myi0= +go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.37.0/go.mod h1:u8hcp8ji5gaM/RfcOo8z9NMnf1pVLfVY7lBY2VOGuUU= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0 h1:kJxSDN4SgWWTjG/hPp3O7LCGLcHXFlvS2/FFOrwL+SE= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0/go.mod h1:mgIOzS7iZeKJdeB8/NYHrJ48fdGc71Llo5bJ1J4DWUE= go.opentelemetry.io/otel/log v0.12.2 h1:yob9JVHn2ZY24byZeaXpTVoPS6l+UrrxmxmPKohXTwc= @@ -1694,10 +1692,10 @@ go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= go4.org/netipx v0.0.0-20230125063823-8449b0a6169f h1:ketMxHg+vWm3yccyYiq+uK8D3fRmna2Fcj+awpQp84s= go4.org/netipx v0.0.0-20230125063823-8449b0a6169f/go.mod h1:tgPU4N2u9RByaTN3NC2p9xOzyFpte4jYwsIIRF7XlSc= -gocloud.dev v0.42.0 h1:qzG+9ItUL3RPB62/Amugws28n+4vGZXEoJEAMfjutzw= -gocloud.dev v0.42.0/go.mod h1:zkaYAapZfQisXOA4bzhsbA4ckiStGQ3Psvs9/OQ5dPM= -gocloud.dev/secrets/hashivault v0.42.0 h1:kPWIIu1AP6ApHf7HwUrzGrwyRJEfTd46JNUNgnbpsFA= -gocloud.dev/secrets/hashivault v0.42.0/go.mod h1:LXprr1XLEAT7BVZ+Y66dJEHQMzDsowIExj5Ktr9HLvM= +gocloud.dev v0.43.0 h1:aW3eq4RMyehbJ54PMsh4hsp7iX8cO/98ZRzJJOzN/5M= +gocloud.dev v0.43.0/go.mod h1:eD8rkg7LhKUHrzkEdLTZ+Ty/vgPHPCd+yMQdfelQVu4= +gocloud.dev/secrets/hashivault v0.43.0 h1:A966rEMpCRUE9209/+k+A2HP2v2qDnrxGpQn+nIH5uY= +gocloud.dev/secrets/hashivault v0.43.0/go.mod h1:KdWKL+TXDi0cXgEd/MTeaidKlotvyJtnTDi71B3rR9U= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= @@ -2091,8 +2089,8 @@ google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRR google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw= google.golang.org/api v0.81.0/go.mod h1:FA6Mb/bZxj706H2j+j2d6mHEEaHBmbbWnkfvmorOCko= -google.golang.org/api v0.235.0 h1:C3MkpQSRxS1Jy6AkzTGKKrpSCOd2WOGrezZ+icKSkKo= -google.golang.org/api v0.235.0/go.mod h1:QpeJkemzkFKe5VCE/PMv7GsUfn9ZF+u+q1Q7w6ckxTg= +google.golang.org/api v0.242.0 h1:7Lnb1nfnpvbkCiZek6IXKdJ0MFuAZNAJKQfA1ws62xg= +google.golang.org/api v0.242.0/go.mod h1:cOVEm2TpdAGHL2z+UwyS+kmlGr3bVWQQ6sYEqkKje50= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -2182,8 +2180,8 @@ google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= -google.golang.org/genproto v0.0.0-20250603155806-513f23925822 h1:rHWScKit0gvAPuOnu87KpaYtjK5zBMLcULh7gxkCXu4= -google.golang.org/genproto v0.0.0-20250603155806-513f23925822/go.mod h1:HubltRL7rMh0LfnQPkMH4NPDFEWp0jw3vixw7jEM53s= +google.golang.org/genproto v0.0.0-20250715232539-7130f93afb79 h1:Nt6z9UHqSlIdIGJdz6KhTIs2VRx/iOsA5iE8bmQNcxs= +google.golang.org/genproto v0.0.0-20250715232539-7130f93afb79/go.mod h1:kTmlBHMPqR5uCZPBvwa2B18mvubkjyY3CRLI0c6fj0s= google.golang.org/genproto/googleapis/api v0.0.0-20250908214217-97024824d090 h1:d8Nakh1G+ur7+P3GcMjpRDEkoLUcLW2iU92XVqR+XMQ= google.golang.org/genproto/googleapis/api v0.0.0-20250908214217-97024824d090/go.mod h1:U8EXRNSd8sUYyDfs/It7KVWodQr+Hf9xtxyxWudSwEw= google.golang.org/genproto/googleapis/rpc v0.0.0-20251002232023-7c0ddcbb5797 h1:CirRxTOwnRWVLKzDNrs0CXAaVozJoR4G9xvdRecrdpk= @@ -2353,5 +2351,5 @@ sigs.k8s.io/structured-merge-diff/v6 v6.3.0/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099Yo sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= -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= diff --git a/go.mod b/go.mod index f909171526f..08ca8ca8112 100644 --- a/go.mod +++ b/go.mod @@ -83,7 +83,7 @@ require ( github.com/google/go-querystring v1.1.0 // indirect; @grafana/oss-big-tent github.com/google/uuid v1.6.0 // @grafana/grafana-backend-group github.com/google/wire v0.7.0 // @grafana/grafana-backend-group - github.com/googleapis/gax-go/v2 v2.14.2 // @grafana/grafana-backend-group + github.com/googleapis/gax-go/v2 v2.15.0 // @grafana/grafana-backend-group github.com/gorilla/mux v1.8.1 // @grafana/grafana-backend-group github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // @grafana/grafana-app-platform-squad github.com/grafana/alerting v0.0.0-20251009192429-9427c24835ae // @grafana/alerting-backend @@ -128,7 +128,7 @@ require ( github.com/jackc/pgx/v5 v5.7.6 // @grafana/grafana-search-and-storage github.com/jmespath-community/go-jmespath v1.1.1 // @grafana/identity-access-team github.com/jmespath/go-jmespath v0.4.0 // indirect; // @grafana/grafana-backend-group - github.com/jmoiron/sqlx v1.3.5 // @grafana/grafana-backend-group + github.com/jmoiron/sqlx v1.4.0 // @grafana/grafana-backend-group github.com/json-iterator/go v1.1.12 // @grafana/grafana-backend-group github.com/lib/pq v1.10.9 // @grafana/grafana-backend-group github.com/m3db/prometheus_remote_client_golang v0.4.4 // @grafana/grafana-backend-group @@ -175,13 +175,12 @@ require ( github.com/ua-parser/uap-go v0.0.0-20250213224047-9c035f085b90 // @grafana/grafana-backend-group github.com/urfave/cli v1.22.17 // indirect; @grafana/grafana-backend-group github.com/urfave/cli/v2 v2.27.7 // @grafana/grafana-backend-group - github.com/urfave/cli/v3 v3.4.1 // @grafana/grafana-backend-group + github.com/urfave/cli/v3 v3.5.0 // @grafana/grafana-backend-group github.com/wk8/go-ordered-map v1.0.0 // @grafana/grafana-backend-group github.com/xlab/treeprint v1.2.0 // @grafana/observability-traces-and-profiling github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // @grafana/grafana-operator-experience-squad github.com/yudai/gojsondiff v1.0.0 // @grafana/grafana-backend-group - go.opencensus.io v0.24.0 // @grafana/grafana-backend-group - go.opentelemetry.io/collector/pdata v1.43.0 // @grafana/grafana-backend-group + go.opentelemetry.io/collector/pdata v1.44.0 // @grafana/grafana-backend-group go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 // @grafana/plugins-platform-backend go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.63.0 // @grafana/grafana-operator-experience-squad go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0 // @grafana/sharing-squad @@ -197,8 +196,8 @@ require ( go.uber.org/goleak v1.3.0 // @grafana/grafana-search-and-storage go.uber.org/mock v0.6.0 // @grafana/grafana-operator-experience-squad go.uber.org/zap v1.27.0 // @grafana/identity-access-team - gocloud.dev v0.42.0 // @grafana/grafana-app-platform-squad - gocloud.dev/secrets/hashivault v0.42.0 // @grafana/grafana-operator-experience-squad + gocloud.dev v0.43.0 // @grafana/grafana-app-platform-squad + gocloud.dev/secrets/hashivault v0.43.0 // @grafana/grafana-operator-experience-squad golang.org/x/crypto v0.43.0 // @grafana/grafana-backend-group golang.org/x/exp v0.0.0-20251002181428-27f1f14c8bb9 // @grafana/alerting-backend golang.org/x/mod v0.29.0 // indirect; @grafana/grafana-backend-group @@ -209,7 +208,7 @@ require ( golang.org/x/time v0.14.0 // @grafana/grafana-backend-group golang.org/x/tools v0.38.0 // indirect; @grafana/grafana-as-code gonum.org/v1/gonum v0.16.0 // @grafana/oss-big-tent - google.golang.org/api v0.235.0 // @grafana/grafana-backend-group + google.golang.org/api v0.242.0 // @grafana/grafana-backend-group google.golang.org/grpc v1.76.0 // @grafana/plugins-platform-backend google.golang.org/protobuf v1.36.10 // @grafana/plugins-platform-backend gopkg.in/ini.v1 v1.67.0 // @grafana/alerting-backend @@ -229,7 +228,7 @@ require ( pgregory.net/rapid v1.2.0 // @grafana/grafana-operator-experience-squad sigs.k8s.io/randfill v1.0.0 // @grafana/grafana-app-platform-squad sigs.k8s.io/structured-merge-diff/v6 v6.3.0 // @grafana/grafana-app-platform-squad - xorm.io/builder v0.3.6 // @grafana/grafana-backend-group + xorm.io/builder v0.3.13 // @grafana/grafana-backend-group ) require ( @@ -290,8 +289,8 @@ replace ( require ( cel.dev/expr v0.24.0 // indirect - cloud.google.com/go v0.121.1 // indirect - cloud.google.com/go/auth v0.16.1 // indirect + cloud.google.com/go v0.121.4 // indirect + cloud.google.com/go/auth v0.16.3 // indirect cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect cloud.google.com/go/compute/metadata v0.7.0 // indirect cloud.google.com/go/iam v1.5.2 // indirect @@ -312,8 +311,8 @@ require ( github.com/AzureAD/microsoft-authentication-library-for-go v1.5.0 // indirect github.com/FZambia/eagle v0.2.0 // indirect github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.29.0 // indirect - github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.51.0 // indirect - github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.51.0 // indirect + github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.53.0 // indirect + github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.53.0 // indirect github.com/Masterminds/goutils v1.1.1 // indirect github.com/Masterminds/squirrel v1.5.4 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect @@ -335,17 +334,17 @@ require ( github.com/aws/aws-sdk-go-v2/config v1.31.2 // indirect github.com/aws/aws-sdk-go-v2/credentials v1.18.6 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.4 // indirect - github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.69 // indirect + github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.84 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.4 // indirect github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.4 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 // indirect - github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.34 // indirect + github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.36 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.0 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.7.0 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.7.4 // indirect github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.4 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.15 // indirect - github.com/aws/aws-sdk-go-v2/service/kms v1.38.1 // indirect - github.com/aws/aws-sdk-go-v2/service/s3 v1.78.2 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.17 // indirect + github.com/aws/aws-sdk-go-v2/service/kms v1.41.2 // indirect + github.com/aws/aws-sdk-go-v2/service/s3 v1.84.0 // indirect github.com/aws/aws-sdk-go-v2/service/sso v1.28.2 // indirect github.com/aws/aws-sdk-go-v2/service/ssooidc v1.33.2 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.38.0 // indirect @@ -437,7 +436,6 @@ require ( github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect github.com/golang-sql/sqlexp v0.1.0 // indirect github.com/golang/geo v0.0.0-20210211234256-740aa86cb551 // indirect - github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect github.com/gomodule/redigo v1.8.9 // indirect github.com/google/btree v1.1.3 // indirect github.com/google/cel-go v0.26.1 // indirect @@ -465,10 +463,10 @@ require ( github.com/hashicorp/go-sockaddr v1.0.7 // indirect github.com/hashicorp/go-uuid v1.0.3 // indirect github.com/hashicorp/golang-lru v1.0.2 // indirect - github.com/hashicorp/hcl v1.0.0 // indirect + github.com/hashicorp/hcl v1.0.1-vault-7 // indirect github.com/hashicorp/memberlist v0.5.2 // indirect github.com/hashicorp/serf v0.10.2 // indirect - github.com/hashicorp/vault/api v1.16.0 // indirect + github.com/hashicorp/vault/api v1.20.0 // indirect github.com/hashicorp/yamux v0.1.2 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/invopop/jsonschema v0.13.0 // indirect @@ -608,10 +606,10 @@ require ( go.etcd.io/etcd/client/v3 v3.6.4 // indirect go.mongodb.org/mongo-driver v1.17.4 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect - go.opentelemetry.io/collector/featuregate v1.43.0 // indirect + go.opentelemetry.io/collector/featuregate v1.44.0 // indirect go.opentelemetry.io/collector/semconv v0.124.0 // indirect go.opentelemetry.io/contrib/bridges/prometheus v0.61.0 // indirect - go.opentelemetry.io/contrib/detectors/gcp v1.36.0 // indirect + go.opentelemetry.io/contrib/detectors/gcp v1.37.0 // indirect go.opentelemetry.io/contrib/exporters/autoexport v0.61.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.12.2 // indirect go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.12.2 // indirect @@ -620,7 +618,7 @@ require ( go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 // indirect go.opentelemetry.io/otel/exporters/prometheus v0.59.0 // indirect go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.12.2 // indirect - go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.36.0 // indirect + go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.37.0 // indirect go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0 // indirect go.opentelemetry.io/otel/log v0.12.2 // indirect go.opentelemetry.io/otel/metric v1.38.0 // indirect @@ -637,7 +635,7 @@ require ( golang.org/x/tools/godoc v0.1.0-deprecated // indirect golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect - google.golang.org/genproto v0.0.0-20250603155806-513f23925822 // indirect + google.golang.org/genproto v0.0.0-20250715232539-7130f93afb79 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250908214217-97024824d090 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20251002232023-7c0ddcbb5797 // indirect gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect diff --git a/go.sum b/go.sum index a19b3327237..799c4a97b4a 100644 --- a/go.sum +++ b/go.sum @@ -46,8 +46,8 @@ cloud.google.com/go v0.105.0/go.mod h1:PrLgOJNe5nfE9UMxKxgXj4mD3voiP+YQ6gdt6KMFO cloud.google.com/go v0.107.0/go.mod h1:wpc2eNrD7hXUTy8EKS10jkxpZBjASrORK7goS+3YX2I= cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= cloud.google.com/go v0.110.2/go.mod h1:k04UEeEtb6ZBRTv3dZz4CeJC3jKGxyhl0sAiVVquxiw= -cloud.google.com/go v0.121.1 h1:S3kTQSydxmu1JfLRLpKtxRPA7rSrYPRPEUmL/PavVUw= -cloud.google.com/go v0.121.1/go.mod h1:nRFlrHq39MNVWu+zESP2PosMWA0ryJw8KUBZ2iZpxbw= +cloud.google.com/go v0.121.4 h1:cVvUiY0sX0xwyxPwdSU2KsF9knOVmtRyAMt8xou0iTs= +cloud.google.com/go v0.121.4/go.mod h1:XEBchUiHFJbz4lKBZwYBDHV/rSyfFktk737TLDU089s= cloud.google.com/go/accessapproval v1.4.0/go.mod h1:zybIuC3KpDOvotz59lFe5qxRZx6C75OtwbisN56xYB4= cloud.google.com/go/accessapproval v1.5.0/go.mod h1:HFy3tuiGvMdcd/u+Cu5b9NkO1pEICJ46IR82PoUdplw= cloud.google.com/go/accessapproval v1.6.0/go.mod h1:R0EiYnwV5fsRFiKZkPHr6mwyk2wxUJ30nL4j2pcFY2E= @@ -109,8 +109,8 @@ cloud.google.com/go/assuredworkloads v1.7.0/go.mod h1:z/736/oNmtGAyU47reJgGN+KVo cloud.google.com/go/assuredworkloads v1.8.0/go.mod h1:AsX2cqyNCOvEQC8RMPnoc0yEarXQk6WEKkxYfL6kGIo= cloud.google.com/go/assuredworkloads v1.9.0/go.mod h1:kFuI1P78bplYtT77Tb1hi0FMxM0vVpRC7VVoJC3ZoT0= cloud.google.com/go/assuredworkloads v1.10.0/go.mod h1:kwdUQuXcedVdsIaKgKTp9t0UJkE5+PAVNhdQm4ZVq2E= -cloud.google.com/go/auth v0.16.1 h1:XrXauHMd30LhQYVRHLGvJiYeczweKQXZxsTbV9TiguU= -cloud.google.com/go/auth v0.16.1/go.mod h1:1howDHJ5IETh/LwYs3ZxvlkXF48aSqqJUM+5o02dNOI= +cloud.google.com/go/auth v0.16.3 h1:kabzoQ9/bobUmnseYnBO6qQG7q4a/CffFRlJSxv2wCc= +cloud.google.com/go/auth v0.16.3/go.mod h1:NucRGjaXfzP1ltpcQ7On/VTZ0H4kWB5Jy+Y9Dnm76fA= cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc= cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c= cloud.google.com/go/automl v1.5.0/go.mod h1:34EjfoFGMZ5sgJ9EoLsRtdPSNZLcfflJR39VbVNS2M0= @@ -641,6 +641,8 @@ filippo.io/age v1.2.1 h1:X0TZjehAZylOIj4DubWYU1vWQxv9bJpo+Uu2/LGhi1o= filippo.io/age v1.2.1/go.mod h1:JL9ew2lTN+Pyft4RiNGguFfOpewKwSHm5ayKD/A4004= gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zumjgTw83q2ge/PI+yyw8= git.sr.ht/~sbinet/gg v0.3.1/go.mod h1:KGYtlADtqsqANL9ueOFkWymvzUvLMQllU5Ixo+8v3pc= +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/1NCE-GmbH/grpc-go-pool v0.0.0-20231117122434-2a5bb974daa2 h1:qFYgLH2zZe3WHpQgUrzeazC+ebDebwAQqS9yE1cP5Bs= github.com/1NCE-GmbH/grpc-go-pool v0.0.0-20231117122434-2a5bb974daa2/go.mod h1:09/ALd1AXCTCOfcJYD8+jIYKmFmi6PVCkTsipC18F7E= github.com/Azure/azure-pipeline-go v0.2.3 h1:7U9HBg1JFK3jHl5qmo4CTZKFTVgMwdFHMVtCdfBE21U= @@ -723,12 +725,12 @@ github.com/FZambia/sentinel v1.0.0 h1:KJ0ryjKTZk5WMp0dXvSdNqp3lFaW1fNFuEYfrkLOYI github.com/FZambia/sentinel v1.0.0/go.mod h1:ytL1Am/RLlAoAXG6Kj5LNuw/TRRQrv2rt2FT26vP5gI= github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.29.0 h1:UQUsRi8WTzhZntp5313l+CHIAT95ojUI2lpP/ExlZa4= github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.29.0/go.mod h1:Cz6ft6Dkn3Et6l2v2a9/RpN7epQ1GtDlO6lj8bEcOvw= -github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.51.0 h1:fYE9p3esPxA/C0rQ0AHhP0drtPXDRhaWiwg1DPqO7IU= -github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.51.0/go.mod h1:BnBReJLvVYx2CS/UHOgVz2BXKXD9wsQPxZug20nZhd0= -github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.51.0 h1:OqVGm6Ei3x5+yZmSJG1Mh2NwHvpVmZ08CB5qJhT9Nuk= -github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.51.0/go.mod h1:SZiPHWGOOk3bl8tkevxkoiwPgsIl6CwrWcbwjfHZpdM= -github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.51.0 h1:6/0iUd0xrnX7qt+mLNRwg5c0PGv8wpE8K90ryANQwMI= -github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.51.0/go.mod h1:otE2jQekW/PqXk1Awf5lmfokJx4uwuqcj1ab5SpGeW0= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.53.0 h1:owcC2UnmsZycprQ5RfRgjydWhuoxg71LUfyiQdijZuM= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.53.0/go.mod h1:ZPpqegjbE99EPKsu3iUWV22A04wzGPcAY/ziSIQEEgs= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.53.0 h1:4LP6hvB4I5ouTbGgWtixJhgED6xdf67twf9PoY96Tbg= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.53.0/go.mod h1:jUZ5LYlw40WMd07qxcQJD5M40aUxrfwqQX1g7zxYnrQ= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.53.0 h1:Ron4zCA/yk6U7WOBXhTJcDpsUBG9npumK6xw2auFltQ= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.53.0/go.mod h1:cSgYe11MCNYunTnRXrKiR/tHc0eoKjICUuWpNZoVCOo= github.com/HdrHistogram/hdrhistogram-go v1.1.2 h1:5IcZpTvzydCQeHzK4Ef/D5rrSqwxob0t8PQPMybUNFM= github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo= github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c/go.mod h1:X0CRv0ky0k6m906ixxpzmDRLvX58TFUKS2eePweuyxk= @@ -852,16 +854,16 @@ github.com/aws/aws-sdk-go-v2/credentials v1.18.6 h1:AmmvNEYrru7sYNJnp3pf57lGbiar github.com/aws/aws-sdk-go-v2/credentials v1.18.6/go.mod h1:/jdQkh1iVPa01xndfECInp1v1Wnp70v3K4MvtlLGVEc= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.4 h1:lpdMwTzmuDLkgW7086jE94HweHCqG+uOJwHf3LZs7T0= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.4/go.mod h1:9xzb8/SV62W6gHQGC/8rrvgNXU6ZoYM3sAIJCIrXJxY= -github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.69 h1:6VFPH/Zi9xYFMJKPQOX5URYkQoXRWeJ7V/7Y6ZDYoms= -github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.69/go.mod h1:GJj8mmO6YT6EqgduWocwhMoxTLFitkhIrK+owzrYL2I= +github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.84 h1:cTXRdLkpBanlDwISl+5chq5ui1d1YWg4PWMR9c3kXyw= +github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.84/go.mod h1:kwSy5X7tfIHN39uucmjQVs2LvDdXEjQucgQQEqCggEo= github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.4 h1:IdCLsiiIj5YJ3AFevsewURCPV+YWUlOW8JiPhoAy8vg= github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.4/go.mod h1:l4bdfCD7XyyZA9BolKBo1eLqgaJxl0/x91PL4Yqe0ao= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.4 h1:j7vjtr1YIssWQOMeOWRbh3z8g2oY/xPjnZH2gLY4sGw= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.4/go.mod h1:yDmJgqOiH4EA8Hndnv4KwAo8jCGTSnM5ASG1nBI+toA= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 h1:bIqFDwgGXXN1Kpp99pDOdKMTTb5d2KyU5X/BZxjOkRo= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3/go.mod h1:H5O/EsxDWyU+LP/V8i5sm8cxoZgc2fdNR9bxlOFrQTo= -github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.34 h1:ZNTqv4nIdE/DiBfUUfXcLZ/Spcuz+RjeziUtNJackkM= -github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.34/go.mod h1:zf7Vcd1ViW7cPqYWEHLHJkS50X0JS2IKz9Cgaj6ugrs= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.36 h1:GMYy2EOWfzdP3wfVAGXBNKY5vK4K8vMET4sYOYltmqs= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.36/go.mod h1:gDhdAV6wL3PmPqBhiPbnlS447GoWs8HTTOYef9/9Inw= github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.45.3 h1:Nn3qce+OHZuMj/edx4its32uxedAmquCDxtZkrdeiD4= github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.45.3/go.mod h1:aqsLGsPs+rJfwDBwWHLcIV8F7AFcikFTPLwUD4RwORQ= github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs v1.51.0 h1:e5cbPZYTIY2nUEFieZUfVdINOiCTvChOMPfdLnmiLzs= @@ -870,20 +872,20 @@ github.com/aws/aws-sdk-go-v2/service/ec2 v1.225.2 h1:IfMb3Ar8xEaWjgH/zeVHYD8izwJ github.com/aws/aws-sdk-go-v2/service/ec2 v1.225.2/go.mod h1:35jGWx7ECvCwTsApqicFYzZ7JFEnBc6oHUuOQ3xIS54= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.0 h1:6+lZi2JeGKtCraAj1rpoZfKqnQ9SptseRZioejfUOLM= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.0/go.mod h1:eb3gfbVIxIoGgJsi9pGne19dhCBpK6opTYpQqAmdy44= -github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.7.0 h1:lguz0bmOoGzozP9XfRJR1QIayEYo+2vP/No3OfLF0pU= -github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.7.0/go.mod h1:iu6FSzgt+M2/x3Dk8zhycdIcHjEFb36IS8HVUVFoMg0= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.7.4 h1:nAP2GYbfh8dd2zGZqFRSMlq+/F6cMPBUuCsGAMkN074= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.7.4/go.mod h1:LT10DsiGjLWh4GbjInf9LQejkYEhBgBCjLG5+lvk4EE= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.4 h1:ueB2Te0NacDMnaC+68za9jLwkjzxGWm0KB5HTUHjLTI= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.4/go.mod h1:nLEfLnVMmLvyIG58/6gsSA03F1voKGaCfHV7+lR8S7s= -github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.15 h1:moLQUoVq91LiqT1nbvzDukyqAlCv89ZmwaHw/ZFlFZg= -github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.15/go.mod h1:ZH34PJUc8ApjBIfgQCFvkWcUDBtl/WTD+uiYHjd8igA= -github.com/aws/aws-sdk-go-v2/service/kms v1.38.1 h1:tecq7+mAav5byF+Mr+iONJnCBf4B4gon8RSp4BrweSc= -github.com/aws/aws-sdk-go-v2/service/kms v1.38.1/go.mod h1:cQn6tAF77Di6m4huxovNM7NVAozWTZLsDRp9t8Z/WYk= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.17 h1:qcLWgdhq45sDM9na4cvXax9dyLitn8EYBRl8Ak4XtG4= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.17/go.mod h1:M+jkjBFZ2J6DJrjMv2+vkBbuht6kxJYtJiwoVgX4p4U= +github.com/aws/aws-sdk-go-v2/service/kms v1.41.2 h1:zJeUxFP7+XP52u23vrp4zMcVhShTWbNO8dHV6xCSvFo= +github.com/aws/aws-sdk-go-v2/service/kms v1.41.2/go.mod h1:Pqd9k4TuespkireN206cK2QBsaBTL6X+VPAez5Qcijk= github.com/aws/aws-sdk-go-v2/service/oam v1.18.3 h1:teOWtElLARLOhpYWwupjLbY9j5I/yZ/H1I8jg41An78= github.com/aws/aws-sdk-go-v2/service/oam v1.18.3/go.mod h1:wGhpdyftHX6/1U4egowHkYdypwBMjpb+KjAAprv6z20= github.com/aws/aws-sdk-go-v2/service/resourcegroupstaggingapi v1.26.6 h1:PwbxovpcJvb25k019bkibvJfCpCmIANOFrXZIFPmRzk= github.com/aws/aws-sdk-go-v2/service/resourcegroupstaggingapi v1.26.6/go.mod h1:Z4xLt5mXspLKjBV92i165wAJ/3T6TIv4n7RtIS8pWV0= -github.com/aws/aws-sdk-go-v2/service/s3 v1.78.2 h1:jIiopHEV22b4yQP2q36Y0OmwLbsxNWdWwfZRR5QRRO4= -github.com/aws/aws-sdk-go-v2/service/s3 v1.78.2/go.mod h1:U5SNqwhXB3Xe6F47kXvWihPl/ilGaEDe8HD/50Z9wxc= +github.com/aws/aws-sdk-go-v2/service/s3 v1.84.0 h1:0reDqfEN+tB+sozj2r92Bep8MEwBZgtAXTND1Kk9OXg= +github.com/aws/aws-sdk-go-v2/service/s3 v1.84.0/go.mod h1:kUklwasNoCn5YpyAqC/97r6dzTA1SRKJfKq16SXeoDU= github.com/aws/aws-sdk-go-v2/service/sso v1.28.2 h1:ve9dYBB8CfJGTFqcQ3ZLAAb/KXWgYlgu/2R2TZL2Ko0= github.com/aws/aws-sdk-go-v2/service/sso v1.28.2/go.mod h1:n9bTZFZcBa9hGGqVz3i/a6+NG0zmZgtkB9qVVFDqPA8= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.33.2 h1:pd9G9HQaM6UZAZh19pYOkpKSQkyQQ9ftnl/LttQOcGI= @@ -1378,8 +1380,6 @@ github.com/go-test/deep v1.1.1 h1:0r/53hagsehfO4bzD2Pgr/+RgHqhmf+k1Bpse2cTu1U= github.com/go-test/deep v1.1.1/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= -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/go-zookeeper/zk v1.0.4 h1:DPzxraQx7OrPyXq2phlGlNSIyWEsAox0RJmjTseMV6I= github.com/go-zookeeper/zk v1.0.4/go.mod h1:nOB03cncLtlp4t+UAkGSV+9beXP/akpekBwL+UX1Qcw= github.com/gobs/pretty v0.0.0-20180724170744-09732c25a95b h1:/vQ+oYKu+JoyaMPDsv5FzwuL2wwWBgBbtj/YLCi4LuA= @@ -1429,8 +1429,6 @@ github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4er github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ= -github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= @@ -1580,8 +1578,8 @@ github.com/googleapis/gax-go/v2 v2.7.1/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38 github.com/googleapis/gax-go/v2 v2.8.0/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI= github.com/googleapis/gax-go/v2 v2.10.0/go.mod h1:4UOEnMCrxsSqQ940WnTiD6qJ63le2ev3xfyagutxiPw= github.com/googleapis/gax-go/v2 v2.11.0/go.mod h1:DxmR61SGKkGLa2xigwuZIQpkCI2S5iydzRfb3peWZJI= -github.com/googleapis/gax-go/v2 v2.14.2 h1:eBLnkZ9635krYIPD+ag1USrOAI0Nr0QYF3+/3GqO0k0= -github.com/googleapis/gax-go/v2 v2.14.2/go.mod h1:ON64QhlJkhVtSqp4v1uaK92VyZ2gmvDQsweuyLV+8+w= +github.com/googleapis/gax-go/v2 v2.15.0 h1:SyjDc1mGgZU5LncH8gimWo9lW1DtIfPibOG81vgd/bo= +github.com/googleapis/gax-go/v2 v2.15.0/go.mod h1:zVVkkxAQHa1RQpg9z2AUCMnKhi0Qld9rcmyfL1OZhoc= github.com/googleapis/gnostic v0.0.0-20170426233943-68f4ded48ba9/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= github.com/googleapis/gnostic v0.3.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= @@ -1759,8 +1757,9 @@ github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iP github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= -github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/hcl v1.0.1-vault-7 h1:ag5OxFVy3QYTFTJODRzTKVZ6xvdfLLCA1cy/Y6xGI0I= +github.com/hashicorp/hcl v1.0.1-vault-7/go.mod h1:XYhtn6ijBSAj6n4YqAaf7RBPS4I06AItNorpy+MoQNM= github.com/hashicorp/hcl/v2 v2.24.0 h1:2QJdZ454DSsYGoaE6QheQZjtKZSUs9Nh2izTWiwQxvE= github.com/hashicorp/hcl/v2 v2.24.0/go.mod h1:oGoO1FIQYfn/AgyOhlg9qLC6/nOJPX3qGbkZpYAcqfM= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= @@ -1780,8 +1779,8 @@ github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpT github.com/hashicorp/serf v0.9.7/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= github.com/hashicorp/serf v0.10.2 h1:m5IORhuNSjaxeljg5DeQVDlQyVkhRIjJDimbkCa8aAc= github.com/hashicorp/serf v0.10.2/go.mod h1:T1CmSGfSeGfnfNy/w0odXQUR1rfECGd2Qdsp84DjOiY= -github.com/hashicorp/vault/api v1.16.0 h1:nbEYGJiAPGzT9U4oWgaaB0g+Rj8E59QuHKyA5LhwQN4= -github.com/hashicorp/vault/api v1.16.0/go.mod h1:KhuUhzOD8lDSk29AtzNjgAu2kxRA9jL9NAbkFlqvkBA= +github.com/hashicorp/vault/api v1.20.0 h1:KQMHElgudOsr+IbJgmbjHnCTxEpKs9LnozA1D3nozU4= +github.com/hashicorp/vault/api v1.20.0/go.mod h1:GZ4pcjfzoOWpkJ3ijHNpEoAxKEsBJnVljyTe3jM2Sms= github.com/hashicorp/yamux v0.1.2 h1:XtB8kyFOyHXYVFnwT5C3+Bdo8gArse7j2AQ0DA0Uey8= github.com/hashicorp/yamux v0.1.2/go.mod h1:C+zze2n6e/7wshOZep2A70/aQU6QBRWJO/G6FT1wIns= github.com/hetznercloud/hcloud-go/v2 v2.19.1 h1:UU/7h3uc/rdgspM8xkQF7wokmwZXePWDXcLqrQRRzzY= @@ -1852,8 +1851,8 @@ github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9Y github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= -github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g= -github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ= +github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o= +github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY= github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= github.com/jonboulle/clockwork v0.5.0 h1:Hyh9A8u51kptdkR+cqRpT1EebBwTn1oK9YfGYbdFz6I= github.com/jonboulle/clockwork v0.5.0/go.mod h1:3mZlmanh0g2NDKO5TWZVJAfofYk64M7XN3SzBPjZF60= @@ -1999,6 +1998,7 @@ github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/go-sqlite3 v1.14.14/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= +github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/mattn/go-sqlite3 v1.14.32 h1:JD12Ag3oLy1zQA+BNn74xRgaBbdhbNIDYvQUEuuErjs= github.com/mattn/go-sqlite3 v1.14.32/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= @@ -2500,8 +2500,8 @@ github.com/urfave/cli v1.22.17 h1:SYzXoiPfQjHBbkYxbew5prZHS1TOLT3ierW8SYLqtVQ= github.com/urfave/cli v1.22.17/go.mod h1:b0ht0aqgH/6pBYzzxURyrM4xXNgsoT/n2ZzwQiEhNVo= github.com/urfave/cli/v2 v2.27.7 h1:bH59vdhbjLv3LAvIu6gd0usJHgoTTPhCFib8qqOwXYU= github.com/urfave/cli/v2 v2.27.7/go.mod h1:CyNAG/xg+iAOg0N4MPGZqVmv2rCoP267496AOXUZjA4= -github.com/urfave/cli/v3 v3.4.1 h1:1M9UOCy5bLmGnuu1yn3t3CB4rG79Rtoxuv1sPhnm6qM= -github.com/urfave/cli/v3 v3.4.1/go.mod h1:FJSKtM/9AiiTOJL4fJ6TbMUkxBXn7GO9guZqoZtpYpo= +github.com/urfave/cli/v3 v3.5.0 h1:qCuFMmdayTF3zmjG8TSsoBzrDqszNrklYg2x3g4MSgw= +github.com/urfave/cli/v3 v3.5.0/go.mod h1:ysVLtOEmg2tOy6PknnYVhDoouyC/6N42TMeoMzskhso= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/vultr/govultr/v2 v2.17.2 h1:gej/rwr91Puc/tgh+j33p/BLR16UrIPnSr+AIwYWZQs= @@ -2594,23 +2594,22 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= -go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= go.opentelemetry.io/collector v0.124.0 h1:g/dfdGFhBcQI0ggGxTmGlJnJ6Yl6T2gVxQoIj4UfXCc= -go.opentelemetry.io/collector/featuregate v1.43.0 h1:Aq8UR5qv1zNlbbkTyqv8kLJtnoQMq/sG1/jS9o1cCJI= -go.opentelemetry.io/collector/featuregate v1.43.0/go.mod h1:d0tiRzVYrytB6LkcYgz2ESFTv7OktRPQe0QEQcPt1L4= -go.opentelemetry.io/collector/pdata v1.43.0 h1:zVkj2hcjiMLwX+QDDNwb7iTh3LBjNXKv2qPSgj1Rzb4= -go.opentelemetry.io/collector/pdata v1.43.0/go.mod h1:KsJzdDG9e5BaHlmYr0sqdSEKeEiSfKzoF+rdWU7J//w= +go.opentelemetry.io/collector/featuregate v1.44.0 h1:/GeGhTD8f+FNWS7C4w1Dj0Ui9Jp4v2WAdlXyW1p3uG8= +go.opentelemetry.io/collector/featuregate v1.44.0/go.mod h1:d0tiRzVYrytB6LkcYgz2ESFTv7OktRPQe0QEQcPt1L4= +go.opentelemetry.io/collector/pdata v1.44.0 h1:q/EfWDDKrSaf4hjTIzyPeg1ZcCRg1Uj7VTFnGfNVdk8= +go.opentelemetry.io/collector/pdata v1.44.0/go.mod h1:LnsjYysFc3AwMVh6KGNlkGKJUF2ReuWxtD9Hb3lSMZk= go.opentelemetry.io/collector/pdata/pprofile v0.124.0 h1:ZjL9wKqzP4BHj0/F1jfGxs1Va8B7xmYayipZeNVoWJE= go.opentelemetry.io/collector/pdata/pprofile v0.124.0/go.mod h1:1EN3Gw5LSI4fSVma/Yfv/6nqeuYgRTm1/kmG5nE5Oyo= go.opentelemetry.io/collector/semconv v0.124.0 h1:YTdo3UFwNyDQCh9DiSm2rbzAgBuwn/9dNZ0rv454goA= go.opentelemetry.io/collector/semconv v0.124.0/go.mod h1:te6VQ4zZJO5Lp8dM2XIhDxDiL45mwX0YAQQWRQ0Qr9U= go.opentelemetry.io/contrib/bridges/prometheus v0.61.0 h1:RyrtJzu5MAmIcbRrwg75b+w3RlZCP0vJByDVzcpAe3M= go.opentelemetry.io/contrib/bridges/prometheus v0.61.0/go.mod h1:tirr4p9NXbzjlbruiRGp53IzlYrDk5CO2fdHj0sSSaY= -go.opentelemetry.io/contrib/detectors/gcp v1.36.0 h1:F7q2tNlCaHY9nMKHR6XH9/qkp8FktLnIcy6jJNyOCQw= -go.opentelemetry.io/contrib/detectors/gcp v1.36.0/go.mod h1:IbBN8uAIIx734PTonTPxAxnjc2pQTxWNkwfstZ+6H2k= +go.opentelemetry.io/contrib/detectors/gcp v1.37.0 h1:B+WbN9RPsvobe6q4vP6KgM8/9plR/HNjgGBrfcOlweA= +go.opentelemetry.io/contrib/detectors/gcp v1.37.0/go.mod h1:K5zQ3TT7p2ru9Qkzk0bKtCql0RGkPj9pRjpXgZJZ+rU= go.opentelemetry.io/contrib/exporters/autoexport v0.61.0 h1:XfzKtKSrbtYk9TNCF8dkO0Y9M7IOfb4idCwBOTwGBiI= go.opentelemetry.io/contrib/exporters/autoexport v0.61.0/go.mod h1:N6otC+qXTD5bAnbK2O1f/1SXq3cX+3KYSWrkBUqG0cw= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 h1:YH4g8lQroajqUwWbq/tr2QX1JFmEXaDLgG+ew9bLMWo= @@ -2650,8 +2649,8 @@ go.opentelemetry.io/otel/exporters/prometheus v0.59.0 h1:HHf+wKS6o5++XZhS98wvILr go.opentelemetry.io/otel/exporters/prometheus v0.59.0/go.mod h1:R8GpRXTZrqvXHDEGVH5bF6+JqAZcK8PjJcZ5nGhEWiE= go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.12.2 h1:12vMqzLLNZtXuXbJhSENRg+Vvx+ynNilV8twBLBsXMY= go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.12.2/go.mod h1:ZccPZoPOoq8x3Trik/fCsba7DEYDUnN6yX79pgp2BUQ= -go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.36.0 h1:rixTyDGXFxRy1xzhKrotaHy3/KXdPhlWARrCgK+eqUY= -go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.36.0/go.mod h1:dowW6UsM9MKbJq5JTz2AMVp3/5iW5I/TStsk8S+CfHw= +go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.37.0 h1:6VjV6Et+1Hd2iLZEPtdV7vie80Yyqf7oikJLjQ/myi0= +go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.37.0/go.mod h1:u8hcp8ji5gaM/RfcOo8z9NMnf1pVLfVY7lBY2VOGuUU= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0 h1:kJxSDN4SgWWTjG/hPp3O7LCGLcHXFlvS2/FFOrwL+SE= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0/go.mod h1:mgIOzS7iZeKJdeB8/NYHrJ48fdGc71Llo5bJ1J4DWUE= go.opentelemetry.io/otel/log v0.12.2 h1:yob9JVHn2ZY24byZeaXpTVoPS6l+UrrxmxmPKohXTwc= @@ -2708,10 +2707,10 @@ go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= go4.org/netipx v0.0.0-20230125063823-8449b0a6169f h1:ketMxHg+vWm3yccyYiq+uK8D3fRmna2Fcj+awpQp84s= go4.org/netipx v0.0.0-20230125063823-8449b0a6169f/go.mod h1:tgPU4N2u9RByaTN3NC2p9xOzyFpte4jYwsIIRF7XlSc= -gocloud.dev v0.42.0 h1:qzG+9ItUL3RPB62/Amugws28n+4vGZXEoJEAMfjutzw= -gocloud.dev v0.42.0/go.mod h1:zkaYAapZfQisXOA4bzhsbA4ckiStGQ3Psvs9/OQ5dPM= -gocloud.dev/secrets/hashivault v0.42.0 h1:kPWIIu1AP6ApHf7HwUrzGrwyRJEfTd46JNUNgnbpsFA= -gocloud.dev/secrets/hashivault v0.42.0/go.mod h1:LXprr1XLEAT7BVZ+Y66dJEHQMzDsowIExj5Ktr9HLvM= +gocloud.dev v0.43.0 h1:aW3eq4RMyehbJ54PMsh4hsp7iX8cO/98ZRzJJOzN/5M= +gocloud.dev v0.43.0/go.mod h1:eD8rkg7LhKUHrzkEdLTZ+Ty/vgPHPCd+yMQdfelQVu4= +gocloud.dev/secrets/hashivault v0.43.0 h1:A966rEMpCRUE9209/+k+A2HP2v2qDnrxGpQn+nIH5uY= +gocloud.dev/secrets/hashivault v0.43.0/go.mod h1:KdWKL+TXDi0cXgEd/MTeaidKlotvyJtnTDi71B3rR9U= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -3326,8 +3325,8 @@ google.golang.org/api v0.118.0/go.mod h1:76TtD3vkgmZ66zZzp72bUUklpmQmKlhh6sYtIjY google.golang.org/api v0.122.0/go.mod h1:gcitW0lvnyWjSp9nKxAbdHKIZ6vF4aajGueeslZOyms= google.golang.org/api v0.124.0/go.mod h1:xu2HQurE5gi/3t1aFCvhPD781p0a3p11sdunTJ2BlP4= google.golang.org/api v0.126.0/go.mod h1:mBwVAtz+87bEN6CbA1GtZPDOqY2R5ONPqJeIlvyo4Aw= -google.golang.org/api v0.235.0 h1:C3MkpQSRxS1Jy6AkzTGKKrpSCOd2WOGrezZ+icKSkKo= -google.golang.org/api v0.235.0/go.mod h1:QpeJkemzkFKe5VCE/PMv7GsUfn9ZF+u+q1Q7w6ckxTg= +google.golang.org/api v0.242.0 h1:7Lnb1nfnpvbkCiZek6IXKdJ0MFuAZNAJKQfA1ws62xg= +google.golang.org/api v0.242.0/go.mod h1:cOVEm2TpdAGHL2z+UwyS+kmlGr3bVWQQ6sYEqkKje50= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -3478,8 +3477,8 @@ google.golang.org/genproto v0.0.0-20230403163135-c38d8f061ccd/go.mod h1:UUQDJDOl google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU= google.golang.org/genproto v0.0.0-20230525234025-438c736192d0/go.mod h1:9ExIQyXL5hZrHzQceCwuSYwZZ5QZBazOcprJ5rgs3lY= google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:xZnkP7mREFX5MORlOPEzLMr+90PPZQ2QWzrVTWfAq64= -google.golang.org/genproto v0.0.0-20250603155806-513f23925822 h1:rHWScKit0gvAPuOnu87KpaYtjK5zBMLcULh7gxkCXu4= -google.golang.org/genproto v0.0.0-20250603155806-513f23925822/go.mod h1:HubltRL7rMh0LfnQPkMH4NPDFEWp0jw3vixw7jEM53s= +google.golang.org/genproto v0.0.0-20250715232539-7130f93afb79 h1:Nt6z9UHqSlIdIGJdz6KhTIs2VRx/iOsA5iE8bmQNcxs= +google.golang.org/genproto v0.0.0-20250715232539-7130f93afb79/go.mod h1:kTmlBHMPqR5uCZPBvwa2B18mvubkjyY3CRLI0c6fj0s= google.golang.org/genproto/googleapis/api v0.0.0-20230525234020-1aefcd67740a/go.mod h1:ts19tUU+Z0ZShN1y3aPyq2+O3d5FUNNgT6FtOzmrNn8= google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= google.golang.org/genproto/googleapis/api v0.0.0-20230526203410-71b5a4ffd15e/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= @@ -3736,5 +3735,5 @@ sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= -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= diff --git a/go.work.sum b/go.work.sum index 995365a4618..07474527d3f 100644 --- a/go.work.sum +++ b/go.work.sum @@ -1,5 +1,3 @@ -atomicgo.dev/assert v0.0.2 h1:FiKeMiZSgRrZsPo9qn/7vmr7mCsh5SZyXY4YGYiYwrg= -atomicgo.dev/assert v0.0.2/go.mod h1:ut4NcI3QDdJtlmAxQULOmA13Gz6e2DWbSAS8RUOmNYQ= atomicgo.dev/cursor v0.2.0 h1:H6XN5alUJ52FZZUkI7AlJbUc1aW38GWZalpYRPpoPOw= atomicgo.dev/cursor v0.2.0/go.mod h1:Lr4ZJB3U7DfPPOkbH7/6TOtJ4vFGHlgj1nc+n900IpU= atomicgo.dev/keyboard v0.2.9 h1:tOsIid3nlPLZ3lwgG8KZMp/SFmr7P0ssEN5JUsm78K8= @@ -10,484 +8,233 @@ buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.6-2025042515311 buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.6-20250425153114-8976f5be98c1.1/go.mod h1:avRlCjnFzl98VPaeCtJ24RrV/wwHFzB8sWXhj26+n/U= buf.build/go/protovalidate v0.12.0 h1:4GKJotbspQjRCcqZMGVSuC8SjwZ/FmgtSuKDpKUTZew= buf.build/go/protovalidate v0.12.0/go.mod h1:q3PFfbzI05LeqxSwq+begW2syjy2Z6hLxZSkP1OH/D0= -cel.dev/expr v0.15.0/go.mod h1:TRSuuV7DlVCE/uwv5QbAiW/v8l5O8C4eEPHeu7gf7Sg= -cel.dev/expr v0.16.0/go.mod h1:TRSuuV7DlVCE/uwv5QbAiW/v8l5O8C4eEPHeu7gf7Sg= -cel.dev/expr v0.16.1/go.mod h1:AsGA5zb3WruAEQeQng1RZdGEXmBj0jvMWh6l5SnNuC8= -cel.dev/expr v0.19.0/go.mod h1:MrpN08Q+lEBs+bGYdLxxHkZoUSsCp0nSKTs0nTymJgw= -cel.dev/expr v0.19.1/go.mod h1:MrpN08Q+lEBs+bGYdLxxHkZoUSsCp0nSKTs0nTymJgw= -cel.dev/expr v0.19.2/go.mod h1:MrpN08Q+lEBs+bGYdLxxHkZoUSsCp0nSKTs0nTymJgw= -cel.dev/expr v0.20.0/go.mod h1:MrpN08Q+lEBs+bGYdLxxHkZoUSsCp0nSKTs0nTymJgw= -cel.dev/expr v0.23.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw= -cel.dev/expr v0.23.1/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw= -cloud.google.com/go v0.112.2/go.mod h1:iEqjp//KquGIJV/m+Pk3xecgKNhV+ry+vVTsy4TbDms= -cloud.google.com/go v0.116.0/go.mod h1:cEPSRWPzZEswwdr9BxE6ChEn01dWlTaF05LiC2Xs70U= -cloud.google.com/go v0.118.1/go.mod h1:CFO4UPEPi8oV21xoezZCrd3d81K4fFkDTEJu4R8K+9M= -cloud.google.com/go v0.118.3/go.mod h1:Lhs3YLnBlwJ4KA6nuObNMZ/fCbOQBPuWKPoE0Wa/9Vc= -cloud.google.com/go v0.120.0/go.mod h1:/beW32s8/pGRuj4IILWQNd4uuebeT4dkOhKmkfit64Q= -cloud.google.com/go v0.121.0/go.mod h1:rS7Kytwheu/y9buoDmu5EIpMMCI4Mb8ND4aeN4Vwj7Q= -cloud.google.com/go/accessapproval v1.8.3 h1:axlU03FRiXDNupsmPG7LKzuS4Enk1gf598M62lWVB74= -cloud.google.com/go/accessapproval v1.8.3/go.mod h1:3speETyAv63TDrDmo5lIkpVueFkQcQchkiw/TAMbBo4= -cloud.google.com/go/accessapproval v1.8.6 h1:UkmDPCKvj24bkGVrvgJPcgSDkmIPw/bAmOiDb9avOiE= -cloud.google.com/go/accessapproval v1.8.6/go.mod h1:FfmTs7Emex5UvfnnpMkhuNkRCP85URnBFt5ClLxhZaQ= -cloud.google.com/go/accesscontextmanager v1.9.3 h1:8zVoeiBa4erMCLEXltOcqVEsZhS26JZ5/Vrgs59eQiI= -cloud.google.com/go/accesscontextmanager v1.9.3/go.mod h1:S1MEQV5YjkAKBoMekpGrkXKfrBdsi4x6Dybfq6gZ8BU= +cloud.google.com/go/accessapproval v1.8.7 h1:Sc9ZjxFBEM/PoAxNlUwVGDcv8DYyjLYWDxHlzPG0q5I= +cloud.google.com/go/accessapproval v1.8.7/go.mod h1:BFvZOW4GJjJnl6aA/YDEg0TGViFHyusa/bMdcVFmh8A= cloud.google.com/go/accesscontextmanager v1.9.6 h1:2LnncRqfYB8NEdh9+FeYxAt9POTW/0zVboktnRlO11w= cloud.google.com/go/accesscontextmanager v1.9.6/go.mod h1:884XHwy1AQpCX5Cj2VqYse77gfLaq9f8emE2bYriilk= -cloud.google.com/go/aiplatform v1.74.0 h1:rE2P5H7FOAFISAZilmdkapbk4CVgwfVs6FDWlhGfuy0= -cloud.google.com/go/aiplatform v1.74.0/go.mod h1:hVEw30CetNut5FrblYd1AJUWRVSIjoyIvp0EVUh51HA= -cloud.google.com/go/aiplatform v1.89.0 h1:niSJYc6ldWWVM9faXPo1Et1MVSQoLvVGriD7fwbJdtE= -cloud.google.com/go/aiplatform v1.89.0/go.mod h1:TzZtegPkinfXTtXVvZZpxx7noINFMVDrLkE7cEWhYEk= -cloud.google.com/go/analytics v0.26.0 h1:O2kWr2Sd4ep3I+YJ4aiY0G4+zWz6sp4eTce+JVns9TM= -cloud.google.com/go/analytics v0.26.0/go.mod h1:KZWJfs8uX/+lTjdIjvT58SFa86V9KM6aPXwZKK6uNVI= -cloud.google.com/go/analytics v0.28.1 h1:W2ft49J/LeEj9A07Jsd5Q2kAzajK0j0IffOyyzbxw04= -cloud.google.com/go/analytics v0.28.1/go.mod h1:iPaIVr5iXPB3JzkKPW1JddswksACRFl3NSHgVHsuYC4= -cloud.google.com/go/apigateway v1.7.3 h1:Mn7cC5iWJz+cSMS/Hb+N2410CpZ6c8XpJKaexBl0Gxs= -cloud.google.com/go/apigateway v1.7.3/go.mod h1:uK0iRHdl2rdTe79bHW/bTsKhhXPcFihjUdb7RzhTPf4= -cloud.google.com/go/apigateway v1.7.6 h1:do+u3rjDYuTxD2ypRfv4uwTMoy/VHFLclvaYcb5Mv6I= -cloud.google.com/go/apigateway v1.7.6/go.mod h1:SiBx36VPjShaOCk8Emf63M2t2c1yF+I7mYZaId7OHiA= -cloud.google.com/go/apigeeconnect v1.7.3 h1:Wlr+30Tha0SMCvQYZKdrh+HkpOyl0CQFSlzeY/Gg1gs= -cloud.google.com/go/apigeeconnect v1.7.3/go.mod h1:2ZkT5VCAqhYrDqf4dz7lGp4N/+LeNBSfou8Qs5bIuSg= -cloud.google.com/go/apigeeconnect v1.7.6 h1:ijEJSni5xROOn1YyiHgqcW0B0TWr0di9VgIi2gvyNjY= -cloud.google.com/go/apigeeconnect v1.7.6/go.mod h1:zqDhHY99YSn2li6OeEjFpAlhXYnXKl6DFb/fGu0ye2w= -cloud.google.com/go/apigeeregistry v0.9.3 h1:j9CJg/oC884OX5cDpiwNt1ZlDXNV6Zb9Mp1YmRrOG0k= -cloud.google.com/go/apigeeregistry v0.9.3/go.mod h1:oNCP2VjOeI6U8yuOuTmU4pkffdcXzR5KxeUD71gF+Dg= +cloud.google.com/go/aiplatform v1.93.0 h1:RaW2Gp/ywcMRVzNEbriviQScRClKUWNZTBaWpthZhvo= +cloud.google.com/go/aiplatform v1.93.0/go.mod h1:4lKl6YhQz5V+zewJ+RsqQ91H7hjy2AmDy+93ZhwSgiE= +cloud.google.com/go/analytics v0.29.0 h1:oYiABctb2wxUs1khR6vpC/T4P1EN27yvKI6Fxqzuv8E= +cloud.google.com/go/analytics v0.29.0/go.mod h1:NysnqKYB3101TBxuyEciW+wxmcGn44tmbq/pu9IsHcY= +cloud.google.com/go/apigateway v1.7.7 h1:ehKUTy+QFsb3n07fEi18S2dpDDjCV4UlRyrbwfZV3Zk= +cloud.google.com/go/apigateway v1.7.7/go.mod h1:j1bCmrUK1BzVHpiIyTApxB7cRyhivKzltqLmp6j6i7U= +cloud.google.com/go/apigeeconnect v1.7.7 h1:S6s2zojwMymx0fyZYKm0eK1TdDxrriIBAlNVvRAOzug= +cloud.google.com/go/apigeeconnect v1.7.7/go.mod h1:ftGK3nca0JePiVLl0A6alaMjKdOc5C+sAkFMyH2RH8U= cloud.google.com/go/apigeeregistry v0.9.6 h1:TgdjAoGoRY81DEc2LYsYvi/OqCFImMzAk/TVKiSRsQw= cloud.google.com/go/apigeeregistry v0.9.6/go.mod h1:AFEepJBKPtGDfgabG2HWaLH453VVWWFFs3P4W00jbPs= cloud.google.com/go/apikeys v0.6.0 h1:B9CdHFZTFjVti89tmyXXrO+7vSNo2jvZuHG8zD5trdQ= -cloud.google.com/go/appengine v1.9.3 h1:jrcanSzj9J1erevZuxldvsDwY+0k/DeFFzlnSfPGfL8= -cloud.google.com/go/appengine v1.9.3/go.mod h1:DtLsE/z3JufM/pCEIyVYebJ0h9UNPpN64GZQrYgOSyM= -cloud.google.com/go/appengine v1.9.6 h1:JJyY8icMmQeWfQ+d36IhkGvd3Guzvw0UAkvxT0wmUx8= -cloud.google.com/go/appengine v1.9.6/go.mod h1:jPp9T7Opvzl97qytaRGPwoH7pFI3GAcLDaui1K8PNjY= -cloud.google.com/go/area120 v0.9.3 h1:dPQ07rW4eku8OgNWDOaQaVGcE4+XfhH8BSbVwdVQ+wU= -cloud.google.com/go/area120 v0.9.3/go.mod h1:F3vxS/+hqzrjJo55Xvda3Jznjjbd+4Foo43SN5eMd8M= -cloud.google.com/go/area120 v0.9.6 h1:iJrZ6AleZr4l+q0/fWVANFOhs90KiSB1Ccait5OYyNg= -cloud.google.com/go/area120 v0.9.6/go.mod h1:qKSokqe0iTmwBDA3tbLWonMEnh0pMAH4YxiceiHUed4= -cloud.google.com/go/artifactregistry v1.16.1 h1:ZNXGB6+T7VmWdf6//VqxLdZ/sk0no8W0ujanHeJwDRw= -cloud.google.com/go/artifactregistry v1.16.1/go.mod h1:sPvFPZhfMavpiongKwfg93EOwJ18Tnj9DIwTU9xWUgs= +cloud.google.com/go/appengine v1.9.7 h1:IxGz6j5xv0nTJX285wu95Vn6KEi2CeV9vbyRgCSEAoU= +cloud.google.com/go/appengine v1.9.7/go.mod h1:y1XpGVeAhbsNzHida79cHbr3pFRsym0ob8xnC8yphbo= +cloud.google.com/go/area120 v0.9.7 h1:BbpzLwaIXVPorrrzTH+ni7P5mLemmPPfSZ7o39k7zQc= +cloud.google.com/go/area120 v0.9.7/go.mod h1:5nJ0yksmjOMfc4Zpk+okWfJ3A1004FvB82rfia+ZLaY= cloud.google.com/go/artifactregistry v1.17.1 h1:A20kj2S2HO9vlyBVyVFHPxArjxkXvLP5LjcdE7NhaPc= cloud.google.com/go/artifactregistry v1.17.1/go.mod h1:06gLv5QwQPWtaudI2fWO37gfwwRUHwxm3gA8Fe568Hc= -cloud.google.com/go/asset v1.20.4 h1:6oNgjcs5KCPGBD71G0IccK6TfeFsEtBTyQ3Q+Dn09bs= -cloud.google.com/go/asset v1.20.4/go.mod h1:DP09pZ+SoFWUZyPZx26xVroHk+6+9umnQv+01yfJxbM= cloud.google.com/go/asset v1.21.1 h1:i55wWC/EwVdHMyJgRfbLp/L6ez4nQuOpZwSxkuqN9ek= cloud.google.com/go/asset v1.21.1/go.mod h1:7AzY1GCC+s1O73yzLM1IpHFLHz3ws2OigmCpOQHwebk= -cloud.google.com/go/assuredworkloads v1.12.3 h1:RU1WhF1zMggdXAZ+ezYTn4Eh/FdiX7sz8lLXGERn4Po= -cloud.google.com/go/assuredworkloads v1.12.3/go.mod h1:iGBkyMGdtlsxhCi4Ys5SeuvIrPTeI6HeuEJt7qJgJT8= cloud.google.com/go/assuredworkloads v1.12.6 h1:ip/shfJYx6lrHBWYADjrrrubcm7uZzy50TTF5tPG7ek= cloud.google.com/go/assuredworkloads v1.12.6/go.mod h1:QyZHd7nH08fmZ+G4ElihV1zoZ7H0FQCpgS0YWtwjCKo= -cloud.google.com/go/auth v0.3.0/go.mod h1:lBv6NKTWp8E3LPzmO1TbiiRKc4drLOfHsgmlH9ogv5w= -cloud.google.com/go/auth v0.13.0/go.mod h1:COOjD9gwfKNKz+IIduatIhYJQIc0mG3H102r/EMxX6Q= -cloud.google.com/go/auth v0.14.0/go.mod h1:CYsoRL1PdiDuqeQpZE0bP2pnPrGqFcOkI0nldEQis+A= -cloud.google.com/go/auth v0.15.0/go.mod h1:WJDGqZ1o9E9wKIL+IwStfyn/+s59zl4Bi+1KQNVXLZ8= -cloud.google.com/go/auth v0.16.0/go.mod h1:1howDHJ5IETh/LwYs3ZxvlkXF48aSqqJUM+5o02dNOI= -cloud.google.com/go/auth/oauth2adapt v0.2.2/go.mod h1:wcYjgpZI9+Yu7LyYBg4pqSiaRkfEK3GQcpb7C/uyF1Q= -cloud.google.com/go/auth/oauth2adapt v0.2.6/go.mod h1:AlmsELtlEBnaNTL7jCj8VQFLy6mbZv0s4Q7NGBeQ5E8= -cloud.google.com/go/auth/oauth2adapt v0.2.7/go.mod h1:NTbTTzfvPl1Y3V1nPpOgl2w6d/FjO7NNUQaWSox6ZMc= -cloud.google.com/go/automl v1.14.4 h1:vkD+hQ75SMINMgJBT/KDpFYvfQLzJbtIQZdw0AWq8Rs= -cloud.google.com/go/automl v1.14.4/go.mod h1:sVfsJ+g46y7QiQXpVs9nZ/h8ntdujHm5xhjHW32b3n4= cloud.google.com/go/automl v1.14.7 h1:ZLj48Ur2Qcso4M3bgOtjsOmeV5Ee92N14wuOc8OW+L0= cloud.google.com/go/automl v1.14.7/go.mod h1:8a4XbIH5pdvrReOU72oB+H3pOw2JBxo9XTk39oljObE= -cloud.google.com/go/baremetalsolution v1.3.3 h1:OL+KT+wCumdDhG44aeqGAdkwdT8Wa4Lh+o4INM+CQjw= -cloud.google.com/go/baremetalsolution v1.3.3/go.mod h1:uF9g08RfmXTF6ZKbXxixy5cGMGFcG6137Z99XjxLOUI= cloud.google.com/go/baremetalsolution v1.3.6 h1:9bdGlpY1LgLONQjFsDwrkjLzdPTlROpfU+GhA97YpOk= cloud.google.com/go/baremetalsolution v1.3.6/go.mod h1:7/CS0LzpLccRGO0HL3q2Rofxas2JwjREKut414sE9iM= -cloud.google.com/go/batch v1.12.0 h1:lXuTaELvU0P0ARbTFxxdpOC/dFnZZeGglSw06BtO//8= -cloud.google.com/go/batch v1.12.0/go.mod h1:CATSBh/JglNv+tEU/x21Z47zNatLQ/gpGnpyKOzbbcM= cloud.google.com/go/batch v1.12.2 h1:gWQdvdPplptpvrkqF6ibtxZkOsYKLTFbxYawHa/TvCg= cloud.google.com/go/batch v1.12.2/go.mod h1:tbnuTN/Iw59/n1yjAYKV2aZUjvMM2VJqAgvUgft6UEU= -cloud.google.com/go/beyondcorp v1.1.3 h1:ezavJc0Gzh4N8zBskO/DnUVMWPa8lqH/tmQSyaknmCA= -cloud.google.com/go/beyondcorp v1.1.3/go.mod h1:3SlVKnlczNTSQFuH5SSyLuRd4KaBSc8FH/911TuF/Cc= cloud.google.com/go/beyondcorp v1.1.6 h1:4FcR+4QmcNGkhVij6TrYS4AQVNLBo7PBXKxNrKzpclQ= cloud.google.com/go/beyondcorp v1.1.6/go.mod h1:V1PigSWPGh5L/vRRmyutfnjAbkxLI2aWqJDdxKbwvsQ= -cloud.google.com/go/bigquery v1.66.2 h1:EKOSqjtO7jPpJoEzDmRctGea3c2EOGoexy8VyY9dNro= -cloud.google.com/go/bigquery v1.66.2/go.mod h1:+Yd6dRyW8D/FYEjUGodIbu0QaoEmgav7Lwhotup6njo= cloud.google.com/go/bigquery v1.69.0 h1:rZvHnjSUs5sHK3F9awiuFk2PeOaB8suqNuim21GbaTc= cloud.google.com/go/bigquery v1.69.0/go.mod h1:TdGLquA3h/mGg+McX+GsqG9afAzTAcldMjqhdjHTLew= -cloud.google.com/go/bigtable v1.35.0 h1:UEacPwaejN2mNbz67i1Iy3G812rxtgcs6ePj1TAg7dw= -cloud.google.com/go/bigtable v1.35.0/go.mod h1:EabtwwmTcOJFXp+oMZAT/jZkyDIjNwrv53TrS4DGrrM= -cloud.google.com/go/bigtable v1.37.0 h1:Q+x7y04lQ0B+WXp03wc1/FLhFt4CwcQdkwWT0M4Jp3w= -cloud.google.com/go/bigtable v1.37.0/go.mod h1:HXqddP6hduwzrtiTCqZPpj9ij4hGZb4Zy1WF/dT+yaU= -cloud.google.com/go/billing v1.20.1 h1:xMlO3hc5BI0s23tRB40bL40xSpxUR1x3E07Y5/VWcjU= -cloud.google.com/go/billing v1.20.1/go.mod h1:DhT80hUZ9gz5UqaxtK/LNoDELfxH73704VTce+JZqrY= +cloud.google.com/go/bigtable v1.38.0 h1:L/PnUXRtAzFfa7qMULJHt4cXa/O2dqPJEkzYNGA4hfo= +cloud.google.com/go/bigtable v1.38.0/go.mod h1:o/lntJarF3Y5C0XYLMJLjLYwxaRbcrtM0BiV57ymXbI= cloud.google.com/go/billing v1.20.4 h1:pqM5/c9UGydB9H90IPCxSvfCNLUPazAOSMsZkz5q5P4= cloud.google.com/go/billing v1.20.4/go.mod h1:hBm7iUmGKGCnBm6Wp439YgEdt+OnefEq/Ib9SlJYxIU= -cloud.google.com/go/binaryauthorization v1.9.3 h1:X8JRfmk0/vyRqLusEyAPr0nZCK6RKae9omB4lrit0XI= -cloud.google.com/go/binaryauthorization v1.9.3/go.mod h1:f3xcb/7vWklDoF+q2EaAIS+/A/e1278IgiYxonRX+Jk= cloud.google.com/go/binaryauthorization v1.9.5 h1:T0zYEroXT+y0O/x/yZd5SwQdFv4UbUINjvJyJKzDm0Q= cloud.google.com/go/binaryauthorization v1.9.5/go.mod h1:CV5GkS2eiY461Bzv+OH3r5/AsuB6zny+MruRju3ccB8= -cloud.google.com/go/certificatemanager v1.9.3 h1:2UP31fg7b+y3F0OmNbPHOKPEJ+6LOMfxAXX4p8xGCy4= -cloud.google.com/go/certificatemanager v1.9.3/go.mod h1:O5T4Lg/dHbDHLFFooV2Mh/VsT3Mj2CzPEWRo4qw5prc= cloud.google.com/go/certificatemanager v1.9.5 h1:+ZPglfDurCcsv4azizDFpBucD1IkRjWjbnU7zceyjfY= cloud.google.com/go/certificatemanager v1.9.5/go.mod h1:kn7gxT/80oVGhjL8rurMUYD36AOimgtzSBPadtAeffs= -cloud.google.com/go/channel v1.19.2 h1:oHyO3QAZ6kdf6SwqnUTBz50ND6Nk2rxZtboUiF4dgLE= -cloud.google.com/go/channel v1.19.2/go.mod h1:syX5opXGXFt17DHCyCdbdlM464Tx0gHMi46UlEWY9Gg= -cloud.google.com/go/channel v1.19.5 h1:UI+ZsRkS15hi9DRF+WAvTVLVuSeZiRmvCU8cjkjOwUU= -cloud.google.com/go/channel v1.19.5/go.mod h1:vevu+LK8Oy1Yuf7lcpDbkQQQm5I7oiY5fFTn3uwfQLY= -cloud.google.com/go/cloudbuild v1.22.0 h1:zmDznviZpvkCla0adbp7jJsMYZ9bABCbcPK2cBUHwg8= -cloud.google.com/go/cloudbuild v1.22.0/go.mod h1:p99MbQrzcENHb/MqU3R6rpqFRk/X+lNG3PdZEIhM95Y= +cloud.google.com/go/channel v1.20.0 h1:EeUa6SnD3+EL9B06G6N9Ud5/p/NtT6PC7lv5kmaUiHs= +cloud.google.com/go/channel v1.20.0/go.mod h1:nBR1Lz+/1TjSA16HTllvW9Y+QULODj3o3jEKrNNeOp4= cloud.google.com/go/cloudbuild v1.22.2 h1:4LlrIFa3IFLgD1mGEXmUE4cm9fYoU71OLwTvjM7Dg3c= cloud.google.com/go/cloudbuild v1.22.2/go.mod h1:rPyXfINSgMqMZvuTk1DbZcbKYtvbYF/i9IXQ7eeEMIM= -cloud.google.com/go/clouddms v1.8.4 h1:CDOd1nwmP4uek+nZhl4bhRIpzj8jMqoMRqKAfKlgLhw= -cloud.google.com/go/clouddms v1.8.4/go.mod h1:RadeJ3KozRwy4K/gAs7W74ZU3GmGgVq5K8sRqNs3HfA= cloud.google.com/go/clouddms v1.8.7 h1:IWJbQBEECTaNanDRN1XdR7FU53MJ1nylTl3s9T3MuyI= cloud.google.com/go/clouddms v1.8.7/go.mod h1:DhWLd3nzHP8GoHkA6hOhso0R9Iou+IGggNqlVaq/KZ4= -cloud.google.com/go/cloudtasks v1.13.3 h1:rXdznKjCa7WpzmvR2plrn2KJ+RZC1oYxPiRWNQjjf3k= -cloud.google.com/go/cloudtasks v1.13.3/go.mod h1:f9XRvmuFTm3VhIKzkzLCPyINSU3rjjvFUsFVGR5wi24= cloud.google.com/go/cloudtasks v1.13.6 h1:Fwan19UiNoFD+3KY0MnNHE5DyixOxNzS1mZ4ChOdpy0= cloud.google.com/go/cloudtasks v1.13.6/go.mod h1:/IDaQqGKMixD+ayM43CfsvWF2k36GeomEuy9gL4gLmU= -cloud.google.com/go/compute v1.34.0 h1:+k/kmViu4TEi97NGaxAATYtpYBviOWJySPZ+ekA95kk= -cloud.google.com/go/compute v1.34.0/go.mod h1:zWZwtLwZQyonEvIQBuIa0WvraMYK69J5eDCOw9VZU4g= -cloud.google.com/go/compute v1.38.0 h1:MilCLYQW2m7Dku8hRIIKo4r0oKastlD74sSu16riYKs= -cloud.google.com/go/compute v1.38.0/go.mod h1:oAFNIuXOmXbK/ssXm3z4nZB8ckPdjltJ7xhHCdbWFZM= -cloud.google.com/go/compute/metadata v0.5.0/go.mod h1:aHnloV2TPI38yx4s9+wAZhHykWvVCfu7hQbF+9CWoiY= -cloud.google.com/go/compute/metadata v0.6.0/go.mod h1:FjyFAW1MW0C203CEOMDTu3Dk1FlqW3Rga40jzHL4hfg= -cloud.google.com/go/contactcenterinsights v1.17.1 h1:xJoZbX0HM1zht8KxAB38hs2v4Hcl+vXGLo454LrdwxA= -cloud.google.com/go/contactcenterinsights v1.17.1/go.mod h1:n8OiNv7buLA2AkGVkfuvtW3HU13AdTmEwAlAu46bfxY= +cloud.google.com/go/compute v1.40.0 h1:dlEzKo/BtyEGNc+SflXwwoBh52dNl/A5BaSYurT0k0k= +cloud.google.com/go/compute v1.40.0/go.mod h1:P1doTJnlwurJDzIQFMp4mgU+vyCe9HU2NWTlqTfq3MY= cloud.google.com/go/contactcenterinsights v1.17.3 h1:lenyU3uzHwKDveCwmpfNxHYvLS3uEBWdn+O7+rSxy+Q= cloud.google.com/go/contactcenterinsights v1.17.3/go.mod h1:7Uu2CpxS3f6XxhRdlEzYAkrChpR5P5QfcdGAFEdHOG8= -cloud.google.com/go/container v1.42.2 h1:8ncSEBjkng6ucCICauaUGzBomoM2VyYzleAum1OFcow= -cloud.google.com/go/container v1.42.2/go.mod h1:y71YW7uR5Ck+9Vsbst0AF2F3UMgqmsN4SP8JR9xEsR8= cloud.google.com/go/container v1.43.0 h1:A6J92FJPfxTvyX7MHF+w4t2W9WCqvHOi9UB5SAeSy3w= cloud.google.com/go/container v1.43.0/go.mod h1:ETU9WZ1KM9ikEKLzrhRVao7KHtalDQu6aPqM34zDr/U= -cloud.google.com/go/containeranalysis v0.13.3 h1:1D8U75BeotZxrG4jR6NYBtOt+uAeBsWhpBZmSYLakQw= -cloud.google.com/go/containeranalysis v0.13.3/go.mod h1:0SYnagA1Ivb7qPqKNYPkCtphhkJn3IzgaSp3mj+9XAY= cloud.google.com/go/containeranalysis v0.14.1 h1:1SoHlNqL3XrhqcoozB+3eoHif2sRUFtp/JeASQTtGKo= cloud.google.com/go/containeranalysis v0.14.1/go.mod h1:28e+tlZgauWGHmEbnI5UfIsjMmrkoR1tFN0K2i71jBI= -cloud.google.com/go/datacatalog v1.24.3 h1:3bAfstDB6rlHyK0TvqxEwaeOvoN9UgCs2bn03+VXmss= -cloud.google.com/go/datacatalog v1.24.3/go.mod h1:Z4g33XblDxWGHngDzcpfeOU0b1ERlDPTuQoYG6NkF1s= cloud.google.com/go/datacatalog v1.26.0 h1:eFgygb3DTufTWWUB8ARk+dSuXz+aefNJXTlkWlQcWwE= cloud.google.com/go/datacatalog v1.26.0/go.mod h1:bLN2HLBAwB3kLTFT5ZKLHVPj/weNz6bR0c7nYp0LE14= -cloud.google.com/go/dataflow v0.10.3 h1:+7IfIXzYWSybIIDGK9FN2uqBsP/5b/Y0pBYzNhcmKSU= -cloud.google.com/go/dataflow v0.10.3/go.mod h1:5EuVGDh5Tg4mDePWXMMGAG6QYAQhLNyzxdNQ0A1FfW4= cloud.google.com/go/dataflow v0.11.0 h1:AdhB4cAkMOC9NtrHJxpKOVvO/VqBLaIyk0tEEhbGjYM= cloud.google.com/go/dataflow v0.11.0/go.mod h1:gNHC9fUjlV9miu0hd4oQaXibIuVYTQvZhMdPievKsPk= -cloud.google.com/go/dataform v0.10.3 h1:ZpGkZV8OyhUhvN/tfLffU2ki5ERTtqOunkIaiVAhmw0= -cloud.google.com/go/dataform v0.10.3/go.mod h1:8SruzxHYCxtvG53gXqDZvZCx12BlsUchuV/JQFtyTCw= cloud.google.com/go/dataform v0.12.0 h1:0eCPTPUC/RZ863aVfXTJLkg0tEpdpn62VD6ywSmmzxM= cloud.google.com/go/dataform v0.12.0/go.mod h1:PuDIEY0lSVuPrZqcFji1fmr5RRvz3DGz4YP/cONc8g4= -cloud.google.com/go/datafusion v1.8.3 h1:FTMtsf2nfGGlDCuE84/RvVaCcTIYE7WQSB0noeO0cwI= -cloud.google.com/go/datafusion v1.8.3/go.mod h1:hyglMzE57KRf0Rf/N2VRPcHCwKfZAAucx+LATY6Jc6Q= cloud.google.com/go/datafusion v1.8.6 h1:GZ6J+CR8CEeWAj8luRCtr8GvImSQRkArIIqGiZOnzBA= cloud.google.com/go/datafusion v1.8.6/go.mod h1:fCyKJF2zUKC+O3hc2F9ja5EUCAbT4zcH692z8HiFZFw= -cloud.google.com/go/datalabeling v0.9.3 h1:PqoA3gnOWaLcHCnqoZe4jh3jmiv6+Z7W2xUUkw/j4jE= -cloud.google.com/go/datalabeling v0.9.3/go.mod h1:3LDFUgOx+EuNUzDyjU7VElO8L+b5LeaZEFA/ZU1O1XU= cloud.google.com/go/datalabeling v0.9.6 h1:VOZ5U+78ttnhNCEID7qdeogqZQzK5N+LPHIQ9Q3YDsc= cloud.google.com/go/datalabeling v0.9.6/go.mod h1:n7o4x0vtPensZOoFwFa4UfZgkSZm8Qs0Pg/T3kQjXSM= -cloud.google.com/go/dataplex v1.22.0 h1:j4hD6opb+gq9CJNPFIlIggoW8Kjymg8Wmy2mdHmQoiw= -cloud.google.com/go/dataplex v1.22.0/go.mod h1:g166QMCGHvwc3qlTG4p34n+lHwu7JFfaNpMfI2uO7b8= -cloud.google.com/go/dataplex v1.25.3 h1:Xr0Toh6wyBlmL3H4EPu1YKwxUtkDSzzq+IP0iLc88kk= -cloud.google.com/go/dataplex v1.25.3/go.mod h1:wOJXnOg6bem0tyslu4hZBTncfqcPNDpYGKzed3+bd+E= +cloud.google.com/go/dataplex v1.26.0 h1:nu8/KrLR5v62L1lApGNgm61Oq+xaa2bS9rgc1csjqE0= +cloud.google.com/go/dataplex v1.26.0/go.mod h1:12R9nlLUzxOscbb2HgoYnkGNibmv4sXEVMXxrdw2a90= cloud.google.com/go/dataproc v1.12.0 h1:W47qHL3W4BPkAIbk4SWmIERwsWBaNnWm0P2sdx3YgGU= -cloud.google.com/go/dataproc/v2 v2.11.0 h1:6aRpyoRfNOP+r2+pGb7HeHtF+SYQID8kzztfHuK0plk= -cloud.google.com/go/dataproc/v2 v2.11.0/go.mod h1:9vgGrn57ra7KBqz+B2KD+ltzEXvnHAUClFgq/ryU99g= -cloud.google.com/go/dataproc/v2 v2.11.2 h1:KhC8wdLILpAs17yeTG6Miwg1v0nOP/OXD+9QNg3w6AQ= -cloud.google.com/go/dataproc/v2 v2.11.2/go.mod h1:xwukBjtfiO4vMEa1VdqyFLqJmcv7t3lo+PbLDcTEw+g= -cloud.google.com/go/dataqna v0.9.3 h1:lGUj2FYs650EUPDMV6plWBAoh8qH9Bu1KCz1PUYF2VY= -cloud.google.com/go/dataqna v0.9.3/go.mod h1:PiAfkXxa2LZYxMnOWVYWz3KgY7txdFg9HEMQPb4u1JA= +cloud.google.com/go/dataproc/v2 v2.14.0 h1:oiEM2efaJfiOClBOYcmW1K+tDP5pHdnYsPmfD55tiRw= +cloud.google.com/go/dataproc/v2 v2.14.0/go.mod h1:AqfdObN5w70H7meRXZOEY52WMK4yMrLtiOd9kROahSM= cloud.google.com/go/dataqna v0.9.7 h1:qTRAG/E3T63Xj1orefRlwupfwH9c9ERUAnWSRGp75so= cloud.google.com/go/dataqna v0.9.7/go.mod h1:4ac3r7zm7Wqm8NAc8sDIDM0v7Dz7d1e/1Ka1yMFanUM= cloud.google.com/go/datastore v1.20.0 h1:NNpXoyEqIJmZFc0ACcwBEaXnmscUpcG4NkKnbCePmiM= cloud.google.com/go/datastore v1.20.0/go.mod h1:uFo3e+aEpRfHgtp5pp0+6M0o147KoPaYNaPAKpfh8Ew= -cloud.google.com/go/datastream v1.13.0 h1:C5AeEdze55feJVb17a40QmlnyH/aMhn/uf3Go3hIqPA= -cloud.google.com/go/datastream v1.13.0/go.mod h1:GrL2+KC8mV4GjbVG43Syo5yyDXp3EH+t6N2HnZb1GOQ= cloud.google.com/go/datastream v1.14.1 h1:j+y0lUKm9pbDjJn0YcWxPI/hXNGUQ80GE6yrFuJC/JA= cloud.google.com/go/datastream v1.14.1/go.mod h1:JqMKXq/e0OMkEgfYe0nP+lDye5G2IhIlmencWxmesMo= -cloud.google.com/go/deploy v1.26.2 h1:1c2Cd3jdb0mrKHHfyzSQ5DRmxgYd07tIZZzuMNrwDxU= -cloud.google.com/go/deploy v1.26.2/go.mod h1:XpS3sG/ivkXCfzbzJXY9DXTeCJ5r68gIyeOgVGxGNEs= cloud.google.com/go/deploy v1.27.2 h1:C0VqBhFyQFp6+xgPHZAD7LeRA4XGy5YLzGmPQ2NhlLk= cloud.google.com/go/deploy v1.27.2/go.mod h1:4NHWE7ENry2A4O1i/4iAPfXHnJCZ01xckAKpZQwhg1M= -cloud.google.com/go/dialogflow v1.66.0 h1:/kfpZw20/3v4sC8czEIuvn3Bu3qOne5aHDYlRYHbu18= -cloud.google.com/go/dialogflow v1.66.0/go.mod h1:BPiRTnnXP/tHLot5h/U62Xcp+i6ekRj/bq6uq88p+Lw= -cloud.google.com/go/dialogflow v1.68.2 h1:bXpoqPRf37KKxB79PKr20B/TAU/Z5iA0FnB6C5N2jrA= -cloud.google.com/go/dialogflow v1.68.2/go.mod h1:E0Ocrhf5/nANZzBju8RX8rONf0PuIvz2fVj3XkbAhiY= -cloud.google.com/go/dlp v1.21.0 h1:9kz7+gaB/0gBZsDUnNT1asDihNZSrRFSeUTBcBdUAkk= -cloud.google.com/go/dlp v1.21.0/go.mod h1:Y9HOVtPoArpL9sI1O33aN/vK9QRwDERU9PEJJfM8DvE= -cloud.google.com/go/dlp v1.23.0 h1:3xWRKylXxhysaQaV+DLev1YcIywFUCc7yJEE6R7ZGDQ= -cloud.google.com/go/dlp v1.23.0/go.mod h1:vVT4RlyPMEMcVHexdPT6iMVac3seq3l6b8UPdYpgFrg= -cloud.google.com/go/documentai v1.35.2 h1:hswVobCWUTXtmn+4QqUIVkai7sDOe0QS2KB3IpqLkik= -cloud.google.com/go/documentai v1.35.2/go.mod h1:oh/0YXosgEq3hVhyH4ZQ7VNXPaveRO4eLVM3tBSZOsI= +cloud.google.com/go/dialogflow v1.69.0 h1:nW3vH/ysZWBdjQJ4rIh3PC5Do/Brz8KEp3OeDy9VW3U= +cloud.google.com/go/dialogflow v1.69.0/go.mod h1:+2drAzrguQ8vltf6qn6foBPHrT/fFa1S3FQ40byV2WU= +cloud.google.com/go/dlp v1.24.0 h1:ThCQO8Qy5TAfFEJQjhq80u5c93UMdM2uqI3pUZVy7Do= +cloud.google.com/go/dlp v1.24.0/go.mod h1:y6EsWNgMDye72NtqjGHYZjN/wUDnO9CUygLV8iuFeW0= cloud.google.com/go/documentai v1.37.0 h1:7fla8GcarupO15eatRTUveXCob6DOSW1Wa+1i63CM3Q= cloud.google.com/go/documentai v1.37.0/go.mod h1:qAf3ewuIUJgvSHQmmUWvM3Ogsr5A16U2WPHmiJldvLA= -cloud.google.com/go/domains v0.10.3 h1:wnqN5YwMrtLSjn+HB2sChgmZ6iocOta4Q41giQsiRjY= -cloud.google.com/go/domains v0.10.3/go.mod h1:m7sLe18p0PQab56bVH3JATYOJqyRHhmbye6gz7isC7o= cloud.google.com/go/domains v0.10.6 h1:TI+Aavwc31KD8huOquJz0ISchCq1zSEWc9M+JcPJyxc= cloud.google.com/go/domains v0.10.6/go.mod h1:3xzG+hASKsVBA8dOPc4cIaoV3OdBHl1qgUpAvXK7pGY= -cloud.google.com/go/edgecontainer v1.4.1 h1:SwQuHQiheVfL7b5ar/AXDberiaqr/yiue8X55AdWnZU= -cloud.google.com/go/edgecontainer v1.4.1/go.mod h1:ubMQvXSxsvtEjJLyqcPFrdWrHfvjQxdoyt+SUrAi5ek= cloud.google.com/go/edgecontainer v1.4.3 h1:9tfGCicvrki927T+hGMB0yYmwIbRuZY6JR1/awrKiZ0= cloud.google.com/go/edgecontainer v1.4.3/go.mod h1:q9Ojw2ox0uhAvFisnfPRAXFTB1nfRIOIXVWzdXMZLcE= cloud.google.com/go/errorreporting v0.3.2 h1:isaoPwWX8kbAOea4qahcmttoS79+gQhvKsfg5L5AgH8= cloud.google.com/go/errorreporting v0.3.2/go.mod h1:s5kjs5r3l6A8UUyIsgvAhGq6tkqyBCUss0FRpsoVTww= -cloud.google.com/go/essentialcontacts v1.7.3 h1:Paw495vxVyKuAgcQ2NQk09iRZBhPYRytknydEnvzcv4= -cloud.google.com/go/essentialcontacts v1.7.3/go.mod h1:uimfZgDbhWNCmBpwUUPHe4vcMY2azsq/axC9f7vZFKI= cloud.google.com/go/essentialcontacts v1.7.6 h1:ysHZ4gr4plW1CL1Ur/AucUUfh20hDjSFbfjxSK0q/sk= cloud.google.com/go/essentialcontacts v1.7.6/go.mod h1:/Ycn2egr4+XfmAfxpLYsJeJlVf9MVnq9V7OMQr9R4lA= -cloud.google.com/go/eventarc v1.15.1 h1:RMymT7R87LaxKugOKwooOoheWXUm1NMeOfh3CVU9g54= -cloud.google.com/go/eventarc v1.15.1/go.mod h1:K2luolBpwaVOujZQyx6wdG4n2Xum4t0q1cMBmY1xVyI= cloud.google.com/go/eventarc v1.15.5 h1:bZW7ZMM+XXNErg6rOZcgxUzAgz4vpReRDP3ZiGf7/sI= cloud.google.com/go/eventarc v1.15.5/go.mod h1:vDCqGqyY7SRiickhEGt1Zhuj81Ya4F/NtwwL3OZNskg= -cloud.google.com/go/filestore v1.9.3 h1:vTXQI5qYKZ8dmCyHN+zVfaMyXCYbyZNM0CkPzpPUn7Q= -cloud.google.com/go/filestore v1.9.3/go.mod h1:Me0ZRT5JngT/aZPIKpIK6N4JGMzrFHRtGHd9ayUS4R4= cloud.google.com/go/filestore v1.10.2 h1:LjoAyp9TvVNBns3sUUzPaNsQiGpR2BReGmTS3bUCuBE= cloud.google.com/go/filestore v1.10.2/go.mod h1:w0Pr8uQeSRQfCPRsL0sYKW6NKyooRgixCkV9yyLykR4= cloud.google.com/go/firestore v1.18.0 h1:cuydCaLS7Vl2SatAeivXyhbhDEIR8BDmtn4egDhIn2s= cloud.google.com/go/firestore v1.18.0/go.mod h1:5ye0v48PhseZBdcl0qbl3uttu7FIEwEYVaWm0UIEOEU= -cloud.google.com/go/functions v1.19.3 h1:V0vCHSgFTUqKn57+PUXp1UfQY0/aMkveAw7wXeM3Lq0= -cloud.google.com/go/functions v1.19.3/go.mod h1:nOZ34tGWMmwfiSJjoH/16+Ko5106x+1Iji29wzrBeOo= cloud.google.com/go/functions v1.19.6 h1:vJgWlvxtJG6p/JrbXAkz83DbgwOyFhZZI1Y32vUddjY= cloud.google.com/go/functions v1.19.6/go.mod h1:0G0RnIlbM4MJEycfbPZlCzSf2lPOjL7toLDwl+r0ZBw= cloud.google.com/go/gaming v1.9.0 h1:7vEhFnZmd931Mo7sZ6pJy7uQPDxF7m7v8xtBheG08tc= -cloud.google.com/go/gkebackup v1.6.3 h1:djdExe/QgoKdp1gnIO1G5BoO1o/yGQOQJJEZ4QKTEXQ= -cloud.google.com/go/gkebackup v1.6.3/go.mod h1:JJzGsA8/suXpTDtqI7n9RZW97PXa2CIp+n8aRC/y57k= cloud.google.com/go/gkebackup v1.8.0 h1:eBqOt61yEChvj7I/GDPBbdCCRdUPudD1qrQYfYWV3Ok= cloud.google.com/go/gkebackup v1.8.0/go.mod h1:FjsjNldDilC9MWKEHExnK3kKJyTDaSdO1vF0QeWSOPU= -cloud.google.com/go/gkeconnect v0.12.1 h1:YVpR0vlHSP/wD74PXEbKua4Aamud+wiYm4TiewNjD3M= -cloud.google.com/go/gkeconnect v0.12.1/go.mod h1:L1dhGY8LjINmWfR30vneozonQKRSIi5DWGIHjOqo58A= cloud.google.com/go/gkeconnect v0.12.4 h1:67/rnPmF/I1Wmf7jWyKH+z4OWjU8ZUI0Vmzxvmzf3KY= cloud.google.com/go/gkeconnect v0.12.4/go.mod h1:bvpU9EbBpZnXGo3nqJ1pzbHWIfA9fYqgBMJ1VjxaZdk= -cloud.google.com/go/gkehub v0.15.3 h1:yZ6lNJ9rNIoQmWrG14dB3+BFjS/EIRBf7Bo6jc5QWlE= -cloud.google.com/go/gkehub v0.15.3/go.mod h1:nzFT/Q+4HdQES/F+FP1QACEEWR9Hd+Sh00qgiH636cU= cloud.google.com/go/gkehub v0.15.6 h1:9iogrmNNa+drDPf/zkLH/6KGgUf7FuuyokmithoGwMQ= cloud.google.com/go/gkehub v0.15.6/go.mod h1:sRT0cOPAgI1jUJrS3gzwdYCJ1NEzVVwmnMKEwrS2QaM= -cloud.google.com/go/gkemulticloud v1.5.1 h1:JWe6PDNpNU88ZYvQkTd7w28fgeIs/gg6i0hcjUkgZ3M= -cloud.google.com/go/gkemulticloud v1.5.1/go.mod h1:OdmhfSPXuJ0Kn9dQ2I3Ou7XZ3QK8caV4XVOJZwrIa3s= cloud.google.com/go/gkemulticloud v1.5.3 h1:334aZmOzIt3LVBpguCof8IHaLaftcZlx+L0TGBukYkY= cloud.google.com/go/gkemulticloud v1.5.3/go.mod h1:KPFf+/RcfvmuScqwS9/2MF5exZAmXSuoSLPuaQ98Xlk= cloud.google.com/go/grafeas v0.2.0 h1:CYjC+xzdPvbV65gi6Dr4YowKcmLo045pm18L0DhdELM= -cloud.google.com/go/grafeas v0.3.11 h1:CobnwnyeY1j1Defi5vbEircI+jfrk3ci5m004ZjiFP4= -cloud.google.com/go/grafeas v0.3.11/go.mod h1:dcQyG2+T4tBgG0MvJAh7g2wl/xHV2w+RZIqivwuLjNg= -cloud.google.com/go/grafeas v0.3.15 h1:lBjwKmhpiqOAFaE0xdqF8CqO74a99s8tUT5mCkBBxPs= -cloud.google.com/go/grafeas v0.3.15/go.mod h1:irwcwIQOBlLBotGdMwme8PipnloOPqILfIvMwlmu8Pk= -cloud.google.com/go/gsuiteaddons v1.7.4 h1:f3eMYsCDdg2AeldIPdKmBRxN1WoiTpE3RvX5orcm/I8= -cloud.google.com/go/gsuiteaddons v1.7.4/go.mod h1:gpE2RUok+HUhuK7RPE/fCOEgnTffS0lCHRaAZLxAMeE= cloud.google.com/go/gsuiteaddons v1.7.7 h1:sk0SxpCGIA7tIO//XdiiG29f2vrF6Pq/dsxxyBGiRBY= cloud.google.com/go/gsuiteaddons v1.7.7/go.mod h1:zTGmmKG/GEBCONsvMOY2ckDiEsq3FN+lzWGUiXccF9o= -cloud.google.com/go/iam v1.2.2/go.mod h1:0Ys8ccaZHdI1dEUilwzqng/6ps2YB6vRsjIe00/+6JY= -cloud.google.com/go/iam v1.4.0/go.mod h1:gMBgqPaERlriaOV0CUl//XUzDhSfXevn4OEUbg6VRs4= -cloud.google.com/go/iap v1.10.3 h1:OWNYFHPyIBNHEAEFdVKOltYWe0g3izSrpFJW6Iidovk= -cloud.google.com/go/iap v1.10.3/go.mod h1:xKgn7bocMuCFYhzRizRWP635E2LNPnIXT7DW0TlyPJ8= cloud.google.com/go/iap v1.11.2 h1:VIioCrYsyWiRGx7Y8RDNylpI6d4t1Qx5ZgSLUVmWWPo= cloud.google.com/go/iap v1.11.2/go.mod h1:Bh99DMUpP5CitL9lK0BC8MYgjjYO4b3FbyhgW1VHJvg= -cloud.google.com/go/ids v1.5.3 h1:wbFF7twu0XScFr+dtsVxTTttbFIRYt/SJjZiHFidtYE= -cloud.google.com/go/ids v1.5.3/go.mod h1:a2MX8g18Eqs7yxD/pnEdid42SyBUm9LIzSWf8Jux9OY= cloud.google.com/go/ids v1.5.6 h1:uKGuaWozDcjg3wyf54Gd7tCH2YK8BFeH9qo1xBNiPKE= cloud.google.com/go/ids v1.5.6/go.mod h1:y3SGLmEf9KiwKsH7OHvYYVNIJAtXybqsD2z8gppsziQ= -cloud.google.com/go/iot v1.8.3 h1:aPWYQ+A1NX6ou/5U0nFAiXWdVT8OBxZYVZt2fBl2gWA= -cloud.google.com/go/iot v1.8.3/go.mod h1:dYhrZh+vUxIQ9m3uajyKRSW7moF/n0rYmA2PhYAkMFE= cloud.google.com/go/iot v1.8.6 h1:A3AhugnIViAZkC3/lHAQDaXBIk2ZOPBZS0XQCyZsjjc= cloud.google.com/go/iot v1.8.6/go.mod h1:MThnkiihNkMysWNeNje2Hp0GSOpEq2Wkb/DkBCVYa0U= -cloud.google.com/go/language v1.14.3 h1:8hmFMiS3wjjj3TX/U1zZYTgzwZoUjDbo9PaqcYEmuB4= -cloud.google.com/go/language v1.14.3/go.mod h1:hjamj+KH//QzF561ZuU2J+82DdMlFUjmiGVWpovGGSA= cloud.google.com/go/language v1.14.5 h1:BVJ/POtlnJ55LElvnQY19UOxpMVtHoHHkFJW2uHJsVU= cloud.google.com/go/language v1.14.5/go.mod h1:nl2cyAVjcBct1Hk73tzxuKebk0t2eULFCaruhetdZIA= -cloud.google.com/go/lifesciences v0.10.3 h1:Z05C+Ui953f0EQx9hJ1la6+QQl8ADrIs3iNwP5Elkpg= -cloud.google.com/go/lifesciences v0.10.3/go.mod h1:hnUUFht+KcZcliixAg+iOh88FUwAzDQQt5tWd7iIpNg= cloud.google.com/go/lifesciences v0.10.6 h1:Vu7XF4s5KJ8+mSLIL4eaQM6JTyWXvSB54oqC+CUZH20= cloud.google.com/go/lifesciences v0.10.6/go.mod h1:1nnZwaZcBThDujs9wXzECnd1S5d+UiDkPuJWAmhRi7Q= -cloud.google.com/go/longrunning v0.5.6/go.mod h1:vUaDrWYOMKRuhiv6JBnn49YxCPz2Ayn9GqyjaBT8/mA= -cloud.google.com/go/longrunning v0.6.2/go.mod h1:k/vIs83RN4bE3YCswdXC5PFfWVILjm3hpEUlSko4PiI= -cloud.google.com/go/longrunning v0.6.4/go.mod h1:ttZpLCe6e7EXvn9OxpBRx7kZEB0efv8yBO6YnVMfhJs= -cloud.google.com/go/longrunning v0.6.6/go.mod h1:hyeGJUrPHcx0u2Uu1UFSoYZLn4lkMrccJig0t4FI7yw= -cloud.google.com/go/managedidentities v1.7.3 h1:b9xGs24BIjfyvLgCtJoClOZpPi8d8owPgWe5JEINgaY= -cloud.google.com/go/managedidentities v1.7.3/go.mod h1:H9hO2aMkjlpY+CNnKWRh+WoQiUIDO8457wWzUGsdtLA= cloud.google.com/go/managedidentities v1.7.6 h1:zrZVWXZJlmHnfpyCrTQIbDBGUBHrcOOvrsjMjoXRxrk= cloud.google.com/go/managedidentities v1.7.6/go.mod h1:pYCWPaI1AvR8Q027Vtp+SFSM/VOVgbjBF4rxp1/z5p4= -cloud.google.com/go/maps v1.19.0 h1:deVm1ZFyCrUwxG11CdvtBz350VG5JUQ/LHTLnQrBgrM= -cloud.google.com/go/maps v1.19.0/go.mod h1:goHUXrmzoZvQjUVd0KGhH8t3AYRm17P8b+fsyR1UAmQ= -cloud.google.com/go/maps v1.21.0 h1:El61AfMxC1sU/RU8Wzs9dkZEgltyunKM86aKF9aDlaE= -cloud.google.com/go/maps v1.21.0/go.mod h1:cqzZ7+DWUKKbPTgqE+KuNQtiCRyg/o7WZF9zDQk+HQs= -cloud.google.com/go/mediatranslation v0.9.3 h1:nRBjeaMLipw05Br+qDAlSCcCQAAlat4mvpafztbEVgc= -cloud.google.com/go/mediatranslation v0.9.3/go.mod h1:KTrFV0dh7duYKDjmuzjM++2Wn6yw/I5sjZQVV5k3BAA= +cloud.google.com/go/maps v1.21.1 h1:IWnCNopmhrjwawsl2b/BdScu7IrGImSNaAD3LKttkxE= +cloud.google.com/go/maps v1.21.1/go.mod h1:TAt/cYHndJQBrir8DN8OHiS0HvKwsBTqDGRfAtLIulU= cloud.google.com/go/mediatranslation v0.9.6 h1:SDGatA73TgZ8iCvILVXpk/1qhTK5DJyufUDEWgbmbV8= cloud.google.com/go/mediatranslation v0.9.6/go.mod h1:WS3QmObhRtr2Xu5laJBQSsjnWFPPthsyetlOyT9fJvE= -cloud.google.com/go/memcache v1.11.3 h1:XH/qT3GbbSH//R0JTqR77lRpBxaa0N9sHgAzfwbTrv0= -cloud.google.com/go/memcache v1.11.3/go.mod h1:UeWI9cmY7hvjU1EU6dwJcQb6EFG4GaM3KNXOO2OFsbI= cloud.google.com/go/memcache v1.11.6 h1:33IVqQEmFiITsBXwGHeTkUhWz0kLNKr90nV3e22uLPs= cloud.google.com/go/memcache v1.11.6/go.mod h1:ZM6xr1mw3F8TWO+In7eq9rKlJc3jlX2MDt4+4H+/+cc= -cloud.google.com/go/metastore v1.14.3 h1:jDqeCw6NGDRAPT9+2Y/EjnWAB0BfCcUfmPLOyhB0eHs= -cloud.google.com/go/metastore v1.14.3/go.mod h1:HlbGVOvg0ubBLVFRk3Otj3gtuzInuzO/TImOBwsKlG4= cloud.google.com/go/metastore v1.14.7 h1:dLm59AHHZCorveCylj7c2iWhkQsmMIeWTsV+tG/BXtY= cloud.google.com/go/metastore v1.14.7/go.mod h1:0dka99KQofeUgdfu+K/Jk1KeT9veWZlxuZdJpZPtuYU= -cloud.google.com/go/monitoring v1.21.2/go.mod h1:hS3pXvaG8KgWTSz+dAdyzPrGUYmi2Q+WFX8g2hqVEZU= -cloud.google.com/go/monitoring v1.22.1/go.mod h1:AuZZXAoN0WWWfsSvET1Cpc4/1D8LXq8KRDU87fMS6XY= -cloud.google.com/go/monitoring v1.24.0/go.mod h1:Bd1PRK5bmQBQNnuGwHBfUamAV1ys9049oEPHnn4pcsc= -cloud.google.com/go/networkconnectivity v1.16.1 h1:YsVhG71ZC4FkqCP2oCI55x/JeGFyd7738Lt8iNTrzJw= -cloud.google.com/go/networkconnectivity v1.16.1/go.mod h1:GBC1iOLkblcnhcnfRV92j4KzqGBrEI6tT7LP52nZCTk= cloud.google.com/go/networkconnectivity v1.17.1 h1:RQcG1rZNCNV5Dn3tnINs4TYswDXk2hKH+85eh+JvoWU= cloud.google.com/go/networkconnectivity v1.17.1/go.mod h1:DTZCq8POTkHgAlOAAEDQF3cMEr/B9k1ZbpklqvHEBtg= -cloud.google.com/go/networkmanagement v1.18.0 h1:oEoFGPYxTBsY47h0zdoE2ojV5aU/541D83UmxfjHWaE= -cloud.google.com/go/networkmanagement v1.18.0/go.mod h1:yTxpAFuvQOOKgL3W7+k2Rp1bSKTxyRcZ5xNHGdHUM6w= cloud.google.com/go/networkmanagement v1.19.1 h1:ecukgArkYCVcK5w2h7WDDd+nHgmBAp9Bst7ClmVKz5A= cloud.google.com/go/networkmanagement v1.19.1/go.mod h1:icgk265dNnilxQzpr6rO9WuAuuCmUOqq9H6WBeM2Af4= -cloud.google.com/go/networksecurity v0.10.3 h1:JLJBFbxc8D7/OS81MyRoKhc2OvnVJxy5VMoQqqAhA7k= -cloud.google.com/go/networksecurity v0.10.3/go.mod h1:G85ABVcPscEgpw+gcu+HUxNZJWjn3yhTqEU7+SsltFM= cloud.google.com/go/networksecurity v0.10.6 h1:6b6fcCG9BFNcmtNO+VuPE04vkZb5TKNX9+7ZhYMgstE= cloud.google.com/go/networksecurity v0.10.6/go.mod h1:FTZvabFPvK2kR/MRIH3l/OoQ/i53eSix2KA1vhBMJec= -cloud.google.com/go/notebooks v1.12.3 h1:+9DrGJcZhCu6B2t0JJorekjIUBvg/KvBmXJYGmfvVvA= -cloud.google.com/go/notebooks v1.12.3/go.mod h1:I0pMxZct+8Rega2LYrXL8jGAGZgLchSmh8Ksc+0xNyA= cloud.google.com/go/notebooks v1.12.6 h1:nCfZwVihArMPP2atRoxRrXOXJ/aC9rAgpBQGCc2zpYw= cloud.google.com/go/notebooks v1.12.6/go.mod h1:3Z4TMEqAKP3pu6DI/U+aEXrNJw9hGZIVbp+l3zw8EuA= -cloud.google.com/go/optimization v1.7.3 h1:JwQjjoBZJpsoMQe/3mhVBMVZuSdagHg2pGOnwh2Jk+E= -cloud.google.com/go/optimization v1.7.3/go.mod h1:GlYFp4Mju0ybK5FlOUtV6zvWC00TIScdbsPyF6Iv144= cloud.google.com/go/optimization v1.7.6 h1:jDvIuSxDsXI2P7l2sYXm6CoX1YBIIT6Khm5m0hq0/KQ= cloud.google.com/go/optimization v1.7.6/go.mod h1:4MeQslrSJGv+FY4rg0hnZBR/tBX2awJ1gXYp6jZpsYY= -cloud.google.com/go/orchestration v1.11.4 h1:SFAsKyqvtS8VFcsq+JgXAeRkrksB9UH+AH7iFamkmlc= -cloud.google.com/go/orchestration v1.11.4/go.mod h1:UKR2JwogaZmDGnAcBgAQgCPn89QMqhXFUCYVhHd31vs= cloud.google.com/go/orchestration v1.11.9 h1:PnlZ/O4R/eiounpxUkhI9ZXRMWbG7vFqxc6L6sR+31k= cloud.google.com/go/orchestration v1.11.9/go.mod h1:KKXK67ROQaPt7AxUS1V/iK0Gs8yabn3bzJ1cLHw4XBg= -cloud.google.com/go/orgpolicy v1.14.2 h1:WFvgmjq/FO5GiXlhebltA9N14KdbLMcgG88ME+SWeBo= -cloud.google.com/go/orgpolicy v1.14.2/go.mod h1:2fTDMT3X048iFKxc6DEgkG+a/gN+68qEgtPrHItKMzo= cloud.google.com/go/orgpolicy v1.15.0 h1:uQziDu3UKYk9ZwUgneZAW5aWxZFKgOXXsuVKFKh0z7Y= cloud.google.com/go/orgpolicy v1.15.0/go.mod h1:NTQLwgS8N5cJtdfK55tAnMGtvPSsy95JJhESwYHaJVs= -cloud.google.com/go/osconfig v1.14.3 h1:cyf1PMK5c2/WOIr5r2lxjH/XBJMA9P4zC8Tm10i0z3M= -cloud.google.com/go/osconfig v1.14.3/go.mod h1:9D2MS1Etne18r/mAeW5jtto3toc9H1qu9wLNDG3NvQg= cloud.google.com/go/osconfig v1.14.6 h1:4uJrA1obzMBp1I+DF15y/MvsXKIODevuANpq3QhvX30= cloud.google.com/go/osconfig v1.14.6/go.mod h1:LS39HDBH0IJDFgOUkhSZUHFQzmcWaCpYXLrc3A4CVzI= -cloud.google.com/go/oslogin v1.14.3 h1:yomxnFPk+ye0zd0mJ15nn9fH4Ns7ex4xA3ll+u2q59A= -cloud.google.com/go/oslogin v1.14.3/go.mod h1:fDEGODTG/W9ZGUTHTlMh8euXWC1fTcgjJ9Kcxxy14a8= cloud.google.com/go/oslogin v1.14.6 h1:BDKVcxo1OO4ZT+PbuFchZjnbrlUGfChilt6+pITY1VI= cloud.google.com/go/oslogin v1.14.6/go.mod h1:xEvcRZTkMXHfNSKdZ8adxD6wvRzeyAq3cQX3F3kbMRw= -cloud.google.com/go/phishingprotection v0.9.3 h1:T5mGFV0ggBKg3qt9myFRiGJu+nIUucuHLAtVpAuQ08I= -cloud.google.com/go/phishingprotection v0.9.3/go.mod h1:ylzN9HruB/X7dD50I4sk+FfYzuPx9fm5JWsYI0t7ncc= cloud.google.com/go/phishingprotection v0.9.6 h1:yl572bBQbPjflX250SOflN6gwO2uYoddN2uRp36fDTo= cloud.google.com/go/phishingprotection v0.9.6/go.mod h1:VmuGg03DCI0wRp/FLSvNyjFj+J8V7+uITgHjCD/x4RQ= -cloud.google.com/go/policytroubleshooter v1.11.3 h1:ekIWI8JbKkpOfrgH/THGamQE/D16tcVBYJyrkseVcYI= -cloud.google.com/go/policytroubleshooter v1.11.3/go.mod h1:AFHlORqh4AnMC0twc2yPKfzlozp3DO0yo9OfOd9aNOs= cloud.google.com/go/policytroubleshooter v1.11.6 h1:Z8+tO2z21MY1arBBuJjwrOjbw8fbZb13AZTHXdzkl2U= cloud.google.com/go/policytroubleshooter v1.11.6/go.mod h1:jdjYGIveoYolk38Dm2JjS5mPkn8IjVqPsDHccTMu3mY= -cloud.google.com/go/privatecatalog v0.10.4 h1:fu2LABMi7CgZORQ2oNGbc0hoZ0FTqLkjGqIgAV/Kc7U= -cloud.google.com/go/privatecatalog v0.10.4/go.mod h1:n/vXBT+Wq8B4nSRUJNDsmqla5BYjbVxOlHzS6PjiF+w= cloud.google.com/go/privatecatalog v0.10.7 h1:R951ikhxIanXEijBCu0xnoUAOteS5m/Xplek0YvsNTE= cloud.google.com/go/privatecatalog v0.10.7/go.mod h1:Fo/PF/B6m4A9vUYt0nEF1xd0U6Kk19/Je3eZGrQ6l60= -cloud.google.com/go/pubsub v1.47.0 h1:Ou2Qu4INnf7ykrFjGv2ntFOjVo8Nloh/+OffF4mUu9w= -cloud.google.com/go/pubsub v1.47.0/go.mod h1:LaENesmga+2u0nDtLkIOILskxsfvn/BXX9Ak1NFxOs8= cloud.google.com/go/pubsub v1.49.0 h1:5054IkbslnrMCgA2MAEPcsN3Ky+AyMpEZcii/DoySPo= cloud.google.com/go/pubsub v1.49.0/go.mod h1:K1FswTWP+C1tI/nfi3HQecoVeFvL4HUOB1tdaNXKhUY= cloud.google.com/go/pubsublite v1.8.2 h1:jLQozsEVr+c6tOU13vDugtnaBSUy/PD5zK6mhm+uF1Y= cloud.google.com/go/pubsublite v1.8.2/go.mod h1:4r8GSa9NznExjuLPEJlF1VjOPOpgf3IT6k8x/YgaOPI= cloud.google.com/go/recaptchaenterprise v1.3.1 h1:u6EznTGzIdsyOsvm+Xkw0aSuKFXQlyjGE9a4exk6iNQ= -cloud.google.com/go/recaptchaenterprise/v2 v2.19.4 h1:T5YGzaXwTesHaPDNTAuU3neDwZEnfjce70zufPFUwno= -cloud.google.com/go/recaptchaenterprise/v2 v2.19.4/go.mod h1:WaglfocMJGkqZVdXY/FVB7OhoVRONPS4uXqtNn6HfX0= cloud.google.com/go/recaptchaenterprise/v2 v2.20.4 h1:P4QMryKcWdi4LIe1Sx0b2ZOAQv5gVfdzPt2peXcN32Y= cloud.google.com/go/recaptchaenterprise/v2 v2.20.4/go.mod h1:3H8nb8j8N7Ss2eJ+zr+/H7gyorfzcxiDEtVBDvDjwDQ= -cloud.google.com/go/recommendationengine v0.9.3 h1:kBpcYPx4ys4lrDGKp4OhP2uy8h7UjlmLW/qoO5Xb2bY= -cloud.google.com/go/recommendationengine v0.9.3/go.mod h1:QRnX5aM7DCvtqtSs7I0zay5Zfq3fzxqnsPbZF7pa1G8= cloud.google.com/go/recommendationengine v0.9.6 h1:slN7h23vswGccW8x3f+xUXCu9Yo18/GNkazH93LJbFk= cloud.google.com/go/recommendationengine v0.9.6/go.mod h1:nZnjKJu1vvoxbmuRvLB5NwGuh6cDMMQdOLXTnkukUOE= -cloud.google.com/go/recommender v1.13.3 h1:dVlOjxsbjuhlwu4MIcyPWe09qVcDqc419iOjdPl5RHk= -cloud.google.com/go/recommender v1.13.3/go.mod h1:6yAmcfqJRKglZrVuTHsieTFEm4ai9JtY3nQzmX4TC0Q= cloud.google.com/go/recommender v1.13.5 h1:cIsyRKGNw4LpCfY5c8CCQadhlp54jP4fHtP+d5Sy2xE= cloud.google.com/go/recommender v1.13.5/go.mod h1:v7x/fzk38oC62TsN5Qkdpn0eoMBh610UgArJtDIgH/E= -cloud.google.com/go/redis v1.18.0 h1:xcu35SCyHSp+nKV6QNIklgkBKTH1qb0aLUXjl0mSR8I= -cloud.google.com/go/redis v1.18.0/go.mod h1:fJ8dEQJQ7DY+mJRMkSafxQCuc8nOyPUwo9tXJqjvNEY= cloud.google.com/go/redis v1.18.2 h1:JlHLceAOILEmbn+NIS7l+vmUKkFuobLToCWTxL7NGcQ= cloud.google.com/go/redis v1.18.2/go.mod h1:q6mPRhLiR2uLf584Lcl4tsiRn0xiFlu6fnJLwCORMtY= -cloud.google.com/go/resourcemanager v1.10.3 h1:SHOMw0kX0xWratC5Vb5VULBeWiGlPYAs82kiZqNtWpM= -cloud.google.com/go/resourcemanager v1.10.3/go.mod h1:JSQDy1JA3K7wtaFH23FBGld4dMtzqCoOpwY55XYR8gs= cloud.google.com/go/resourcemanager v1.10.6 h1:LIa8kKE8HF71zm976oHMqpWFiaDHVw/H1YMO71lrGmo= cloud.google.com/go/resourcemanager v1.10.6/go.mod h1:VqMoDQ03W4yZmxzLPrB+RuAoVkHDS5tFUUQUhOtnRTg= cloud.google.com/go/resourcesettings v1.8.3 h1:13HOFU7v4cEvIHXSAQbinF4wp2Baybbq7q9FMctg1Ek= cloud.google.com/go/resourcesettings v1.8.3/go.mod h1:BzgfXFHIWOOmHe6ZV9+r3OWfpHJgnqXy8jqwx4zTMLw= -cloud.google.com/go/retail v1.19.2 h1:PT6CUlazIFIOLLJnV+bPBtiSH8iusKZ+FZRzZYFt2vk= -cloud.google.com/go/retail v1.19.2/go.mod h1:71tRFYAcR4MhrZ1YZzaJxr030LvaZiIcupH7bXfFBcY= -cloud.google.com/go/retail v1.21.0 h1:8jgWgtAg1mk91WmaoWRTlL9CcvazPwqZ3YT9n6Gva9U= -cloud.google.com/go/retail v1.21.0/go.mod h1:LuG+QvBdLfKfO+7nnF3eA3l1j4TQw3Sg+UqlUorquRc= -cloud.google.com/go/run v1.9.0 h1:9WeTqeEcriXqRViXMNwczjFJjixOSBlSlk/fW3lfKPg= -cloud.google.com/go/run v1.9.0/go.mod h1:Dh0+mizUbtBOpPEzeXMM22t8qYQpyWpfmUiWQ0+94DU= -cloud.google.com/go/run v1.10.0 h1:CDhz0PPzI/cVpmNFyHe3Yp21jNpiAqtkfRxuoLi+JU0= -cloud.google.com/go/run v1.10.0/go.mod h1:z7/ZidaHOCjdn5dV0eojRbD+p8RczMk3A7Qi2L+koHg= -cloud.google.com/go/scheduler v1.11.4 h1:ewVvigBnEnrr9Ih8CKnLVoB5IiULaWfYU5nEnnfVAto= -cloud.google.com/go/scheduler v1.11.4/go.mod h1:0ylvH3syJnRi8EDVo9ETHW/vzpITR/b+XNnoF+GPSz4= +cloud.google.com/go/retail v1.22.0 h1:4Nvso8WG3J2T8F78rs61g1INwpd3feX8WPI/gS71w8s= +cloud.google.com/go/retail v1.22.0/go.mod h1:INfBxkiT1UcK+ohGFP9hsCM2UVECK3EzjfCut4lgDf8= +cloud.google.com/go/run v1.10.1 h1:MbP5yejLol5IagqF5TYnU7JNXR5UhzCqPZ9OMZXr5c0= +cloud.google.com/go/run v1.10.1/go.mod h1:aQWMoB2SNXQJUYIOeLRCacO/2VwdSO9FxpM6jxrimAo= cloud.google.com/go/scheduler v1.11.7 h1:zkMEJ0UbEJ3O7NwEUlKLIp6eXYv1L7wHjbxyxznajKM= cloud.google.com/go/scheduler v1.11.7/go.mod h1:gqYs8ndLx2M5D0oMJh48aGS630YYvC432tHCnVWN13s= -cloud.google.com/go/secretmanager v1.14.5 h1:W++V0EL9iL6T2+ec24Dm++bIti0tI6Gx6sCosDBters= -cloud.google.com/go/secretmanager v1.14.5/go.mod h1:GXznZF3qqPZDGZQqETZwZqHw4R6KCaYVvcGiRBA+aqY= -cloud.google.com/go/secretmanager v1.14.7 h1:VkscIRzj7GcmZyO4z9y1EH7Xf81PcoiAo7MtlD+0O80= -cloud.google.com/go/secretmanager v1.14.7/go.mod h1:uRuB4F6NTFbg0vLQ6HsT7PSsfbY7FqHbtJP1J94qxGc= -cloud.google.com/go/security v1.18.3 h1:ya9gfY1ign6Yy25VMMMgZ9xy7D/TczDB0ElXcyWmEVE= -cloud.google.com/go/security v1.18.3/go.mod h1:NmlSnEe7vzenMRoTLehUwa/ZTZHDQE59IPRevHcpCe4= -cloud.google.com/go/security v1.18.5 h1:6hqzvuwC8za9jyCTxygmEHnp4vZ8hfhwKVArxSCAVCo= -cloud.google.com/go/security v1.18.5/go.mod h1:D1wuUkDwGqTKD0Nv7d4Fn2Dc53POJSmO4tlg1K1iS7s= -cloud.google.com/go/securitycenter v1.36.0 h1:IdDiAa7gYtL7Gdx+wEaNHimudk3ZkEGNhdz9FuEuxWM= -cloud.google.com/go/securitycenter v1.36.0/go.mod h1:AErAQqIvrSrk8cpiItJG1+ATl7SD7vQ6lgTFy/Tcs4Q= -cloud.google.com/go/securitycenter v1.36.2 h1:hLA58IBYmWrNiXDIONvuCUQ4sHLVPy8JvDo2j1wSYCw= -cloud.google.com/go/securitycenter v1.36.2/go.mod h1:80ocoXS4SNWxmpqeEPhttYrmlQzCPVGaPzL3wVcoJvE= +cloud.google.com/go/secretmanager v1.15.0 h1:RtkCMgTpaBMbzozcRUGfZe46jb9a3qh5EdEtVRUATF8= +cloud.google.com/go/secretmanager v1.15.0/go.mod h1:1hQSAhKK7FldiYw//wbR/XPfPc08eQ81oBsnRUHEvUc= +cloud.google.com/go/security v1.19.0 h1:GI6kufPbHFINq998M7x60rfV5MVo6yhD+uVrjNzueKw= +cloud.google.com/go/security v1.19.0/go.mod h1:ks6NsA9Q6UODfLLgXr4MrxC/p7Bc5k15zqcfwvqlIlw= +cloud.google.com/go/securitycenter v1.37.0 h1:UR8cUgXFYpWxKkKnUNy65hlrAzgwBZBVxZilJ50ESXU= +cloud.google.com/go/securitycenter v1.37.0/go.mod h1:DdQi6OEzw1rmLtPpqtUx6bqnQq8ZdCVuG9eZRYz2QAE= cloud.google.com/go/servicecontrol v1.11.1 h1:d0uV7Qegtfaa7Z2ClDzr9HJmnbJW7jn0WhZ7wOX6hLE= -cloud.google.com/go/servicedirectory v1.12.3 h1:oFkCp6ti7fc7hzeROmOPQuPBHFqwyhcsv3Yrma28+uc= -cloud.google.com/go/servicedirectory v1.12.3/go.mod h1:dwTKSCYRD6IZMrqoBCIvZek+aOYK/6+jBzOGw8ks5aY= cloud.google.com/go/servicedirectory v1.12.6 h1:pl/KUNvFzlXpxgnPgzQjyTQQcv5WsQ97zCHaPrLQlYA= cloud.google.com/go/servicedirectory v1.12.6/go.mod h1:OojC1KhOMDYC45oyTn3Mup08FY/S0Kj7I58dxUMMTpg= cloud.google.com/go/servicemanagement v1.8.0 h1:fopAQI/IAzlxnVeiKn/8WiV6zKndjFkvi+gzu+NjywY= cloud.google.com/go/serviceusage v1.6.0 h1:rXyq+0+RSIm3HFypctp7WoXxIA563rn206CfMWdqXX4= -cloud.google.com/go/shell v1.8.3 h1:mjYgUsOtV3jl9xvDmcvlRRmA64deEPf52zOfuc68b/g= -cloud.google.com/go/shell v1.8.3/go.mod h1:OYcrgWF6JSp/uk76sNTtYFlMD0ho2+Cdzc7U3P/bF54= cloud.google.com/go/shell v1.8.6 h1:jLWyztGlNWBx55QXBM4HbWvfv7aiRjPzRKTUkZA8dXk= cloud.google.com/go/shell v1.8.6/go.mod h1:GNbTWf1QA/eEtYa+kWSr+ef/XTCDkUzRpV3JPw0LqSk= -cloud.google.com/go/spanner v1.82.0 h1:w9uO8RqEoBooBLX4nqV1RtgudyU2ZX780KTLRgeVg60= -cloud.google.com/go/spanner v1.82.0/go.mod h1:BzybQHFQ/NqGxvE/M+/iU29xgutJf7Q85/4U9RWMto0= -cloud.google.com/go/speech v1.26.0 h1:qvURtJs7BQzQhbxWxwai0pT79S8KLVKJ/4W8igVkt1Y= -cloud.google.com/go/speech v1.26.0/go.mod h1:78bqDV2SgwFlP/M4n3i3PwLthFq6ta7qmyG6lUV7UCA= -cloud.google.com/go/speech v1.27.1 h1:+OktATNlQc+4WH78OrQadIP4CzXb9mBucdDGCO1NrlI= -cloud.google.com/go/speech v1.27.1/go.mod h1:efCfklHFL4Flxcdt9gpEMEJh9MupaBzw3QiSOVeJ6ck= -cloud.google.com/go/storage v1.49.0/go.mod h1:k1eHhhpLvrPjVGfo0mOUPEJ4Y2+a/Hv5PiwehZI9qGU= -cloud.google.com/go/storage v1.50.0/go.mod h1:l7XeiD//vx5lfqE3RavfmU9yvk5Pp0Zhcv482poyafY= -cloud.google.com/go/storage v1.53.0/go.mod h1:7/eO2a/srr9ImZW9k5uufcNahT2+fPb8w5it1i5boaA= -cloud.google.com/go/storagetransfer v1.12.1 h1:W3v9A7MGBN7H9sAFstyciwP/1XEQhUhZfrjclmDnpMs= -cloud.google.com/go/storagetransfer v1.12.1/go.mod h1:hQqbfs8/LTmObJyCC0KrlBw8yBJ2bSFlaGila0qBMk4= +cloud.google.com/go/spanner v1.83.0 h1:AH3QIoSIa01l3WbeTppkwCEYFNK1AER6drcYhPmwhxY= +cloud.google.com/go/spanner v1.83.0/go.mod h1:QSWcjxszT0WRHNd8zyGI0WctrYA1N7j0yTFsWyol9Yw= +cloud.google.com/go/speech v1.28.0 h1:9AuiAxDTmh/aeREtw+/0e7aI27T5QN4fK5lhssc9MxA= +cloud.google.com/go/speech v1.28.0/go.mod h1:hJf6oa+1rzCW/CeDE/qCXedV20B2TXEUje5iaGwW+JI= cloud.google.com/go/storagetransfer v1.13.0 h1:uqKX3OgcYzR1W1YI943ZZ45id0RqA2eXXoCBSPstlbw= cloud.google.com/go/storagetransfer v1.13.0/go.mod h1:+aov7guRxXBYgR3WCqedkyibbTICdQOiXOdpPcJCKl8= -cloud.google.com/go/talent v1.8.0 h1:olv+s2g+LGXeJi+MYF1wI44/TwHaVnO0N7PiucVf5ZQ= -cloud.google.com/go/talent v1.8.0/go.mod h1:/gvOzSrtMcfTL/9xWhdYaZATaxUNhQ+L+3ZaGOGs7bA= cloud.google.com/go/talent v1.8.3 h1:wDP+++O/P1cTJBMkYlSY46k0a6atSoyO+UkBGuU9+Ao= cloud.google.com/go/talent v1.8.3/go.mod h1:oD3/BilJpJX8/ad8ZUAxlXHCslTg2YBbafFH3ciZSLQ= -cloud.google.com/go/texttospeech v1.11.0 h1:YF/RdNb+jUEp22cIZCvqiFjfA5OxGE+Dxss3mhXU7oQ= -cloud.google.com/go/texttospeech v1.11.0/go.mod h1:7M2ro3I2QfIEvArFk1TJ+pqXJqhszDtxUpnIv/150As= cloud.google.com/go/texttospeech v1.13.0 h1:oWWFQp0yFl4EJOr3opDkKH9304wUsZjgPjrTDS6S1a8= cloud.google.com/go/texttospeech v1.13.0/go.mod h1:g/tW/m0VJnulGncDrAoad6WdELMTes8eb77Idz+4HCo= -cloud.google.com/go/tpu v1.8.0 h1:BvMNijOb6Vd46Rr/SR5jWv1MPosOhVsi0UaeAGNjeds= -cloud.google.com/go/tpu v1.8.0/go.mod h1:XyNzyK1xc55WvL5rZEML0Z9/TUHDfnq0uICkQw6rWMo= cloud.google.com/go/tpu v1.8.3 h1:S4Ptq+yFIPNLEzQ/OQwiIYDNzk5I2vYmhf0SmFQOmWo= cloud.google.com/go/tpu v1.8.3/go.mod h1:Do6Gq+/Jx6Xs3LcY2WhHyGwKDKVw++9jIJp+X+0rxRE= -cloud.google.com/go/trace v1.11.3/go.mod h1:pt7zCYiDSQjC9Y2oqCsh9jF4GStB/hmjrYLsxRR27q8= -cloud.google.com/go/translate v1.10.3/go.mod h1:GW0vC1qvPtd3pgtypCv4k4U8B7EdgK9/QEF2aJEUovs= -cloud.google.com/go/translate v1.12.3 h1:XJ7LipYJi80BCgVk2lx1fwc7DIYM6oV2qx1G4IAGQ5w= -cloud.google.com/go/translate v1.12.3/go.mod h1:qINOVpgmgBnY4YTFHdfVO4nLrSBlpvlIyosqpGEgyEg= -cloud.google.com/go/translate v1.12.5 h1:QPMNi4WCtHwc2PPfxbyUMwdN/0+cyCGLaKi2tig41J8= -cloud.google.com/go/translate v1.12.5/go.mod h1:o/v+QG/bdtBV1d1edmtau0PwTfActvxPk/gtqdSDBi4= -cloud.google.com/go/video v1.23.3 h1:C2FH+6yr6LCZC4fP0gm9FwJB/SRh5Ul88O5Sc/bL83I= -cloud.google.com/go/video v1.23.3/go.mod h1:Kvh/BheubZxGZDXSb0iO6YX7ZNcaYHbLjnnaC8Qyy3g= +cloud.google.com/go/translate v1.12.6 h1:QHcszWZvBLEZHM2WJ6IDg2BUTWzEPMiHhbJAd15yKGU= +cloud.google.com/go/translate v1.12.6/go.mod h1:nB3AXuX+iHbV8ZURmElcW85qkEDWZw68sf4kqMT/E5o= cloud.google.com/go/video v1.24.0 h1:KTB2BEXjGm2K/JcKxQXEgx3nSoMTByepnPZa4kln064= cloud.google.com/go/video v1.24.0/go.mod h1:h6Bw4yUbGNEa9dH4qMtUMnj6cEf+OyOv/f2tb70G6Fk= -cloud.google.com/go/videointelligence v1.12.3 h1:zNTOUQyatGQtnCJ2dR3faRtpWQOlC8wszJqwG5CtwVM= -cloud.google.com/go/videointelligence v1.12.3/go.mod h1:dUA6V+NH7CVgX6TePq0IelVeBMGzvehxKPR4FGf1dtw= cloud.google.com/go/videointelligence v1.12.6 h1:heq7jEO39sH5TycBh8TGFJ827XCxK0tIWatmBY/n0jI= cloud.google.com/go/videointelligence v1.12.6/go.mod h1:/l34WMndN5/bt04lHodxiYchLVuWPQjCU6SaiTswrIw= cloud.google.com/go/vision v1.2.0 h1:/CsSTkbmO9HC8iQpxbK8ATms3OQaX3YQUeTMGCxlaK4= -cloud.google.com/go/vision/v2 v2.9.3 h1:dPvfDuPqPH+Yscf0f2f1RprvKkoo+N/j0a+IbLYX7Cs= -cloud.google.com/go/vision/v2 v2.9.3/go.mod h1:weAcT8aNYSgrWWVTC2PuJTc7fcXKvUeAyDq8B6HkLSg= cloud.google.com/go/vision/v2 v2.9.5 h1:UJZ0H6UlOaYKgCn6lWG2iMAOJIsJZLnseEfzBR8yIqQ= cloud.google.com/go/vision/v2 v2.9.5/go.mod h1:1SiNZPpypqZDbOzU052ZYRiyKjwOcyqgGgqQCI/nlx8= -cloud.google.com/go/vmmigration v1.8.3 h1:dpCQq3pj2HnKdbvGTftdWymm3r4ovF7JW5z8xBcO2x4= -cloud.google.com/go/vmmigration v1.8.3/go.mod h1:8CzUpK9eBzohgpL4RvBVtW4sY/sDliVyQonTFQfWcJ4= cloud.google.com/go/vmmigration v1.8.6 h1:68hOQDhs1DOITrCrhritrwr8xy6s8QMdwDyMzMiFleU= cloud.google.com/go/vmmigration v1.8.6/go.mod h1:uZ6/KXmekwK3JmC8PzBM/cKQmq404TTfWtThF6bbf0U= -cloud.google.com/go/vmwareengine v1.3.3 h1:TfuQr5j7qriINulUMotaC/+27SQaW2thIkF3Gb6VJ38= -cloud.google.com/go/vmwareengine v1.3.3/go.mod h1:G7vz05KGijha0c0dj1INRKyDAaQW8TRMZt/FrfOZVXc= cloud.google.com/go/vmwareengine v1.3.5 h1:OsGd1SB91y9fDuzdzFngMv4UcT4cqmRxjsCsS4Xmcu8= cloud.google.com/go/vmwareengine v1.3.5/go.mod h1:QuVu2/b/eo8zcIkxBYY5QSwiyEcAy6dInI7N+keI+Jg= -cloud.google.com/go/vpcaccess v1.8.3 h1:vxVaoFM64M/ht619c4wZNF0iq0QPaMWElOh7Ns4r41A= -cloud.google.com/go/vpcaccess v1.8.3/go.mod h1:bqOhyeSh/nEmLIsIUoCiQCBHeNPNjaK9M3bIvKxFdsY= cloud.google.com/go/vpcaccess v1.8.6 h1:RYtUB9rQEijX9Tc6lQcGst58ZOzPgaYTkz6+2pyPQTM= cloud.google.com/go/vpcaccess v1.8.6/go.mod h1:61yymNplV1hAbo8+kBOFO7Vs+4ZHYI244rSFgmsHC6E= -cloud.google.com/go/webrisk v1.10.3 h1:yh0v/5n49VO4/i9pYfDm1gLJUj1Ph3Xzegn8WvK9YRA= -cloud.google.com/go/webrisk v1.10.3/go.mod h1:rRAqCA5/EQOX8ZEEF4HMIrLHGTK/Y1hEQgWMnih+jAw= cloud.google.com/go/webrisk v1.11.1 h1:yZKNB7zRxOMriLrhP5WDE+BjxXVl0wJHHZSdaYzbdVU= cloud.google.com/go/webrisk v1.11.1/go.mod h1:+9SaepGg2lcp1p0pXuHyz3R2Yi2fHKKb4c1Q9y0qbtA= -cloud.google.com/go/websecurityscanner v1.7.3 h1:/uxhVCWKXzPw5pVfnBOVjaSiQ6Bm0tDExDOCLV40thw= -cloud.google.com/go/websecurityscanner v1.7.3/go.mod h1:gy0Kmct4GNLoCePWs9xkQym1D7D59ld5AjhXrjipxSs= cloud.google.com/go/websecurityscanner v1.7.6 h1:cIPKJKZA3l7D8DfL4nxce8HGOWXBw3WAUBF0ymOW9GQ= cloud.google.com/go/websecurityscanner v1.7.6/go.mod h1:ucaaTO5JESFn5f2pjdX01wGbQ8D6h79KHrmO2uGZeiY= -cloud.google.com/go/workflows v1.13.3 h1:lNFDMranJymDEB7cTI7DI9czbc1WU0RWY9KCEv9zuDY= -cloud.google.com/go/workflows v1.13.3/go.mod h1:Xi7wggEt/ljoEcyk+CB/Oa1AHBCk0T1f5UH/exBB5CE= cloud.google.com/go/workflows v1.14.2 h1:phBz5TOAES0YGogxZ6Q7ISSudaf618lRhE3euzBpE9U= cloud.google.com/go/workflows v1.14.2/go.mod h1:5nqKjMD+MsJs41sJhdVrETgvD5cOK3hUcAs8ygqYvXQ= codeberg.org/go-fonts/liberation v0.5.0 h1:SsKoMO1v1OZmzkG2DY+7ZkCL9U+rrWI09niOLfQ5Bo0= @@ -496,41 +243,17 @@ codeberg.org/go-latex/latex v0.1.0 h1:hoGO86rIbWVyjtlDLzCqZPjNykpWQ9YuTZqAzPcfL3 codeberg.org/go-latex/latex v0.1.0/go.mod h1:LA0q/AyWIYrqVd+A9Upkgsb+IqPcmSTKc9Dny04MHMw= codeberg.org/go-pdf/fpdf v0.10.0 h1:u+w669foDDx5Ds43mpiiayp40Ov6sZalgcPMDBcZRd4= codeberg.org/go-pdf/fpdf v0.10.0/go.mod h1:Y0DGRAdZ0OmnZPvjbMp/1bYxmIPxm0ws4tfoPOc4LjU= -contrib.go.opencensus.io/exporter/aws v0.0.0-20230502192102-15967c811cec h1:CSNP8nIEQt4sZEo2sGUiWSmVJ9c5QdyIQvwzZAsn+8Y= -contrib.go.opencensus.io/exporter/aws v0.0.0-20230502192102-15967c811cec/go.mod h1:uu1P0UCM/6RbsMrgPa98ll8ZcHM858i/AD06a9aLRCA= contrib.go.opencensus.io/exporter/ocagent v0.6.0 h1:Z1n6UAyr0QwM284yUuh5Zd8JlvxUGAhFZcgMJkMPrGM= -contrib.go.opencensus.io/exporter/ocagent v0.7.1-0.20200907061046-05415f1de66d h1:LblfooH1lKOpp1hIhukktmSAxFkqMPFk9KR6iZ0MJNI= -contrib.go.opencensus.io/exporter/ocagent v0.7.1-0.20200907061046-05415f1de66d/go.mod h1:IshRmMJBhDfFj5Y67nVhMYTTIze91RUeT73ipWKs/GY= -contrib.go.opencensus.io/exporter/prometheus v0.4.2 h1:sqfsYl5GIY/L570iT+l93ehxaWJs2/OwXtiWwew3oAg= -contrib.go.opencensus.io/exporter/prometheus v0.4.2/go.mod h1:dvEHbiKmgvbr5pjaF9fpw1KeYcjrnC1J8B+JKjsZyRQ= -contrib.go.opencensus.io/exporter/stackdriver v0.13.14 h1:zBakwHardp9Jcb8sQHcHpXy/0+JIb1M8KjigCJzx7+4= -contrib.go.opencensus.io/exporter/stackdriver v0.13.14/go.mod h1:5pSSGY0Bhuk7waTHuDf4aQ8D2DrhgETRo9fy6k3Xlzc= -contrib.go.opencensus.io/exporter/zipkin v0.1.2 h1:YqE293IZrKtqPnpwDPH/lOqTWD/s3Iwabycam74JV3g= -contrib.go.opencensus.io/exporter/zipkin v0.1.2/go.mod h1:mP5xM3rrgOjpn79MM8fZbj3gsxcuytSqtH0dxSWW1RE= -contrib.go.opencensus.io/integrations/ocsql v0.1.7 h1:G3k7C0/W44zcqkpRSFyjU9f6HZkbwIrL//qqnlqWZ60= -contrib.go.opencensus.io/integrations/ocsql v0.1.7/go.mod h1:8DsSdjz3F+APR+0z0WkU1aRorQCFfRxvqjUUPMbF3fE= -dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9 h1:VpgP7xuJadIUuKccphEpTJnWhS2jkQyMt6Y7pJCD7fY= gioui.org v0.0.0-20210308172011-57750fc8a0a6 h1:K72hopUosKG3ntOPNG4OzzbuhxGuVf06fa2la1/H/Ho= git.sr.ht/~sbinet/gg v0.6.0 h1:RIzgkizAk+9r7uPzf/VfbJHBMKUr0F5hRFxTUGMnt38= git.sr.ht/~sbinet/gg v0.6.0/go.mod h1:uucygbfC9wVPQIfrmwM2et0imr8L7KQWywX0xpFMm94= -github.com/99designs/basicauth-go v0.0.0-20160802081356-2a93ba0f464d h1:j6oB/WPCigdOkxtuPl1VSIiLpy7Mdsu6phQffbF19Ng= -github.com/99designs/httpsignatures-go v0.0.0-20170731043157-88528bf4ca7e h1:rl2Aq4ZODqTDkeSqQBy+fzpZPamacO1Srp8zq7jf2Sc= github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 h1:He8afgbRMd7mFxO99hRNu+6tazq8nFF9lIwo9JFroBk= github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8= github.com/Azure/azure-amqp-common-go/v3 v3.2.3 h1:uDF62mbd9bypXWi19V1bN5NZEO84JqgmI5G73ibAmrk= github.com/Azure/azure-amqp-common-go/v3 v3.2.3/go.mod h1:7rPmbSfszeovxGfc5fSAXE4ehlXQZHpMja2OtxC2Tas= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.1/go.mod h1:zGqV2R4Cr/k8Uye5w+dgQ06WJtEcbQG/8J7BB6hnCr4= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0/go.mod h1:Ot/6aikWnKWi4l9QB7qVSwa8iMphQNqkWALMoNT3rzM= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.2/go.mod h1:SqINnQ9lVVdRlyC8cd1lCI0SdX4n2paeABd2K8ggfnE= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.9.0/go.mod h1:kUjrAo8bgEwLeZ/CmHqNl3Z/kPm7y6FKfxxK0izYUg4= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.0/go.mod h1:j2chePtV91HrC22tGoRX3sGY42uF13WzmmV80/OdVAA= -github.com/Azure/azure-sdk-for-go/sdk/messaging/azservicebus v1.7.1 h1:o/Ws6bEqMeKZUfj1RRm3mQ51O8JGU5w+Qdg2AhHib6A= -github.com/Azure/azure-sdk-for-go/sdk/messaging/azservicebus v1.7.1/go.mod h1:6QAMYBAbQeeKX+REFJMZ1nFWu9XLw/PPcjYpuc9RDFs= -github.com/Azure/azure-sdk-for-go/sdk/messaging/azservicebus v1.8.0 h1:JNgM3Tz592fUHU2vgwgvOgKxo5s9Ki0y2wicBeckn70= -github.com/Azure/azure-sdk-for-go/sdk/messaging/azservicebus v1.8.0/go.mod h1:6vUKmzY17h6dpn9ZLAhM4R/rcrltBeq52qZIkUR7Oro= -github.com/Azure/go-amqp v1.0.5 h1:po5+ljlcNSU8xtapHTe8gIc8yHxCzC03E8afH2g1ftU= -github.com/Azure/go-amqp v1.0.5/go.mod h1:vZAogwdrkbyK3Mla8m/CxSc/aKdnTZ4IbPxl51Y5WZE= +github.com/Azure/azure-sdk-for-go/sdk/messaging/azservicebus v1.9.1 h1:CRZwf68N55u7ZZo3Xx2ynuqEA6k5GZfwsEUkU8qsAPk= +github.com/Azure/azure-sdk-for-go/sdk/messaging/azservicebus v1.9.1/go.mod h1:NydgUaroiShkgOcb+X6OUdS3RalWBrvDNtOyFHJtsZY= github.com/Azure/go-amqp v1.4.0 h1:Xj3caqi4comOF/L1Uc5iuBxR/pB6KumejC01YQOqOR4= github.com/Azure/go-amqp v1.4.0/go.mod h1:vZAogwdrkbyK3Mla8m/CxSc/aKdnTZ4IbPxl51Y5WZE= github.com/Azure/go-autorest/autorest/azure/auth v0.5.13 h1:Ov8avRZi2vmrE2JcXw+tu5K/yB41r7xK9GZDiBF7NdM= @@ -538,12 +261,8 @@ github.com/Azure/go-autorest/autorest/azure/auth v0.5.13/go.mod h1:5BAVfWLWXihP4 github.com/Azure/go-autorest/autorest/azure/cli v0.4.6 h1:w77/uPk80ZET2F+AfQExZyEWtn+0Rk/uw17m9fv5Ajc= github.com/Azure/go-autorest/autorest/azure/cli v0.4.6/go.mod h1:piCfgPho7BiIDdEQ1+g4VmKyD5y+p/XtSNqE6Hc4QD0= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802 h1:1BDTz0u9nC3//pOCMdNH+CiXJVYJh5UQNCOBG7jbELc= -github.com/ClickHouse/ch-go v0.65.1 h1:SLuxmLl5Mjj44/XbINsK2HFvzqup0s6rwKLFH347ZhU= -github.com/ClickHouse/ch-go v0.65.1/go.mod h1:bsodgURwmrkvkBe5jw1qnGDgyITsYErfONKAHn05nv4= github.com/ClickHouse/ch-go v0.67.0 h1:18MQF6vZHj+4/hTRaK7JbS/TIzn4I55wC+QzO24uiqc= github.com/ClickHouse/ch-go v0.67.0/go.mod h1:2MSAeyVmgt+9a2k2SQPPG1b4qbTPzdGDpf1+bcHh+18= -github.com/ClickHouse/clickhouse-go/v2 v2.34.0 h1:Y4rqkdrRHgExvC4o/NTbLdY5LFQ3LHS77/RNFxFX3Co= -github.com/ClickHouse/clickhouse-go/v2 v2.34.0/go.mod h1:yioSINoRLVZkLyDzdMXPLRIqhDvel8iLBlwh6Iefso8= github.com/ClickHouse/clickhouse-go/v2 v2.40.1 h1:PbwsHBgqXRydU7jKULD1C8CHmifczffvQqmFvltM2W4= github.com/ClickHouse/clickhouse-go/v2 v2.40.1/go.mod h1:GDzSBLVhladVm8V01aEB36IoBOVLLICfyeuiIp/8Ezc= github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53 h1:sR+/8Yb4slttB4vD+b9btVEnWgL3Q00OBTzVT8B9C0c= @@ -557,17 +276,12 @@ github.com/DataDog/zstd v1.5.2 h1:vUG4lAyuPCXO0TLbXvPv7EB7cNK1QV/luu55UHLrrn8= github.com/DataDog/zstd v1.5.2/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= github.com/DmitriyVTitov/size v1.5.0 h1:/PzqxYrOyOUX1BXj6J9OuVRVGe+66VL4D9FlUaW515g= github.com/DmitriyVTitov/size v1.5.0/go.mod h1:le6rNI4CoLQV1b9gzp1+3d7hMAD/uu2QcJ+aYbNgiU0= -github.com/GoogleCloudPlatform/cloudsql-proxy v1.36.0 h1:kAtNAWwvTt5+iew6baV0kbOrtjYTXPtWNSyOFlcxkBU= -github.com/GoogleCloudPlatform/cloudsql-proxy v1.36.0/go.mod h1:VRKXU8C7Y/aUKjRBTGfw0Ndv4YqNxlB8zAPJJDxbASE= -github.com/GoogleCloudPlatform/cloudsql-proxy v1.37.6 h1:UucmvNRPE75F3KzT68GHhKzOPwttxiFkh1d5LTTywW8= -github.com/GoogleCloudPlatform/cloudsql-proxy v1.37.6/go.mod h1:XGripOBEUAcge8IUWR/NMAB5qO9k82tkbpoewBpyjYQ= -github.com/GoogleCloudPlatform/grpc-gcp-go/grpcgcp v1.5.2 h1:DBjmt6/otSdULyJdVg2BlG0qGZO5tKL4VzOs0jpvw5Q= -github.com/GoogleCloudPlatform/grpc-gcp-go/grpcgcp v1.5.2/go.mod h1:dppbR7CwXD4pgtV9t3wD1812RaLDcBjtblcDF5f1vI0= -github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.25.0/go.mod h1:obipzmGjfSjam60XLwGfqUkJsfiheAl+TUjG+4yzyPM= -github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.48.1/go.mod h1:jyqM3eLpJ3IbIFDTKVz2rF9T/xWGW0rIriGwnz8l9Tk= -github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.50.0/go.mod h1:ZV4VOm0/eHR06JLrXWe09068dHpr3TRpY9Uo7T+anuA= -github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.48.1/go.mod h1:viRWSEhtMZqz1rhwmOVKkWl6SwmVowfL9O2YR5gI2PE= -github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.50.0/go.mod h1:otE2jQekW/PqXk1Awf5lmfokJx4uwuqcj1ab5SpGeW0= +github.com/GoogleCloudPlatform/cloudsql-proxy v1.37.8 h1:9aTh5GPncdE8BjUn+xanuF/BT3m2BJiyvS50Mmws/fw= +github.com/GoogleCloudPlatform/cloudsql-proxy v1.37.8/go.mod h1:exon/I6I+5u/ab7AHmGh0eCXGoYZO5cjqA3wHJlYFFQ= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/trace v1.29.0 h1:YVtMlmfRUTaWs3+1acwMBp7rBUo6zrxl6Kn13/R9YW4= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/trace v1.29.0/go.mod h1:rKOFVIPbNs2wZeh7ZeQ0D9p/XLgbNiTr5m7x6KuAshk= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/propagator v0.53.0 h1:RAHqDHJmNMLe6JvDoRIlXmb72w+62Ue/k5p/qP9yfAg= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/propagator v0.53.0/go.mod h1:dtCRwgvytbGKWdlrjMOg9geBoRwRpCYWIOM/JhVsDIc= github.com/IBM/go-sdk-core/v5 v5.17.4 h1:VGb9+mRrnS2HpHZFM5hy4J6ppIWnwNrw0G+tLSgcJLc= github.com/IBM/go-sdk-core/v5 v5.17.4/go.mod h1:KsAAI7eStAWwQa4F96MLy+whYSh39JzNjklZRbN/8ns= github.com/IBM/ibm-cos-sdk-go v1.11.0 h1:Jp55NLN3OvBwucMGpP5wNybyjncsmTZ9+GPHai/1cE8= @@ -581,20 +295,8 @@ github.com/KimMachineGun/automemlimit v0.7.1 h1:QcG/0iCOLChjfUweIMC3YL5Xy9C3VBeN github.com/KimMachineGun/automemlimit v0.7.1/go.mod h1:QZxpHaGOQoYvFhv/r4u3U0JTC2ZcOwbSr11UZF46UBM= github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= -github.com/MarvinJWendt/testza v0.1.0/go.mod h1:7AxNvlfeHP7Z/hDQ5JtE3OKYT3XFUeLCDE2DQninSqs= -github.com/MarvinJWendt/testza v0.2.1/go.mod h1:God7bhG8n6uQxwdScay+gjm9/LnO4D3kkcZX4hv9Rp8= -github.com/MarvinJWendt/testza v0.2.8/go.mod h1:nwIcjmr0Zz+Rcwfh3/4UhBp7ePKVhuBExvZqnKYWlII= -github.com/MarvinJWendt/testza v0.2.10/go.mod h1:pd+VWsoGUiFtq+hRKSU1Bktnn+DMCSrDrXDpX2bG66k= -github.com/MarvinJWendt/testza v0.2.12/go.mod h1:JOIegYyV7rX+7VZ9r77L/eH6CfJHHzXjB69adAhzZkI= -github.com/MarvinJWendt/testza v0.3.0/go.mod h1:eFcL4I0idjtIx8P9C6KkAuLgATNKpX4/2oUqKc6bF2c= -github.com/MarvinJWendt/testza v0.4.2/go.mod h1:mSdhXiKH8sg/gQehJ63bINcCKp7RtYewEjXsvsVUPbE= -github.com/MarvinJWendt/testza v0.5.2 h1:53KDo64C1z/h/d/stCYCPY69bt/OSwjq5KpFNwi+zB4= -github.com/MarvinJWendt/testza v0.5.2/go.mod h1:xu53QFE5sCdjtMCKk8YMQ2MnymimEctc4n3EjyIYvEY= -github.com/Masterminds/semver/v3 v3.3.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= github.com/MicahParks/keyfunc/v2 v2.1.0 h1:6ZXKb9Rp6qp1bDbJefnG7cTH8yMN1IC/4nf+GVjO99k= github.com/MicahParks/keyfunc/v2 v2.1.0/go.mod h1:rW42fi+xgLJ2FRRXAfNx9ZA8WpD4OeE/yHVMteCkw9k= -github.com/Microsoft/go-winio v0.4.21/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= -github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= github.com/PuerkitoBio/goquery v1.10.3 h1:pFYcNSqHxBD06Fpj/KsbStFRsgRATgnf3LeXiUkhzPo= github.com/PuerkitoBio/goquery v1.10.3/go.mod h1:tMUX0zDMHXYlAQk6p35XxQMqMweEKB7iK7iLNd4RH4Y= @@ -602,7 +304,6 @@ github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tN github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= github.com/RaveNoX/go-jsoncommentstrip v1.0.0 h1:t527LHHE3HmiHrq74QMpNPZpGCIJzTx+apLkMKt4HC0= github.com/RoaringBitmap/gocroaring v0.4.0 h1:5nufXUgWpBEUNEJXw7926YAA58ZAQRpWPrQV1xCoSjc= -github.com/RoaringBitmap/real-roaring-datasets v0.0.0-20190726190000-eb7c87156f76 h1:ZYlhPbqQFU+AHfgtCdHGDTtRW1a8geZyiE8c6Q+Sl1s= github.com/Sereal/Sereal/Go/sereal v0.0.0-20231009093132-b9187f1a92c6 h1:5kUcJJAKWWI82Xnp/CaU0eu5hLlHkmm9acjowSkwCd0= github.com/Sereal/Sereal/Go/sereal v0.0.0-20231009093132-b9187f1a92c6/go.mod h1:JwrycNnC8+sZPDyzM3MQ86LvaGzSpfxg885KOOwFRW4= github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06 h1:KkH3I3sJuOLP3TjA/dfr4NAY8bghDwnXiU7cTKxQqo0= @@ -610,6 +311,8 @@ github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06/go.mod h1:7erjK github.com/Shopify/sarama v1.38.1 h1:lqqPUPQZ7zPqYlWpTh+LQ9bhYNu2xJL6k1SJN4WVe2A= github.com/Shopify/sarama v1.38.1/go.mod h1:iwv9a67Ha8VNa+TifujYoWGxWnu2kNVAQdSdZ4X2o5g= github.com/Shopify/toxiproxy v2.1.4+incompatible h1:TKdv8HiTLgE5wdJuEML90aBgNWsokNbMijUGhmcoBJc= +github.com/XSAM/otelsql v0.39.0 h1:4o374mEIMweaeevL7fd8Q3C710Xi2Jh/c8G4Qy9bvCY= +github.com/XSAM/otelsql v0.39.0/go.mod h1:uMOXLUX+wkuAuP0AR3B45NXX7E9lJS2mERa8gqdU8R0= github.com/agnivade/levenshtein v1.2.1 h1:EHBY3UOn1gwdy/VbFwgo4cxecRznFk7fKWN1KOX7eoM= github.com/agnivade/levenshtein v1.2.1/go.mod h1:QVVI16kDrtSuwcpd0p1+xMC6Z/VfhtCyDIjcwga4/DU= github.com/ajstarks/deck v0.0.0-20200831202436-30c9fc6549a9 h1:7kQgkwGRoLzC9K0oyXdJo7nve/bynv/KwUsxbiTlzAM= @@ -627,8 +330,6 @@ github.com/alexflint/go-arg v1.5.1 h1:nBuWUCpuRy0snAG+uIJ6N0UvYxpxA0/ghA/AaHxlT8 github.com/alexflint/go-arg v1.5.1/go.mod h1:A7vTJzvjoaSTypg4biM5uYNTkJ27SkNTArtYXnlqVO8= github.com/alexflint/go-scalar v1.2.0 h1:WR7JPKkeNpnYIOfHRa7ivM21aWAdHD0gEWHCx+WQBRw= github.com/alexflint/go-scalar v1.2.0/go.mod h1:LoFvNMqS1CPrMVltza4LvnGKhaSpc3oyLEBUZVhhS2o= -github.com/alicebob/miniredis v2.5.0+incompatible h1:yBHoLpsyjupjz3NL3MhKMVkR41j82Yjf3KFv7ApYzUI= -github.com/alicebob/miniredis v2.5.0+incompatible/go.mod h1:8HZjEj4yU0dwhYHky+DxYx+6BMjkBbe5ONFIF1MXffk= github.com/aliyun/aliyun-oss-go-sdk v2.2.10+incompatible h1:ROMcuN61gI8SfQ+AEMh4d7GZ3gwTZLIhPjtd05TQCG4= github.com/aliyun/aliyun-oss-go-sdk v2.2.10+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8= github.com/andybalholm/cascadia v1.3.3 h1:AG2YHrzJIm4BZ19iwJ/DAua6Btl3IwJX+VI4kktS1LM= @@ -638,59 +339,44 @@ github.com/antchfx/xmlquery v1.4.4/go.mod h1:AEPEEPYE9GnA2mj5Ur2L5Q5/2PycJ0N9Fus github.com/antchfx/xpath v1.3.4 h1:1ixrW1VnXd4HurCj7qnqnR0jo14g8JMe20Fshg1Vgz4= github.com/antchfx/xpath v1.3.4/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwqzXNcs= github.com/antihax/optional v1.0.0 h1:xK2lYat7ZLaVVcIuj82J8kIro4V6kDe0AUDFboUCwcg= -github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230512164433-5d1fd1a340c9 h1:goHVqTbFX3AIo0tzGr14pgfAW2ZfPChKO21Z9MGf/gk= -github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230512164433-5d1fd1a340c9/go.mod h1:pSwJ0fSY5KhvocuWSx4fz3BA8OrA1bQn+K1Eli3BRwM= -github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g= -github.com/apache/arrow-go/v18 v18.4.0/go.mod h1:Aawvwhj8x2jURIzD9Moy72cF0FyJXOpkYpdmGRHcw14= github.com/apache/arrow/go/arrow v0.0.0-20211112161151-bc219186db40 h1:q4dksr6ICHXqG5hm0ZW5IHyeEJXoIJSOZeBLmWPNeIQ= github.com/apache/arrow/go/arrow v0.0.0-20211112161151-bc219186db40/go.mod h1:Q7yQnSMnLvcXlZ8RV+jwz/6y1rQTqbX6C82SndT52Zs= github.com/apache/arrow/go/v10 v10.0.1 h1:n9dERvixoC/1JjDmBcs9FPaEryoANa2sCgVFo6ez9cI= github.com/apache/arrow/go/v11 v11.0.0 h1:hqauxvFQxww+0mEU/2XHG6LT7eZternCZq+A5Yly2uM= -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/apparentlymart/go-dump v0.0.0-20180507223929-23540a00eaa3 h1:ZSTrOEhiM5J5RFxEaFvMZVEAM1KvT1YzbEOwB2EAGjA= -github.com/apparentlymart/go-dump v0.0.0-20180507223929-23540a00eaa3/go.mod h1:oL81AME2rN47vu18xqj1S1jPIPuN7afo62yKTNn3XMM= -github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e h1:QEF07wC0T1rKkctt1RINW/+RMTVmiwxETico2l3gxJA= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6 h1:G1bPvciwNyF7IUmKXNt9Ak3m6u9DE1rF+RmtIkBpVdA= github.com/atc0005/go-teams-notify/v2 v2.13.0 h1:nbDeHy89NjYlF/PEfLVF6lsserY9O5SnN1iOIw3AxXw= github.com/atc0005/go-teams-notify/v2 v2.13.0/go.mod h1:WSv9moolRsBcpZbwEf6gZxj7h0uJlJskJq5zkEWKO8Y= -github.com/atomicgo/cursor v0.0.1 h1:xdogsqa6YYlLfM+GyClC/Lchf7aiMerFiZQn7soTOoU= -github.com/atomicgo/cursor v0.0.1/go.mod h1:cBON2QmmrysudxNBFthvMtN32r3jxVRIvzkUiF/RuIk= github.com/aws/aws-lambda-go v1.47.0 h1:0H8s0vumYx/YKs4sE7YM0ktwL2eWse+kfopsRI1sXVI= github.com/aws/aws-lambda-go v1.47.0/go.mod h1:dpMpZgvWx5vuQJfBt0zqBha60q7Dd7RfgJv23DymV8A= github.com/aws/aws-msk-iam-sasl-signer-go v1.0.1 h1:nMp7diZObd4XEVUR0pEvn7/E13JIgManMX79Q6quV6E= github.com/aws/aws-msk-iam-sasl-signer-go v1.0.1/go.mod h1:MVYeeOhILFFemC/XlYTClvBjYZrg/EPd3ts885KrNTI= +github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.19.5 h1:oUEqVqonG3xuarrsze1KVJ30KagNYDemikTbdu8KlN8= +github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.19.5/go.mod h1:VNM08cHlOsIbSHRqb6D/M2L4kKXfJv3A2/f0GNbOQSc= +github.com/aws/aws-sdk-go-v2/feature/dynamodb/expression v1.7.87 h1:oDPArGgCrG/4aTi86ij3S2PB59XXkTSKYVNQlmqRHXQ= +github.com/aws/aws-sdk-go-v2/feature/dynamodb/expression v1.7.87/go.mod h1:ZeQC4gVarhdcWeM1c90DyBLaBCNhEeAbKUXwVI/byvw= +github.com/aws/aws-sdk-go-v2/service/dynamodb v1.44.0 h1:A99gjqZDbdhjtjJVZrmVzVKO2+p3MSg35bDWtbMQVxw= +github.com/aws/aws-sdk-go-v2/service/dynamodb v1.44.0/go.mod h1:mWB0GE1bqcVSvpW7OtFA0sKuHk52+IqtnsYU2jUfYAs= +github.com/aws/aws-sdk-go-v2/service/dynamodbstreams v1.26.0 h1:0wOCTKrmwkyC8Bk76hYH/B4IJn5MGt6gMkSXc0A2uyc= +github.com/aws/aws-sdk-go-v2/service/dynamodbstreams v1.26.0/go.mod h1:He/RikglWUczbkV+fkdpcV/3GdL/rTRNVy7VaUiezMo= +github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.10.17 h1:x187MqiHwBGjMGAed8Y8K1VGuCtFvQvXb24r+bwmSdo= +github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.10.17/go.mod h1:mC9qMbA6e1pwEq6X3zDGtZRXMG2YaElJkbJlMVHLs5I= github.com/aws/aws-sdk-go-v2/service/kinesis v1.33.0 h1:JPXkrQk5OS/+Q81fKH97Ll/Vmmy0p9vwHhxw+V+tVjg= github.com/aws/aws-sdk-go-v2/service/kinesis v1.33.0/go.mod h1:dJngkoVMrq0K7QvRkdRZYM4NUp6cdWa2GBdpm8zoY8U= -github.com/aws/aws-sdk-go-v2/service/kms v1.35.3 h1:UPTdlTOwWUX49fVi7cymEN6hDqCwe3LNv1vi7TXUutk= -github.com/aws/aws-sdk-go-v2/service/kms v1.35.3/go.mod h1:gjDP16zn+WWalyaUqwCCioQ8gU8lzttCCc9jYsiQI/8= -github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.32.4 h1:NgRFYyFpiMD62y4VPXh4DosPFbZd4vdMVBWKk0VmWXc= -github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.32.4/go.mod h1:TKKN7IQoM7uTnyuFm9bm9cw5P//ZYTl4m3htBWQ1G/c= -github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.35.2 h1:vlYXbindmagyVA3RS2SPd47eKZ00GZZQcr+etTviHtc= -github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.35.2/go.mod h1:yGhDiLKguA3iFJYxbrQkQiNzuy+ddxesSZYWVeeEH5Q= -github.com/aws/aws-sdk-go-v2/service/sns v1.31.3 h1:eSTEdxkfle2G98FE+Xl3db/XAXXVTJPNQo9K/Ar8oAI= -github.com/aws/aws-sdk-go-v2/service/sns v1.31.3/go.mod h1:1dn0delSO3J69THuty5iwP0US2Glt0mx2qBBlI13pvw= -github.com/aws/aws-sdk-go-v2/service/sns v1.34.2 h1:PajtbJ/5bEo6iUAIGMYnK8ljqg2F1h4mMCGh1acjN30= -github.com/aws/aws-sdk-go-v2/service/sns v1.34.2/go.mod h1:PJtxxMdj747j8DeZENRTTYAz/lx/pADn/U0k7YNNiUY= -github.com/aws/aws-sdk-go-v2/service/sqs v1.34.3 h1:Vjqy5BZCOIsn4Pj8xzyqgGmsSqzz7y/WXbN3RgOoVrc= -github.com/aws/aws-sdk-go-v2/service/sqs v1.34.3/go.mod h1:L0enV3GCRd5iG9B64W35C4/hwsCB00Ib+DKVGTadKHI= -github.com/aws/aws-sdk-go-v2/service/sqs v1.38.3 h1:j5BchjfDoS7K26vPdyJlyxBIIBGDflq3qjjJKBDlbcI= -github.com/aws/aws-sdk-go-v2/service/sqs v1.38.3/go.mod h1:Bar4MrRxeqdn6XIh8JGfiXuFRmyrrsZNTJotxEJmWW0= -github.com/aws/aws-sdk-go-v2/service/ssm v1.52.4 h1:hgSBvRT7JEWx2+vEGI9/Ld5rZtl7M5lu8PqdvOmbRHw= -github.com/aws/aws-sdk-go-v2/service/ssm v1.52.4/go.mod h1:v7NIzEFIHBiicOMaMTuEmbnzGnqW0d+6ulNALul6fYE= -github.com/aws/aws-sdk-go-v2/service/ssm v1.58.0 h1:zQz6Q5uaC8s9734DV9UDAm2q1TEEfOvEejDBSulOapI= -github.com/aws/aws-sdk-go-v2/service/ssm v1.58.0/go.mod h1:PUWUl5MDiYNQkUHN9Pyd9kgtA/YhbxnSnHP+yQqzrM8= -github.com/aws/smithy-go v1.22.5 h1:P9ATCXPMb2mPjYBgueqJNCA5S9UfktsW0tTxi+a7eqw= -github.com/aws/smithy-go v1.22.5/go.mod h1:t1ufH5HMublsJYulve2RKmHDC15xu1f26kHCp/HgceI= +github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.35.7 h1:d+mnMa4JbJlooSbYQfrJpit/YINaB30JEVgrhtjZneA= +github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.35.7/go.mod h1:1X1NotbcGHH7PCQJ98PsExSxsJj/VWzz8MfFz43+02M= +github.com/aws/aws-sdk-go-v2/service/sns v1.34.7 h1:OBuZE9Wt8h2imuRktu+WfjiTGrnYdCIJg8IX92aalHE= +github.com/aws/aws-sdk-go-v2/service/sns v1.34.7/go.mod h1:4WYoZAhHt+dWYpoOQUgkUKfuQbE6Gg/hW4oXE0pKS9U= +github.com/aws/aws-sdk-go-v2/service/sqs v1.38.8 h1:80dpSqWMwx2dAm30Ib7J6ucz1ZHfiv5OCRwN/EnCOXQ= +github.com/aws/aws-sdk-go-v2/service/sqs v1.38.8/go.mod h1:IzNt/udsXlETCdvBOL0nmyMe2t9cGmXmZgsdoZGYYhI= +github.com/aws/aws-sdk-go-v2/service/ssm v1.60.1 h1:OwMzNDe5VVTXD4kGmeK/FtqAITiV8Mw4TCa8IyNO0as= +github.com/aws/aws-sdk-go-v2/service/ssm v1.60.1/go.mod h1:IyVabkWrs8SNdOEZLyFFcW9bUltV4G6OQS0s6H20PHg= github.com/awslabs/aws-lambda-go-api-proxy v0.16.2 h1:CJyGEyO1CIwOnXTU40urf0mchf6t3voxpvUDikOU9LY= github.com/awslabs/aws-lambda-go-api-proxy v0.16.2/go.mod h1:vxxjwBHe/KbgFeNlAP/Tvp4SsVRL3WQamcWRxqVh0z0= github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= github.com/baidubce/bce-sdk-go v0.9.188 h1:8MA7ewe4VpX01uYl7Kic6ZvfIReUFdSKbY46ZqlQM7U= github.com/baidubce/bce-sdk-go v0.9.188/go.mod h1:zbYJMQwE4IZuyrJiFO8tO8NbtYiKTFTbwh4eIsqjVdg= -github.com/bazelbuild/rules_go v0.49.0 h1:5vCbuvy8Q11g41lseGJDc5vxhDjJtfxr6nM/IC4VmqM= -github.com/bazelbuild/rules_go v0.49.0/go.mod h1:Dhcz716Kqg1RHNWos+N6MlXNkjNP2EwZQ0LukRKJfMs= github.com/benbjohnson/immutable v0.4.0 h1:CTqXbEerYso8YzVPxmWxh2gnoRQbbB9X1quUC8+vGZA= github.com/benbjohnson/immutable v0.4.0/go.mod h1:iAr8OjJGLnLmVUr9MZ/rz4PWUy6Ouc2JLYuMArmvAJM= github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY= @@ -713,8 +399,6 @@ github.com/bradleyjkemp/cupaloy/v2 v2.6.0 h1:knToPYa2xtfg42U3I6punFEjaGFKWQRXJwj github.com/bradleyjkemp/cupaloy/v2 v2.6.0/go.mod h1:bm7JXdkRd4BHJk9HpwqAI8BoAY1lps46Enkdqw6aRX0= github.com/bsm/sarama-cluster v2.1.13+incompatible h1:bqU3gMJbWZVxLZ9PGWVKP05yOmFXUlfw61RBwuE3PYU= github.com/bsm/sarama-cluster v2.1.13+incompatible/go.mod h1:r7ao+4tTNXvWm+VRpRJchr2kQhqxgmAp2iEX5W96gMM= -github.com/bufbuild/protovalidate-go v0.9.1 h1:cdrIA33994yCcJyEIZRL36ZGTe9UDM/WHs5MBHEimiE= -github.com/bufbuild/protovalidate-go v0.9.1/go.mod h1:5jptBxfvlY51RhX32zR6875JfPBRXUsQjyZjm/NqkLQ= github.com/bwesterb/go-ristretto v1.2.3 h1:1w53tCkGhCQ5djbat3+MH0BAQ5Kfgbt56UZQ/JMzngw= github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= github.com/bytedance/sonic v1.10.0-rc3 h1:uNSnscRapXTwUgTyOF0GVljYD08p9X/Lbr9MweSV3V0= @@ -729,38 +413,22 @@ github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLI github.com/chromedp/sysutil v1.1.0 h1:PUFNv5EcprjqXZD9nJb9b/c9ibAbxiYo4exNWZyipwM= github.com/chromedp/sysutil v1.1.0/go.mod h1:WiThHUdltqCNKGc4gaU50XgYjwjYIhKWoHGPTUfWTJ8= github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE= -github.com/chzyer/logex v1.2.1 h1:XHDu3E6q+gdHgsdTPH6ImJMIp436vR6MPtH8gP05QzM= -github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ= github.com/chzyer/readline v1.5.1 h1:upd/6fQk4src78LMRzh5vItIt361/o4uq553V8B5sGI= github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 h1:q763qf9huN11kDQavWsoZXJNW3xEE4JJyHa5Q25/sd8= -github.com/chzyer/test v1.0.0 h1:p3BQDXSxOhOG0P9z6/hGnII4LGiEPOYBhs8asl/fC04= -github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8= github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible h1:C29Ae4G5GtYyYMm1aztcyj/J5ckgJm2zwdDajFbx1NY= github.com/circonus-labs/circonusllhist v0.1.3 h1:TJH+oke8D16535+jHExHj4nQvzlZrj7ug5D7I/orNUA= github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI= github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe h1:QQ3GSy+MqSHxm/d8nCtnAiZdYFd45cYZPs8vOOIYKfk= -github.com/cncf/xds/go v0.0.0-20240723142845-024c85f92f20/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= -github.com/cncf/xds/go v0.0.0-20240905190251-b4127c9b8d78/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= -github.com/cncf/xds/go v0.0.0-20250121191232-2f005788dc42/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= -github.com/cncf/xds/go v0.0.0-20250326154945-ae57f3c0d45f/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= github.com/cockroachdb/cockroach-go v0.0.0-20181001143604-e0a95dfd547c h1:2zRrJWIt/f9c9HhNHAgrRgq0San5gRRUJTBXLkchal0= -github.com/cockroachdb/datadriven v1.0.2 h1:H9MtNqVoVhvd9nCBwOyDjUEdZCREqbIdCJD93PBm/jA= -github.com/cockroachdb/datadriven v1.0.2/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd h1:qMd81Ts1T2OTKmB4acZcyKaMtRnY5Y44NuXGX2GFJ1w= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= github.com/coder/quartz v0.1.0 h1:cLL+0g5l7xTf6ordRnUMMiZtRE8Sq5LxpghS63vEXrQ= github.com/coder/quartz v0.1.0/go.mod h1:vsiCc+AHViMKH2CQpGIpFgdHIEQsxwm8yCscqKmzbRA= github.com/coder/websocket v1.8.12 h1:5bUXkEPPIbewrnkU8LTCLVaxi4N4J8ahufH2vlo4NAo= github.com/coder/websocket v1.8.12/go.mod h1:LNVeNrXQZfe5qhS9ALED3uA+l5pPqvwXg3CKoDBB2gs= -github.com/coder/websocket v1.8.13 h1:f3QZdXy7uGVz+4uCJy2nTZyM0yTBj8yANEHhqlXZ9FE= -github.com/coder/websocket v1.8.13/go.mod h1:LNVeNrXQZfe5qhS9ALED3uA+l5pPqvwXg3CKoDBB2gs= -github.com/containerd/console v1.0.3 h1:lIr7SlA5PxZyMV30bDW0MGbiOPXwc63yRuCP0ARubLw= -github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= github.com/containerd/console v1.0.5 h1:R0ymNeydRqH2DmakFNdmjR2k0t7UPuiOV/N/27/qqsc= github.com/containerd/console v1.0.5/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk= -github.com/containerd/containerd v1.6.18 h1:qZbsLvmyu+Vlty0/Ex5xc0z2YtKpIsb5n45mAMI+2Ns= -github.com/containerd/containerd v1.6.18/go.mod h1:1RdCUu95+gc2v9t3IL+zIlpClSmew7/0YS8O5eQZrOw= github.com/containerd/containerd v1.7.18 h1:jqjZTQNfXGoEaZdW1WwPU0RqSn1Bm2Ay/KJPUuO8nao= github.com/containerd/containerd v1.7.18/go.mod h1:IYEk9/IO6wAPUz2bCMVUbsfXjzw5UNP5fLz4PsUygQ4= github.com/containerd/fifo v1.1.0 h1:4I2mbh5stb1u6ycIABlBw9zgtlK8viPI9QkQNRQEEmY= @@ -785,12 +453,7 @@ github.com/couchbase/moss v0.2.0/go.mod h1:9MaHIaRuy9pvLPUJxB8sh8OrLfyDczECVL37g github.com/cpuguy83/dockercfg v0.3.2 h1:DlJTyZGBDlXqUZ2Dk2Q3xHs/FtnooJJVaad2S9GKorA= github.com/cpuguy83/dockercfg v0.3.2/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc= github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk= -github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9 h1:uDmaGzcdjhF4i/plgjmEsriH11Y0o7RKapEf/LDaM3w= -github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= -github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/creasty/defaults v1.8.0 h1:z27FJxCAa0JKt3utc0sCImAEb+spPucmKoOdLHvHYKk= github.com/creasty/defaults v1.8.0/go.mod h1:iGzKe6pbEHnpMPtfDXZEr0NVxWnPTjb1bbDy08fPzYM= github.com/crewjam/httperr v0.2.0 h1:b2BfXR8U3AlIHwNeFFvZ+BV1LFvKLlzMjzaTnZMybNo= @@ -801,14 +464,10 @@ github.com/crossdock/crossdock-go v0.0.0-20160816171116-049aabb0122b h1:WR1qVJzb github.com/crossdock/crossdock-go v0.0.0-20160816171116-049aabb0122b/go.mod h1:v9FBN7gdVTpiD/+LZ7Po0UKvROyT87uLVxTHVky/dlQ= github.com/cucumber/gherkin/go/v26 v26.2.0 h1:EgIjePLWiPeslwIWmNQ3XHcypPsWAHoMCz/YEBKP4GI= github.com/cucumber/gherkin/go/v26 v26.2.0/go.mod h1:t2GAPnB8maCT4lkHL99BDCVNzCh1d7dBhCLt150Nr/0= -github.com/cucumber/godog v0.15.0 h1:51AL8lBXF3f0cyA5CV4TnJFCTHpgiy+1x1Hb3TtZUmo= -github.com/cucumber/godog v0.15.0/go.mod h1:FX3rzIDybWABU4kuIXLZ/qtqEe1Ac5RdXmqvACJOces= github.com/cucumber/godog v0.15.1 h1:rb/6oHDdvVZKS66hrhpjFQFHjthFSrQBCOI1LwshNTI= github.com/cucumber/godog v0.15.1/go.mod h1:qju+SQDewOljHuq9NSM66s0xEhogx0q30flfxL4WUk8= github.com/cucumber/messages/go/v21 v21.0.1 h1:wzA0LxwjlWQYZd32VTlAVDTkW6inOFmSM+RuOwHZiMI= github.com/cucumber/messages/go/v21 v21.0.1/go.mod h1:zheH/2HS9JLVFukdrsPWoPdmUtmYQAQPLk7w5vWsk5s= -github.com/cucumber/messages/go/v22 v22.0.0 h1:hk3ITpEWQ+KWDe619zYcqtaLOfcu9jgClSeps3DlNWI= -github.com/cucumber/messages/go/v22 v22.0.0/go.mod h1:aZipXTKc0JnjCsXrJnuZpWhtay93k7Rn3Dee7iyPJjs= github.com/cznic/b v0.0.0-20180115125044-35e9bbe41f07 h1:UHFGPvSxX4C4YBApSPvmUfL8tTvWLj2ryqvT9K4Jcuk= github.com/cznic/fileutil v0.0.0-20180108211300-6a051e75936f h1:7uSNgsgcarNk4oiN/nNkO0J7KAjlsF5Yv5Gf/tFdHas= github.com/cznic/golex v0.0.0-20170803123110-4ab7c5e190e4 h1:CVAqftqbj+exlab+8KJQrE+kNIVlQfJt58j4GxCMF1s= @@ -823,27 +482,18 @@ github.com/d4l3k/messagediff v1.2.1 h1:ZcAIMYsUg0EAp9X+tt8/enBE/Q8Yd5kzPynLyKptt github.com/d4l3k/messagediff v1.2.1/go.mod h1:Oozbb1TVXFac9FtSIxHBMnBCq2qeH/2KkEQxENCrlLo= github.com/davecgh/go-xdr v0.0.0-20161123171359-e6a2ba005892 h1:qg9VbHo1TlL0KDM0vYvBG9EY0X0Yku5WYIPoFWt8f6o= github.com/davecgh/go-xdr v0.0.0-20161123171359-e6a2ba005892/go.mod h1:CTDl0pzVzE5DEzZhPfvhY/9sPFMQIxaJ9VAMs9AagrE= -github.com/dchest/siphash v1.2.3 h1:QXwFc8cFOR2dSa/gE6o/HokBMWtLUaNDVd+22aKHeEA= -github.com/dchest/siphash v1.2.3/go.mod h1:0NvQU092bT0ipiFN++/rXm69QG9tVxLAlQHIXMPAkHc= github.com/dchest/uniuri v1.2.0 h1:koIcOUdrTIivZgSLhHQvKgqdWZq5d7KdMEWF1Ud6+5g= github.com/dchest/uniuri v1.2.0/go.mod h1:fSzm4SLHzNZvWLvWJew423PhAzkpNQYq+uNLq4kxhkY= github.com/denisenkom/go-mssqldb v0.0.0-20190515213511-eb9f6a1743f3 h1:tkum0XDgfR0jcVVXuTsYv/erY2NnEDqwRojbxR1rBYA= -github.com/dgryski/go-ddmin v0.0.0-20210904190556-96a6d69f1034 h1:BuCyszxPxUjBrYW2HNVrimC0rBUs2U27jCJGVh0IKTM= -github.com/dgryski/go-ddmin v0.0.0-20210904190556-96a6d69f1034/go.mod h1:zz4KxBkcXUWKjIcrc+uphJ1gPh/t18ymGm3PmQ+VGTk= github.com/dgryski/go-sip13 v0.0.0-20190329191031-25c5027a8c7b h1:Yqiad0+sloMPdd/0Fg22actpFx0dekpzt1xJmVNVkU0= github.com/dhui/dktest v0.3.0 h1:kwX5a7EkLcjo7VpsPQSYJcKGbXBXdjI9FGjuUj1jn6I= github.com/dimchansky/utfbom v1.1.1 h1:vV6w1AhK4VMnhBno/TPVCoK9U/LP0PkLCS9tbxHdi/U= github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE= -github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= github.com/dlclark/regexp2 v1.4.0 h1:F1rxgk7p4uKjwIQxBs9oAXe5CqrXlCduYEJvrF4u93E= github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= -github.com/dmarkham/enumer v1.5.11 h1:quorLCaEfzjJ23Pf7PB9lyyaHseh91YfTM/sAD/4Mbo= -github.com/dmarkham/enumer v1.5.11/go.mod h1:yixql+kDDQRYqcuBM2n9Vlt7NoT9ixgXhaXry8vmRg8= github.com/dnaeon/go-vcr v1.1.0 h1:ReYa/UBrRyQdant9B4fNHGoCNKw6qh6P0fsdGmZpR7c= github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko= github.com/docker/distribution v2.7.0+incompatible h1:neUDAlf3wX6Ml4HdqTrbcOHXtfRN0TFIwt6YFL7N9RU= -github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= -github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8= github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw= github.com/docker/go-plugins-helpers v0.0.0-20240701071450-45e2431495c8 h1:IMfrF5LCzP2Vhw7j4IIH3HxPsCLuZYjDqFAM/C88ulg= @@ -856,9 +506,6 @@ github.com/dolthub/swiss v0.2.1 h1:gs2osYs5SJkAaH5/ggVJqXQxRXtWshF6uE0lgR/Y3Gw= github.com/dolthub/swiss v0.2.1/go.mod h1:8AhKZZ1HK7g18j7v7k6c5cYIGEZJcPn0ARsai8cUrh0= github.com/drone/envsubst v1.0.3 h1:PCIBwNDYjs50AsLZPYdfhSATKaRg/FJmDc2D6+C2x8g= github.com/drone/envsubst v1.0.3/go.mod h1:N2jZmlMufstn1KEqvbHjw40h1KyTmnVzHcSc9bFiJ2g= -github.com/drone/funcmap v0.0.0-20220929084810-72602997d16f h1:/jEs7lulqVO2u1+XI5rW4oFwIIusxuDOVKD9PAzlW2E= -github.com/drone/funcmap v0.0.0-20220929084810-72602997d16f/go.mod h1:nDRkX7PHq+p39AD5/usv3KZMerxZTYU/9rfLS5IDspU= -github.com/drone/signal v1.0.0 h1:NrnM2M/4yAuU/tXs6RP1a1ZfxnaHwYkd0kJurA1p6uI= github.com/dvyukov/go-fuzz v0.0.0-20210103155950-6a8e9d1f2415 h1:q1oJaUPdmpDm/VyXosjgPgr6wS7c5iV2p0PwJD73bUI= github.com/dvyukov/go-fuzz v0.0.0-20210103155950-6a8e9d1f2415/go.mod h1:11Gm+ccJnvAhCNLlf5+cS9KjtbaD5I5zaZpFMsTHWTw= github.com/eapache/go-resiliency v1.7.0 h1:n3NRTnBn5N0Cbi/IeOHuQn9s2UwVUH7Ga0ZWcP+9JTA= @@ -868,8 +515,6 @@ github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3/go.mod h1 github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc= github.com/ebitengine/purego v0.8.2 h1:jPPGWs2sZ1UgOSgD2bClL0MJIqu58nOmIcBuXr62z1I= github.com/ebitengine/purego v0.8.2/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= -github.com/ebitengine/purego v0.8.4 h1:CF7LEKg5FFOsASUj0+QwaXf8Ht6TlFxg09+S9wz0omw= -github.com/ebitengine/purego v0.8.4/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= github.com/efficientgo/tools/core v0.0.0-20220225185207-fe763185946b h1:ZHiD4/yE4idlbqvAO6iYCOYRzOMRpxkW+FKasRA3tsQ= github.com/efficientgo/tools/core v0.0.0-20220225185207-fe763185946b/go.mod h1:OmVcnJopJL8d3X3sSXTiypGoUSgFq1aDGmlrdi9dn/M= github.com/elastic/elastic-transport-go/v8 v8.6.1 h1:h2jQRqH6eLGiBSN4eZbQnJLtL4bC5b4lfVFRjw2R4e4= @@ -878,34 +523,13 @@ github.com/elastic/go-elasticsearch/v8 v8.17.1 h1:bOXChDoCMB4TIwwGqKd031U8OXssmW github.com/elastic/go-elasticsearch/v8 v8.17.1/go.mod h1:MVJCtL+gJJ7x5jFeUmA20O7rvipX8GcQmo5iBcmaJn4= github.com/elastic/go-grok v0.3.1 h1:WEhUxe2KrwycMnlvMimJXvzRa7DoByJB4PVUIE1ZD/U= github.com/elastic/go-grok v0.3.1/go.mod h1:n38ls8ZgOboZRgKcjMY8eFeZFMmcL9n2lP0iHhIDk64= -github.com/elastic/go-sysinfo v1.8.1/go.mod h1:JfllUnzoQV/JRYymbH3dO1yggI3mV2oTKSXsDHM+uIM= -github.com/elastic/go-sysinfo v1.15.3 h1:W+RnmhKFkqPTCRoFq2VCTmsT4p/fwpo+3gKNQsn1XU0= -github.com/elastic/go-sysinfo v1.15.3/go.mod h1:K/cNrqYTDrSoMh2oDkYEMS2+a72GRxMvNP+GC+vRIlo= github.com/elastic/go-sysinfo v1.15.4 h1:A3zQcunCxik14MgXu39cXFXcIw2sFXZ0zL886eyiv1Q= github.com/elastic/go-sysinfo v1.15.4/go.mod h1:ZBVXmqS368dOn/jvijV/zHLfakWTYHBZPk3G244lHrU= -github.com/elastic/go-windows v1.0.0/go.mod h1:TsU0Nrp7/y3+VwE82FoZF8gC/XFg/Elz6CcloAxnPgU= github.com/elastic/go-windows v1.0.2 h1:yoLLsAsV5cfg9FLhZ9EXZ2n2sQFKeDYrHenkcivY4vI= github.com/elastic/go-windows v1.0.2/go.mod h1:bGcDpBzXgYSqM0Gx3DM4+UxFj300SZLixie9u9ixLM8= github.com/elastic/lunes v0.1.0 h1:amRtLPjwkWtzDF/RKzcEPMvSsSseLDLW+bnhfNSLRe4= github.com/elastic/lunes v0.1.0/go.mod h1:xGphYIt3XdZRtyWosHQTErsQTd4OP1p9wsbVoHelrd4= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633 h1:H2pdYOb3KQ1/YsqVWoWNLQO+fusocsw354rqGTZtAgw= -github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= -github.com/emicklei/go-restful/v3 v3.12.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= -github.com/emicklei/proto v1.10.0/go.mod h1:rn1FgRS/FANiZdD2djyH7TMA9jdRDcYQ9IEN9yvjX0A= -github.com/envoyproxy/go-control-plane v0.13.1/go.mod h1:X45hY0mufo6Fd0KW3rqsGvQMw58jvjymeCzBU3mWyHw= -github.com/envoyproxy/go-control-plane/envoy v1.32.3/go.mod h1:F6hWupPfh75TBXGKA++MCT/CZHFq5r9/uwt/kQYkZfE= -github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew= -github.com/envoyproxy/protoc-gen-validate v1.1.0/go.mod h1:sXRDRVmzEbkM7CVcM06s9shE/m23dg3wzjl0UWqJ2q4= -github.com/ettle/strcase v0.2.0 h1:fGNiVF21fHXpX1niBgk0aROov1LagYsOwV/xqKDKR/Q= -github.com/ettle/strcase v0.2.0/go.mod h1:DajmHElDSaX76ITe3/VHVyMin4LWSJN5Z909Wp+ED1A= -github.com/evanphx/json-patch/v5 v5.9.11 h1:/8HVnzMq13/3x9TPvjG08wUGqBTmZBsCWzjTM0wiaDU= -github.com/evanphx/json-patch/v5 v5.9.11/go.mod h1:3j+LviiESTElxA4p3EMKAB9HXj3/XEtnUf6OZxqIQTM= -github.com/expr-lang/expr v1.16.9/go.mod h1:8/vRC7+7HBzESEqt5kKpYXxrxkr31SaO8r40VO/1IT4= -github.com/expr-lang/expr v1.17.0/go.mod h1:8/vRC7+7HBzESEqt5kKpYXxrxkr31SaO8r40VO/1IT4= -github.com/expr-lang/expr v1.17.2/go.mod h1:8/vRC7+7HBzESEqt5kKpYXxrxkr31SaO8r40VO/1IT4= -github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= -github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= -github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI= github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/felixge/fgprof v0.9.4 h1:ocDNwMFlnA0NU0zSB3I52xkO4sFXk80VK9lXjLClu88= @@ -916,14 +540,10 @@ github.com/fluent/fluent-bit-go v0.0.0-20230731091245-a7a013e2473c h1:yKN46XJHYC github.com/fluent/fluent-bit-go v0.0.0-20230731091245-a7a013e2473c/go.mod h1:L92h+dgwElEyUuShEwjbiHjseW410WIcNz+Bjutc8YQ= github.com/fogleman/gg v1.3.0 h1:/7zJX8F6AaYQc57WQCyN9cAIz+4bCJGO9B+dyW29am8= github.com/form3tech-oss/jwt-go v3.2.2+incompatible h1:TcekIExNqud5crz4xD2pavyTgWiPvpYe4Xau31I0PRk= -github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= -github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= -github.com/fsouza/fake-gcs-server v1.7.0 h1:Un0BXUXrRWYSmYyC1Rqm2e2WJfTPyDy/HGMz31emTi8= github.com/fsouza/fake-gcs-server v1.52.2 h1:j6ne83nqHrlX5EEor7WWVIKdBsztGtwJ1J2mL+k+iio= github.com/fsouza/fake-gcs-server v1.52.2/go.mod h1:47HKyIkz6oLTes1R8vEaHLwXfzYsGfmDUk1ViHHAUsA= github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= -github.com/getkin/kin-openapi v0.128.0/go.mod h1:OZrfXzUfGrNbsKj+xmFBx6E5c6yH3At/tAKSc2UszXM= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= @@ -940,23 +560,13 @@ github.com/go-fonts/liberation v0.2.0 h1:jAkAWJP4S+OsrPLZM4/eC9iW7CtHy+HBXrEwZXW github.com/go-fonts/stix v0.1.0 h1:UlZlgrvvmT/58o573ot7NFw0vZasZ5I6bcIft/oMdgg= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1 h1:QbL/5oDUmRBzO9/Z7Seo6zf912W/a6Sr4Eu0G/3Jho0= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4 h1:WtGNWLvXpe6ZudgnXrq0barxBImvnnJoMEhXAzcbM0I= -github.com/go-jose/go-jose/v4 v4.0.4/go.mod h1:NKb5HO1EZccyMpiZNbdUw/14tiXNyUJh188dfnMCAfc= -github.com/go-jose/go-jose/v4 v4.0.5/go.mod h1:s3P1lRrkT8igV8D9OjyL4WRyHvjB6a4JSllnOrmmBOA= -github.com/go-jose/go-jose/v4 v4.1.1/go.mod h1:BdsZGqgdO3b6tTc6LSE56wcDbMMLuPsw5d4ZD5f94kA= github.com/go-json-experiment/json v0.0.0-20250211171154-1ae217ad3535 h1:yE7argOs92u+sSCRgqqe6eF+cDaVhSPlioy1UkA0p/w= github.com/go-json-experiment/json v0.0.0-20250211171154-1ae217ad3535/go.mod h1:BWmvoE1Xia34f3l/ibJweyhrT+aROb/FQ6d+37F0e2s= github.com/go-kit/kit v0.12.0 h1:e4o3o3IsBfAKQh5Qbbiqyfu97Ku7jrO/JbohvztANh4= github.com/go-kit/kit v0.12.0/go.mod h1:lHd+EkCZPIwYItmGDDRdhinkzX2A1sj+M9biaEaizzs= github.com/go-latex/latex v0.0.0-20210823091927-c0d11ff05a81 h1:6zl3BbBhdnMkpSj2YY30qV3gDcVBGtFgVsV3+/i+mKQ= -github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= -github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= -github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= -github.com/go-openapi/jsonreference v0.20.1/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= -github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= -github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= github.com/go-pdf/fpdf v0.6.0 h1:MlgtGIfsdMEEQJr2le6b/HNr1ZlQwxyWr77r2aj2U/8= github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= @@ -966,18 +576,10 @@ github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91 github.com/go-playground/validator/v10 v10.19.0 h1:ol+5Fu+cSq9JD7SoSqe04GMI92cbn0+wvQ3bZ8b/AU4= github.com/go-playground/validator/v10 v10.19.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= -github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= -github.com/go-viper/mapstructure/v2 v2.3.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= -github.com/gobuffalo/flect v1.0.3 h1:xeWBM2nui+qnVvNM4S3foBhCAL2XgPU+a7FdpelbTq4= -github.com/gobuffalo/flect v1.0.3/go.mod h1:A5msMlrHtLqh9umBSnvabjsMrCcCpAyzglnDvkbYKHs= github.com/goccmack/gocc v0.0.0-20230228185258-2292f9e40198 h1:FSii2UQeSLngl3jFoR4tUKZLprO7qUlh/TKKticc0BM= github.com/goccmack/gocc v0.0.0-20230228185258-2292f9e40198/go.mod h1:DTh/Y2+NbnOVVoypCCQrovMPDKUGp4yZpSbWg5D0XIM= -github.com/goccy/go-yaml v1.11.0 h1:n7Z+zx8S9f9KgzG6KtQKf+kwqXZlLNR2F6018Dgau54= -github.com/goccy/go-yaml v1.11.0/go.mod h1:H+mJrWtjPTJAHvRbV09MCK9xYwODM+wRTVFFTWckfng= github.com/goccy/go-yaml v1.17.1 h1:LI34wktB2xEE3ONG/2Ar54+/HJVBriAGJ55PHls4YuY= github.com/goccy/go-yaml v1.17.1/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA= -github.com/gocql/gocql v0.0.0-20200526081602-cd04bd7f22a7 h1:TvUE5vjfoa7fFHMlmGOk0CsauNj1w4yJjR9+/GnWVCw= -github.com/gocql/gocql v0.0.0-20200526081602-cd04bd7f22a7/go.mod h1:DL0ekTmBSTdlNF25Orwt/JMzqIq3EJ4MVa/J/uK64OY= github.com/gocql/gocql v1.7.0 h1:O+7U7/1gSN7QTEAaMEsJc1Oq2QHXvCWoF3DFK9HDHus= github.com/gocql/gocql v1.7.0/go.mod h1:vnlvXyFZeLBF0Wy+RS8hrOdbn0UWsWtdg07XJnFxZ+4= github.com/gocraft/dbr/v2 v2.7.2 h1:ccUxMuz6RdZvD7VPhMRRMSS/ECF3gytPhPtcavjktHk= @@ -985,48 +587,25 @@ github.com/gocraft/dbr/v2 v2.7.2/go.mod h1:5bCqyIXO5fYn3jEp/L06QF4K1siFdhxChMjdN github.com/godbus/dbus/v5 v5.0.4 h1:9349emZab16e7zQvpmsbtjc18ykshndd8y2PG3sgJbA= github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= -github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= -github.com/gofrs/uuid v4.3.1+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= -github.com/gogo/status v1.1.0/go.mod h1:BFv9nrluPLmrS0EmGVvLaPNmRosr9KapBYd5/hpY1WM= github.com/golang-jwt/jwt v3.2.1+incompatible h1:73Z+4BJcrTC+KczS6WvTPvRGOp1WmfEP4Q1lOd9Z/+c= github.com/golang-jwt/jwt v3.2.1+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= -github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g= +github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ= +github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw= github.com/gomarkdown/markdown v0.0.0-20230716120725-531d2d74bc12 h1:uK3X/2mt4tbSGoHvbLBHUny7CKiuwUip3MArtukol4E= github.com/gomarkdown/markdown v0.0.0-20230716120725-531d2d74bc12/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA= -github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= -github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= -github.com/google/cel-go v0.23.2/go.mod h1:52Pb6QsDbC5kvgxvZhiL9QX1oZEkcUF/ZqaPx1J5Wwo= -github.com/google/cel-go v0.26.0/go.mod h1:A9O8OU9rdvrK5MQyrqfIxo1a0u4g3sF8KB6PUIaryMM= -github.com/google/go-jsonnet v0.18.0 h1:/6pTy6g+Jh1a1I2UMoAODkqELFiVIdOxbNwv0DDzoOg= -github.com/google/go-jsonnet v0.18.0/go.mod h1:C3fTzyVJDslXdiTqw/bTFk7vSGyCtH3MGRbDfvEwGd0= github.com/google/go-pkcs11 v0.3.0 h1:PVRnTgtArZ3QQqTGtbtjtnIkzl2iY2kt24yqbrf7td8= github.com/google/go-pkcs11 v0.3.0/go.mod h1:6eQoGcuNJpa7jnd5pMGdkSaQpNDYvPlXWMcjXXThLlY= 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-20240727154555-813a5fbdbec8/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= -github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= -github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= -github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= github.com/google/renameio v0.1.0 h1:GOZbcHa3HfsPKPlmyPyN2KEohoMXOhdMbHrvbpl2QaA= github.com/google/renameio/v2 v2.0.0 h1:UifI23ZTGY8Tt29JbYFiuyIU3eX+RNFtUwefq9qAhxg= github.com/google/renameio/v2 v2.0.0/go.mod h1:BtmJXm5YlszgC+TD4HOEEUFgkJP3nLxehU6hfe7jRt4= -github.com/google/s2a-go v0.1.8/go.mod h1:6iNWHTpQ+nfNRN5E00MSdfDwVesa8hhS32PhPO8deJA= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= -github.com/googleapis/cloud-bigtable-clients-test v0.0.3 h1:afMKTvA/jc6jSTMkeHBZGFDTt8Cc+kb1ATFzqMK85hw= -github.com/googleapis/cloud-bigtable-clients-test v0.0.3/go.mod h1:TWtDzrrAI70C3dNLDY+nZN3gxHtFdZIbpL9rCTFyxE0= -github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= -github.com/googleapis/enterprise-certificate-proxy v0.3.4/go.mod h1:YKe7cfqYXjKGpGvmSg28/fFvhNzinZQm8DGnaburhGA= -github.com/googleapis/enterprise-certificate-proxy v0.3.5/go.mod h1:MkHOF77EYAE7qfSuSS9PU6g4Nt4e11cnsDUowfwewLA= -github.com/googleapis/gax-go/v2 v2.12.3/go.mod h1:AKloxT6GtNbaLm8QTNSidHUVsHYcBHwWRvkNFJUQcS4= -github.com/googleapis/gax-go/v2 v2.14.0/go.mod h1:lhBCnjdLrWRaPvLWhmc8IS24m9mr07qSYnHncrgo+zk= -github.com/googleapis/gax-go/v2 v2.14.1/go.mod h1:Hb/NubMaVM88SrNkvl8X/o8XWwDJEPqouaLeN2IUxoA= github.com/googleapis/gnostic v0.3.0 h1:CcQijm0XKekKjP/YCz28LXVSpgguuB+nCxaSjCe09y0= github.com/googleapis/go-type-adapters v1.0.0 h1:9XdMn+d/G57qq1s8dNc5IesGCXHf6V2HZ2JwRxfA2tA= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8 h1:tlyzajkF3030q6M8SvmJSemC9DTHL/xaMa18b65+JM4= -github.com/gookit/color v1.4.2/go.mod h1:fqRyamkC1W8uxl+lxCQxOT09l/vYfZ+QeiX3rKQHCoQ= -github.com/gookit/color v1.5.0/go.mod h1:43aQb+Zerm/BWh2GnrgOQm7ffz7tvQXEKV6BFMl7wAo= github.com/gookit/color v1.5.4 h1:FZmqs7XOyGgCAxmWyPslpiok1k05wmY3SJTytgvYFs0= github.com/gookit/color v1.5.4/go.mod h1:pZJOeOS8DM43rXbp4AZo1n9zCU2qjpcRko0b6/QJi9w= github.com/gophercloud/gophercloud v1.13.0/go.mod h1:aAVqcocTSXh2vYFZ1JTvx4EQmfgzxRcNupUfxZbBNDM= @@ -1035,148 +614,33 @@ github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY= github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c= github.com/gorilla/handlers v1.5.2 h1:cLTUSsNkgcwhgRqvCNmdbRWG0A3N4F+M2nWKdScwyEE= github.com/gorilla/handlers v1.5.2/go.mod h1:dX+xVpaxdSw+q0Qek8SSsl3dfMk3jNddUkMzo0GtH0w= -github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= -github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= -github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= -github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/grafana/alerting v0.0.0-20250129195454-3e5b80036b7a/go.mod h1:QsnoKX/iYZxA4Cv+H+wC7uxutBD8qi8ZW5UJvD2TYmU= -github.com/grafana/alerting v0.0.0-20250310104713-16b885f1c79e/go.mod h1:HfvjmU3UqCIpoy9Z2wgKGrZ4A5vz+yQlP9ZXvCfEkiA= -github.com/grafana/alerting v0.0.0-20250403153742-418bc7118d05 h1:hMzOzI/S0nkZt0nUqpfAa4Rdb+YL8z8oG3pl4Jb31h8= -github.com/grafana/alerting v0.0.0-20250403153742-418bc7118d05/go.mod h1:K3YAJumchx5EEZItGv4D3pCv/Ux796hmoOibP/p/eYk= -github.com/grafana/alerting v0.0.0-20250429131604-de176b4a0309 h1:H2p3XKDHnTBGkMXLCgXiqb2dFnHbQ4zPDXOwKK4Ne3Y= -github.com/grafana/alerting v0.0.0-20250429131604-de176b4a0309/go.mod h1:pMfhRxL2LZ3Pm8iy7VcVsb9CLYuBtjFYbf1oxgx7yFA= -github.com/grafana/alerting v0.0.0-20250701210250-cea2d1683945 h1:3imTbxFpZSVI6IBIB9mn+Xc40lUweWjfMaBSgXR7rLs= -github.com/grafana/alerting v0.0.0-20250701210250-cea2d1683945/go.mod h1:gtR7agmxVfJOmNKV/n2ZULgOYTYNL+PDKYB5N48tQ7Q= -github.com/grafana/alerting v0.0.0-20250709204613-c5c6f9c1653d/go.mod h1:gtR7agmxVfJOmNKV/n2ZULgOYTYNL+PDKYB5N48tQ7Q= -github.com/grafana/alerting v0.0.0-20250911172908-2b26ef8f17eb/go.mod h1:XWqj/rlsy4OV/E9XNNyFn+a7U4GNsSugPb2rDBj9+58= -github.com/grafana/alerting v0.0.0-20250923203439-adb598e7d509 h1:8JMtYCClxrxRXsF5jc64GTURZFHJHFK/kzC7joRNTtI= -github.com/grafana/alerting v0.0.0-20250923203439-adb598e7d509/go.mod h1:T5sitas9VhVj8/S9LeRLy6H75kTBdh/sCCqHo7gaQI8= -github.com/grafana/alerting v0.0.0-20250925193206-bd061d3d9185 h1:R494uXJOz7glN76hJXKjbwu+VBYFsT0CFprsXmdHla0= -github.com/grafana/alerting v0.0.0-20250925193206-bd061d3d9185/go.mod h1:T5sitas9VhVj8/S9LeRLy6H75kTBdh/sCCqHo7gaQI8= -github.com/grafana/authlib v0.0.0-20250123104008-e99947858901/go.mod h1:/gYfphsNu9v1qYWXxpv1NSvMEMSwvdf8qb8YlgwIRl8= -github.com/grafana/authlib v0.0.0-20250909101823-1b466dbd19a1/go.mod h1:C6CmTG6vfiqebjJswKsc6zes+1F/OtTCi6aAtL5Um6A= -github.com/grafana/authlib v0.0.0-20250924100039-ea07223cdb6c/go.mod h1:C6CmTG6vfiqebjJswKsc6zes+1F/OtTCi6aAtL5Um6A= -github.com/grafana/authlib/types v0.0.0-20250120144156-d6737a7dc8f5/go.mod h1:qYjSd1tmJiuVoSICp7Py9/zD54O9uQQA3wuM6Gg4DFM= -github.com/grafana/authlib/types v0.0.0-20250120145936-5f0e28e7a87c/go.mod h1:qYjSd1tmJiuVoSICp7Py9/zD54O9uQQA3wuM6Gg4DFM= -github.com/grafana/authlib/types v0.0.0-20250314102521-a77865c746c0/go.mod h1:qeWYbnWzaYGl88JlL9+DsP1GT2Cudm58rLtx13fKZdw= -github.com/grafana/authlib/types v0.0.0-20250721184729-1593a38e4933/go.mod h1:qeWYbnWzaYGl88JlL9+DsP1GT2Cudm58rLtx13fKZdw= -github.com/grafana/authlib/types v0.0.0-20250917093142-83a502239781/go.mod h1:qeWYbnWzaYGl88JlL9+DsP1GT2Cudm58rLtx13fKZdw= github.com/grafana/cloudflare-go v0.0.0-20230110200409-c627cf6792f2 h1:qhugDMdQ4Vp68H0tp/0iN17DM2ehRo1rLEdOFe/gB8I= github.com/grafana/cloudflare-go v0.0.0-20230110200409-c627cf6792f2/go.mod h1:w/aiO1POVIeXUQyl0VQSZjl5OAGDTL5aX+4v0RA1tcw= -github.com/grafana/cog v0.0.37/go.mod h1:UDstzYqMdgIROmbfkHL8fB9XWQO2lnf5z+4W/eJo4Dc= -github.com/grafana/cog v0.0.38 h1:V7gRRn/mh7Bg1ptrCxo0bv6K0SnG9TiDZk+3Ppftn6s= -github.com/grafana/cog v0.0.38/go.mod h1:UDstzYqMdgIROmbfkHL8fB9XWQO2lnf5z+4W/eJo4Dc= -github.com/grafana/cog v0.0.40/go.mod h1:TDunc7TYF7EfzjwFOlC5AkMe3To/U2KqyyG3QVvrF38= -github.com/grafana/cog v0.0.41/go.mod h1:TDunc7TYF7EfzjwFOlC5AkMe3To/U2KqyyG3QVvrF38= -github.com/grafana/dskit v0.0.0-20250818234656-8ff9c6532e85/go.mod h1:kImsvJ1xnmeT9Z6StK+RdEKLzlpzBsKwJbEQfmBJdFs= github.com/grafana/go-gelf/v2 v2.0.1 h1:BOChP0h/jLeD+7F9mL7tq10xVkDG15he3T1zHuQaWak= github.com/grafana/go-gelf/v2 v2.0.1/go.mod h1:lexHie0xzYGwCgiRGcvZ723bSNyNI8ZRD4s0CLobh90= -github.com/grafana/gomemcache v0.0.0-20250228145437-da7b95fd2ac1/go.mod h1:j/s0jkda4UXTemDs7Pgw/vMT06alWc42CHisvYac0qw= -github.com/grafana/grafana-app-sdk v0.40.1/go.mod h1:4P8h7VB6KcDjX9bAoBQc6IP8iNylxe6bSXLR9gA39gM= -github.com/grafana/grafana-app-sdk v0.41.0 h1:SYHN3U7B1myRKY3UZZDkFsue9TDmAOap0UrQVTqtYBU= -github.com/grafana/grafana-app-sdk v0.41.0/go.mod h1:Wg/3vEZfok1hhIWiHaaJm+FwkosfO98o8KbeLFEnZpY= -github.com/grafana/grafana-app-sdk v0.46.0/go.mod h1:LCTrqR1SwBS13XGVYveBmM7giJDDjzuXK+M9VzPuPWc= -github.com/grafana/grafana-app-sdk/logging v0.38.0/go.mod h1:Y/bvbDhBiV/tkIle9RW49pgfSPIPSON8Q4qjx3pyqDk= -github.com/grafana/grafana-app-sdk/logging v0.39.0 h1:3GgN5+dUZYqq74Q+GT9/ET+yo+V54zWQk/Q2/JsJQB4= -github.com/grafana/grafana-app-sdk/logging v0.39.0/go.mod h1:WhDENSnaGHtyVVwZGVnAR7YLvh2xlLDYR3D7E6h7XVk= -github.com/grafana/grafana-app-sdk/logging v0.39.1/go.mod h1:WhDENSnaGHtyVVwZGVnAR7YLvh2xlLDYR3D7E6h7XVk= -github.com/grafana/grafana-app-sdk/logging v0.40.0/go.mod h1:otUD9XpJD7A5sCLb8mcs9hIXGdeV6lnhzVwe747g4RU= -github.com/grafana/grafana-app-sdk/logging v0.43.0/go.mod h1:0xrjKSGY5z+NLGuGsXQpxiCHR4Smu79i/CbAfdkaB1M= -github.com/grafana/grafana-app-sdk/logging v0.43.1/go.mod h1:0xrjKSGY5z+NLGuGsXQpxiCHR4Smu79i/CbAfdkaB1M= -github.com/grafana/grafana-app-sdk/logging v0.43.2/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA= -github.com/grafana/grafana-app-sdk/logging v0.45.0/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA= -github.com/grafana/grafana-app-sdk/logging v0.48.0 h1:xolkQxBlA2LQF4hprKIAeu+zUem1DigYZ6XC1TOhFJE= -github.com/grafana/grafana-app-sdk/logging v0.48.0/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA= -github.com/grafana/grafana-app-sdk/plugin v0.41.0 h1:ShUvGpAVzM3UxcsfwS6l/lwW4ytDeTbCQXf8w2P8Yp8= -github.com/grafana/grafana-app-sdk/plugin v0.41.0/go.mod h1:YIhimVfAqtOp3kdhxOanaSZjypVKh/bYxf9wfFfhDm0= -github.com/grafana/grafana-aws-sdk v0.38.2 h1:TzQD0OpWsNjtldi5G5TLDlBRk8OyDf+B5ujcoAu4Dp0= -github.com/grafana/grafana-aws-sdk v0.38.2/go.mod h1:j3vi+cXYHEFqjhBGrI6/lw1TNM+dl0Y3f0cSnDOPy+s= -github.com/grafana/grafana-aws-sdk v1.0.2 h1:98eBuHYFmgvH0xO9kKf4RBsEsgQRp8EOA/9yhDIpkss= -github.com/grafana/grafana-aws-sdk v1.0.2/go.mod h1:hO7q7yWV+t6dmiyJjMa3IbuYnYkBua+G/IAlOPVIYKE= -github.com/grafana/grafana-azure-sdk-go/v2 v2.1.6/go.mod h1:V7y2BmsWxS3A9Ohebwn4OiSfJJqi//4JQydQ8fHTduo= -github.com/grafana/grafana-plugin-sdk-go v0.263.0/go.mod h1:U43Cnrj/9DNYyvFcNdeUWNjMXTKNB0jcTcQGpWKd2gw= -github.com/grafana/grafana-plugin-sdk-go v0.267.0/go.mod h1:OuwS4c/JYgn0rr/w5zhJBpLo4gKm/vw15RsfpYAvK9Q= -github.com/grafana/grafana-plugin-sdk-go v0.269.1/go.mod h1:yv2KbO4mlr9WuDK2f+2gHAMTwwLmLuqaEnrPXTRU+OI= -github.com/grafana/grafana-plugin-sdk-go v0.275.0/go.mod h1:mO9LJqdXDh5JpO/xIdPAeg5LdThgQ06Y/SLpXDWKw2c= -github.com/grafana/grafana-plugin-sdk-go v0.277.0/go.mod h1:mAUWg68w5+1f5TLDqagIr8sWr1RT9h7ufJl5NMcWJAU= -github.com/grafana/grafana-plugin-sdk-go v0.279.0/go.mod h1:/7oGN6Z7DGTGaLHhgIYrRr6Wvmdsb3BLw5hL4Kbjy88= -github.com/grafana/grafana/apps/advisor v0.0.0-20250123151950-b066a6313173/go.mod h1:goSDiy3jtC2cp8wjpPZdUHRENcoSUHae1/Px/MDfddA= -github.com/grafana/grafana/apps/advisor v0.0.0-20250220154326-6e5de80ef295/go.mod h1:9I1dKV3Dqr0NPR9Af0WJGxOytp5/6W3JLiNChOz8r+c= -github.com/grafana/grafana/apps/alerting/notifications v0.0.0-20250121113133-e747350fee2d/go.mod h1:AvleS6icyPmcBjihtx5jYEvdzLmHGBp66NuE0AMR57A= -github.com/grafana/grafana/apps/alerting/notifications v0.0.0-20250416173722-ec17e0e4ce03/go.mod h1:oemrhKvFxxc5m32xKHPxInEHAObH0/hPPyHUiBUZ1Cc= -github.com/grafana/grafana/apps/alerting/notifications v0.0.0-20250506052906-7a2fc797fb4a/go.mod h1:VkX53kBiqIMHBoGgeEDJnzm5Nwcmv/726tuZuT5SvJY= -github.com/grafana/grafana/apps/alerting/rules v0.0.0-20250731223157-26b18dda3364/go.mod h1:wi4njPm5mJ8IpK13h57be8sWoxOhqr1UQOwmXhRM9Gk= -github.com/grafana/grafana/apps/dashboard v0.0.0-20250616135341-59c2f154336b/go.mod h1:OIlvNnUufYDhBXa4xK4CyzPI2C69ZJkHy5+aFDyPtXw= -github.com/grafana/grafana/apps/dashboard v0.0.0-20250616145019-8d27f12428cb/go.mod h1:OIlvNnUufYDhBXa4xK4CyzPI2C69ZJkHy5+aFDyPtXw= -github.com/grafana/grafana/apps/dashboard v0.0.0-20250627191313-2f1a6ae1712b/go.mod h1:eR8wca74ADgxBrvX0uNpdB1qnPaGx/KhCm4Xj8oqHfQ= -github.com/grafana/grafana/apps/investigation v0.0.0-20250121113133-e747350fee2d/go.mod h1:HQprw3MmiYj5OUV9CZnkwA1FKDZBmYACuAB3oDvUOmI= -github.com/grafana/grafana/apps/playlist v0.0.0-20250121113133-e747350fee2d/go.mod h1:DjJe5osrW/BKrzN9hAAOSElNWutj1bcriExa7iDP7kA= -github.com/grafana/grafana/apps/preferences v0.0.0-20250805113453-4b17c24d67ff h1:JDT0Mcfpi3c525xzeli+v5dR9pf5HhdFjr8djRdhs10= -github.com/grafana/grafana/apps/preferences v0.0.0-20250805113453-4b17c24d67ff/go.mod h1:NQlHMO5fHhjexw71wVjv522532NRvFg5F4tcjUEktjs= -github.com/grafana/grafana/apps/preferences v0.0.0-20250805120145-0c5a00302924 h1:uGXX6gCF1q2ytIL0w1X3UAKgF/UZ7eDDAgOaSqLOeW8= -github.com/grafana/grafana/apps/preferences v0.0.0-20250805120145-0c5a00302924/go.mod h1:NQlHMO5fHhjexw71wVjv522532NRvFg5F4tcjUEktjs= -github.com/grafana/grafana/apps/preferences v0.0.0-20250805123034-066163d71001 h1:y2AHkdji2I+zXv8rsSC8OjWEzJJjqW5OlmCsZR5+RuU= -github.com/grafana/grafana/apps/preferences v0.0.0-20250805123034-066163d71001/go.mod h1:NQlHMO5fHhjexw71wVjv522532NRvFg5F4tcjUEktjs= -github.com/grafana/grafana/pkg/aggregator v0.0.0-20250121113133-e747350fee2d/go.mod h1:1sq0guad+G4SUTlBgx7SXfhnzy7D86K/LcVOtiQCiMA= -github.com/grafana/grafana/pkg/semconv v0.0.0-20250121113133-e747350fee2d/go.mod h1:tfLnBpPYgwrBMRz4EXqPCZJyCjEG4Ev37FSlXnocJ2c= -github.com/grafana/grafana/pkg/storage/unified/apistore v0.0.0-20250121113133-e747350fee2d/go.mod h1:CXpwZ3Mkw6xVlGKc0SqUxqXCP3Uv182q6qAQnLaLxRg= -github.com/grafana/grafana/pkg/storage/unified/apistore v0.0.0-20250514132646-acbc7b54ed9e/go.mod h1:xrKQcxQxz+IUF90ybtfENFeEXtlj9nAsX/3Fw0KEIeQ= -github.com/grafana/nanogit v0.0.0-20250616082354-5e94194d02ed h1:59JF1WhHLT+lNX89Tm1OzOEySMVMASAhaPbsRjtp8Kc= -github.com/grafana/nanogit v0.0.0-20250616082354-5e94194d02ed/go.mod h1:OIAAKNgG5fpuJQRNO1lUSj9nc18Xl3O7M8fjIlBO1cI= -github.com/grafana/nanogit v0.0.0-20250619160700-ebf70d342aa5 h1:MAQ2B0cu0V1S91ZjVa7NomNZFjaR2SmdtvdwhqBtyhU= -github.com/grafana/nanogit v0.0.0-20250619160700-ebf70d342aa5/go.mod h1:tN93IZUaAmnSWgL0IgnKdLv6DNeIhTJGvl1wvQMrWco= -github.com/grafana/prometheus-alertmanager v0.25.1-0.20240930132144-b5e64e81e8d3 h1:6D2gGAwyQBElSrp3E+9lSr7k8gLuP3Aiy20rweLWeBw= -github.com/grafana/prometheus-alertmanager v0.25.1-0.20240930132144-b5e64e81e8d3/go.mod h1:YeND+6FDA7OuFgDzYODN8kfPhXLCehcpxe4T9mdnpCY= -github.com/grafana/prometheus-alertmanager v0.25.1-0.20250331083058-4563aec7a975 h1:4/BZkGObFWZf4cLbE2Vqg/1VTz67Q0AJ7LHspWLKJoQ= -github.com/grafana/prometheus-alertmanager v0.25.1-0.20250331083058-4563aec7a975/go.mod h1:FGdGvhI40Dq+CTQaSzK9evuve774cgOUdGfVO04OXkw= -github.com/grafana/prometheus-alertmanager v0.25.1-0.20250604130045-92c8f6389b36 h1:AjZ58JRw1ZieFH/SdsddF5BXtsDKt5kSrKNPWrzYz3Y= -github.com/grafana/prometheus-alertmanager v0.25.1-0.20250604130045-92c8f6389b36/go.mod h1:O/QP1BCm0HHIzbKvgMzqb5sSyH88rzkFk84F4TfJjBU= github.com/grafana/tail v0.0.0-20230510142333-77b18831edf0 h1:bjh0PVYSVVFxzINqPFYJmAmJNrWPgnVjuSdYJGHmtFU= github.com/grafana/tail v0.0.0-20230510142333-77b18831edf0/go.mod h1:7t5XR+2IA8P2qggOAHTj/GCZfoLBle3OvNSYh1VkRBU= github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA= github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= -github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= -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/go.mod h1:XKMd7iuf/RGPSMJ/U4HP0zS2Z9Fh8Ps9a+6X26m/tmI= -github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.0/go.mod h1:qOchhhIlmRcqk/O9uCo/puJlyo07YINaIqdZfZG3Jkc= github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1/go.mod h1:5SN9VR2LTsRFsrEC6FHgRbTWrTHu6tqPeKxEQv15giM= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0/go.mod h1:qztMSjm835F2bXf+5HKAPIS5qsmQDqZna/PgVt4rWtI= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3/go.mod h1:ndYquD05frm2vACXE1nsccT4oJzjhw2arTS2cpUD1PI= github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645 h1:MJG/KsmcqMwFAkh8mTnAwhyKoB+sTAnY4CACC110tbU= github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645/go.mod h1:6iZfnjpejD4L/4DwD7NryNaJyCQdzwWwH2MWhCA90Kw= github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed h1:5upAirOpQc1Q53c0bnx2ufif5kANL7bfZWcc6VJWJd8= -github.com/hamba/avro/v2 v2.28.0 h1:E8J5D27biyAulWKNiEBhV85QPc9xRMCUCGJewS0KYCE= -github.com/hamba/avro/v2 v2.28.0/go.mod h1:9TVrlt1cG1kkTUtm9u2eO5Qb7rZXlYzoKqPt8TSH+TA= github.com/hamba/avro/v2 v2.29.0 h1:fkqoWEPxfygZxrkktgSHEpd0j/P7RKTBTDbcEeMdVEY= github.com/hamba/avro/v2 v2.29.0/go.mod h1:Pk3T+x74uJoJOFmHrdJ8PRdgSEL/kEKteJ31NytCKxI= -github.com/hashicorp/consul/api v1.15.3/go.mod h1:/g/qgcoBcEXALCNZgRRisyTW0nY86++L0KbeAMXYCeY= -github.com/hashicorp/consul/sdk v0.11.0/go.mod h1:yPkX5Q6CsxTFMjQQDJwzeNmUUF5NUGGbrDsv9wTb8cw= -github.com/hashicorp/go-hclog v0.14.1/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= -github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= -github.com/hashicorp/go-immutable-radix v1.3.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-memdb v1.3.4 h1:XSL3NR682X/cVk2IeV0d70N4DZ9ljI885xAEU8IoK3c= github.com/hashicorp/go-memdb v1.3.4/go.mod h1:uBTr1oQbtuMgd1SSGoR8YV27eT3sBHbYiNm53bMpgSg= github.com/hashicorp/go-msgpack v1.1.5 h1:9byZdVjKTe5mce63pRVNP1L7UAmdHOTEMGehn6KvJWs= github.com/hashicorp/go-msgpack v1.1.5/go.mod h1:gWVc3sv/wbDmR3rQsj1CAktEZzoz1YNK9NfGLXJ69/4= -github.com/hashicorp/go-msgpack/v2 v2.1.1/go.mod h1:upybraOAblm4S7rx0+jeNy+CWWhzywQsSRV5033mMu4= -github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= -github.com/hashicorp/go-sockaddr v1.0.5/go.mod h1:uoUUmtwU7n9Dv3O4SNLeFvg0SxQ3lyjsj6+CCykpaxI= github.com/hashicorp/go-syslog v1.0.0 h1:KaodqZuhUoZereWVIYmpUgZysurB1kBLX2j0MwMrUAE= -github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go.net v0.0.1 h1:sNCoNyDEvN1xa+X0baata4RdcpKwcMS6DH+xwfqPgjw= -github.com/hashicorp/golang-lru/v2 v2.0.5/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= -github.com/hashicorp/hcl/v2 v2.17.0/go.mod h1:gJyW2PTShkJqQBKpAmPO3yxMxIuoXkOF2TpqXzrQyx4= github.com/hashicorp/logutils v1.0.0 h1:dLEQVugN8vlakKOUE3ihGLTZJRB4j+M2cdTm/ORI65Y= github.com/hashicorp/mdns v1.0.5 h1:1M5hW1cunYeoXOqHwEb/GBDDHAFo0Yqb/uz/beC6LbE= github.com/hashicorp/mdns v1.0.5/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= -github.com/hashicorp/memberlist v0.3.1/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= github.com/hashicorp/raft v1.7.0 h1:4u24Qn6lQ6uwziM++UgsyiT64Q8GyRn43CV41qPiz1o= github.com/hashicorp/raft v1.7.0/go.mod h1:N1sKh6Vn47mrWvEArQgILTyng8GoDRNYlgKyK7PMjs0= github.com/hashicorp/raft-wal v0.4.1 h1:aU8XZ6x8R9BAIB/83Z1dTDtXvDVmv9YVYeXxd/1QBSA= github.com/hashicorp/raft-wal v0.4.1/go.mod h1:A6vP5o8hGOs1LHfC1Okh9xPwWDcmb6Vvuz/QyqUXlOE= -github.com/hashicorp/serf v0.10.1/go.mod h1:yL2t6BqATOLGc5HF7qbFkTfXoPIY0WZdWHfEvMqbG+4= github.com/heroku/x v0.0.61 h1:yfoAAtnFWSFZj+UlS+RZL/h8QYEp1R4wHVEg0G+Hwh4= github.com/heroku/x v0.0.61/go.mod h1:C7xYbpMdond+s6L5VpniDUSVPRwm3kZum1o7XiD5ZHk= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= @@ -1196,25 +660,17 @@ github.com/invopop/yaml v0.3.1/go.mod h1:PMOp3nn4/12yEZUFfmOuNHJsZToEEOwoWsT+D81 github.com/iris-contrib/schema v0.0.6 h1:CPSBLyx2e91H2yJzPuhGuifVRnZBBJ3pCOMbOvPZaTw= github.com/iris-contrib/schema v0.0.6/go.mod h1:iYszG0IOsuIsfzjymw1kMzTL8YQcCWlm65f3wX8J5iA= github.com/jackc/fake v0.0.0-20150926172116-812a484cc733 h1:vr3AYkKovP8uR8AvSGGUK1IDqRa5lAAvEkZG1LKaCRc= -github.com/jackspirou/syscerts v0.0.0-20160531025014-b68f5469dff1 h1:9Xm8CKtMZIXgcopfdWk/qZ1rt0HjMgfMR9nxxSeK6vk= -github.com/jackspirou/syscerts v0.0.0-20160531025014-b68f5469dff1/go.mod h1:zuHl3Hh+e9P6gmBPvcqR1HjkaWHC/csgyskg6IaFKFo= github.com/jedib0t/go-pretty/v6 v6.6.7 h1:m+LbHpm0aIAPLzLbMfn8dc3Ht8MW7lsSO4MPItz/Uuo= github.com/jedib0t/go-pretty/v6 v6.6.7/go.mod h1:YwC5CE4fJ1HFUDeivSV1r//AmANFHyqczZk+U6BDALU= -github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jhump/gopoet v0.1.0 h1:gYjOPnzHd2nzB37xYQZxj4EIQNpBrBskRqQQ3q4ZgSg= github.com/jhump/goprotoc v0.5.0 h1:Y1UgUX+txUznfqcGdDef8ZOVlyQvnV0pKWZH08RmZuo= -github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901 h1:rp+c0RAYOWj8l6qbCUTSiRLG/iKnW3K3/QfPPuSsBt4= -github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901/go.mod h1:Z86h9688Y0wesXCyonoVr47MasHilkuLMqGhRZ4Hpak= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/jon-whit/go-grpc-prometheus v1.4.0 h1:/wmpGDJcLXuEjXryWhVYEGt9YBRhtLwFEN7T+Flr8sw= github.com/jon-whit/go-grpc-prometheus v1.4.0/go.mod h1:iTPm+Iuhh3IIqR0iGZ91JJEg5ax6YQEe1I0f6vtBuao= -github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc= github.com/joncrlsn/dque v0.0.0-20211108142734-c2ef48c5192a h1:sfe532Ipn7GX0V6mHdynBk393rDmqgI0QmjLK7ct7TU= github.com/joncrlsn/dque v0.0.0-20211108142734-c2ef48c5192a/go.mod h1:dNKs71rs2VJGBAmttu7fouEsRQlRjxy0p1Sx+T5wbpY= github.com/jstemmer/go-junit-report v0.9.1 h1:6QPYqodiu3GuPL+7mfx+NwDdp2eTkp9IfEUpgAwUN0o= -github.com/jsternberg/zap-logfmt v1.2.0 h1:1v+PK4/B48cy8cfQbxL4FmmNZrjnIMr2BsnyEmXqv2o= -github.com/jsternberg/zap-logfmt v1.2.0/go.mod h1:kz+1CUmCutPWABnNkOu9hOHKdT2q3TDYCcsFy9hpqb0= github.com/jsternberg/zap-logfmt v1.3.0 h1:z1n1AOHVVydOOVuyphbOKyR4NICDQFiJMn1IK5hVQ5Y= github.com/jsternberg/zap-logfmt v1.3.0/go.mod h1:N3DENp9WNmCZxvkBD/eReWwz1149BK6jEN9cQ4fNwZE= github.com/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d h1:c93kUJDtVAXFEhsCh5jSxyOJmFHuzcihnslQiX8Urwo= @@ -1234,21 +690,13 @@ github.com/kataras/sitemap v0.0.6/go.mod h1:dW4dOCNs896OR1HmG+dMLdT7JjDk7mYBzoIR github.com/kataras/tunnel v0.0.4 h1:sCAqWuJV7nPzGrlb0os3j49lk2JhILT0rID38NHNLpA= github.com/kataras/tunnel v0.0.4/go.mod h1:9FkU4LaeifdMWqZu7o20ojmW4B7hdhv2CMLwfnHGpYw= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= -github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8= github.com/kevinmbeaulieu/eq-go v1.0.0 h1:AQgYHURDOmnVJ62jnEk0W/7yFKEn+Lv8RHN6t7mB0Zo= github.com/kevinmbeaulieu/eq-go v1.0.0/go.mod h1:G3S8ajA56gKBZm4UB9AOyoOS37JO3roToPzKNM8dtdM= -github.com/keybase/dbus v0.0.0-20220506165403-5aa21ea2c23a h1:K0EAzgzEQHW4Y5lxrmvPMltmlRDzlhLfGmots9EHUTI= -github.com/keybase/dbus v0.0.0-20220506165403-5aa21ea2c23a/go.mod h1:YPNKjjE7Ubp9dTbnWvsP3HT+hYnY6TfXzubYTBeUxc8= github.com/kisielk/errcheck v1.5.0 h1:e8esj/e4R+SAOwFwN+n3zr0nYeCyeweozKfO23MvHzY= github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg= github.com/kisielk/sqlstruct v0.0.0-20201105191214-5f3e10d3ab46 h1:veS9QfglfvqAw2e+eeNT/SbGySq8ajECXJ9e4fPoLhY= -github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= -github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/klauspost/cpuid v1.3.1 h1:5JNjFYYQrZeKRJ0734q51WCEEn2huer72Dc7K+R/b6s= github.com/klauspost/cpuid v1.3.1/go.mod h1:bYW4mA6ZgKPob1/Dlai2LviZJO7KGI3uoWLd42rAQw4= -github.com/klauspost/cpuid/v2 v2.0.10/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= -github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= -github.com/klauspost/cpuid/v2 v2.2.11/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU= github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= github.com/knadh/koanf v1.5.0 h1:q2TSd/3Pyc/5yP9ldIrSdIz26MCcyNQzW0pEAugLPNs= @@ -1278,12 +726,8 @@ github.com/kr/pty v1.1.5 h1:hyz3dwM5QLc1Rfoz4FuWJQG5BN7tc6K1MndAUnGpQr4= github.com/kshvakov/clickhouse v1.3.5 h1:PDTYk9VYgbjPAWry3AoDREeMgOVUFij6bh6IjlloHL0= github.com/labstack/echo-contrib v0.17.2 h1:K1zivqmtcC70X9VdBFdLomjPDEVHlrcAObqmuFj1c6w= github.com/labstack/echo-contrib v0.17.2/go.mod h1:NeDh3PX7j/u+jR4iuDt1zHmWZSCz9c/p9mxXcDpyS8E= -github.com/labstack/echo/v4 v4.11.1 h1:dEpLU2FLg4UVmvCGPuk/APjlH6GDpbEPti61srUUUs4= -github.com/labstack/echo/v4 v4.11.1/go.mod h1:YuYRTSM3CHs2ybfrL8Px48bO6BAnYIN4l8wSTMP6BDQ= github.com/labstack/echo/v4 v4.13.3 h1:pwhpCPrTl5qry5HRdM5FwdXnhXSLSY+WE+YQSeCaafY= github.com/labstack/echo/v4 v4.13.3/go.mod h1:o90YNEeQWjDozo584l7AwhJMHN0bOC4tAfg+Xox9q5g= -github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8= -github.com/labstack/gommon v0.4.0/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM= github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0= github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU= github.com/leodido/go-syslog/v4 v4.1.0 h1:Wsl194qyWXr7V6DrGWC3xmxA9Ra6XgWO+toNt2fmCaI= @@ -1305,17 +749,12 @@ github.com/lufia/plan9stats v0.0.0-20240909124753-873cd0166683/go.mod h1:ilwx/Dt github.com/lyft/protoc-gen-star v0.6.1 h1:erE0rdztuaDq3bpGifD95wfoPrSZc95nGA6tbiNYh6M= github.com/lyft/protoc-gen-star/v2 v2.0.4-0.20230330145011-496ad1ac90a4 h1:sIXJOMrYnQZJu7OB7ANSF4MYri2fTEGIsRLz6LwI4xE= github.com/lyft/protoc-gen-star/v2 v2.0.4-0.20230330145011-496ad1ac90a4/go.mod h1:amey7yeodaJhXSbf/TlLvWiqQfLOSpEk//mLlc+axEk= -github.com/madflojo/testcerts v1.1.1 h1:YsSHWV79nMNZK0mJtwXjKoYHjJEbLPFefR8TxmmWupY= -github.com/madflojo/testcerts v1.1.1/go.mod h1:MW8sh39gLnkKh4K0Nc55AyHEDl9l/FBLDUsQhpmkuo0= github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE= github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mailgun/raymond/v2 v2.0.48 h1:5dmlB680ZkFG2RN/0lvTAghrSxIESeu9/2aeDqACtjw= github.com/mailgun/raymond/v2 v2.0.48/go.mod h1:lsgvL50kgt1ylcFJYZiULi5fjPBkkhNfj4KA0W54Z18= github.com/matryer/moq v0.5.2 h1:b2bsanSaO6IdraaIvPBzHnqcrkkQmk1/310HdT2nNQs= github.com/matryer/moq v0.5.2/go.mod h1:W/k5PLfou4f+bzke9VPXTbfJljxoeR1tLHigsmbshmU= -github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= -github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg= github.com/maxbrunsfeld/counterfeiter/v6 v6.11.2 h1:yVCLo4+ACVroOEr4iFU1iH46Ldlzz2rTuu18Ra7M8sU= github.com/maxbrunsfeld/counterfeiter/v6 v6.11.2/go.mod h1:VzB2VoMh1Y32/QqDfg9ZJYHj99oM4LiGtqPZydTiQSQ= @@ -1323,39 +762,25 @@ github.com/mfridman/xflag v0.1.0 h1:TWZrZwG1QklFX5S4j1vxfF1sZbZeZSGofMwPMLAF29M= github.com/mfridman/xflag v0.1.0/go.mod h1:/483ywM5ZO5SuMVjrIGquYNE5CzLrj5Ux/LxWWnjRaE= github.com/microcosm-cc/bluemonday v1.0.25 h1:4NEwSfiJ+Wva0VxN5B8OwMicaJvD8r9tlJWm9rtloEg= github.com/microcosm-cc/bluemonday v1.0.25/go.mod h1:ZIOjCQp1OrzBBPIJmfX4qDYFuhU02nx4bn030ixfHLE= -github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= -github.com/miekg/dns v1.1.56/go.mod h1:cRm6Oo2C8TY9ZS/TqsSrseAcncm74lfK5G+ikN2SWWY= github.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU= github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= github.com/mitchellh/cli v1.1.5 h1:OxRIeJXpAMztws/XHlN2vu6imG5Dpq+j61AzAX5fLng= github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ= github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw= -github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0= 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/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= github.com/mitchellh/gox v0.4.0 h1:lfGJxY7ToLJQjHHwi0EX6uYBdK78egf954SQl13PQJc= github.com/mitchellh/iochan v1.0.0 h1:C+X3KsSTLFVBr/tK1eYN/vs4rJcvsiLU338UhYPJWeY= -github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mithrandie/readline-csvq v1.3.0 h1:VTJEOGouJ8j27jJCD4kBBbNTxM0OdBvE1aY1tMhlqE8= github.com/mithrandie/readline-csvq v1.3.0/go.mod h1:FKyYqDgf/G4SNov7SMFXRWO6LQLXIOeTog/NB97FZl0= -github.com/mkevac/debugcharts v0.0.0-20191222103121-ae1c48aa8615 h1:/mD+ABZyXD39BzJI2XyRJlqdZG11gXFo0SSynL+OFeU= -github.com/mkevac/debugcharts v0.0.0-20191222103121-ae1c48aa8615/go.mod h1:Ad7oeElCZqA1Ufj0U9/liOF4BtVepxRcTvr2ey7zTvM= -github.com/moby/go-archive v0.1.0 h1:Kk/5rdW/g+H8NHdJW2gsXyZ7UnzvJNOy6VKJqueWdcQ= -github.com/moby/go-archive v0.1.0/go.mod h1:G9B+YoujNohJmrIYFBpSd54GTUB4lt9S+xVQvsJyFuo= github.com/moby/moby v27.5.1+incompatible h1:/pN59F/t3U7Q4FPzV88nzqf7Fp0qqCSL2KzhZaiKcKw= github.com/moby/moby v27.5.1+incompatible/go.mod h1:fDXVQ6+S340veQPv35CzDahGBmHsiclFwfEygB/TWMc= github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= -github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7zgvCU= -github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko= github.com/moby/sys/user v0.1.0 h1:WmZ93f5Ux6het5iituh9x2zAG7NFY9Aqi49jjE1PaQg= github.com/moby/sys/user v0.1.0/go.mod h1:fKJhFOnsCN6xZ5gSfbM6zaHGgDJMrqt9/reuj4T7MmU= -github.com/moby/sys/user v0.4.0 h1:jhcMKit7SA80hivmFJcbB1vqmw//wU61Zdui2eQXuMs= -github.com/moby/sys/user v0.4.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs= github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g= github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28= -github.com/montanaflynn/stats v0.7.0/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE= github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= github.com/mostynb/go-grpc-compression v1.2.3 h1:42/BKWMy0KEJGSdWvzqIyOZ95YcR9mLPqKctH7Uo//I= @@ -1363,7 +788,6 @@ github.com/mostynb/go-grpc-compression v1.2.3/go.mod h1:AghIxF3P57umzqM9yz795+y1 github.com/nakagami/firebirdsql v0.0.0-20190310045651-3c02a58cfed8 h1:P48LjvUQpTReR3TQRbxSeSBsMXzfK0uol7eRcr7VBYQ= github.com/natefinch/atomic v1.0.1 h1:ZPYKxkqQOx3KZ+RsbnP/YsgvxWQPGxjC0oBt2AhwV0A= github.com/natefinch/atomic v1.0.1/go.mod h1:N/D/ELrljoqDyT3rZrsUmtsuzvHkeB/wWjHV22AZRbM= -github.com/natessilva/dag v0.0.0-20180124060714-7194b8dcc5c4 h1:dnMxwus89s86tI8rcGVp2HwZzlz7c5o92VOy7dSckBQ= github.com/ncw/swift v1.0.53 h1:luHjjTNtekIEvHg5KdAFIBaH7bWfNkefwFnpDffSIks= github.com/ncw/swift v1.0.53/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM= github.com/ncw/swift/v2 v2.0.2 h1:jx282pcAKFhmoZBSdMcCRFn9VWkoBIRsCpe+yZq7vEk= @@ -1377,12 +801,6 @@ github.com/nsf/jsondiff v0.0.0-20230430225905-43f6cf3098c1 h1:dOYG7LS/WK00RWZc8X github.com/nsf/jsondiff v0.0.0-20230430225905-43f6cf3098c1/go.mod h1:mpRZBD8SJ55OIICQ3iWH0Yz3cjzA61JdqMLoWXeB2+8= github.com/olivere/elastic v6.2.37+incompatible h1:UfSGJem5czY+x/LqxgeCBgjDn6St+z8OnsCuxwD3L0U= github.com/olivere/elastic v6.2.37+incompatible/go.mod h1:J+q1zQJTgAz9woqsbVRqGeB5G1iqDKVBWLNSYW8yfJ8= -github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To= -github.com/onsi/ginkgo/v2 v2.21.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo= -github.com/onsi/ginkgo/v2 v2.22.1/go.mod h1:S6aTpoRsSq2cZOd+pssHAlKW/Q/jZt6cPrPlnj4a1xM= -github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0= -github.com/onsi/gomega v1.35.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog= -github.com/open-feature/go-sdk v1.15.1/go.mod h1:2WAFYzt8rLYavcubpCoiym3iSCXiHdPB6DxtMkv2wyo= github.com/open-telemetry/opentelemetry-collector-contrib/connector/spanmetricsconnector v0.121.0 h1:gX7HGoRE0OTMS8ZVh/zPeQe+ZEASKxAo6Wn9dIcsgRE= github.com/open-telemetry/opentelemetry-collector-contrib/connector/spanmetricsconnector v0.121.0/go.mod h1:y6UqtUREKcyDzLPQC5wSPbOlZR2HLUrNp/2ITZalVKA= github.com/open-telemetry/opentelemetry-collector-contrib/exporter/kafkaexporter v0.121.0 h1:1J3XbT944dDqif4TINht6SBz1l+HXpOeyZglaUfdY+0= @@ -1447,7 +865,6 @@ github.com/open-telemetry/opentelemetry-collector-contrib/receiver/opencensusrec github.com/open-telemetry/opentelemetry-collector-contrib/receiver/opencensusreceiver v0.124.1/go.mod h1:4+9pSfniXXdRpkKf0QNdElOd7yIWD4ux8D260tSPV54= github.com/open-telemetry/opentelemetry-collector-contrib/receiver/zipkinreceiver v0.124.1 h1:XkxqUEoukMWXF+EpEWeM9itXKt62yKi13Lzd8ZEASP4= github.com/open-telemetry/opentelemetry-collector-contrib/receiver/zipkinreceiver v0.124.1/go.mod h1:CuCZVPz+yn88b5vhZPAlxaMrVuhAVexUV6f8b07lpUc= -github.com/opentracing-contrib/go-grpc v0.0.0-20210225150812-73cb765af46e/go.mod h1:DYR5Eij8rJl8h7gblRrOZ8g0kW1umSpKqYIBTgeDtLo= github.com/oschwald/geoip2-golang v1.11.0 h1:hNENhCn1Uyzhf9PTmquXENiWS6AlxAEnBII6r8krA3w= github.com/oschwald/geoip2-golang v1.11.0/go.mod h1:P9zG+54KPEFOliZ29i7SeYZ/GM6tfEL+rgSn03hYuUo= github.com/oschwald/maxminddb-golang v1.13.0 h1:R8xBorY71s84yO06NgTmQvqvTvlS/bnYZrrWX1MElnU= @@ -1456,12 +873,8 @@ github.com/pablor21/echo-etag/v4 v4.0.3 h1:o49j5NmxbqWIMfKHtzJan33PW12LQnORDFlM6 github.com/pablor21/echo-etag/v4 v4.0.3/go.mod h1:cKXqBSw57xk+jT68+CR9HZTD4yWgbmGjvDdQcxRWdY0= github.com/parquet-go/parquet-go v0.25.1-0.20250428214007-401fed3de956 h1:EqOiLPZlZ3UfC9d51fuYWP13FxwSzUCTArR0wg1LlxM= github.com/parquet-go/parquet-go v0.25.1-0.20250428214007-401fed3de956/go.mod h1:OqBBRGBl7+llplCvDMql8dEKaDqjaFA/VAPw+OJiNiw= -github.com/pascaldekloe/name v1.0.1 h1:9lnXOHeqeHHnWLbKfH6X98+4+ETVqFqxN09UXSjcMb0= -github.com/pascaldekloe/name v1.0.1/go.mod h1:Z//MfYJnH4jVpQ9wkclwu2I2MkHmXTlT9wR5UZScttM= github.com/paulmach/orb v0.11.1 h1:3koVegMC4X/WeiXYz9iswopaTwMem53NzTJuTF20JzU= github.com/paulmach/orb v0.11.1/go.mod h1:5mULz1xQfs3bmQm63QEJA6lNGujuRafwA5S/EnuLaLU= -github.com/paulmach/protoscan v0.2.1 h1:rM0FpcTjUMvPUNk2BhPJrreDKetq43ChnL+x1sRg8O8= -github.com/paulmach/protoscan v0.2.1/go.mod h1:SpcSwydNLrxUGSDvXvO0P7g7AuhJ7lcKfDlhJCDw2gY= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0= github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y= github.com/pborman/getopt v0.0.0-20170112200414-7148bc3a4c30 h1:BHT1/DKsYDGkUgQ2jmMaozVcdk+sVfz0+1ZJq4zkWgw= @@ -1471,14 +884,10 @@ github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR github.com/philhofer/fwd v1.1.2 h1:bnDivRJ1EWPjUIRXV5KfORO897HTbpFAQddBdE8t7Gw= github.com/philhofer/fwd v1.1.2/go.mod h1:qkPdfjR2SIEbspLqpe1tO4n5yICnr2DY7mqEx2tUTP0= github.com/phpdave11/gofpdf v1.4.2 h1:KPKiIbfwbvC/wOncwhrpRdXVj2CZTCFlw4wnoyjtHfQ= -github.com/pierrec/lz4 v2.0.5+incompatible h1:2xWsjqPFWcplujydGg4WmhC/6fZqK42wMM8aXeqhl0I= github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= -github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e h1:aoZm08cpOy4WuID//EZDgcC4zIxODThtZNPirFr42+A= github.com/pkg/sftp v1.13.1 h1:I2qBYMChEhIjOgazfJmV3/mZM256btk6wkCDRmW7JYs= -github.com/pkg/sftp v1.13.7 h1:uv+I3nNJvlKZIQGSr8JVQLNHFU9YhhNpvC14Y6KgmSM= -github.com/pkg/sftp v1.13.7/go.mod h1:KMKI0t3T6hfA+lTR/ssZdunHo+uwq7ghoN09/FSu3DY= github.com/pkg/xattr v0.4.10 h1:Qe0mtiNFHQZ296vRgUjRCoPHPqH7VdTOrZx3g0T+pGA= github.com/pkg/xattr v0.4.10/go.mod h1:di8WF84zAKk8jzR1UBTEWh9AUlIZZ7M/JNt8e9B6ktU= github.com/posener/complete v1.2.3 h1:NP0eAhjcjImqslEwo/1hq7gpajME0fTLTezBKDqfXqo= @@ -1488,25 +897,9 @@ github.com/pquerna/cachecontrol v0.1.0 h1:yJMy84ti9h/+OEWa752kBTKv4XC30OtVVHYv/8 github.com/pquerna/cachecontrol v0.1.0/go.mod h1:NrUG3Z7Rdu85UNR3vm7SOsl1nFIeSiQnrHV5K9mBcUI= github.com/pquerna/ffjson v0.0.0-20190930134022-aa0246cd15f7 h1:xoIK0ctDddBMnc74udxJYBqlo9Ylnsp1waqjLsnef20= github.com/pquerna/ffjson v0.0.0-20190930134022-aa0246cd15f7/go.mod h1:YARuvh7BUWHNhzDq2OM5tzR2RiCcN2D7sapiKyCel/M= -github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= -github.com/prometheus/client_golang v1.23.0/go.mod h1:i/o0R9ByOnHX0McrTMTyhYvKE4haaf2mW08I+jGAjEE= -github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I= -github.com/prometheus/common v0.64.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8= -github.com/prometheus/common v0.66.1/go.mod h1:gcaUsgf3KfRSwHY4dIMXLPV0K/Wg1oZ8+SbZk/HH/dA= github.com/prometheus/common/assets v0.2.0 h1:0P5OrzoHrYBOSM1OigWL3mY8ZvV2N4zIE/5AahrSrfM= -github.com/prometheus/exporter-toolkit v0.10.1-0.20230714054209-2f4150c63f97/go.mod h1:LoBCZeRh+5hX+fSULNyFnagYlQG/gBsyA/deNzROkq8= -github.com/prometheus/procfs v0.0.0-20190425082905-87a4384529e0/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/statsd_exporter v0.26.1 h1:ucbIAdPmwAUcA+dU+Opok8Qt81Aw8HanlO+2N/Wjv7w= github.com/prometheus/statsd_exporter v0.26.1/go.mod h1:XlDdjAmRmx3JVvPPYuFNUg+Ynyb5kR69iPPkQjxXFMk= -github.com/pterm/pterm v0.12.27/go.mod h1:PhQ89w4i95rhgE+xedAoqous6K9X+r6aSOI2eFF7DZI= -github.com/pterm/pterm v0.12.29/go.mod h1:WI3qxgvoQFFGKGjGnJR849gU0TsEOvKn5Q8LlY1U7lg= -github.com/pterm/pterm v0.12.30/go.mod h1:MOqLIyMOgmTDz9yorcYbcw+HsgoZo3BQfg2wtl3HEFE= -github.com/pterm/pterm v0.12.31/go.mod h1:32ZAWZVXD7ZfG0s8qqHXePte42kdz8ECtRyEejaWgXU= -github.com/pterm/pterm v0.12.33/go.mod h1:x+h2uL+n7CP/rel9+bImHD5lF3nM9vJj80k9ybiiTTE= -github.com/pterm/pterm v0.12.36/go.mod h1:NjiL09hFhT/vWjQHSj1athJpx6H8cjpHXNAK5bUw8T8= -github.com/pterm/pterm v0.12.40/go.mod h1:ffwPLwlbXxP+rxT0GsgDTzS3y3rmpAO1NMjUkGTYf8s= -github.com/pterm/pterm v0.12.80 h1:mM55B+GnKUnLMUSqhdINe4s6tOuVQIetQ3my8JGyAIg= -github.com/pterm/pterm v0.12.80/go.mod h1:c6DeF9bSnOSeFPZlfs4ZRAFcf5SCoTwvwQ5xaKGQlHo= github.com/pterm/pterm v0.12.81 h1:ju+j5I2++FO1jBKMmscgh5h5DPFDFMB7epEjSoKehKA= github.com/pterm/pterm v0.12.81/go.mod h1:TyuyrPjnxfwP+ccJdBTeWHtd/e0ybQHkOS/TakajZCw= github.com/r3labs/diff/v3 v3.0.1 h1:CBKqf3XmNRHXKmdU7mZP1w7TV0pDyVCis1AUHtA4Xtg= @@ -1515,23 +908,14 @@ github.com/rabbitmq/amqp091-go v1.9.0 h1:qrQtyzB4H8BQgEuJwhmVQqVHB9O4+MNDJCCAcpc github.com/rabbitmq/amqp091-go v1.9.0/go.mod h1:+jPrT9iY2eLjRaMSRHUhc3z14E/l85kv/f+6luSD3pc= github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM= github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= -github.com/redis/go-redis/v9 v9.7.3/go.mod h1:bGUrSggJ9X9GUmZpZNEOQKaANxSGgOEBRltRTZHSvrA= -github.com/rekby/fixenv v0.6.1 h1:jUFiSPpajT4WY2cYuc++7Y1zWrnCxnovGCIX72PZniM= -github.com/rekby/fixenv v0.6.1/go.mod h1:/b5LRc06BYJtslRtHKxsPWFT/ySpHV+rWvzTg+XWk4c= github.com/relvacode/iso8601 v1.6.0 h1:eFXUhMJN3Gz8Rcq82f9DTMW0svjtAVuIEULglM7QHTU= github.com/relvacode/iso8601 v1.6.0/go.mod h1:FlNp+jz+TXpyRqgmM7tnzHHzBnz776kmAH2h3sZCn0I= github.com/richardartoul/molecule v1.0.0 h1:+LFA9cT7fn8KF39zy4dhOnwcOwRoqKiBkPqKqya+8+U= github.com/richardartoul/molecule v1.0.0/go.mod h1:uvX/8buq8uVeiZiFht+0lqSLBHF+uGV8BrTv8W/SIwk= -github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rogpeppe/fastuuid v1.2.0 h1:Ppwyp6VYCF1nvBTXL3trRso7mXMlRrw9ooo375wvi2s= -github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= -github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= -github.com/rs/dnscache v0.0.0-20230804202142-fc85eb664529 h1:18kd+8ZUlt/ARXhljq+14TwAoKa61q6dX8jtwOf6DH8= -github.com/rs/dnscache v0.0.0-20230804202142-fc85eb664529/go.mod h1:qe5TWALJ8/a1Lqznoc5BDHpYX/8HU60Hm2AwRmqzxqA= github.com/russross/blackfriday v1.6.0 h1:KqfZb0pUVN2lYqZUYRddxF4OR8ZMURnJIG5Y3VRLtww= github.com/russross/blackfriday v1.6.0/go.mod h1:ti0ldHuxg49ri4ksnFxlkCfN+hvslNlmVHqNRXXJNAY= github.com/ruudk/golang-pdf417 v0.0.0-20201230142125-a7e3863a1245 h1:K1Xf3bKttbF+koVGaX5xngRIZ5bVjbmPnaxE/dR08uY= -github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/ryanuber/columnize v2.1.2+incompatible h1:C89EOx/XBWwIXl8wm8OPJBd7kPF25UfsK2X7Ph/zCAk= github.com/sagikazarmark/crypt v0.6.0 h1:REOEXCs/NFY/1jOCEouMuT4zEniE5YoXbvpC5X/TLF8= github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= @@ -1552,41 +936,19 @@ github.com/segmentio/fasthash v1.0.3 h1:EI9+KE1EwvMLBWwjpRDc+fEM+prwxDYbslddQGtr github.com/segmentio/fasthash v1.0.3/go.mod h1:waKX8l2N8yckOgmSsXJi7x1ZfdKZ4x7KRMzBtS3oedY= github.com/sercand/kuberesolver/v5 v5.1.1 h1:CYH+d67G0sGBj7q5wLK61yzqJJ8gLLC8aeprPTHb6yY= github.com/sercand/kuberesolver/v5 v5.1.1/go.mod h1:Fs1KbKhVRnB2aDWN12NjKCB+RgYMWZJ294T3BtmVCpQ= -github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= -github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= -github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shirou/gopsutil/v3 v3.23.12 h1:z90NtUkp3bMtmICZKpC4+WaknU1eXtp5vtbQ11DgpE4= github.com/shirou/gopsutil/v3 v3.23.12/go.mod h1:1FrWgea594Jp7qmjHUUPlJDTPgcsb9mGnXDxavtikzM= github.com/shirou/gopsutil/v4 v4.25.3 h1:SeA68lsu8gLggyMbmCn8cmp97V1TI9ld9sVzAUcKcKE= github.com/shirou/gopsutil/v4 v4.25.3/go.mod h1:xbuxyoZj+UsgnZrENu3lQivsngRR5BdjbJwf2fv4szA= -github.com/shirou/gopsutil/v4 v4.25.5 h1:rtd9piuSMGeU8g1RMXjZs9y9luK5BwtnG7dZaQUJAsc= -github.com/shirou/gopsutil/v4 v4.25.5/go.mod h1:PfybzyydfZcN+JMMjkF6Zb8Mq1A/VcogFFg7hj50W9c= github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= github.com/shurcooL/go v0.0.0-20200502201357-93f07166e636 h1:aSISeOcal5irEhJd1M+IrApc0PdcN7e7Aj4yuEnOrfQ= github.com/shurcooL/go v0.0.0-20200502201357-93f07166e636/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= -github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/spf13/afero v1.10.0/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= -github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= -github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g= -github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= -github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= -github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad h1:fiWzISvDn0Csy5H0iwgAuJGQTUpVfEMJJd4nRFXogbc= -github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= -github.com/stretchr/testify v1.11.0/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= -github.com/substrait-io/substrait v0.66.1-0.20250205013839-a30b3e2d7ec6 h1:XqtxwYFCjS4L0o1QD4ipGHCuFG94U0f6BeldbilGQjU= -github.com/substrait-io/substrait v0.66.1-0.20250205013839-a30b3e2d7ec6/go.mod h1:MPFNw6sToJgpD5Z2rj0rQrdP/Oq8HG7Z2t3CAEHtkHw= github.com/substrait-io/substrait v0.69.0 h1:qfwUe1qKa3PsCclMpubQOF6nqIqS14geUuvzJ1P7gsM= github.com/substrait-io/substrait v0.69.0/go.mod h1:MPFNw6sToJgpD5Z2rj0rQrdP/Oq8HG7Z2t3CAEHtkHw= -github.com/substrait-io/substrait-go/v3 v3.9.1 h1:2yfHDHpK6KMcvLd0bJVzUJoeXO+K98yS+ciBruxD9po= -github.com/substrait-io/substrait-go/v3 v3.9.1/go.mod h1:VG7jCqtUm28bSngHwq86FywtU74knJ25LNX63SZ53+E= -github.com/substrait-io/substrait-go/v4 v4.3.0 h1:Y0aFCLWnU8ypRAF/wg8khMvo7LnMdIb8i3ePd+JXSZ0= -github.com/substrait-io/substrait-go/v4 v4.3.0/go.mod h1:GzpaFqO5VRtMkEjATgRxGK5p82OmEtCmszAVYxE+iWc= github.com/substrait-io/substrait-go/v4 v4.4.0 h1:mFArMNFxlOLyTuhPcaPzZCwYh6kUopTExTy7XOqtYBM= github.com/substrait-io/substrait-go/v4 v4.4.0/go.mod h1:GzpaFqO5VRtMkEjATgRxGK5p82OmEtCmszAVYxE+iWc= github.com/substrait-io/substrait-protobuf/go v0.71.0 h1:vkYGEEPJ8lWSwaJvX7Y+hEmwmrz5/qeDmGI43JpKJZE= @@ -1601,19 +963,14 @@ github.com/tdewolff/minify/v2 v2.12.8 h1:Q2BqOTmlMjoutkuD/OPCnJUpIqrzT3nRPkw+q+K github.com/tdewolff/minify/v2 v2.12.8/go.mod h1:YRgk7CC21LZnbuke2fmYnCTq+zhCgpb0yJACOTUNJ1E= github.com/tdewolff/parse/v2 v2.6.7 h1:WrFllrqmzAcrKHzoYgMupqgUBIfBVOb0yscFzDf8bBg= github.com/tdewolff/parse/v2 v2.6.7/go.mod h1:XHDhaU6IBgsryfdnpzUXBlT6leW/l25yrFBTEb4eIyM= -github.com/testcontainers/testcontainers-go v0.35.0 h1:uADsZpTKFAtp8SLK+hMwSaa+X+JiERHtd4sQAFmXeMo= -github.com/testcontainers/testcontainers-go v0.35.0/go.mod h1:oEVBj5zrfJTrgjwONs1SsRbnBtH9OKl+IGl3UMcr2B4= github.com/testcontainers/testcontainers-go v0.36.0 h1:YpffyLuHtdp5EUsI5mT4sRw8GZhO/5ozyDT1xWGXt00= github.com/testcontainers/testcontainers-go v0.36.0/go.mod h1:yk73GVJ0KUZIHUtFna6MO7QS144qYpoY8lEEtU9Hed0= -github.com/testcontainers/testcontainers-go v0.38.0 h1:d7uEapLcv2P8AvH8ahLqDMMxda2W9gQN1nRbHS28HBw= -github.com/testcontainers/testcontainers-go v0.38.0/go.mod h1:C52c9MoHpWO+C4aqmgSU+hxlR5jlEayWtgYrb8Pzz1w= github.com/testcontainers/testcontainers-go/modules/azurite v0.35.0 h1:gUZ25e1DVE/0+ZZ0nupsIo+C1j7UNloN7Pkg3w6tceI= github.com/testcontainers/testcontainers-go/modules/azurite v0.35.0/go.mod h1:2Fc67EpyOEexLAF99zhSuzu9H22zd83pkjxEHHTtHf4= github.com/testcontainers/testcontainers-go/modules/mongodb v0.35.0 h1:i1Kh9fmXgHG9z3uzJv5Arz7pDKVaaNpLrqyd+0xhYMA= github.com/testcontainers/testcontainers-go/modules/mongodb v0.35.0/go.mod h1:SD8nVMK1m7b/K2YJqYjYNzfHmZfqHtqNOlI44nfxjdg= github.com/testcontainers/testcontainers-go/modules/redis v0.35.0 h1:RBgVefU5j5IWapp3TNKqMTYX+M22OSjtuORjPd4+g08= github.com/testcontainers/testcontainers-go/modules/redis v0.35.0/go.mod h1:UgghVXQ0//D3MjC8X71Bpb/lUCChidjNCRILD+btqfU= -github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY= github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= @@ -1629,8 +986,6 @@ github.com/tklauser/go-sysconf v0.3.14/go.mod h1:1ym4lWMLUOhuBOPGtRcJm7tEGX4SCYN github.com/tklauser/numcpus v0.8.0 h1:Mx4Wwe/FjZLeQsK/6kt2EOepwwSl7SmJrK5bV/dXYgY= github.com/tklauser/numcpus v0.8.0/go.mod h1:ZJZlAY+dmR4eut8epnzf0u/VwodKmryxR8txiloSqBE= github.com/trivago/tgo v1.0.7 h1:uaWH/XIy9aWYWpjm2CU3RpcqZXmX2ysQ9/Go+d9gyrM= -github.com/tsenart/vegeta/v12 v12.12.0 h1:FKMMNomd3auAElO/TtbXzRFXAKGee6N/GKCGweFVm2U= -github.com/tsenart/vegeta/v12 v12.12.0/go.mod h1:gpdfR++WHV9/RZh4oux0f6lNPhsOH8pCjIGUlcPQe1M= github.com/tursodatabase/libsql-client-go v0.0.0-20240902231107-85af5b9d094d h1:dOMI4+zEbDI37KGb0TI44GUAwxHF9cMsIoDTJ7UmgfU= github.com/tursodatabase/libsql-client-go v0.0.0-20240902231107-85af5b9d094d/go.mod h1:l8xTsYB90uaVdMHXMCxKKLSgw5wLYBwBKKefNIUnm9s= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926 h1:G3dpKMzFDjgEh2q1Z7zUUtKa8ViPtH+ocF0bE0g00O8= @@ -1652,16 +1007,10 @@ github.com/twmb/murmur3 v1.1.8 h1:8Yt9taO/WN3l08xErzjeschgZU2QSrwm1kclYq+0aRg= github.com/twmb/murmur3 v1.1.8/go.mod h1:Qq/R7NUyOfr65zD+6Q5IHKsJLwP7exErjN6lyyq3OSQ= github.com/uber-go/atomic v1.4.0 h1:yOuPqEq4ovnhEjpHmfFwsqBXDYbQeT6Nb0bwD6XnD5o= github.com/uber-go/atomic v1.4.0/go.mod h1:/Ct5t2lcmbJ4OSe/waGBoaVvVqtO0bmtfVNex1PFV8g= -github.com/uber/jaeger-client-go v2.28.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= -github.com/uber/jaeger-lib v2.2.0+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U= -github.com/urfave/cli/v2 v2.27.6/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ= -github.com/urfave/cli/v3 v3.3.3/go.mod h1:FJSKtM/9AiiTOJL4fJ6TbMUkxBXn7GO9guZqoZtpYpo= github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= github.com/vertica/vertica-sql-go v1.3.3 h1:fL+FKEAEy5ONmsvya2WH5T8bhkvY27y/Ik3ReR2T+Qw= github.com/vertica/vertica-sql-go v1.3.3/go.mod h1:jnn2GFuv+O2Jcjktb7zyc4Utlbu9YVqpHH/lx63+1M4= -github.com/vmihailenco/msgpack/v5 v5.3.5 h1:5gO0H1iULLWGhs2H5tbAHIZTV8/cYafcFOr9znI5mJU= -github.com/vmihailenco/msgpack/v5 v5.3.5/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc= github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8= github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok= github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= @@ -1672,9 +1021,7 @@ github.com/willf/bloom v2.0.3+incompatible h1:QDacWdqcAUI1MPOwIQZRy9kOR7yxfyEmxX github.com/willf/bloom v2.0.3+incompatible/go.mod h1:MmAltL9pDMNTrvUkxdg0k0q5I0suxmuwp3KbyrZLOZ8= github.com/xanzy/go-gitlab v0.15.0 h1:rWtwKTgEnXyNUGrOArN7yyc3THRkpYcKXIXia9abywQ= github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= -github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY= -github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8= github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8= github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c h1:u40Z8hqBAAQyv+vATcGgV0YCnDjqSL7/q/JyPhhJSPk= github.com/xdg/stringprep v1.0.0 h1:d9X0esnoa3dFsV0FG35rAT0RIhYFlPq7MiP+DW89La0= @@ -1690,7 +1037,6 @@ github.com/xitongsys/parquet-go v1.6.2 h1:MhCaXii4eqceKPu9BwrjLqyK10oX9WF+xGhwvw github.com/xitongsys/parquet-go v1.6.2/go.mod h1:IulAQyalCm0rPiZVNnCgm/PCL64X2tdSVGMQ/UeKqWA= github.com/xitongsys/parquet-go-source v0.0.0-20230830030807-0dd610dbff1d h1:VVWj8KWdzpebBaXpTVpOaQW32y2UCWy3JXJ5lVDa/e8= github.com/xitongsys/parquet-go-source v0.0.0-20230830030807-0dd610dbff1d/go.mod h1:HaLl1OAA7RAuQURU3Enxn7aRAI9yezsPPaxiGrbzxW4= -github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs= github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no= github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77 h1:ESFSdwYZvkeru3RtdrYueztKhOBCSAAzS4Gf+k0tEow= @@ -1700,14 +1046,10 @@ github.com/ydb-platform/ydb-go-sdk/v3 v3.108.1 h1:ixAiqjj2S/dNuJqrz4AxSqgw2P5OBM github.com/ydb-platform/ydb-go-sdk/v3 v3.108.1/go.mod h1:l5sSv153E18VvYcsmr51hok9Sjc16tEC8AXGbwrk+ho= github.com/yosssi/ace v0.0.5 h1:tUkIP/BLdKqrlrPwcmH0shwEEhTRHoGnc1wFIWmaBUA= github.com/yosssi/ace v0.0.5/go.mod h1:ALfIzm2vT7t5ZE7uoIZqF3TQ7SAOyupFZnkrF5id+K0= -github.com/yuin/goldmark v1.4.13 h1:fVcFKWvrslecOb/tg+Cc05dkeYx540o0FuFt3nUVDoE= github.com/yuin/goldmark v1.7.13 h1:GPddIs617DnBLFFVJFgpo1aBfe/4xcvMc3SB5t/D0pA= github.com/yuin/goldmark v1.7.13/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg= github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= -github.com/zclconf/go-cty v1.13.0/go.mod h1:YKQzy/7pZ7iq2jNFzy5go57xdxdWoLLpaEp4u238AE0= -github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b h1:FosyBZYxY34Wul7O/MSKey3txpPYyCqVO5ZyceuQJEI= -github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b/go.mod h1:ZRKQfBXbGkpdV6QMzT3rU1kSTAnfu1dO8dPKjYprgj8= github.com/zenazn/goji v1.0.1 h1:4lbD8Mx2h7IvloP7r2C0D6ltZP6Ufip8Hn0wmSK5LR8= github.com/zenazn/goji v1.0.1/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs= @@ -1715,20 +1057,10 @@ github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wK gitlab.com/nyarla/go-crypt v0.0.0-20160106005555-d9a5dc2b789b h1:7gd+rd8P3bqcn/96gOZa3F5dpJr/vEiDQYlNb/y2uNs= go.einride.tech/aip v0.68.1 h1:16/AfSxcQISGN5z9C5lM+0mLYXihrHbQ1onvYTr93aQ= go.einride.tech/aip v0.68.1/go.mod h1:XaFtaj4HuA3Zwk9xoBtTWgNubZ0ZZXv9BZJCkuKuWbg= -go.etcd.io/bbolt v1.3.11/go.mod h1:dksAq7YMXoljX0xu6VF5DMZGbhYYoLUalEiSySYAS4I= -go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= -go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= go.etcd.io/etcd/client/v2 v2.305.4 h1:Dcx3/MYyfKcPNLpR4VVQUP5KgYrBeJtktBwEKkw08Ao= -go.etcd.io/etcd/client/v2 v2.305.21 h1:eLiFfexc2mE+pTLz9WwnoEsX5JTTpLCYVivKkmVXIRA= -go.etcd.io/etcd/client/v2 v2.305.21/go.mod h1:OKkn4hlYNf43hpjEM3Ke3aRdUkhSl8xjKjSf8eCq2J8= -go.etcd.io/etcd/client/v3 v3.5.0/go.mod h1:AIKXXVX/DQXtfTEqBryiLTUXwON+GuvO6Z7lLS/oTh0= -go.etcd.io/etcd/raft/v3 v3.5.21 h1:dOmE0mT55dIUsX77TKBLq+RgyumsQuYeiRQnW/ylugk= -go.etcd.io/etcd/raft/v3 v3.5.21/go.mod h1:fmcuY5R2SNkklU4+fKVBQi2biVp5vafMrWUEj4TJ4Cs= go.etcd.io/gofail v0.2.0 h1:p19drv16FKK345a09a1iubchlw/vmRuksmRzgBIGjcA= go.etcd.io/gofail v0.2.0/go.mod h1:nL3ILMGfkXTekKI3clMBNazKnjUZjYLKmBHzsVAnC1o= -go.mongodb.org/mongo-driver v1.11.4/go.mod h1:PTSz5yu21bkT/wXpkS7WR5f0ddqw5quethTUn9WM+2g= -go.mongodb.org/mongo-driver v1.14.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c= -go.mongodb.org/mongo-driver v1.16.1/go.mod h1:oB6AhJQvFQL4LEHyXi6aJzQJtBiTQHiAd83l0GdFaiw= +go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opentelemetry.io/collector v0.124.0/go.mod h1:QzERYfmHUedawjr8Ph/CBEEkVqWS8IlxRLAZt+KHlCg= go.opentelemetry.io/collector/client v1.30.0 h1:QbvOrvwUGcnVjnIBn2zyLLubisOjgh7kMgkzDAiYpHg= go.opentelemetry.io/collector/client v1.30.0/go.mod h1:msXhZlNdAra2fZiyeT0o/xj43Kl1yvF9zYW0r+FhGUI= @@ -1818,8 +1150,6 @@ go.opentelemetry.io/collector/extension/xextension v0.124.0 h1:Yzf11HXaiMHfS50Zy go.opentelemetry.io/collector/extension/xextension v0.124.0/go.mod h1:GeM0aSgwVSba3Bvvspuy1E+1aa/Q1CDxoK+e/xcJFVg= go.opentelemetry.io/collector/extension/zpagesextension v0.121.0 h1:zCnIPyZwHkqq33MRROQN2JTKxpLadTq8ppiR1x9rbOM= go.opentelemetry.io/collector/extension/zpagesextension v0.121.0/go.mod h1:W2ZcPYdyN7ux7AD5fA0/YzW8EA2aOpUSia/YoDsh7ck= -go.opentelemetry.io/collector/featuregate v1.30.0 h1:mx7+iP/FQnY7KO8qw/xE3Qd1MQkWcU8VgcqLNrJ8EU8= -go.opentelemetry.io/collector/featuregate v1.30.0/go.mod h1:Y/KsHbvREENKvvN9RlpiWk/IGBK+CATBYzIIpU7nccc= go.opentelemetry.io/collector/internal/fanoutconsumer v0.124.0 h1:8+xc3OxriK1nZNBApFCzF7lszXyBQxyJ/Nnzy5Q4hCM= go.opentelemetry.io/collector/internal/fanoutconsumer v0.124.0/go.mod h1:CoT5fVYpTT4RWUE9DihSMlxXqGP/VnILnBBGld8Bu6o= go.opentelemetry.io/collector/internal/memorylimiter v0.121.0 h1:0QZGL5zwaHMAJqUVfyRtXNCJWhG47eyDBoRNSeQvEEc= @@ -1830,8 +1160,6 @@ go.opentelemetry.io/collector/internal/telemetry v0.124.0 h1:kzd1/ZYhLj4bt2pDB52 go.opentelemetry.io/collector/internal/telemetry v0.124.0/go.mod h1:ZjXjqV0dJ+6D4XGhTOxg/WHjnhdmXsmwmUSgALea66Y= go.opentelemetry.io/collector/otelcol v0.124.0 h1:q/+ebTZgEZX+yFbvO7FeqpEtvtRPJ+YzZzHsVzqA71s= go.opentelemetry.io/collector/otelcol v0.124.0/go.mod h1:mFGJZn5YuffdMVO/lPBavbW+R64Dgd3jOMgw2WAmJEM= -go.opentelemetry.io/collector/pdata v1.30.0 h1:j3jyq9um436r6WzWySzexP2nLnFdmL5uVBYAlyr9nDM= -go.opentelemetry.io/collector/pdata v1.30.0/go.mod h1:0Bxu1ktuj4wE7PIASNSvd0SdBscQ1PLtYasymJ13/Cs= go.opentelemetry.io/collector/pdata/testdata v0.124.0 h1:vY+pWG7CQfzzGSB5+zGYHQOltRQr59Ek9QiPe+rI+NY= go.opentelemetry.io/collector/pdata/testdata v0.124.0/go.mod h1:lNH48lGhGv4CYk27fJecpsR1zYHmZjKgNrAprwjym0o= go.opentelemetry.io/collector/pipeline v0.124.0 h1:hKvhDyH2GPnNO8LGL34ugf36sY7EOXPjBvlrvBhsOdw= @@ -1872,231 +1200,33 @@ go.opentelemetry.io/contrib/bridges/otelzap v0.10.0 h1:ojdSRDvjrnm30beHOmwsSvLpo go.opentelemetry.io/contrib/bridges/otelzap v0.10.0/go.mod h1:oTTm4g7NEtHSV2i/0FeVdPaPgUIZPfQkFbq0vbzqnv0= go.opentelemetry.io/contrib/config v0.14.0 h1:QAG8uHNp5ZiCkpT7XggSmg5AyW1sA0LgypMoXgBB1+4= go.opentelemetry.io/contrib/config v0.14.0/go.mod h1:77rDmFPqBae5jtQ2C78RuDTHz4P27C8LzoN0MZyumYQ= -go.opentelemetry.io/contrib/detectors/gcp v1.29.0/go.mod h1:GW2aWZNwR2ZxDLdv8OyC2G8zkRoQBuURgV7RPQgcPoU= -go.opentelemetry.io/contrib/detectors/gcp v1.34.0/go.mod h1:cV4BMFcscUR/ckqLkbfQmF0PRsq8w/lMGzdbCSveBHo= -go.opentelemetry.io/contrib/detectors/gcp v1.35.0/go.mod h1:qGWP8/+ILwMRIUf9uIVLloR1uo5ZYAslM4O6OqUi1DA= +go.opentelemetry.io/contrib/detectors/aws/ec2 v1.37.0 h1:BJnWw8+FULhuuF/6R6B/JYqAlCTCy9E4J8qmLpo/7KU= +go.opentelemetry.io/contrib/detectors/aws/ec2 v1.37.0/go.mod h1:gs3y8jvJscW5D+FzrZvJZEsGj+xlMCF0S1x4R6ktiNo= go.opentelemetry.io/contrib/instrumentation/github.com/labstack/echo/otelecho v0.59.0 h1:I8k9HW4yl8SRYNmECKKtjhcOvq9lAP9riqYPixBU3qw= go.opentelemetry.io/contrib/instrumentation/github.com/labstack/echo/otelecho v0.59.0/go.mod h1:/vTiuiSKBQAerQeMB3CsVJbXd+cvTbhcdOk5AV5Z5R0= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0/go.mod h1:Mjt1i1INqiaoZOMGR1RIUJN+i3ChKoFRqzrRQhlkbs0= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0/go.mod h1:B9yO6b04uB80CzjedvewuqDhxJxi11s7/GtiGa8bAjI= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.58.0/go.mod h1:HDBUsEjOuRC0EzKZ1bSaRGZWUBAzo+MhAcUUORSr4D0= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.59.0/go.mod h1:ijPqXp5P6IRRByFVVg9DY8P5HkxkHE5ARIa+86aXPf4= -go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.60.0/go.mod h1:CosX/aS4eHnG9D7nESYpV753l4j9q5j3SL/PUYd2lR8= -go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.62.0/go.mod h1:WfEApdZDMlLUAev/0QQpr8EJ/z0VWDKYZ5tF5RH5T1U= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0/go.mod h1:umTcuxiv1n/s/S6/c2AT/g2CQ7u5C59sHDNmfSwgz7Q= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0/go.mod h1:FRmFuRJfag1IZ2dPkHnEoSFVgTVPUd2qf5Vi69hLb8I= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0/go.mod h1:69uWxva0WgAA/4bu2Yy70SLDBwZXuQ6PbBpbsa5iZrQ= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q= -go.opentelemetry.io/contrib/instrumentation/runtime v0.62.0 h1:ZIt0ya9/y4WyRIzfLC8hQRRsWg0J9M9GyaGtIMiElZI= -go.opentelemetry.io/contrib/instrumentation/runtime v0.62.0/go.mod h1:F1aJ9VuiKWOlWwKdTYDUp1aoS0HzQxg38/VLxKmhm5U= go.opentelemetry.io/contrib/otelconf v0.15.0 h1:BLNiIUsrNcqhSKpsa6CnhE6LdrpY1A8X0szMVsu99eo= go.opentelemetry.io/contrib/otelconf v0.15.0/go.mod h1:OPH1seO5z9dp1P26gnLtoM9ht7JDvh3Ws6XRHuXqImY= +go.opentelemetry.io/contrib/propagators/aws v1.37.0 h1:cp8AFiM/qjBm10C/ATIRnEDXpD5MBknrA0ANw4T2/ss= +go.opentelemetry.io/contrib/propagators/aws v1.37.0/go.mod h1:Cy8Hk2E2iSGEbsLnPUdeigrexaAOAGIAmBFK919EQs0= go.opentelemetry.io/contrib/propagators/b3 v1.35.0 h1:DpwKW04LkdFRFCIgM3sqwTJA/QREHMeMHYPWP1WeaPQ= go.opentelemetry.io/contrib/propagators/b3 v1.35.0/go.mod h1:9+SNxwqvCWo1qQwUpACBY5YKNVxFJn5mlbXg/4+uKBg= -go.opentelemetry.io/contrib/propagators/jaeger v1.35.0/go.mod h1:0ciyFyYZxE6JqRAQvIgGRabKWDUmNdW3GAQb6y/RlFU= -go.opentelemetry.io/contrib/propagators/jaeger v1.37.0/go.mod h1:x7bd+t034hxLTve1hF9Yn9qQJlO/pP8H5pWIt7+gsFM= -go.opentelemetry.io/contrib/samplers/jaegerremote v0.31.0/go.mod h1:XAOSk4bqj5vtoiY08bexeiafzxdXeLlxKFnwscvn8Fc= go.opentelemetry.io/contrib/zpages v0.60.0 h1:wOM9ie1Hz4H88L9KE6GrGbKJhfm+8F1NfW/Y3q9Xt+8= go.opentelemetry.io/contrib/zpages v0.60.0/go.mod h1:xqfToSRGh2MYUsfyErNz8jnNDPlnpZqWM/y6Z2Cx7xw= -go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= -go.opentelemetry.io/otel v1.29.0/go.mod h1:N/WtXPs1CNCUEx+Agz5uouwCba+i+bJGFicT8SR4NP8= -go.opentelemetry.io/otel v1.31.0/go.mod h1:O0C14Yl9FgkjqcCZAsE053C13OaddMYr/hz6clDkEJE= -go.opentelemetry.io/otel v1.33.0/go.mod h1:SUUkR6csvUQl+yjReHu5uM3EtVV7MBm5FHKRlNx4I8I= -go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y= -go.opentelemetry.io/otel v1.36.0/go.mod h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E= go.opentelemetry.io/otel/bridge/opencensus v1.35.0 h1:4nJfffRbozhqnuukfRkiahA94mnpryCLJLiduMIDJKI= go.opentelemetry.io/otel/bridge/opencensus v1.35.0/go.mod h1:359S30saRYNsB4A46EDx91SpXsQFNgkma7ftg2/L5/M= go.opentelemetry.io/otel/bridge/opentracing v1.35.0 h1:qT4jl1fYl0hHuRopNcwS94QosLFhGYcS0HacPUeXmT4= go.opentelemetry.io/otel/bridge/opentracing v1.35.0/go.mod h1:p5CbIL4v7uQz7mnQD6T/AZc1pPUzwz+2wZ1zrGY9Kgs= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.36.0/go.mod h1:rUKCPscaRWWcqGT6HnEmYrK+YNe5+Sw64xgQTOJ5b30= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.36.0/go.mod h1:RboSDkp7N292rgu+T0MgVt2qgFGu6qa1RpZDOtpL76w= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.33.0/go.mod h1:cpgtDBaqD/6ok/UG0jT15/uKjAY8mRA53diogHBg3UI= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0/go.mod h1:7Bept48yIeqxP2OZ9/AqIpYS94h2or0aB4FypJTc8ZM= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.36.0/go.mod h1:90PoxvaEB5n6AOdZvi+yWJQoE95U8Dhhw2bSyRqnTD0= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.33.0/go.mod h1:57gTHJSE5S1tqg+EKsLPlTWhpHMsWlVmer+LA926XiA= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.34.0/go.mod h1:U7HYyW0zt/a9x5J1Kjs+r1f/d4ZHnYFclhYY2+YbeoE= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.36.0/go.mod h1:179AK5aar5R3eS9FucPy6rggvU0g52cvKId8pv4+v0c= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.22.0/go.mod h1:hYwym2nDEeZfG/motx0p7L7J1N1vyzIThemQsb4g2qY= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.36.0/go.mod h1:r49hO7CgrxY9Voaj3Xe8pANWtr0Oq916d0XAmOoCZAQ= -go.opentelemetry.io/otel/exporters/prometheus v0.58.0/go.mod h1:7qo/4CLI+zYSNbv0GMNquzuss2FVZo3OYrGh96n4HNc= -go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.35.0/go.mod h1:U2R3XyVPzn0WX7wOIypPuptulsMcPDPs/oiSVOMVnHY= -go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.36.0/go.mod h1:PD57idA/AiFD5aqoxGxCvT/ILJPeHy3MjqU/NS7KogY= -go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= -go.opentelemetry.io/otel/metric v1.29.0/go.mod h1:auu/QWieFVWx+DmQOUMgj0F8LHWdgalxXqvp7BII/W8= -go.opentelemetry.io/otel/metric v1.31.0/go.mod h1:C3dEloVbLuYoX41KpmAhOqNriGbA+qqH6PQ5E5mUfnY= -go.opentelemetry.io/otel/metric v1.33.0/go.mod h1:L9+Fyctbp6HFTddIxClbQkjtubW6O9QS3Ann/M82u6M= -go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE= -go.opentelemetry.io/otel/metric v1.36.0/go.mod h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zLbVjV2PzT6qzbs= -go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg= -go.opentelemetry.io/otel/sdk v1.29.0/go.mod h1:pM8Dx5WKnvxLCb+8lG1PRNIDxu9g9b9g59Qr7hfAAok= -go.opentelemetry.io/otel/sdk v1.31.0/go.mod h1:TfRbMdhvxIIr/B2N2LQW2S5v9m3gOQ/08KsbbO5BPT0= -go.opentelemetry.io/otel/sdk v1.33.0/go.mod h1:A1Q5oi7/9XaMlIWzPSxLRWOI8nG3FnzHJNbiENQuihM= -go.opentelemetry.io/otel/sdk v1.34.0/go.mod h1:0e/pNiaMAqaykJGKbi+tSjWfNNHMTxoC9qANsCzbyxU= -go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg= -go.opentelemetry.io/otel/sdk v1.36.0/go.mod h1:+lC+mTgD+MUWfjJubi2vvXWcVxyr9rmlshZni72pXeY= -go.opentelemetry.io/otel/sdk/metric v1.29.0/go.mod h1:6zZLdCl2fkauYoZIOn/soQIDSWFmNSRcICarHfuhNJQ= -go.opentelemetry.io/otel/sdk/metric v1.31.0/go.mod h1:CRInTMVvNhUKgSAMbKyTMxqOBC0zgyxzW55lZzX43Y8= -go.opentelemetry.io/otel/sdk/metric v1.34.0/go.mod h1:jQ/r8Ze28zRKoNRdkjCZxfs6YvBTG1+YIqyFVFYec5w= -go.opentelemetry.io/otel/sdk/metric v1.35.0/go.mod h1:is6XYCUMpcKi+ZsOvfluY5YstFnhW0BidkR+gL+qN+w= -go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4= -go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= -go.opentelemetry.io/otel/trace v1.29.0/go.mod h1:eHl3w0sp3paPkYstJOmAimxhiFXPg+MMTlEh3nsQgWQ= -go.opentelemetry.io/otel/trace v1.31.0/go.mod h1:TXZkRk7SM2ZQLtR6eoAWQFIHPvzQ06FJAsO1tJg480A= -go.opentelemetry.io/otel/trace v1.33.0/go.mod h1:uIcdVUZMpTAmz0tI1z04GoVSezK37CbGV4fr1f2nBck= -go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc= -go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA= -go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= -go.opentelemetry.io/proto/otlp v1.4.0/go.mod h1:PPBWZIP98o2ElSqI35IHfu7hIhSwvc5N38Jw8pXuGFY= -go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4= -go.opentelemetry.io/proto/otlp v1.6.0/go.mod h1:cicgGehlFuNdgZkcALOCh3VE6K/u2tAjzlRhDwmVpZc= -go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs= go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8= -go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o= -go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= golang.org/x/arch v0.4.0 h1:A8WCeEWhLwPBKNbFi5Wv5UTCBx5zzubnXDlMOFAzFMc= golang.org/x/arch v0.4.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= -golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= -golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= -golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= -golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= -golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ= -golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= -golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc= -golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw= -golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= -golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc= -golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8= -golang.org/x/exp v0.0.0-20230321023759-10a507213a29/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= -golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w= -golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8/go.mod h1:CQ1k9gNrJ50XIzaKCRR2hssIjF07kZFEiieALBM/ARQ= -golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc= -golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= -golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY= -golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8/go.mod h1:tujkw807nyEEAamNbDrEGzRav+ilXA7PCRAd6xsmwiU= -golang.org/x/exp v0.0.0-20250305212735-054e65f0b394/go.mod h1:sIifuuw/Yco/y6yb6+bDNfyeQ/MdPUy/hKEMYQV17cM= -golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0/go.mod h1:S9Xr4PYopiDyqSyp5NjCrhFrqg6A5zA2E/iPHPhqnS8= -golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b/go.mod h1:3//PLf8L/X+8b4vuAfHzxeRUl04Adcb341+IGKfnqS8= -golang.org/x/exp v0.0.0-20250811191247-51f88131bc50/go.mod h1:rT6SFzZ7oxADUDx58pcaKFTcZ+inxAa9fTrYx/uVYwg= golang.org/x/exp/typeparams v0.0.0-20220218215828-6cf2b201936e h1:qyrTQ++p1afMkO4DPEeLGq/3oTsdlvdH4vqZUBWzUKM= golang.org/x/exp/typeparams v0.0.0-20220218215828-6cf2b201936e/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/image v0.25.0 h1:Y6uW6rH1y5y/LK1J8BPWZtr6yZ7hrsy6hFrXjgsc2fQ= golang.org/x/image v0.25.0/go.mod h1:tCAmOEGthTtkalusGp1g3xa2gke8J6c2N565dTyl9Rs= golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028 h1:4+4C/Iv2U4fMZBiMCc98MG1In4gJY5YRhtpDNeDeHWs= -golang.org/x/mod v0.6.0-dev.0.20220818022119-ed83ed61efb9/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= -golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= -golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= -golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= -golang.org/x/mod v0.27.0/go.mod h1:rWI627Fq0DEoudcK+MBkNkCe0EetEaDSwJJkCcjpazc= -golang.org/x/mod v0.28.0/go.mod h1:yfB/L0NOf/kmEbXjzCPOx1iK1fRutOydrCMsqRhEBxI= -golang.org/x/net v0.0.0-20190921015927-1a5e07d1ff72/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211123203042-d83791d6bcd9/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= -golang.org/x/net v0.16.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= -golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= -golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= -golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM= -golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= -golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= -golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= -golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= -golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= -golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E= -golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds= -golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= -golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg= -golang.org/x/net v0.44.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY= -golang.org/x/net v0.45.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY= -golang.org/x/oauth2 v0.19.0/go.mod h1:vYi7skDa1x015PmRRYZ7+s1cWyPgrPiSYRe4rnsexc8= -golang.org/x/oauth2 v0.22.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= -golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= -golang.org/x/oauth2 v0.25.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= -golang.org/x/oauth2 v0.28.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= -golang.org/x/oauth2 v0.29.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= -golang.org/x/oauth2 v0.31.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= -golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= -golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= -golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= -golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= -golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211013075003-97ac67df715c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/telemetry v0.0.0-20240521205824-bda55230c457 h1:zf5N6UOrA487eEFacMePxjXAJctxKmyjKUsjA11Uzuk= -golang.org/x/telemetry v0.0.0-20240521205824-bda55230c457/go.mod h1:pRgIJT+bRLFKnoM1ldnzKoxTIn14Yxz928LQRYYgIN0= -golang.org/x/telemetry v0.0.0-20250710130107-8d8967aff50b h1:DU+gwOBXU+6bO0sEyO7o/NeMlxZxCZEvI7v+J4a1zRQ= -golang.org/x/telemetry v0.0.0-20250710130107-8d8967aff50b/go.mod h1:4ZwOYna0/zsOKwuR5X/m0QFOJpSZvAxFfkQT+Erd9D4= -golang.org/x/telemetry v0.0.0-20250807160809-1a19826ec488 h1:3doPGa+Gg4snce233aCWnbZVFsyFMo/dR40KK/6skyE= -golang.org/x/telemetry v0.0.0-20250807160809-1a19826ec488/go.mod h1:fGb/2+tgXXjhjHsTNdVEEMZNWA0quBnfrO+AfoDSAKw= -golang.org/x/telemetry v0.0.0-20250908211612-aef8a434d053/go.mod h1:+nZKN+XVh4LCiA9DV3ywrzN4gumyCnKjau3NGb9SGoE= -golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g= -golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ= -golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw= -golang.org/x/term v0.35.0/go.mod h1:TPGtkTLesOwf2DE8CgVYiZinHAOuy5AYUYT1lENIZnA= -golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= -golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= -golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= -golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= -golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU= -golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA= -golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= -golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU= -golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4= -golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= -golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= -golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= -golang.org/x/time v0.10.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= -golang.org/x/time v0.13.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= -golang.org/x/tools v0.0.0-20190424220101-1e8e1cfdf96b/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ= -golang.org/x/tools v0.11.0/go.mod h1:anzJrxPjNtfgiYQYirP2CPGzGLxrH2u2QBhn6Bf3qY8= -golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= -golang.org/x/tools v0.16.1/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0= -golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c= -golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ= -golang.org/x/tools v0.24.1/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ= -golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0= -golang.org/x/tools v0.28.0/go.mod h1:dcIOrVd3mfQKTgrDVQHqCPMWy6lnhfhtX3hLXYVLfRw= -golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY= -golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI= -golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg= -golang.org/x/tools v0.36.0/go.mod h1:WBDiHKJK8YgLHlcQPYQzNCkUxUypCaa5ZegCVutKm+s= -golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w= -golang.org/x/tools/go/expect v0.1.0-deprecated h1:jY2C5HGYR5lqex3gEniOQL0r7Dq5+VGVgY1nudX5lXY= -golang.org/x/tools/go/expect v0.1.0-deprecated/go.mod h1:eihoPOH+FgIqa3FpoTwguz/bVUSGBlGQU67vpBeOrBY= golang.org/x/tools/go/expect v0.1.1-deprecated h1:jpBZDwmgPhXsKZC6WhL20P4b/wmnpsEAGHaNy0n/rJM= golang.org/x/tools/go/expect v0.1.1-deprecated/go.mod h1:eihoPOH+FgIqa3FpoTwguz/bVUSGBlGQU67vpBeOrBY= golang.org/x/tools/go/packages/packagestest v0.1.1-deprecated h1:1h2MnaIAIXISqTFKdENegdpAgUXz6NrPEsbIeWaBRvM= @@ -2104,122 +1234,13 @@ golang.org/x/tools/go/packages/packagestest v0.1.1-deprecated/go.mod h1:RVAQXBGN gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0 h1:OE9mWmgKkjJyEmDAAtGMPjXu+YNeGvK9VTSHY6+Qihc= gonum.org/v1/plot v0.15.2 h1:Tlfh/jBk2tqjLZ4/P8ZIwGrLEWQSPDLRm/SNWKNXiGI= gonum.org/v1/plot v0.15.2/go.mod h1:DX+x+DWso3LTha+AdkJEv5Txvi+Tql3KAGkehP0/Ubg= -google.golang.org/api v0.177.0/go.mod h1:srbhue4MLjkjbkux5p3dw/ocYOSZTaIEvf7bCOnFQDw= -google.golang.org/api v0.211.0/go.mod h1:XOloB4MXFH4UTlQSGuNUxw0UT74qdENK8d6JNsXKLi0= -google.golang.org/api v0.214.0/go.mod h1:bYPpLG8AyeMWwDU6NXoB00xC0DFkikVvd5MfwoxjLqE= -google.golang.org/api v0.215.0/go.mod h1:fta3CVtuJYOEdugLNWm6WodzOS8KdFckABwN4I40hzY= -google.golang.org/api v0.216.0/go.mod h1:K9wzQMvWi47Z9IU7OgdOofvZuw75Ge3PPITImZR/UyI= -google.golang.org/api v0.218.0/go.mod h1:5VGHBAkxrA/8EFjLVEYmMUJ8/8+gWWQ3s4cFH0FxG2M= -google.golang.org/api v0.224.0/go.mod h1:3V39my2xAGkodXy0vEqcEtkqgw2GtrFL5WuBZlCTCOQ= -google.golang.org/api v0.227.0/go.mod h1:EIpaG6MbTgQarWF5xJvX0eOJPK9n/5D4Bynb9j2HXvQ= -google.golang.org/api v0.229.0/go.mod h1:wyDfmq5g1wYJWn29O22FDWN48P7Xcz0xz+LBpptYvB0= -google.golang.org/api v0.232.0/go.mod h1:p9QCfBWZk1IJETUdbTKloR5ToFdKbYh2fkjsUL6vNoY= google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= -google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d/go.mod h1:yZTlhN0tQnXo3h00fuXNCxJdLdIdnVFVBaRJ5LWBbw4= -google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80/go.mod h1:cc8bqMqtv9gMOr0zHg2Vzff5ULhhL2IXP4sbcn32Dro= -google.golang.org/genproto v0.0.0-20241118233622-e639e219e697/go.mod h1:JJrvXBWRZaFMxBufik1a4RpFw4HhgVtBBWQeQgUj2cc= -google.golang.org/genproto v0.0.0-20250106144421-5f5ef82da422/go.mod h1:1NPAxoesyw/SgLPqaUp9u1f9PWCLAk/jVmhx7gJZStg= -google.golang.org/genproto v0.0.0-20250122153221-138b5a5a4fd4/go.mod h1:qbZzneIOXSq+KFAFut9krLfRLZiFLzZL5u2t8SV83EE= -google.golang.org/genproto v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:sAo5UzpjUwgFBCzupwhcLcxHVDK7vG5IqI30YnwX2eE= -google.golang.org/genproto v0.0.0-20250505200425-f936aa4a68b2/go.mod h1:49MsLSx0oWMOZqcpB3uL8ZOkAh1+TndpJ8ONoCBWiZk= -google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d/go.mod h1:KjSP20unUpOx5kyQUFa7k4OJg0qeJ7DEZflGDu2p6Bk= -google.golang.org/genproto/googleapis/api v0.0.0-20240429193739-8cf5692501f6/go.mod h1:10yRODfgim2/T8csjQsMPgZOMvtytXKTDRzH6HRGzRw= -google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157/go.mod h1:99sLkeliLXfdj2J75X3Ho+rrVCaJze0uwN7zDDkjPVU= -google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142/go.mod h1:d6be+8HhtEtucleCbxpPW9PA9XwISACu8nvpPqF0BVo= -google.golang.org/genproto/googleapis/api v0.0.0-20240826202546-f6391c0de4c7/go.mod h1:OCdP9MfskevB/rbYvHTsXTtKC+3bHWajPdoKgjcYkfo= -google.golang.org/genproto/googleapis/api v0.0.0-20241118233622-e639e219e697/go.mod h1:+D9ySVjN8nY8YCVjc5O7PZDIdZporIDY3KaGfJunh88= -google.golang.org/genproto/googleapis/api v0.0.0-20241202173237-19429a94021a/go.mod h1:jehYqy3+AhJU9ve55aNOaSml7wUXjF9x6z2LcCfpAhY= -google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576/go.mod h1:1R3kvZ1dtP3+4p4d3G8uJ8rFk/fWlScl38vanWACI08= -google.golang.org/genproto/googleapis/api v0.0.0-20250106144421-5f5ef82da422/go.mod h1:b6h1vNKhxaSoEI+5jc3PJUCustfli/mRab7295pY7rw= -google.golang.org/genproto/googleapis/api v0.0.0-20250124145028-65684f501c47/go.mod h1:AfA77qWLcidQWywD0YgqfpJzf50w2VjzBml3TybHeJU= -google.golang.org/genproto/googleapis/api v0.0.0-20250227231956-55c901821b1e/go.mod h1:Xsh8gBVxGCcbV8ZeTB9wI5XPyZ5RvC6V3CTeeplHbiA= -google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:jbe3Bkdp+Dh2IrslsFCklNhweNTBgSYanP1UXhJDhKg= -google.golang.org/genproto/googleapis/api v0.0.0-20250311190419-81fb87f6b8bf/go.mod h1:jbe3Bkdp+Dh2IrslsFCklNhweNTBgSYanP1UXhJDhKg= -google.golang.org/genproto/googleapis/api v0.0.0-20250313205543-e70fdf4c4cb4/go.mod h1:c8q6Z6OCqnfVIqUFJkCzKcrj8eCvUrz+K4KRzSTuANg= -google.golang.org/genproto/googleapis/api v0.0.0-20250414145226-207652e42e2e/go.mod h1:085qFyf2+XaZlRdCgKNCIZ3afY2p4HHZdoIRpId8F4A= -google.golang.org/genproto/googleapis/api v0.0.0-20250425173222-7b384671a197/go.mod h1:Cd8IzgPo5Akum2c9R6FsXNaZbH3Jpa2gpHlW89FqlyQ= -google.golang.org/genproto/googleapis/api v0.0.0-20250505200425-f936aa4a68b2/go.mod h1:pKLAc5OolXC3ViWGI62vvC0n10CpwAtRcTNCFwTKBEw= -google.golang.org/genproto/googleapis/api v0.0.0-20250512202823-5a2f75b736a9/go.mod h1:W3S/3np0/dPWsWLi1h/UymYctGXaGBM2StwzD0y140U= -google.golang.org/genproto/googleapis/api v0.0.0-20250519155744-55703ea1f237/go.mod h1:ezi0AVyMKDWy5xAncvjLWH7UcLBB5n7y2fQ8MzjJcto= -google.golang.org/genproto/googleapis/api v0.0.0-20250528174236-200df99c418a/go.mod h1:a77HrdMjoeKbnd2jmgcWdaS++ZLZAEq3orIOAEIKiVw= -google.golang.org/genproto/googleapis/api v0.0.0-20250707201910-8d1bb00bc6a7/go.mod h1:kXqgZtrWaf6qS3jZOCnCH7WYfrvFjkC51bM8fz3RsCA= -google.golang.org/genproto/googleapis/api v0.0.0-20250728155136-f173205681a0/go.mod h1:8ytArBbtOy2xfht+y2fqKd5DRDJRUQhqbyEnQ4bDChs= -google.golang.org/genproto/googleapis/api v0.0.0-20250804133106-a7a43d27e69b/go.mod h1:oDOGiMSXHL4sDTJvFvIB9nRQCGdLP1o/iVaqQK8zB+M= -google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c/go.mod h1:ea2MjsO70ssTfCjiwHgI0ZFqcw45Ksuk2ckf9G468GA= -google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5/go.mod h1:j3QtIyytwqGr1JUDtYXwtMXWPKsEa5LtzIFN1Wn5WvE= -google.golang.org/genproto/googleapis/bytestream v0.0.0-20250505200425-f936aa4a68b2 h1:DbpkGFGRkd4GORg+IWQW2EhxUaa/My/PM8d1CGyTDMY= -google.golang.org/genproto/googleapis/bytestream v0.0.0-20250505200425-f936aa4a68b2/go.mod h1:h6yxum/C2qRb4txaZRLDHK8RyS0H/o2oEDeKY4onY/Y= -google.golang.org/genproto/googleapis/bytestream v0.0.0-20250512202823-5a2f75b736a9 h1:YI36gCL8AQMhzYN6+jH8PdV/iZ0On+Zd0rO/7lCH3k8= -google.golang.org/genproto/googleapis/bytestream v0.0.0-20250512202823-5a2f75b736a9/go.mod h1:h6yxum/C2qRb4txaZRLDHK8RyS0H/o2oEDeKY4onY/Y= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:oQ5rr10WTTMvP4A36n8JpR1OrO1BEiV4f78CneXZxkA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80/go.mod h1:PAREbraiVEVGVdTZsVWjSbbTtSyGbAgIIvni8a8CD5s= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240415180920-8c6c420018be/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240429193739-8cf5692501f6/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240826202546-f6391c0de4c7/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= -google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI= -google.golang.org/genproto/googleapis/rpc v0.0.0-20241202173237-19429a94021a/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU= -google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU= -google.golang.org/genproto/googleapis/rpc v0.0.0-20241223144023-3abc09e42ca8/go.mod h1:lcTa1sDdWEIHMWlITnIczmw5w60CF9ffkb8Z+DVmmjA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250106144421-5f5ef82da422/go.mod h1:3ENsm/5D1mzDyhpzeRi1NR784I0BcofWBoSc5QqqMK4= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250124145028-65684f501c47/go.mod h1:+2Yz8+CLJbIfL9z73EW45avw8Lmge3xVElCP9zEKi50= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a/go.mod h1:uRxBH1mhmO8PGhU89cMcHaXKZqO+OfakD8QQO0oYwlQ= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250227231956-55c901821b1e/go.mod h1:LuRYeWDFV6WOn90g357N17oMCaxpgCnbi/44qJvDn2I= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:LuRYeWDFV6WOn90g357N17oMCaxpgCnbi/44qJvDn2I= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250311190419-81fb87f6b8bf/go.mod h1:LuRYeWDFV6WOn90g357N17oMCaxpgCnbi/44qJvDn2I= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250313205543-e70fdf4c4cb4/go.mod h1:LuRYeWDFV6WOn90g357N17oMCaxpgCnbi/44qJvDn2I= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250414145226-207652e42e2e/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250425173222-7b384671a197/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250505200425-f936aa4a68b2/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250512202823-5a2f75b736a9/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250519155744-55703ea1f237/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250728155136-f173205681a0/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250804133106-a7a43d27e69b/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250811230008-5f3141c8851a/go.mod h1:gw1tLEfykwDz2ET4a12jcXt4couGAm7IwsVaTy0Sflo= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c/go.mod h1:gw1tLEfykwDz2ET4a12jcXt4couGAm7IwsVaTy0Sflo= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5/go.mod h1:M4/wBTSeyLxupu3W3tJtOgB14jILAS/XWPSSa3TAlJc= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250826171959-ef028d996bc1/go.mod h1:GmFNa4BdJZ2a8G+wCe9Bg3wwThLrJun751XstdJt5Og= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090/go.mod h1:GmFNa4BdJZ2a8G+wCe9Bg3wwThLrJun751XstdJt5Og= -google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= -google.golang.org/grpc v1.61.0/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs= -google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= -google.golang.org/grpc v1.63.2/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA= -google.golang.org/grpc v1.64.1/go.mod h1:hiQF4LFZelK2WKaP6W0L92zGHtiQdZxk8CrSdvyjeP0= -google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= -google.golang.org/grpc v1.67.3/go.mod h1:YGaHCc6Oap+FzBJTZLBzkGSYt/cvGPFTPxkn7QfSU8s= -google.golang.org/grpc v1.68.1/go.mod h1:+q1XYFJjShcqn0QZHvCyeR4CXPA+llXIeUIfIe00waw= -google.golang.org/grpc v1.69.4/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4= -google.golang.org/grpc v1.70.0/go.mod h1:ofIJqVKDXx/JiXrwr2IG4/zwdH9txy3IlF40RmcJSQw= -google.golang.org/grpc v1.71.0/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec= -google.golang.org/grpc v1.71.1/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec= -google.golang.org/grpc v1.72.0/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= -google.golang.org/grpc v1.72.1/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= -google.golang.org/grpc v1.72.2/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= -google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc= -google.golang.org/grpc v1.74.0/go.mod h1:NZUaK8dAMUfzhK6uxZ+9511LtOrk73UGWOFoNvz7z+s= -google.golang.org/grpc v1.75.0/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ= -google.golang.org/grpc v1.75.1/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ= +google.golang.org/genproto/googleapis/bytestream v0.0.0-20250603155806-513f23925822 h1:zWFRixYR5QlotL+Uv3YfsPRENIrQFXiGs+iwqel6fOQ= +google.golang.org/genproto/googleapis/bytestream v0.0.0-20250603155806-513f23925822/go.mod h1:h6yxum/C2qRb4txaZRLDHK8RyS0H/o2oEDeKY4onY/Y= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0 h1:M1YKkFIboKNieVO5DLUEVzQfGwJD30Nv2jfUgzb5UcE= google.golang.org/grpc/examples v0.0.0-20230224211313-3775f633ce20 h1:MLBCGN1O7GzIx+cBiwfYPwtmZ41U3Mn/cotLJciaArI= google.golang.org/grpc/examples v0.0.0-20230224211313-3775f633ce20/go.mod h1:Nr5H8+MlGWr5+xX/STzdoEqJrO+YteqFbMyCsrb6mH0= -google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= -google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= -google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= -google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= -google.golang.org/protobuf v1.36.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= -google.golang.org/protobuf v1.36.3/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= -google.golang.org/protobuf v1.36.4/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= -google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= -google.golang.org/protobuf v1.36.7/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= -google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU= -google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU= gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc= gopkg.in/errgo.v2 v2.1.0 h1:0vLT13EuvQ0hNvakwLuFZ/jYrLp5F3kcWHXdRggjCE8= gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= @@ -2232,92 +1253,32 @@ gopkg.in/src-d/go-billy.v4 v4.3.2 h1:0SQA1pRztfTFx2miS8sA97XvooFeNOmvUenF4o0EcVg gopkg.in/src-d/go-billy.v4 v4.3.2/go.mod h1:nDjArDMp+XMs1aFAESLRjfGSgfvoYN0hDfzEk0GjC98= gopkg.in/vmihailenco/msgpack.v2 v2.9.2 h1:gjPqo9orRVlSAH/065qw3MsFCDpH7fa1KpiizXyllY4= gopkg.in/vmihailenco/msgpack.v2 v2.9.2/go.mod h1:/3Dn1Npt9+MYyLpYYXjInO/5jvMLamn+AEGwNEOatn8= -gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0 h1:POO/ycCATvegFmVuPpQzZFJ+pGZeX22Ufu6fibxDVjU= -gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg= honnef.co/go/tools v0.3.2 h1:ytYb4rOqyp1TSa2EPvNVwtPQJctSELKaMyLfqNP4+34= honnef.co/go/tools v0.3.2/go.mod h1:jzwdWgg7Jdq75wlfblQxO4neNaFFSvgc1tD5Wv8U0Yw= -howett.net/plist v0.0.0-20181124034731-591f970eefbb/go.mod h1:vMygbs4qMhSZSc4lCUl2OEE+rDiIIJAIdR4m7MiMcm0= howett.net/plist v1.0.1 h1:37GdZ8tP09Q35o9ych3ehygcsL+HqKSwzctveSlarvM= howett.net/plist v1.0.1/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g= -k8s.io/api v0.34.0/go.mod h1:YzgkIzOOlhl9uwWCZNqpw6RJy9L2FK4dlJeayUoydug= -k8s.io/apiextensions-apiserver v0.34.0/go.mod h1:hLI4GxE1BDBy9adJKxUxCEHBGZtGfIg98Q+JmTD7+g0= -k8s.io/apimachinery v0.34.0/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= -k8s.io/apiserver v0.34.0/go.mod h1:52ti5YhxAvewmmpVRqlASvaqxt0gKJxvCeW7ZrwgazQ= -k8s.io/client-go v0.34.0/go.mod h1:ozgMnEKXkRjeMvBZdV1AijMHLTh3pbACPvK7zFR+QQY= -k8s.io/code-generator v0.33.1 h1:ZLzIRdMsh3Myfnx9BaooX6iQry29UJjVfVG+BuS+UMw= -k8s.io/code-generator v0.33.1/go.mod h1:HUKT7Ubp6bOgIbbaPIs9lpd2Q02uqkMCMx9/GjDrWpY= -k8s.io/code-generator v0.33.2 h1:PCJ0Y6viTCxxJHMOyGqYwWEteM4q6y1Hqo2rNpl6jF4= -k8s.io/code-generator v0.33.2/go.mod h1:hBjCA9kPMpjLWwxcr75ReaQfFXY8u+9bEJJ7kRw3J8c= -k8s.io/code-generator v0.33.3 h1:6+34LhYkIuQ/yn/E3qlpVqjQaP8smzCu4NE1A8b0LWs= -k8s.io/code-generator v0.33.3/go.mod h1:6Y02+HQJYgNphv9z3wJB5w+sjYDIEBQW7sh62PkufvA= k8s.io/code-generator v0.34.1 h1:WpphT26E+j7tEgIUfFr5WfbJrktCGzB3JoJH9149xYc= k8s.io/code-generator v0.34.1/go.mod h1:DeWjekbDnJWRwpw3s0Jat87c+e0TgkxoR4ar608yqvg= -k8s.io/component-base v0.34.0/go.mod h1:RSCqUdvIjjrEm81epPcjQ/DS+49fADvGSCkIP3IC6vg= k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6 h1:4s3/R4+OYYYUKptXPhZKjQ04WJ6EhQQVFdjOFvCazDk= -k8s.io/gengo/v2 v2.0.0-20240826214909-a7b603a56eb7/go.mod h1:EJykeLsmFC60UQbYJezXkEsG2FLrt0GPNkU5iK5GWxU= -k8s.io/gengo/v2 v2.0.0-20250207200755-1244d31929d7 h1:2OX19X59HxDprNCVrWi6jb7LW1PoqTlYqEq5H2oetog= -k8s.io/gengo/v2 v2.0.0-20250207200755-1244d31929d7/go.mod h1:EJykeLsmFC60UQbYJezXkEsG2FLrt0GPNkU5iK5GWxU= k8s.io/gengo/v2 v2.0.0-20250604051438-85fd79dbfd9f h1:SLb+kxmzfA87x4E4brQzB33VBbT2+x7Zq9ROIHmGn9Q= k8s.io/gengo/v2 v2.0.0-20250604051438-85fd79dbfd9f/go.mod h1:EJykeLsmFC60UQbYJezXkEsG2FLrt0GPNkU5iK5GWxU= k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= -k8s.io/klog/v2 v2.80.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= -k8s.io/kms v0.34.0/go.mod h1:s1CFkLG7w9eaTYvctOxosx88fl4spqmixnNpys0JAtM= -k8s.io/kube-aggregator v0.33.1/go.mod h1:16/wlU5Lj7hNJSv7JSu5FLvxyrgiJVLCHzfVoECAsuI= -k8s.io/kube-aggregator v0.33.2/go.mod h1:qQbliLwcdmx7/8mtvkc/9QV/ON2M6ZBMcffEUmrqKFw= -k8s.io/kube-aggregator v0.33.3/go.mod h1:hwvkUoQ8q6gv0+SgNnlmQ3eUue1zHhJKTHsX7BwxwSE= -k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b/go.mod h1:UZ2yyWbFTpuhSbFhv24aGNOdoRdJZgsIObGBUaYVsts= -k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -knative.dev/hack v0.0.0-20250514121446-f525e187efdc h1:8HmclJlA0zNE/G1SkgdC3/IFSSyhaSz2iIhihU6YbEo= -knative.dev/hack v0.0.0-20250514121446-f525e187efdc/go.mod h1:R0ritgYtjLDO9527h5vb5X6gfvt5LCrJ55BNbVDsWiY= lukechampine.com/uint128 v1.2.0 h1:mBi/5l91vocEN8otkC5bDLhi2KdCticRiwbdB0O+rjI= modernc.org/cc/v3 v3.36.3 h1:uISP3F66UlixxWEcKuIWERa4TwrZENHSL8tWxZz8bHg= -modernc.org/cc/v3 v3.41.0 h1:QoR1Sn3YWlmA1T4vLaKZfawdVtSiGx8H+cEojbC7v1Q= -modernc.org/cc/v3 v3.41.0/go.mod h1:Ni4zjJYJ04CDOhG7dn640WGfwBzfE0ecX8TyMB0Fv0Y= -modernc.org/cc/v4 v4.26.2/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0= modernc.org/ccgo/v3 v3.16.9 h1:AXquSwg7GuMk11pIdw7fmO1Y/ybgazVkMhsZWCV0mHM= -modernc.org/ccgo/v3 v3.17.0 h1:o3OmOqx4/OFnl4Vm3G8Bgmqxnvxnh0nbxeT5p/dWChA= -modernc.org/ccgo/v3 v3.17.0/go.mod h1:Sg3fwVpmLvCUTaqEUjiBDAvshIaKDB0RXaf+zgqFu8I= -modernc.org/ccgo/v4 v4.28.0/go.mod h1:JygV3+9AV6SmPhDasu4JgquwU81XAKLd3OKTUDNOiKE= modernc.org/ccorpus v1.11.6 h1:J16RXiiqiCgua6+ZvQot4yUuUy8zxgqbqEEUuGPlISk= -modernc.org/ccorpus2 v1.5.2 h1:Ui+4tc58mf/W+2arcYCJR903y3zl3ecsI7Fpaaqozyw= -modernc.org/ccorpus2 v1.5.2/go.mod h1:Wifvo4Q/qS/h1aRoC2TffcHsnxwTikmi1AuLANuucJQ= -modernc.org/ccorpus2 v1.5.4 h1:k9A52f3NsUQzHStOav5ukvkdKz63CW5po4gaC5VH4Qc= -modernc.org/ccorpus2 v1.5.4/go.mod h1:Wifvo4Q/qS/h1aRoC2TffcHsnxwTikmi1AuLANuucJQ= -modernc.org/fileutil v1.3.8/go.mod h1:HxmghZSZVAz/LXcMNwZPA/DRrQZEVP9VX0V4LQGQFOc= modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 h1:5D53IMaUuA5InSeMu9eJtlQXS2NxAhyWQvkKEgXZhHI= modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6/go.mod h1:Qz0X07sNOR1jWYCrJMEnbW/X55x206Q7Vt4mz6/wHp4= modernc.org/httpfs v1.0.6 h1:AAgIpFZRXuYnkjftxTAZwMIiwEqAfk8aVB2/oA6nAeM= -modernc.org/lex v1.1.1 h1:prSCNTLw1R4rn7M/RzwsuMtAuOytfyR3cnyM07P+Pas= -modernc.org/lex v1.1.1/go.mod h1:6r8o8DLJkAnOsQaGi8fMoi+Vt6LTbDaCrkUK729D8xM= -modernc.org/lexer v1.0.4 h1:hU7xVbZsqwPphyzChc7nMSGrsuaD2PDNOmzrzkS5AlE= -modernc.org/lexer v1.0.4/go.mod h1:tOajb8S4sdfOYitzCgXDFmbVJ/LE0v1fNJ7annTw36U= -modernc.org/libc v1.41.0/go.mod h1:w0eszPsiXoOnoMJgrXjglgLuDy/bt5RR4y3QzUUeodY= -modernc.org/libc v1.66.3 h1:cfCbjTUcdsKyyZZfEUKfoHcP3S0Wkvz3jgSzByEWVCQ= -modernc.org/libc v1.66.3/go.mod h1:XD9zO8kt59cANKvHPXpx7yS2ELPheAey0vjIuZOhOU8= -modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo= -modernc.org/memory v1.7.2/go.mod h1:NO4NVCQy0N7ln+T9ngWqOQfi7ley4vpwvARR+Hjw95E= -modernc.org/scannertest v1.0.2 h1:JPtfxcVdbRvzmRf2YUvsDibJsQRw8vKA/3jb31y7cy0= -modernc.org/scannertest v1.0.2/go.mod h1:RzTm5RwglF/6shsKoEivo8N91nQIoWtcWI7ns+zPyGA= -modernc.org/sqlite v1.29.6/go.mod h1:S02dvcmm7TnTRvGhv8IGYyLnIt7AS2KPaB1F/71p75U= -modernc.org/sqlite v1.38.0/go.mod h1:1Bj+yES4SVvBZ4cBOpVZ6QgesMCKpJZDq0nxYzOpmNE= -modernc.org/sqlite v1.38.2 h1:Aclu7+tgjgcQVShZqim41Bbw9Cho0y/7WzYptXqkEek= -modernc.org/sqlite v1.38.2/go.mod h1:cPTJYSlgg3Sfg046yBShXENNtPrWrDX8bsbAQBzgQ5E= -modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0= modernc.org/tcl v1.13.1 h1:npxzTwFTZYM8ghWicVIX1cRWzj7Nd8i6AqqX2p+IYao= modernc.org/z v1.5.1 h1:RTNHdsrOpeoSeOF4FbzTo8gBYByaJ5xT7NgZ9ZqRiJM= rsc.io/binaryregexp v0.2.0 h1:HfqmD5MEmC0zvwBuF187nq9mdnXjXsSivRiXN7SmRkE= rsc.io/pdf v0.1.1 h1:k1MczvYDUvJBe93bYd7wrZLLUEcLZAuF824/I4e5Xr4= rsc.io/quote/v3 v3.1.0 h1:9JKUTTIUgS6kzR9mK1YuGKv6Nl+DijDNIc0ghT58FaY= rsc.io/sampler v1.3.0 h1:7uVkIFmeBqHfdjD+gZwtXXI+RODJ2Wc4O7MPEh/QiW4= -sigs.k8s.io/controller-runtime v0.20.4 h1:X3c+Odnxz+iPTRobG4tp092+CvBU9UK0t/bRf+n0DGU= -sigs.k8s.io/controller-runtime v0.20.4/go.mod h1:xg2XB0K5ShQzAgsoujxuKN4LNXR2LfwwHsPj7Iaw+XY= sigs.k8s.io/controller-runtime v0.22.1 h1:Ah1T7I+0A7ize291nJZdS1CabF/lB4E++WizgV24Eqg= sigs.k8s.io/controller-runtime v0.22.1/go.mod h1:FwiwRjkRPbiN+zp2QRp7wlTCzbUXxZ/D4OzuQUDwBHY= -sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= -sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3/go.mod h1:18nIHnGi6636UCz6m8i4DhaJ65T6EruyzmoQqI2BVDo= sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e h1:4Z09Hglb792X0kfOBBJUPFEyvVfQWrYT/l8h5EKA6JQ= sigs.k8s.io/structured-merge-diff/v4 v4.5.0 h1:nbCitCK2hfnhyiKo6uf2HxUPTCodY6Qaf85SbDIaMBk= sigs.k8s.io/structured-merge-diff/v4 v4.5.0/go.mod h1:N8f93tFZh9U6vpxwRArLiikrE5/2tiu1w1AGfACIGE4= -sigs.k8s.io/structured-merge-diff/v6 v6.2.0/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= diff --git a/pkg/build/go.mod b/pkg/build/go.mod index 05b30eb9bff..2cdfd52db21 100644 --- a/pkg/build/go.mod +++ b/pkg/build/go.mod @@ -38,7 +38,7 @@ require ( dagger.io/dagger v0.18.8 github.com/Masterminds/semver v1.5.0 github.com/quasilyte/go-ruleguard/dsl v0.3.22 - github.com/urfave/cli/v3 v3.4.1 + github.com/urfave/cli/v3 v3.5.0 ) require ( diff --git a/pkg/build/go.sum b/pkg/build/go.sum index 1f40522ad51..51f1b7868aa 100644 --- a/pkg/build/go.sum +++ b/pkg/build/go.sum @@ -53,8 +53,8 @@ github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/urfave/cli/v2 v2.27.7 h1:bH59vdhbjLv3LAvIu6gd0usJHgoTTPhCFib8qqOwXYU= github.com/urfave/cli/v2 v2.27.7/go.mod h1:CyNAG/xg+iAOg0N4MPGZqVmv2rCoP267496AOXUZjA4= -github.com/urfave/cli/v3 v3.4.1 h1:1M9UOCy5bLmGnuu1yn3t3CB4rG79Rtoxuv1sPhnm6qM= -github.com/urfave/cli/v3 v3.4.1/go.mod h1:FJSKtM/9AiiTOJL4fJ6TbMUkxBXn7GO9guZqoZtpYpo= +github.com/urfave/cli/v3 v3.5.0 h1:qCuFMmdayTF3zmjG8TSsoBzrDqszNrklYg2x3g4MSgw= +github.com/urfave/cli/v3 v3.5.0/go.mod h1:ysVLtOEmg2tOy6PknnYVhDoouyC/6N42TMeoMzskhso= github.com/vektah/gqlparser/v2 v2.5.27 h1:RHPD3JOplpk5mP5JGX8RKZkt2/Vwj/PZv0HxTdwFp0s= github.com/vektah/gqlparser/v2 v2.5.27/go.mod h1:D1/VCZtV3LPnQrcPBeR/q5jkSQIPti0uYCP/RI0gIeo= github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4= diff --git a/pkg/promlib/go.mod b/pkg/promlib/go.mod index 0f3cdb2d3d4..c545a9b1e8a 100644 --- a/pkg/promlib/go.mod +++ b/pkg/promlib/go.mod @@ -18,6 +18,7 @@ require ( ) require ( + cloud.google.com/go/auth v0.16.3 // indirect github.com/Azure/azure-sdk-for-go/sdk/azcore v1.19.1 // indirect github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.12.0 // indirect github.com/apache/arrow-go/v18 v18.4.1 // indirect @@ -47,6 +48,7 @@ require ( github.com/google/gnostic-models v0.7.0 // indirect github.com/google/go-cmp v0.7.0 // indirect github.com/google/uuid v1.6.0 // indirect + github.com/googleapis/gax-go/v2 v2.15.0 // indirect github.com/grafana/grafana/pkg/apimachinery v0.0.0-20251007081214-26e147d01f0a // indirect github.com/grafana/otel-profiling-go v0.5.1 // indirect github.com/grafana/pyroscope-go/godeltaprof v0.1.9 // indirect @@ -106,7 +108,7 @@ require ( golang.org/x/time v0.14.0 // indirect golang.org/x/tools v0.38.0 // indirect golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect - google.golang.org/api v0.235.0 // indirect + google.golang.org/api v0.242.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250908214217-97024824d090 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20251002232023-7c0ddcbb5797 // indirect google.golang.org/grpc v1.76.0 // indirect diff --git a/pkg/promlib/go.sum b/pkg/promlib/go.sum index 7b561e15375..01986d4d1c7 100644 --- a/pkg/promlib/go.sum +++ b/pkg/promlib/go.sum @@ -1,6 +1,6 @@ cloud.google.com/go v0.121.0 h1:pgfwva8nGw7vivjZiRfrmglGWiCJBP+0OmDpenG/Fwg= -cloud.google.com/go/auth v0.16.1 h1:XrXauHMd30LhQYVRHLGvJiYeczweKQXZxsTbV9TiguU= -cloud.google.com/go/auth v0.16.1/go.mod h1:1howDHJ5IETh/LwYs3ZxvlkXF48aSqqJUM+5o02dNOI= +cloud.google.com/go/auth v0.16.3 h1:kabzoQ9/bobUmnseYnBO6qQG7q4a/CffFRlJSxv2wCc= +cloud.google.com/go/auth v0.16.3/go.mod h1:NucRGjaXfzP1ltpcQ7On/VTZ0H4kWB5Jy+Y9Dnm76fA= cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc= cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c= cloud.google.com/go/compute/metadata v0.7.0 h1:PBWF+iiAerVNe8UCHxdOt6eHLVc3ydFeOCw78U8ytSU= @@ -126,8 +126,8 @@ 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/googleapis/enterprise-certificate-proxy v0.3.6 h1:GW/XbdyBFQ8Qe+YAmFU9uHLo7OnF5tL52HFAgMmyrf4= github.com/googleapis/enterprise-certificate-proxy v0.3.6/go.mod h1:MkHOF77EYAE7qfSuSS9PU6g4Nt4e11cnsDUowfwewLA= -github.com/googleapis/gax-go/v2 v2.14.2 h1:eBLnkZ9635krYIPD+ag1USrOAI0Nr0QYF3+/3GqO0k0= -github.com/googleapis/gax-go/v2 v2.14.2/go.mod h1:ON64QhlJkhVtSqp4v1uaK92VyZ2gmvDQsweuyLV+8+w= +github.com/googleapis/gax-go/v2 v2.15.0 h1:SyjDc1mGgZU5LncH8gimWo9lW1DtIfPibOG81vgd/bo= +github.com/googleapis/gax-go/v2 v2.15.0/go.mod h1:zVVkkxAQHa1RQpg9z2AUCMnKhi0Qld9rcmyfL1OZhoc= github.com/grafana/dskit v0.0.0-20250908063411-6b6da59b5cc4 h1:jSojuc7njleS3UOz223WDlXOinmuLAIPI0z2vtq8EgI= github.com/grafana/dskit v0.0.0-20250908063411-6b6da59b5cc4/go.mod h1:VahT+GtfQIM+o8ht2StR6J9g+Ef+C2Vokh5uuSmOD/4= github.com/grafana/grafana-plugin-sdk-go v0.281.0 h1:V8dGyatzcOLQeivFhBV2JWMwTSZH/clDnpfKG9p3dTA= @@ -374,8 +374,8 @@ golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da h1:noIWHXmPHxILtqtCOPIhS golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= -google.golang.org/api v0.235.0 h1:C3MkpQSRxS1Jy6AkzTGKKrpSCOd2WOGrezZ+icKSkKo= -google.golang.org/api v0.235.0/go.mod h1:QpeJkemzkFKe5VCE/PMv7GsUfn9ZF+u+q1Q7w6ckxTg= +google.golang.org/api v0.242.0 h1:7Lnb1nfnpvbkCiZek6IXKdJ0MFuAZNAJKQfA1ws62xg= +google.golang.org/api v0.242.0/go.mod h1:cOVEm2TpdAGHL2z+UwyS+kmlGr3bVWQQ6sYEqkKje50= google.golang.org/genproto/googleapis/api v0.0.0-20250908214217-97024824d090 h1:d8Nakh1G+ur7+P3GcMjpRDEkoLUcLW2iU92XVqR+XMQ= google.golang.org/genproto/googleapis/api v0.0.0-20250908214217-97024824d090/go.mod h1:U8EXRNSd8sUYyDfs/It7KVWodQr+Hf9xtxyxWudSwEw= google.golang.org/genproto/googleapis/rpc v0.0.0-20251002232023-7c0ddcbb5797 h1:CirRxTOwnRWVLKzDNrs0CXAaVozJoR4G9xvdRecrdpk= diff --git a/pkg/storage/unified/search/bleve_test.go b/pkg/storage/unified/search/bleve_test.go index 7d81fbe19ee..9bc867ba0d3 100644 --- a/pkg/storage/unified/search/bleve_test.go +++ b/pkg/storage/unified/search/bleve_test.go @@ -40,7 +40,6 @@ import ( func TestMain(m *testing.M) { goleak.VerifyTestMain(m, goleak.IgnoreTopFunction("github.com/open-feature/go-sdk/openfeature.(*eventExecutor).startEventListener.func1.1"), - goleak.IgnoreTopFunction("go.opencensus.io/stats/view.(*worker).start"), goleak.IgnoreTopFunction("github.com/blevesearch/bleve_index_api.AnalysisWorker"), // These don't stop when index is closed. ) } diff --git a/pkg/util/testutil/context_test.go b/pkg/util/testutil/context_test.go index b841deaa7e6..4d7ecf670f6 100644 --- a/pkg/util/testutil/context_test.go +++ b/pkg/util/testutil/context_test.go @@ -7,14 +7,12 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" - "go.opencensus.io/stats/view" "go.uber.org/goleak" "github.com/grafana/grafana/pkg/util/testutil/mocks" ) func TestMain(m *testing.M) { - view.Stop() // make sure we don't leak goroutines after tests in this package have // finished, which means we haven't leaked contexts either goleak.VerifyTestMain(m) From 92fb6872f037e11f8fb52c00b7a20aeddfc4d52f Mon Sep 17 00:00:00 2001 From: Ashley Harrison Date: Tue, 28 Oct 2025 09:22:09 +0000 Subject: [PATCH 040/378] FileDropzone: expose `id` to underlying input, fix story a11y violations (#113042) * expose inputId to underlying input, add field to story * just use id instead of inputId --- eslint-suppressions.json | 5 ----- .../FileDropzone/FileDropzone.story.tsx | 14 +++++++++++--- .../components/FileDropzone/FileDropzone.tsx | 17 +++++++++++++++-- 3 files changed, 26 insertions(+), 10 deletions(-) diff --git a/eslint-suppressions.json b/eslint-suppressions.json index 09e46121320..708c8f9fbcc 100644 --- a/eslint-suppressions.json +++ b/eslint-suppressions.json @@ -671,11 +671,6 @@ "count": 1 } }, - "packages/grafana-ui/src/components/FileDropzone/FileDropzone.story.tsx": { - "no-restricted-syntax": { - "count": 1 - } - }, "packages/grafana-ui/src/components/FormField/FormField.tsx": { "no-restricted-syntax": { "count": 1 diff --git a/packages/grafana-ui/src/components/FileDropzone/FileDropzone.story.tsx b/packages/grafana-ui/src/components/FileDropzone/FileDropzone.story.tsx index 9ac5e775590..133022394f3 100644 --- a/packages/grafana-ui/src/components/FileDropzone/FileDropzone.story.tsx +++ b/packages/grafana-ui/src/components/FileDropzone/FileDropzone.story.tsx @@ -1,4 +1,7 @@ import { Meta, StoryFn } from '@storybook/react'; +import { useId } from 'react'; + +import { Field } from '../Forms/Field'; import { FileDropzone } from './FileDropzone'; import mdx from './FileDropzone.mdx'; @@ -10,12 +13,17 @@ const meta: Meta = { docs: { page: mdx, }, - // TODO fix a11y issue in story and remove this - a11y: { test: 'off' }, }, }; -const Template: StoryFn = (args) => ; +const Template: StoryFn = (args) => { + const inputId = useId(); + return ( + + + + ); +}; export const Basic = Template.bind({}); diff --git a/packages/grafana-ui/src/components/FileDropzone/FileDropzone.tsx b/packages/grafana-ui/src/components/FileDropzone/FileDropzone.tsx index 1d27de173a1..120c7e08a09 100644 --- a/packages/grafana-ui/src/components/FileDropzone/FileDropzone.tsx +++ b/packages/grafana-ui/src/components/FileDropzone/FileDropzone.tsx @@ -47,6 +47,11 @@ export interface FileDropzoneProps { */ fileListRenderer?: (file: DropzoneFile, removeFile: (file: DropzoneFile) => void) => ReactNode; onFileRemove?: (file: DropzoneFile) => void; + /** + * Optional id attribute for the underlying input element + * Use to link a label to the input for accessibility + */ + id?: string; } export interface DropzoneFile { @@ -58,7 +63,15 @@ export interface DropzoneFile { retryUpload?: () => void; } -export function FileDropzone({ options, children, readAs, onLoad, fileListRenderer, onFileRemove }: FileDropzoneProps) { +export function FileDropzone({ + options, + children, + readAs, + onLoad, + fileListRenderer, + onFileRemove, + id, +}: FileDropzoneProps) { const [files, setFiles] = useState([]); const [fileErrors, setErrorMessages] = useState([]); @@ -218,7 +231,7 @@ export function FileDropzone({ options, children, readAs, onLoad, fileListRender return (
- + {children ?? }
{fileErrors.length > 0 && renderErrorMessages(fileErrors)} From a0180f803157136f9ff7dbf6d71cb84bd8ca0990 Mon Sep 17 00:00:00 2001 From: "grafana-pr-automation[bot]" <140550294+grafana-pr-automation[bot]@users.noreply.github.com> Date: Tue, 28 Oct 2025 09:37:03 +0000 Subject: [PATCH 041/378] I18n: Download translations from Crowdin (#113068) New Crowdin translations by GitHub Action Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- .../src/locales/cs-CZ/grafana-prometheus.json | 12 +- .../src/locales/de-DE/grafana-prometheus.json | 12 +- .../src/locales/es-ES/grafana-prometheus.json | 12 +- .../src/locales/fr-FR/grafana-prometheus.json | 12 +- .../src/locales/hu-HU/grafana-prometheus.json | 12 +- .../src/locales/id-ID/grafana-prometheus.json | 12 +- .../src/locales/it-IT/grafana-prometheus.json | 12 +- .../src/locales/ja-JP/grafana-prometheus.json | 12 +- .../src/locales/ko-KR/grafana-prometheus.json | 12 +- .../src/locales/nl-NL/grafana-prometheus.json | 12 +- .../src/locales/pl-PL/grafana-prometheus.json | 12 +- .../src/locales/pt-BR/grafana-prometheus.json | 12 +- .../src/locales/pt-PT/grafana-prometheus.json | 12 +- .../src/locales/ru-RU/grafana-prometheus.json | 12 +- .../src/locales/sv-SE/grafana-prometheus.json | 12 +- .../src/locales/tr-TR/grafana-prometheus.json | 12 +- .../locales/zh-Hans/grafana-prometheus.json | 12 +- .../locales/zh-Hant/grafana-prometheus.json | 12 +- .../src/locales/cs-CZ/grafana-sql.json | 10 +- .../src/locales/de-DE/grafana-sql.json | 10 +- .../src/locales/es-ES/grafana-sql.json | 10 +- .../src/locales/fr-FR/grafana-sql.json | 10 +- .../src/locales/hu-HU/grafana-sql.json | 10 +- .../src/locales/id-ID/grafana-sql.json | 10 +- .../src/locales/it-IT/grafana-sql.json | 10 +- .../src/locales/ja-JP/grafana-sql.json | 10 +- .../src/locales/ko-KR/grafana-sql.json | 10 +- .../src/locales/nl-NL/grafana-sql.json | 10 +- .../src/locales/pl-PL/grafana-sql.json | 10 +- .../src/locales/pt-BR/grafana-sql.json | 10 +- .../src/locales/pt-PT/grafana-sql.json | 10 +- .../src/locales/ru-RU/grafana-sql.json | 10 +- .../src/locales/sv-SE/grafana-sql.json | 10 +- .../src/locales/tr-TR/grafana-sql.json | 10 +- .../src/locales/zh-Hans/grafana-sql.json | 10 +- .../src/locales/zh-Hant/grafana-sql.json | 10 +- .../grafana-azure-monitor-datasource.json | 6 +- .../grafana-azure-monitor-datasource.json | 6 +- .../grafana-azure-monitor-datasource.json | 6 +- .../grafana-azure-monitor-datasource.json | 6 +- .../grafana-azure-monitor-datasource.json | 6 +- .../grafana-azure-monitor-datasource.json | 6 +- .../grafana-azure-monitor-datasource.json | 6 +- .../grafana-azure-monitor-datasource.json | 6 +- .../grafana-azure-monitor-datasource.json | 6 +- .../grafana-azure-monitor-datasource.json | 6 +- .../grafana-azure-monitor-datasource.json | 6 +- .../grafana-azure-monitor-datasource.json | 6 +- .../grafana-azure-monitor-datasource.json | 6 +- .../grafana-azure-monitor-datasource.json | 6 +- .../grafana-azure-monitor-datasource.json | 6 +- .../grafana-azure-monitor-datasource.json | 6 +- .../grafana-azure-monitor-datasource.json | 6 +- .../grafana-azure-monitor-datasource.json | 6 +- .../datasource/mssql/locales/cs-CZ/mssql.json | 26 +-- .../datasource/mssql/locales/de-DE/mssql.json | 26 +-- .../datasource/mssql/locales/es-ES/mssql.json | 26 +-- .../datasource/mssql/locales/fr-FR/mssql.json | 26 +-- .../datasource/mssql/locales/hu-HU/mssql.json | 26 +-- .../datasource/mssql/locales/id-ID/mssql.json | 26 +-- .../datasource/mssql/locales/it-IT/mssql.json | 26 +-- .../datasource/mssql/locales/ja-JP/mssql.json | 26 +-- .../datasource/mssql/locales/ko-KR/mssql.json | 26 +-- .../datasource/mssql/locales/nl-NL/mssql.json | 26 +-- .../datasource/mssql/locales/pl-PL/mssql.json | 26 +-- .../datasource/mssql/locales/pt-BR/mssql.json | 26 +-- .../datasource/mssql/locales/pt-PT/mssql.json | 26 +-- .../datasource/mssql/locales/ru-RU/mssql.json | 26 +-- .../datasource/mssql/locales/sv-SE/mssql.json | 26 +-- .../datasource/mssql/locales/tr-TR/mssql.json | 26 +-- .../mssql/locales/zh-Hans/mssql.json | 26 +-- .../mssql/locales/zh-Hant/mssql.json | 26 +-- public/locales/cs-CZ/grafana.json | 200 ++++++++++-------- public/locales/de-DE/grafana.json | 196 +++++++++-------- public/locales/es-ES/grafana.json | 196 +++++++++-------- public/locales/fr-FR/grafana.json | 196 +++++++++-------- public/locales/hu-HU/grafana.json | 196 +++++++++-------- public/locales/id-ID/grafana.json | 194 +++++++++-------- public/locales/it-IT/grafana.json | 196 +++++++++-------- public/locales/ja-JP/grafana.json | 194 +++++++++-------- public/locales/ko-KR/grafana.json | 194 +++++++++-------- public/locales/nl-NL/grafana.json | 196 +++++++++-------- public/locales/pl-PL/grafana.json | 200 ++++++++++-------- public/locales/pt-BR/grafana.json | 196 +++++++++-------- public/locales/pt-PT/grafana.json | 196 +++++++++-------- public/locales/ru-RU/grafana.json | 200 ++++++++++-------- public/locales/sv-SE/grafana.json | 196 +++++++++-------- public/locales/tr-TR/grafana.json | 194 +++++++++-------- public/locales/zh-Hans/grafana.json | 192 +++++++++-------- public/locales/zh-Hant/grafana.json | 194 +++++++++-------- 90 files changed, 2376 insertions(+), 2122 deletions(-) diff --git a/packages/grafana-prometheus/src/locales/cs-CZ/grafana-prometheus.json b/packages/grafana-prometheus/src/locales/cs-CZ/grafana-prometheus.json index 7afae00fd13..2379436aa18 100644 --- a/packages/grafana-prometheus/src/locales/cs-CZ/grafana-prometheus.json +++ b/packages/grafana-prometheus/src/locales/cs-CZ/grafana-prometheus.json @@ -85,9 +85,9 @@ "tooltip-classic-query": "Původní implementace editoru proměnných dotazů Prometheus. Zadejte řetězec se správným typem dotazu a parametry, jak je popsáno v těchto dokumentech. Například {{exampleQuery}}.", "tooltip-label": "Vrátí seznam hodnot štítků pro název štítku ve všech metrikách, pokud není metrika zadána.", "tooltip-metric-regex": "Vrátí seznam názvů štítků, volitelně filtrování podle zadaného metrického regulárního výrazu.", - "tooltip-query": "Vrátí seznam výsledků dotazu Prometheus pro daný dotaz. To může zahrnovat funkce Prometheus, tj. {{exampleQuery}}.", + "tooltip-query": "", "tooltip-query-type": "Zásuvný modul zdroje dat Prometheus poskytuje následující typy dotazů pro proměnné šablony.", - "tooltip-series-query": "Zadejte metriku se štítky, pouze metriku nebo pouze štítky, tj. {{example1}}, {{example2}} nebo {{example3}}. Vrátí seznam časových řad spojených se zadanými daty." + "tooltip-series-query": "" }, "selector-actions": { "aria-label-selector": "volič", @@ -175,16 +175,16 @@ "label-scrape-interval": "Interval scrapingu", "label-series-limit": "Limit řady", "label-use-series-endpoint": "Použít koncový bod řady", - "more-info": "Další informace o konfiguraci typu a verze Prometheus ve zdrojích dat najdete v <2>dokumentaci k zajišťování.", + "more-info": "", "placeholder-example-maxsourceresolutionmtimeout": "Příklad: {{example}}", "title-interval-behaviour": "Chování intervalu", "title-other": "Ostatní", "title-performance": "Výkon", "title-query-editor": "Editor dotazů", "tooltip-cache-level": "Nastaví úroveň ukládání do vyrovnávací paměti prohlížeče pro dotazy editoru. Pro zdroje dat s vysokou kardinalitou se doporučuje nastavit vyšší úroveň vyrovnávací paměti.", - "tooltip-custom-query-parameters": "Přidejte vlastní parametry do adresy URL dotazu Prometheus. Například {{example1}}, {{example2}}, {{example3}} nebo {{example4}}. Více parametrů by mělo být pospojováno pomocí {{concatenationChar}}.", + "tooltip-custom-query-parameters": "", "tooltip-default-editor": "Nastavit výchozí možnost editoru pro všechny uživatele tohoto zdroje dat.", - "tooltip-disable-metrics-lookup": "Zaškrtnutím této možnosti zakážete výběr metrik a podporu metrik/štítků v automatickém doplňování pole dotazu. Užitečné, pokud máte problémy s výkonem u větších instancí Prometheus. ", + "tooltip-disable-metrics-lookup": "", "tooltip-disable-recording-rules-beta": "Tato funkce zakáže pravidla nahrávání. Zapněte tuto možnost pro zlepšení výkonu nástěnky", "tooltip-http-method": "K dotazu na zdroj dat Prometheus můžete použít metodu POST nebo GET HTTP. Doporučenou metodou je POST, protože umožňuje větší dotazy. Změňte na GET, pokud máte verzi Prometheus starší než 2.1 nebo pokud jsou požadavky POST ve vaší síti omezeny.", "tooltip-incremental-querying-beta": "Tato funkce změní výchozí chování relativních dotazů tak, aby vždy požadovaly aktuální data z instance Prometheus. Místo toho budou výsledky dotazů uloženy do vyrovnávací paměti a budou požadovány pouze nové záznamy. Povolte tuto možnost pro snížení zatížení databáze a sítě.", @@ -479,7 +479,7 @@ "aria-label-selector": "volič" }, "results-table": { - "content-descriptive-type": "Při vytváření {{descriptiveType}} Prometheus zobrazí více řad s počítadlem typů. ", + "content-descriptive-type": "", "description": "Popis", "message-expand-label-filters": "Nebyly nalezeny žádné metriky. Zkuste rozšířit filtry štítků.", "message-expand-search": "Nebyly nalezeny žádné metriky. Zkuste rozšířit vyhledávání a filtry.", diff --git a/packages/grafana-prometheus/src/locales/de-DE/grafana-prometheus.json b/packages/grafana-prometheus/src/locales/de-DE/grafana-prometheus.json index 5b95ca6bdf4..3b63c9cfc00 100644 --- a/packages/grafana-prometheus/src/locales/de-DE/grafana-prometheus.json +++ b/packages/grafana-prometheus/src/locales/de-DE/grafana-prometheus.json @@ -85,9 +85,9 @@ "tooltip-classic-query": "Die ursprüngliche Implementierung des Prometheus-Variablen-Abfrageeditors. Geben Sie eine Zeichenfolge mit dem richtigen Abfragetyp und den richtigen Parametern ein, wie in diesen Dokumenten beschrieben. Zum Beispiel: {{exampleQuery}}.", "tooltip-label": "Gibt eine Liste von Label-Werten für den Label-Namen in allen Metriken zurück, es sei denn, die Metrik ist angegeben.", "tooltip-metric-regex": "Gibt eine Liste von Label-Namen zurück, die optional gemäß dem angegebenen Metrik-Regex gefiltert werden.", - "tooltip-query": "Gibt eine Liste der Prometheus-Abfrageergebnisse für die Abfrage zurück. Dies kann Prometheus-Funktionen umfassen, z. B. {{exampleQuery}}.", + "tooltip-query": "", "tooltip-query-type": "Das Prometheus-Datenquellen-Plugin bietet die folgenden Abfragetypen für Vorlagenvariablen.", - "tooltip-series-query": "Geben Sie eine Metrik mit Labels ein, nur eine Metrik oder nur Labels, z. B. {{example1}}, {{example2}} oder {{example3}}. Gibt eine Liste der Zeitreihen zurück, die den eingegebenen Daten zugeordnet sind." + "tooltip-series-query": "" }, "selector-actions": { "aria-label-selector": "Selektor", @@ -175,16 +175,16 @@ "label-scrape-interval": "Scrape-Intervall", "label-series-limit": "Reihengrenze", "label-use-series-endpoint": "Reihenendpunkt verwenden", - "more-info": "Weitere Informationen zur Konfiguration des Typs und der Version von Prometheus in Datenquellen finden Sie in der <2>Bereitstellungsdokumentation.", + "more-info": "", "placeholder-example-maxsourceresolutionmtimeout": "Beispiel: {{example}}", "title-interval-behaviour": "Intervallverhalten", "title-other": "Sonstiges", "title-performance": "Leistung", "title-query-editor": "Abfrage-Editor", "tooltip-cache-level": "Legt die Browser-Cache-Level für Editor-Abfragen fest. Für Datenquellen mit hoher Kardinalität werden höhere Cache-Einstellungen empfohlen.", - "tooltip-custom-query-parameters": "Fügen Sie der URL der Prometheus-Abfrage benutzerdefinierte Parameter hinzu. Zum Beispiel {{example1}}, {{example2}}, {{example3}} oder {{example4}}. Mehrere Parameter sollten mit {{concatenationChar}} verknüpft werden.", + "tooltip-custom-query-parameters": "", "tooltip-default-editor": "Legen Sie die Standard-Editoroption für alle Nutzer dieser Datenquelle fest.", - "tooltip-disable-metrics-lookup": "Wenn diese Option aktiviert ist, werden die Metrikauswahl und die Unterstützung für Metriken/Labels im Rahmen der Autovervollständigung des Abfragefelds deaktiviert. Dies hilft, wenn Sie Leistungsprobleme mit größeren Prometheus-Instanzen haben. ", + "tooltip-disable-metrics-lookup": "", "tooltip-disable-recording-rules-beta": "Diese Funktion deaktiviert die Aufnahmeregeln. Wenn Sie dies aktivieren, wird die Dashboard-Leistung verbessert", "tooltip-http-method": "Sie können entweder die HTTP-Methode POST oder GET für die Abfrage Ihrer Prometheus-Datenquelle verwenden. POST ist die empfohlene Methode, da sie größere Abfragen ermöglicht. Ändern Sie dies zu GET, wenn Ihre Prometheus-Version älter als 2.1 ist oder POST-Abfragen in Ihrem Netzwerk beschränkt sind.", "tooltip-incremental-querying-beta": "Diese Funktion ändert das Standardverhalten von relativen Abfragen, sodass immer neue Daten von der Prometheus-Instanz abgefragt werden. Stattdessen werden Abfrageergebnisse zwischengespeichert und nur neue Datensätze abgefragt. Wenn Sie dies aktivieren, wird die Datenbank- und Netzwerklast reduziert.", @@ -479,7 +479,7 @@ "aria-label-selector": "Selektor" }, "results-table": { - "content-descriptive-type": "Bei der Erstellung von {{descriptiveType}} zeigt Prometheus mehrere Reihen mit dem Typ Counter. ", + "content-descriptive-type": "", "description": "Beschreibung", "message-expand-label-filters": "Es wurden keine Metriken gefunden. Versuchen Sie, Ihre Label-Filter zu erweitern.", "message-expand-search": "Es wurden keine Metriken gefunden. Versuchen Sie, Ihre Suche und Ihre Filter zu erweitern.", diff --git a/packages/grafana-prometheus/src/locales/es-ES/grafana-prometheus.json b/packages/grafana-prometheus/src/locales/es-ES/grafana-prometheus.json index 8b0b9d4c5d1..80739214809 100644 --- a/packages/grafana-prometheus/src/locales/es-ES/grafana-prometheus.json +++ b/packages/grafana-prometheus/src/locales/es-ES/grafana-prometheus.json @@ -85,9 +85,9 @@ "tooltip-classic-query": "La implementación original del editor de consultas de variables de Prometheus. Introduzca una cadena con el tipo de consulta y los parámetros correctos como se describe en estos documentos. Por ejemplo, {{exampleQuery}}.", "tooltip-label": "Devuelve una lista de valores de etiqueta para el nombre de etiqueta en todas las métricas, a menos que se especifique la métrica.", "tooltip-metric-regex": "Devuelve una lista de nombres de etiquetas, filtrando opcionalmente por la expresión regular de métrica especificada.", - "tooltip-query": "Devuelve una lista de resultados de la consulta de Prometheus para la consulta. Esto puede incluir funciones de Prometheus, es decir, {{exampleQuery}}.", + "tooltip-query": "", "tooltip-query-type": "El plugin de fuente de datos de Prometheus proporciona los siguientes tipos de consulta para las variables de plantilla.", - "tooltip-series-query": "Introduzca una métrica con etiquetas, solo una métrica o solo etiquetas, es decir, {{example1}}, {{example2}} o {{example3}}. Devuelve una lista de series temporales asociadas con los datos introducidos." + "tooltip-series-query": "" }, "selector-actions": { "aria-label-selector": "selector", @@ -175,16 +175,16 @@ "label-scrape-interval": "Intervalo de recuperación de datos", "label-series-limit": "Límite de series", "label-use-series-endpoint": "Utilizar punto de conexión de la serie", - "more-info": "Para obtener más información sobre cómo configurar el tipo y la versión de Prometheus en las fuentes de datos, consulte la <2>documentación de aprovisionamiento.", + "more-info": "", "placeholder-example-maxsourceresolutionmtimeout": "Ejemplo: {{example}}", "title-interval-behaviour": "Comportamiento del intervalo", "title-other": "Otro", "title-performance": "Rendimiento", "title-query-editor": "Editor de consultas", "tooltip-cache-level": "Establece el nivel de caché del navegador para las consultas del editor. Se recomienda una configuración de caché más alta para fuentes de datos de alta cardinalidad.", - "tooltip-custom-query-parameters": "Añada parámetros personalizados a la URL de la consulta de Prometheus. Por ejemplo, {{example1}}, {{example2}}, {{example3}} o{{example4}}. Deben concatenarse varios parámetros junto con {{concatenationChar}}.", + "tooltip-custom-query-parameters": "", "tooltip-default-editor": "Establece la opción de editor predeterminada para todos los usuarios de esta fuente de datos.", - "tooltip-disable-metrics-lookup": "Al marcar esta opción, se desactivará el selector de métricas y la compatibilidad con métricas/etiquetas en el autocompletado del campo de consulta. Esto es útil si tienes problemas de rendimiento con instancias de Prometheus de mayor tamaño. ", + "tooltip-disable-metrics-lookup": "", "tooltip-disable-recording-rules-beta": "Esta función deshabilitará las reglas de registro. Actívelo para mejorar el rendimiento del dashboard", "tooltip-http-method": "Puede utilizar el método HTTP POST o GET para consultar su fuente de datos de Prometheus. POST es el método recomendado, ya que permite consultas de mayor tamaño. Cámbielo a GET si tiene una versión de Prometheus anterior a la 2.1 o si las solicitudes POST están restringidas en su red.", "tooltip-incremental-querying-beta": "Esta función cambiará el comportamiento predeterminado de las consultas relativas para solicitar siempre datos nuevos de la instancia de Prometheus, en lugar de almacenar en caché los resultados de las consultas y solo se solicitarán nuevos registros. Actívelo para disminuir la carga de la base de datos y de la red.", @@ -479,7 +479,7 @@ "aria-label-selector": "selector" }, "results-table": { - "content-descriptive-type": "Al crear un {{descriptiveType}}, Prometheus expone varias series con el contador de tipos. ", + "content-descriptive-type": "", "description": "Descripción", "message-expand-label-filters": "No se han encontrado métricas. Intenta ampliar los filtros de etiquetas.", "message-expand-search": "No se han encontrado métricas. Intenta ampliar la búsqueda y los filtros.", diff --git a/packages/grafana-prometheus/src/locales/fr-FR/grafana-prometheus.json b/packages/grafana-prometheus/src/locales/fr-FR/grafana-prometheus.json index 2ad85dcac95..86169b30725 100644 --- a/packages/grafana-prometheus/src/locales/fr-FR/grafana-prometheus.json +++ b/packages/grafana-prometheus/src/locales/fr-FR/grafana-prometheus.json @@ -85,9 +85,9 @@ "tooltip-classic-query": "L’implémentation d’origine de l’éditeur de requêtes à variables Prometheus. Saisissez une chaîne de caractères avec le type de requête et les paramètres appropriés comme décrit dans la documentation. Par exemple, {{exampleQuery}}.", "tooltip-label": "Renvoie une liste de valeurs d’étiquette pour le nom d’étiquette dans toutes les métriques, sauf si la métrique est spécifiée.", "tooltip-metric-regex": "Renvoie une liste de noms d’étiquettes, en filtrant éventuellement par expression régulière de métrique spécifiée.", - "tooltip-query": "Renvoie une liste de résultats de requête Prometheus pour la requête. Cela peut inclure des fonctions Prometheus, par exemple {{exampleQuery}}.", + "tooltip-query": "", "tooltip-query-type": "Le plugin de source de données Prometheus fournit les types de requêtes suivants pour les variables de modèle.", - "tooltip-series-query": "Saisissez une métrique avec des étiquettes, uniquement une métrique ou uniquement des étiquettes, c’est-à-dire {{example1}}, {{example2}} ou {{example3}}. Renvoie une liste de séries chronologiques associées aux données saisies." + "tooltip-series-query": "" }, "selector-actions": { "aria-label-selector": "sélecteur", @@ -175,16 +175,16 @@ "label-scrape-interval": "Intervalle de scraping", "label-series-limit": "Limite de séries", "label-use-series-endpoint": "Utiliser le point de terminaison de la série", - "more-info": "Pour en savoir plus sur la configuration du type et de la version de Prometheus dans les sources de données, consultez la <2>documentation sur le provisionnement.", + "more-info": "", "placeholder-example-maxsourceresolutionmtimeout": "Exemple : {{example}}", "title-interval-behaviour": "Comportement de l’intervalle", "title-other": "Autre", "title-performance": "Performance", "title-query-editor": "Éditeur de requêtes", "tooltip-cache-level": "Définit le niveau de mise en cache du navigateur pour les requêtes de l’éditeur. Des paramètres de cache plus élevés sont recommandés pour les sources de données à cardinalité élevée.", - "tooltip-custom-query-parameters": "Ajoutez des paramètres personnalisés à l’URL de la requête Prometheus. Par exemple {{example1}}, {{example2}}, {{example3}}, ou {{example4}}. Plusieurs paramètres doivent être concaténés avec {{concatenationChar}}.", + "tooltip-custom-query-parameters": "", "tooltip-default-editor": "Définir l’option d’éditeur par défaut pour tous les utilisateurs de cette source de données.", - "tooltip-disable-metrics-lookup": "Cocher cette option désactivera le sélecteur de métriques et la prise en charge des métriques/étiquettes dans la saisie semi-automatique du champ de requête. Cela vous aide si vous avez des problèmes de performances avec des instances Prometheus plus grandes. ", + "tooltip-disable-metrics-lookup": "", "tooltip-disable-recording-rules-beta": "Cette fonctionnalité désactivera les règles d’enregistrement. Activez cette option pour améliorer les performances du tableau de bord", "tooltip-http-method": "Vous pouvez utiliser la méthode POST ou GET HTTP pour interroger votre source de données Prometheus. POST est la méthode recommandée car elle permet des requêtes plus volumineuses. Changez ceci en GET si vous avez une version Prometheus antérieure à la version 2.1 ou si les demandes POST sont restreintes dans votre réseau.", "tooltip-incremental-querying-beta": "Cette fonctionnalité modifiera le comportement par défaut des requêtes relatives pour toujours demander des données récentes à l’instance Prometheus. Au lieu de cela, les résultats des requêtes seront mis en cache et seuls les nouveaux enregistrements seront demandés. Activez cette option pour réduire la charge de la base de données et du réseau.", @@ -479,7 +479,7 @@ "aria-label-selector": "sélecteur" }, "results-table": { - "content-descriptive-type": "Lors de la création d’un(e) {{descriptiveType}}, Prometheus expose plusieurs séries avec le compteur de type. ", + "content-descriptive-type": "", "description": "Description", "message-expand-label-filters": "Aucune métrique trouvée. Essayez d’élargir vos filtres d’étiquettes.", "message-expand-search": "Aucune métrique trouvée. Essayez d’élargir votre recherche et vos filtres.", diff --git a/packages/grafana-prometheus/src/locales/hu-HU/grafana-prometheus.json b/packages/grafana-prometheus/src/locales/hu-HU/grafana-prometheus.json index 5a8d1906a38..bceeabefdc1 100644 --- a/packages/grafana-prometheus/src/locales/hu-HU/grafana-prometheus.json +++ b/packages/grafana-prometheus/src/locales/hu-HU/grafana-prometheus.json @@ -85,9 +85,9 @@ "tooltip-classic-query": "A Prometheus változólekérdezés-szerkesztő eredeti implementációja. Adjon meg egy karakterláncot a megfelelő lekérdezéstípussal és paraméterekkel, a jelen dokumentumokban leírtak szerint. Például: {{exampleQuery}}.", "tooltip-label": "A címke nevéhez tartozó címkeértékek listáját adja vissza az összes metrikában, kivéve, ha a metrika meg van adva.", "tooltip-metric-regex": "A címkenevek listáját adja vissza, opcionálisan a megadott metrikai reguláris kifejezés szerint szűrve.", - "tooltip-query": "A lekérdezéshez a Prometheus-lekérdezési eredmények listáját adja vissza. Ez magában foglalhatja a Prometheus-funkciókat, azaz {{exampleQuery}}.", + "tooltip-query": "", "tooltip-query-type": "A Prometheus adatforrás-beépülőmodul a következő lekérdezéstípusokat biztosítja a sablonváltozókhoz.", - "tooltip-series-query": "Adjon meg egy metrikát címkékkel, csak egy metrikát vagy csak címkéket: {{example1}}, {{example2}} vagy {{example3}}. A bevitt adatokhoz társított idősorok listáját adja vissza." + "tooltip-series-query": "" }, "selector-actions": { "aria-label-selector": "választó", @@ -175,16 +175,16 @@ "label-scrape-interval": "Adatgyűjtési intervallum", "label-series-limit": "Sorozatkorlát", "label-use-series-endpoint": "Sorozat végpontjának használata", - "more-info": "A Prometheus-típus és -verzió adatforrásokban történő konfigurálásával kapcsolatos további információkért tekintse meg a <2>kiépítési dokumentációt.", + "more-info": "", "placeholder-example-maxsourceresolutionmtimeout": "Példa: {{example}}", "title-interval-behaviour": "Intervallum viselkedése", "title-other": "Egyéb", "title-performance": "Teljesítmény", "title-query-editor": "Lekérdezésszerkesztő", "tooltip-cache-level": "Beállítja a böngésző gyorsítótárának szintjét a szerkesztői lekérdezésekhez. A magasabb számossági adatforrásokhoz magasabb gyorsítótár-beállítások ajánlottak.", - "tooltip-custom-query-parameters": "Egyéni paraméterek hozzáadása a Prometheus lekérdezési URL-jéhez. Például: {{example1}}, {{example2}}, {{example3}} vagy {{example4}}. Több paramétert a következővel kell összefűzni: {{concatenationChar}}.", + "tooltip-custom-query-parameters": "", "tooltip-default-editor": "Beállítja az alapértelmezett szerkesztőopciót az adatforrás minden felhasználója számára.", - "tooltip-disable-metrics-lookup": "Ennek az opciónak a bejelölése letiltja a metrikaválasztót és a metrika-/címketámogatást a lekérdezési mező automatikus kitöltésében. Ez segít, ha a nagyobb Prometheus-példányokkal teljesítményproblémái vannak. ", + "tooltip-disable-metrics-lookup": "", "tooltip-disable-recording-rules-beta": "Ez a funkció letiltja a felvételkészítési szabályokat. Kapcsolja be az irányítópult teljesítményének javítása érdekében", "tooltip-http-method": "A Prometheus-adatforrás lekérdezéséhez használhatja a POST- vagy a GET HTTP-metódust. A POST az ajánlott metódus, mivel nagyobb lekérdezéseket tesz lehetővé. Módosítsa ezt GET-re, ha a Prometheus-verziója régebbi, mint a 2.1-es, vagy ha a POST-kérések korlátozva vannak a hálózatában.", "tooltip-incremental-querying-beta": "Ez a funkció megváltoztatja a relatív lekérdezések azon alapértelmezett viselkedését, hogy mindig friss adatokat kérjenek le a Prometheus-példányból, ehelyett a lekérdezési eredményeket a rendszer gyorsítótárazza, és csak új rekordok lesznek lekérve. Kapcsolja be az adatbázis és a hálózat terhelésének csökkentése érdekében.", @@ -479,7 +479,7 @@ "aria-label-selector": "választó" }, "results-table": { - "content-descriptive-type": "{{descriptiveType}} létrehozásakor a Prometheus több, számláló típusú sorozatot jelenít meg. ", + "content-descriptive-type": "", "description": "Leírás", "message-expand-label-filters": "Nem található metrika. Próbálja meg kibővíteni a címkeszűrőket.", "message-expand-search": "Nem található metrika. Próbálja meg kibővíteni a keresést és a szűrőket.", diff --git a/packages/grafana-prometheus/src/locales/id-ID/grafana-prometheus.json b/packages/grafana-prometheus/src/locales/id-ID/grafana-prometheus.json index cf37adca5c0..74b9ed50d74 100644 --- a/packages/grafana-prometheus/src/locales/id-ID/grafana-prometheus.json +++ b/packages/grafana-prometheus/src/locales/id-ID/grafana-prometheus.json @@ -85,9 +85,9 @@ "tooltip-classic-query": "Implementasi awal dari editor kueri variabel Prometheus. Masukkan string dengan jenis kueri dan parameter yang benar seperti yang dijelaskan dalam dokumen ini. Misalnya, {{exampleQuery}}.", "tooltip-label": "Mengembalikan daftar nilai label untuk nama label di semua metrik kecuali metrik tersebut ditentukan.", "tooltip-metric-regex": "Mengembalikan daftar nama label, secara opsional menyaring berdasarkan regex metrik yang ditentukan.", - "tooltip-query": "Mengembalikan daftar hasil kueri Prometheus untuk kueri tersebut. Ini dapat mencakup fungsi Prometheus, yaitu {{exampleQuery}}.", + "tooltip-query": "", "tooltip-query-type": "Plugin sumber data Prometheus menyediakan jenis kueri berikut untuk variabel templat.", - "tooltip-series-query": "Masukkan metrik dengan label, hanya metrik atau hanya label, yaitu {{example1}}, {{example2}}, atau {{example3}}. Mengembalikan daftar deret waktu yang terkait dengan data yang dimasukkan." + "tooltip-series-query": "" }, "selector-actions": { "aria-label-selector": "selektor", @@ -175,16 +175,16 @@ "label-scrape-interval": "Interval scrape", "label-series-limit": "Batas data seri", "label-use-series-endpoint": "Gunakan titik akhir data seri", - "more-info": "Untuk informasi lengkap tentang mengonfigurasi jenis dan versi prometheus dalam sumber data, lihat <2>dokumentasi penyediaan.", + "more-info": "", "placeholder-example-maxsourceresolutionmtimeout": "Contoh: {{example}}", "title-interval-behaviour": "Perilaku interval", "title-other": "Lainnya", "title-performance": "Kinerja", "title-query-editor": "Editor kueri", "tooltip-cache-level": "Mengatur level cache peramban untuk kueri editor. Pengaturan cache yang lebih tinggi disarankan untuk sumber data dengan kardinalitas tinggi.", - "tooltip-custom-query-parameters": "Tambahkan parameter kustom ke URL kueri Prometheus. Misalnya {{example1}}, {{example2}}, {{example3}}, atau {{example4}}. Beberapa parameter harus digabungkan bersama dengan {{concatenationChar}}.", + "tooltip-custom-query-parameters": "", "tooltip-default-editor": "Atur opsi editor default untuk semua pengguna sumber data ini.", - "tooltip-disable-metrics-lookup": "Memeriksa opsi ini akan menonaktifkan pemilih metrik dan dukungan metrik/label dalam pelengkapan otomatis bidang kueri. Ini membantu jika Anda memiliki masalah kinerja dengan instans Prometheus yang lebih besar. ", + "tooltip-disable-metrics-lookup": "", "tooltip-disable-recording-rules-beta": "Fitur ini akan menonaktifkan aturan perekaman. Aktifkan ini untuk meningkatkan kinerja dasbor", "tooltip-http-method": "Anda dapat menggunakan metode HTTP POST atau GET untuk melakukan kueri sumber data Prometheus Anda. POST adalah metode yang disarankan karena memungkinkan kueri yang lebih besar. Ubah ini menjadi GET jika Anda memiliki versi Prometheus yang lebih lama dari 2.1 atau jika permintaan POST dibatasi di jaringan Anda.", "tooltip-incremental-querying-beta": "Fitur ini akan mengubah perilaku default kueri relatif: alih-alih selalu meminta data terbaru dari instans Prometheus, hasil kueri akan disimpan sementara, dan hanya data baru yang akan diminta. Aktifkan ini untuk mengurangi beban basis data dan jaringan.", @@ -479,7 +479,7 @@ "aria-label-selector": "selektor" }, "results-table": { - "content-descriptive-type": "Saat membuat {{descriptiveType}}, Prometheus mengekspos beberapa data seri dengan penghitung jenis. ", + "content-descriptive-type": "", "description": "Deskripsi", "message-expand-label-filters": "Tidak ada metrik yang ditemukan. Coba perluas filter label Anda.", "message-expand-search": "Tidak ada metrik yang ditemukan. Coba perluas pencarian dan filter Anda.", diff --git a/packages/grafana-prometheus/src/locales/it-IT/grafana-prometheus.json b/packages/grafana-prometheus/src/locales/it-IT/grafana-prometheus.json index 314ac50298e..f3cf622ddd1 100644 --- a/packages/grafana-prometheus/src/locales/it-IT/grafana-prometheus.json +++ b/packages/grafana-prometheus/src/locales/it-IT/grafana-prometheus.json @@ -85,9 +85,9 @@ "tooltip-classic-query": "L'implementazione originale dell'editor di query variabile Prometheus. Inserisci una stringa con il tipo di query e i parametri corretti come descritto in questi documenti. Ad esempio, {{exampleQuery}}.", "tooltip-label": "Restituisce un elenco di valori di etichetta per il nome dell'etichetta in tutte le metriche, a meno che la metrica non sia specificata.", "tooltip-metric-regex": "Restituisce un elenco di nomi di etichette, filtrando facoltativamente in base all'espressione regolare metrica specificata.", - "tooltip-query": "Restituisce un elenco di risultati della query Prometheus per la query. Questo può includere funzioni Prometheus, ad esempio {{exampleQuery}}.", + "tooltip-query": "", "tooltip-query-type": "Il plugin dell'origine dati di Prometheus fornisce i seguenti tipi di query per le variabili del modello.", - "tooltip-series-query": "Inserisci una metrica con etichette, solo una metrica o solo etichette, ad esempio {{example1}}, {{example2}} o {{example3}}. Restituisce un elenco di serie temporali associate ai dati inseriti." + "tooltip-series-query": "" }, "selector-actions": { "aria-label-selector": "selettore", @@ -175,16 +175,16 @@ "label-scrape-interval": "Intervallo di raccolta", "label-series-limit": "Limite della serie", "label-use-series-endpoint": "Usa endpoint della serie", - "more-info": "Per ulteriori informazioni sulla configurazione del tipo e della versione di Prometheus nelle origini dati, consulta la <2>documentazione sul provisioning.", + "more-info": "", "placeholder-example-maxsourceresolutionmtimeout": "Esempio: {{example}}", "title-interval-behaviour": "Comportamento intervallo", "title-other": "Altro", "title-performance": "Performance", "title-query-editor": "Editor query", "tooltip-cache-level": "Imposta il livello di memorizzazione nella cache del browser per le query dell'editor. Si consigliano impostazioni della cache più elevate per origini dati ad alta cardinalità.", - "tooltip-custom-query-parameters": "Aggiungi parametri personalizzati all'URL della query Prometheus. Ad esempio {{example1}}, {{example2}}, {{example3}} o {{example4}}. Più parametri devono essere concatenati insieme a {{concatenationChar}}.", + "tooltip-custom-query-parameters": "", "tooltip-default-editor": "Imposta l'opzione editor predefinita per tutti gli utenti di questa origine dati.", - "tooltip-disable-metrics-lookup": "Selezionando questa opzione, il selettore di metriche e il supporto di metriche/etichette nel completamento automatico del campo di query verranno disabilitati. Questo è utile se hai problemi di prestazioni con istanze Prometheus più grandi. ", + "tooltip-disable-metrics-lookup": "", "tooltip-disable-recording-rules-beta": "Questa funzionalità disabiliterà le regole di registrazione. Attiva questa opzione per migliorare le prestazioni della dashboard", "tooltip-http-method": "Puoi utilizzare il metodo POST o GET HTTP per eseguire query sull'origine dati di Prometheus. POST è il metodo consigliato in quanto consente query più grandi. Usa GET se hai una versione di Prometheus precedente alla 2.1 o se le richieste POST sono limitate nella tua rete.", "tooltip-incremental-querying-beta": "Questa funzionalità modificherà il comportamento predefinito delle query relative per richiedere sempre dati aggiornati dall'istanza di Prometheus, mentre i risultati delle query verranno memorizzati nella cache e verranno richiesti solo i nuovi record. Attiva questa opzione per ridurre il carico del database e della rete.", @@ -479,7 +479,7 @@ "aria-label-selector": "selettore" }, "results-table": { - "content-descriptive-type": "Quando si crea un {{descriptiveType}}, Prometheus mostra più serie con il contatore di tipo. ", + "content-descriptive-type": "", "description": "Descrizione", "message-expand-label-filters": "Non sono state trovate metriche. Prova ad espandere i filtri delle etichette.", "message-expand-search": "Non sono state trovate metriche. Prova ad espandere la ricerca e i filtri.", diff --git a/packages/grafana-prometheus/src/locales/ja-JP/grafana-prometheus.json b/packages/grafana-prometheus/src/locales/ja-JP/grafana-prometheus.json index 9efa150bca3..8f6fcef6ab6 100644 --- a/packages/grafana-prometheus/src/locales/ja-JP/grafana-prometheus.json +++ b/packages/grafana-prometheus/src/locales/ja-JP/grafana-prometheus.json @@ -85,9 +85,9 @@ "tooltip-classic-query": "Prometheus変数クエリエディターの元の実装。これらのドキュメントに記載されているように、正しいクエリタイプとパラメーターを含む文字列を入力してください。例: {{exampleQuery}}。", "tooltip-label": "メトリックが指定されていない限り、すべてのメトリックのラベル名に対するラベル値のリストを返します。", "tooltip-metric-regex": "ラベル名のリストを返します。オプションで、指定されたメトリック正規表現でフィルタリングすることも可能です。", - "tooltip-query": "クエリのPrometheusクエリ結果のリストを返します。これには、Prometheus関数を含めることもできます。例: {{exampleQuery}}。", + "tooltip-query": "", "tooltip-query-type": "Prometheusデータソースプラグインは、テンプレート変数に以下のクエリタイプを入力します。", - "tooltip-series-query": "ラベル付きメトリック、メトリックのみ、またはラベルのみを入力します。例: {{example1}}、{{example2}}、または{{example3}}。入力されたデータに関連する時系列のリストを返します。" + "tooltip-series-query": "" }, "selector-actions": { "aria-label-selector": "セレクター", @@ -175,16 +175,16 @@ "label-scrape-interval": "スクレイプ間隔", "label-series-limit": "系列制限", "label-use-series-endpoint": "系列エンドポイントを使用", - "more-info": "データソースでのPrometheusタイプとバージョンの設定の詳細については、<2>プロビジョニングドキュメントをご覧ください。", + "more-info": "", "placeholder-example-maxsourceresolutionmtimeout": "例: {{example}}", "title-interval-behaviour": "間隔の動作", "title-other": "その他", "title-performance": "パフォーマンス", "title-query-editor": "クエリエディター", "tooltip-cache-level": "エディタークエリのブラウザーキャッシュレベルを設定します。高カーディナリティデータソースには、より高いキャッシュ設定を推奨します。", - "tooltip-custom-query-parameters": "PrometheusクエリURLにカスタムパラメーターを追加します。例: {{example1}}、{{example2}}、{{example3}}、または{{example4}}。複数のパラメーターは{{concatenationChar}}で連結する必要があります。", + "tooltip-custom-query-parameters": "", "tooltip-default-editor": "このデータソースのすべてのユーザーにデフォルトエディターオプションを設定します。", - "tooltip-disable-metrics-lookup": "このオプションをオンにすると、クエリフィールドのオートコンプリートでメトリック選択とメトリック/ラベルサポートが無効になります。これは、大規模なPrometheusインスタンスをご利用でパフォーマンスの問題がある場合に役立ちます。", + "tooltip-disable-metrics-lookup": "", "tooltip-disable-recording-rules-beta": "この機能は記録ルールを無効にします。ダッシュボードのパフォーマンスを向上させるには、この機能をオンにしてください", "tooltip-http-method": "PrometheusデータソースをクエリするにはPOSTまたはGET HTTPメソッドのいずれかを使用できます。POSTメソッドだと、より大きなクエリを実行できるため、推奨される方法です。Prometheusのバージョンが2.1より古い場合、またはネットワークでPOSTリクエストが制限されている場合は、これをGETに変更してください。", "tooltip-incremental-querying-beta": "この機能は相対クエリのデフォルト動作が変更され、常にPrometheusインスタンスから新しいデータをリクエストする代わりに、クエリ結果をキャッシュして新しいレコードのみをリクエストするようになります。データベースとネットワークの負荷を軽減するには、これをオンにしてください。", @@ -479,7 +479,7 @@ "aria-label-selector": "セレクター" }, "results-table": { - "content-descriptive-type": "{{descriptiveType}}を作成する際、Prometheusはタイプカウンターで複数の系列を公開します。", + "content-descriptive-type": "", "description": "説明", "message-expand-label-filters": "メトリックが見つかりません。ラベルフィルターを拡張してみてください。", "message-expand-search": "メトリックが見つかりません。検索とフィルターを拡張してみてください。", diff --git a/packages/grafana-prometheus/src/locales/ko-KR/grafana-prometheus.json b/packages/grafana-prometheus/src/locales/ko-KR/grafana-prometheus.json index 857372ed06e..60576a8c7b6 100644 --- a/packages/grafana-prometheus/src/locales/ko-KR/grafana-prometheus.json +++ b/packages/grafana-prometheus/src/locales/ko-KR/grafana-prometheus.json @@ -85,9 +85,9 @@ "tooltip-classic-query": "Prometheus 변수 쿼리 편집기의 원래 구현입니다. 이 문서에 설명된 대로 올바른 쿼리 유형 및 매개변수가 있는 문자열을 입력합니다. 예: {{exampleQuery}}.", "tooltip-label": "메트릭이 지정되지 않은 한, 모든 메트릭에서 레이블 이름에 대한 레이블 값 목록을 반환합니다.", "tooltip-metric-regex": "필요에 따라 지정된 메트릭 정규식을 기준으로 필터링하여, 레이블 이름 목록을 반환합니다.", - "tooltip-query": "쿼리에 대한 Prometheus 쿼리 결과 목록을 반환합니다. 여기에는 Prometheus 기능이 포함될 수 있습니다. 예: {{exampleQuery}}.", + "tooltip-query": "", "tooltip-query-type": "Prometheus 데이터 소스 플러그인은 템플릿 변수에 대해 다음과 같은 쿼리 유형을 제공합니다.", - "tooltip-series-query": "레이블이 있는 메트릭 또는 메트릭만 단독으로 또는 레이블만 단독으로 입력하세요. 예: {{example1}}, {{example2}}, {{example3}}. 입력된 데이터와 관련된 시계열 목록을 반환합니다." + "tooltip-series-query": "" }, "selector-actions": { "aria-label-selector": "선택기", @@ -175,16 +175,16 @@ "label-scrape-interval": "스크레이핑 간격", "label-series-limit": "계열 한도", "label-use-series-endpoint": "계열 엔드포인트 사용", - "more-info": "데이터 소스에서 prometheus 유형 및 버전을 구성하는 방법에 대한 자세한 내용은 <2>프로비저닝 문서를 참조하시기 바랍니다.", + "more-info": "", "placeholder-example-maxsourceresolutionmtimeout": "예: {{example}} ", "title-interval-behaviour": "간격 동작", "title-other": "기타", "title-performance": "성능", "title-query-editor": "쿼리 편집기", "tooltip-cache-level": "편집기 쿼리에 대한 브라우저 캐싱 수준을 설정합니다. 카디널리티(cardinality)가 높은 데이터 소스에는 더 높은 캐시 설정을 권장합니다.", - "tooltip-custom-query-parameters": "Prometheus 쿼리 URL에 사용자 지정 매개변수를 추가합니다. 예: {{example1}}, {{example2}}, {{example3}}, {{example4}}. 여러 파라미터는 {{concatenationChar}}와(과) 함께 연결해야 합니다.", + "tooltip-custom-query-parameters": "", "tooltip-default-editor": "이 데이터 소스의 모든 사용자에 대한 기본 편집기 옵션을 설정합니다.", - "tooltip-disable-metrics-lookup": "이 옵션을 선택하면, 쿼리 필드의 자동 완성에서 메트릭 선택기 및 메트릭/레이블 지원이 비활성화됩니다. 이는 대규모 Prometheus 인스턴스에서 성능 문제가 발생하는 경우에 유용합니다. ", + "tooltip-disable-metrics-lookup": "", "tooltip-disable-recording-rules-beta": "이 기능을 사용하면 기록 규칙이 비활성화됩니다. 대시보드 성능을 향상시키려면 이 기능을 켜세요.", "tooltip-http-method": "POST 또는 GET HTTP 메소드를 사용하여 Prometheus 데이터 소스를 쿼리할 수 있습니다. POST는 더 큰 쿼리를 허용하기 때문에 권장되는 메소드입니다. Prometheus 버전이 2.1보다 이전 버전이거나 네트워크에서 POST 요청이 제한되어 있는 경우 이를 GET으로 변경하세요.", "tooltip-incremental-querying-beta": "이 기능은 상대적 쿼리의 기본 동작을 항상 Prometheus 인스턴스에서 최신 데이터를 요청하도록 변경합니다. 대신 쿼리 결과가 캐시되고 새 레코드만 요청됩니다. 데이터베이스 및 네트워크 부하를 줄이려면 이 기능을 켜세요.", @@ -479,7 +479,7 @@ "aria-label-selector": "선택기" }, "results-table": { - "content-descriptive-type": "{{descriptiveType}}을 생성할 때 Prometheus는 유형 카운터와 함께 여러 계열을 노출합니다. ", + "content-descriptive-type": "", "description": "설명", "message-expand-label-filters": "메트릭을 찾을 수 없습니다. 레이블 필터를 확장해 보세요.", "message-expand-search": "메트릭을 찾을 수 없습니다. 검색 및 필터를 확장해 보세요.", diff --git a/packages/grafana-prometheus/src/locales/nl-NL/grafana-prometheus.json b/packages/grafana-prometheus/src/locales/nl-NL/grafana-prometheus.json index 991614b0524..feaca3639d9 100644 --- a/packages/grafana-prometheus/src/locales/nl-NL/grafana-prometheus.json +++ b/packages/grafana-prometheus/src/locales/nl-NL/grafana-prometheus.json @@ -85,9 +85,9 @@ "tooltip-classic-query": "De oorspronkelijke implementatie van de Prometheus-variabele queryeditor. Voer een tekenreeks in met het juiste querytype en de juiste parameters zoals beschreven in deze documenten. Bijvoorbeeld, {{exampleQuery}}.", "tooltip-label": "Retourneert een lijst met labelwaarden voor de labelnaam in alle metriek, tenzij de metriek is opgegeven.", "tooltip-metric-regex": "Retourneert een lijst met labelnamen, optioneel gefilterd op opgegeven metriekregex.", - "tooltip-query": "Retourneert een lijst met Prometheus-zoekresultaten voor de zoekopdracht. Dit kan Prometheus-functies omvatten, bijv. {{exampleQuery}}.", + "tooltip-query": "", "tooltip-query-type": "De Prometheus-gegevensbronplugin biedt de volgende querytypes voor sjabloonvariabelen.", - "tooltip-series-query": "Voer een metriek in met labels, alleen een metriek of alleen labels, bijv. {{example1}}, {{example2}} of {{example3}}. Retourneert een lijst met tijdreeksen die zijn gekoppeld aan de ingevoerde gegevens." + "tooltip-series-query": "" }, "selector-actions": { "aria-label-selector": "kiezer", @@ -175,16 +175,16 @@ "label-scrape-interval": "Scrape-interval", "label-series-limit": "Reekslimiet", "label-use-series-endpoint": "Serie-eindpunt gebruiken", - "more-info": "Zie de <2>provisioning-documentatie voor meer informatie over het configureren van het Prometheus-type en de versie in gegevensbronnen.", + "more-info": "", "placeholder-example-maxsourceresolutionmtimeout": "Voorbeeld: {{example}}", "title-interval-behaviour": "Intervalgedrag", "title-other": "Overige", "title-performance": "Prestaties", "title-query-editor": "Query-editor", "tooltip-cache-level": "Stelt het cacheniveau van de browser in voor editor-query's. Hogere cache-instellingen worden aanbevolen voor gegevensbronnen met een hoge kardinaliteit.", - "tooltip-custom-query-parameters": "Voeg aangepaste parameters toe aan de Prometheus-query-URL. Bijvoorbeeld {{example1}}, {{example2}}, {{example3}}, of{{example4}}. Meerdere parameters moeten worden samengevoegd met {{concatenationChar}}.", + "tooltip-custom-query-parameters": "", "tooltip-default-editor": "Stel de standaard editoroptie in voor alle gebruikers van deze gegevensbron.", - "tooltip-disable-metrics-lookup": "Als je deze optie aanvinkt, worden de metriekkiezer en de metriek/label-ondersteuning in de auto-aanvulling van het query-veld uitgeschakeld. Dit helpt als je prestatieproblemen hebt met grotere Prometheus-instanties. ", + "tooltip-disable-metrics-lookup": "", "tooltip-disable-recording-rules-beta": "Deze functie schakelt opnameregels uit. Schakel dit in om de prestaties van het dashboard te verbeteren", "tooltip-http-method": "Je kunt de HTTP-methode POST of GET gebruiken om je Prometheus-gegevensbron op te vragen. POST is de aanbevolen methode omdat het grotere query's toestaat. Wijzig dit in GET als je een Prometheus-versie ouder dan 2.1 hebt of als POST-verzoeken in je netwerk zijn beperkt.", "tooltip-incremental-querying-beta": "Deze functie zal het standaardgedrag van relatieve query's veranderen om altijd nieuwe gegevens van de Prometheus-instantie op te vragen, in plaats daarvan worden query-resultaten in de cache opgeslagen en worden alleen nieuwe records opgevraagd. Schakel dit in om de database- en netwerkbelasting te verminderen.", @@ -479,7 +479,7 @@ "aria-label-selector": "kiezer" }, "results-table": { - "content-descriptive-type": "Bij het maken van een {{descriptiveType}} stelt Prometheus meerdere series bloot met de typeteller. ", + "content-descriptive-type": "", "description": "Beschrijving", "message-expand-label-filters": "Er zijn geen statistieken gevonden. Probeer uw labelfilters uit te breiden.", "message-expand-search": "Er zijn geen statistieken gevonden. Probeer uw zoekopdracht en filters uit te breiden.", diff --git a/packages/grafana-prometheus/src/locales/pl-PL/grafana-prometheus.json b/packages/grafana-prometheus/src/locales/pl-PL/grafana-prometheus.json index 3c949a12c2f..f0b3e694062 100644 --- a/packages/grafana-prometheus/src/locales/pl-PL/grafana-prometheus.json +++ b/packages/grafana-prometheus/src/locales/pl-PL/grafana-prometheus.json @@ -85,9 +85,9 @@ "tooltip-classic-query": "Oryginalna implementacja edytora zapytań zmiennych w systemie Prometheus. Wpisz ciąg z prawidłowym typem zapytania i parametrami zgodnie z opisem w tych dokumentach. Przykład: {{exampleQuery}}.", "tooltip-label": "Zwraca listę wartości etykiet dla nazwy etykiety we wszystkich wskaźnikach, chyba że wskaźnik został określony.", "tooltip-metric-regex": "Zwraca listę nazw etykiet, opcjonalnie filtrując ją według określonego wyrażenia regularnego wskaźnika.", - "tooltip-query": "Zwraca listę wyników zapytania Prometheus dla zapytania. Może to obejmować funkcje systemu Prometheus, czyli {{exampleQuery}}.", + "tooltip-query": "", "tooltip-query-type": "Wtyczka źródła danych Prometheus zapewnia następujące typy zapytań dla zmiennych szablonu.", - "tooltip-series-query": "Wprowadź wskaźnik z etykietami, sam wskaźnik lub same etykiety, czyli {{example1}}, {{example2}} lub {{example3}}. Zwraca listę szeregów czasowych powiązanych z wprowadzonymi danymi." + "tooltip-series-query": "" }, "selector-actions": { "aria-label-selector": "selektor", @@ -175,16 +175,16 @@ "label-scrape-interval": "Odstęp czasowy pobierania danych", "label-series-limit": "Limit szeregu", "label-use-series-endpoint": "Użyj punktu końcowego szeregu", - "more-info": "Więcej informacji na temat konfigurowania typu i wersji systemu Prometheus w źródłach danych można znaleźć w <2>dokumentach dotyczących aprowizacji.", + "more-info": "", "placeholder-example-maxsourceresolutionmtimeout": "Przykład: {{example}}", "title-interval-behaviour": "Sposób działania odstępu czasu", "title-other": "Inne", "title-performance": "Wydajność", "title-query-editor": "Edytor zapytań", "tooltip-cache-level": "Ustawia poziom buforowania przeglądarki dla zapytań edytora. W przypadku źródeł danych o wysokiej kardynalności zaleca się ustawienie pamięci podręcznej na wyższym poziomie.", - "tooltip-custom-query-parameters": "Dodaj niestandardowe parametry do adresu URL zapytania Prometheus. Na przykład {{example1}}, {{example2}}, {{example3}} lub {{example4}}. Wiele parametrów należy połączyć razem za pomocą znaków {{concatenationChar}}.", + "tooltip-custom-query-parameters": "", "tooltip-default-editor": "Ustaw domyślną opcję edytora dla wszystkich użytkowników tego źródła danych.", - "tooltip-disable-metrics-lookup": "Zaznaczenie tej opcji spowoduje wyłączenie selektora wskaźników i obsługi wskaźników/etykiet w autouzupełnianiu pola zapytania. Pomaga to w przypadku problemów z wydajnością większych instancji systemu Prometheus. ", + "tooltip-disable-metrics-lookup": "", "tooltip-disable-recording-rules-beta": "Ta funkcja wyłącza reguły rejestrowania. Włącz tę opcję, aby poprawić wydajność pulpitu", "tooltip-http-method": "Możesz użyć metody HTTP POST lub GET, aby wysłać zapytanie do źródła danych Prometheus. POST jest zalecaną metodą, ponieważ obsługuje większe zapytania. Wybierz metodę GET, jeśli wersja systemu Prometheus jest starsza niż 2.1 lub jeśli żądania POST są objęte ograniczeniami w Twojej sieci.", "tooltip-incremental-querying-beta": "Ta funkcja zmienia domyślny sposób działania zapytań względnych, aby zawsze żądały świeżych danych z instancji Prometheus. Zamiast tego wyniki zapytań będą buforowane, a wysyłane żądania będą uwzględniać tylko nowe rekordy. Włącz tę opcję, aby zmniejszyć obciążenie bazy danych i sieci.", @@ -479,7 +479,7 @@ "aria-label-selector": "selektor" }, "results-table": { - "content-descriptive-type": "Podczas tworzenia zapytania {{descriptiveType}} system Prometheus udostępnia wiele szeregów z licznikiem typu. ", + "content-descriptive-type": "", "description": "Opis", "message-expand-label-filters": "Nie znaleziono żadnych metryk. Spróbuj rozszerzyć filtry etykiet.", "message-expand-search": "Nie znaleziono żadnych metryk. Spróbuj rozszerzyć wyszukiwanie i filtry.", diff --git a/packages/grafana-prometheus/src/locales/pt-BR/grafana-prometheus.json b/packages/grafana-prometheus/src/locales/pt-BR/grafana-prometheus.json index 74d47a5342b..07598624e45 100644 --- a/packages/grafana-prometheus/src/locales/pt-BR/grafana-prometheus.json +++ b/packages/grafana-prometheus/src/locales/pt-BR/grafana-prometheus.json @@ -85,9 +85,9 @@ "tooltip-classic-query": "A implementação original do editor de consultas variáveis do Prometheus. Insira uma string com o tipo de consulta e os parâmetros corretos, conforme descrito nesta documentação. Por exemplo, {{exampleQuery}}.", "tooltip-label": "Retorna uma lista de valores de rótulo para o nome do rótulo em todas as métricas, a menos que a métrica seja especificada.", "tooltip-metric-regex": "Retorna uma lista de nomes de rótulos, havendo a opção de filtrar por métrica regex especificada.", - "tooltip-query": "Retorna uma lista de resultados de consulta do Prometheus para a consulta. Isso pode incluir funções do Prometheus, como {{exampleQuery}}.", + "tooltip-query": "", "tooltip-query-type": "O plug-in de fonte de dados do Prometheus fornece os seguintes tipos de consulta para variáveis de modelo.", - "tooltip-series-query": "Insira uma métrica com rótulos, apenas uma métrica ou apenas rótulos, como {{example1}}, {{example2}} ou {{example3}}. Retorna uma lista de séries temporais associadas aos dados inseridos." + "tooltip-series-query": "" }, "selector-actions": { "aria-label-selector": "seletor", @@ -175,16 +175,16 @@ "label-scrape-interval": "Intervalo de coleta", "label-series-limit": "Limite de série", "label-use-series-endpoint": "Usar endpoint da série", - "more-info": "Para mais informações sobre como configurar o tipo e a versão do Prometheus em fontes de dados, consulte a <2>documentação de provisionamento.", + "more-info": "", "placeholder-example-maxsourceresolutionmtimeout": "Exemplo: {{example}}", "title-interval-behaviour": "Comportamento de intervalo", "title-other": "Outro", "title-performance": "Desempenho", "title-query-editor": "Editor de consultas", "tooltip-cache-level": "Define o nível de cache do navegador para consultas do editor. Recomenda-se usar configurações de cache mais elevadas para fontes de dados de alta cardinalidade.", - "tooltip-custom-query-parameters": "Adicione parâmetros personalizados ao URL de consulta do Prometheus. Por exemplo, {{example1}}, {{example2}}, {{example3}} ou{{example4}}. Vários parâmetros devem ser concatenados com {{concatenationChar}}.", + "tooltip-custom-query-parameters": "", "tooltip-default-editor": "Defina a opção de editor padrão para todos os usuários desta fonte de dados.", - "tooltip-disable-metrics-lookup": "Marcar esta opção desativará o seletor de métricas e a compatibilidade com métricas/rótulos no preenchimento automático do campo de consulta. Isso é útil se você tiver problemas de desempenho com instâncias maiores do Prometheus. ", + "tooltip-disable-metrics-lookup": "", "tooltip-disable-recording-rules-beta": "Este recurso desativará as regras de registro. Ative o recurso para aprimorar o desempenho do painel", "tooltip-http-method": "Você pode usar o método HTTP POST ou GET para consultar sua fonte de dados do Prometheus. POST é o método recomendado por permitir consultas maiores. Altere para GET se sua versão do Prometheus for anterior à versão 2.1 ou se as solicitações POST estiverem restritas na sua rede.", "tooltip-incremental-querying-beta": "Este recurso alterará o comportamento padrão das consultas relativas: os dados recentes deixam de ser sempre solicitados da instância do Prometheus e passam a utilizar dados em cache e a solicitar apenas novos registros. Ative o recurso para diminuir a carga do banco de dados e da rede.", @@ -479,7 +479,7 @@ "aria-label-selector": "seletor" }, "results-table": { - "content-descriptive-type": "Ao criar um {{descriptiveType}}, o Prometheus expõe várias séries com o contador de tipos. ", + "content-descriptive-type": "", "description": "Descrição", "message-expand-label-filters": "Não há métricas encontradas. Tente expandir seus filtros de rótulo.", "message-expand-search": "Não há métricas encontradas. Tente expandir sua busca e filtros.", diff --git a/packages/grafana-prometheus/src/locales/pt-PT/grafana-prometheus.json b/packages/grafana-prometheus/src/locales/pt-PT/grafana-prometheus.json index 0c56b656f66..eb90445ed3e 100644 --- a/packages/grafana-prometheus/src/locales/pt-PT/grafana-prometheus.json +++ b/packages/grafana-prometheus/src/locales/pt-PT/grafana-prometheus.json @@ -85,9 +85,9 @@ "tooltip-classic-query": "A implementação original do editor de consultas de variáveis Prometheus. Introduzir uma cadeia de carateres com o tipo de consulta e parâmetros corretos, conforme descrito nestes documentos. Por exemplo, {{exampleQuery}}.", "tooltip-label": "Devolve uma lista de valores de etiqueta para o nome da etiqueta em todas as métricas, a menos que a métrica seja especificada.", "tooltip-metric-regex": "Devolve uma lista de nomes de etiquetas, filtrando opcionalmente por regex métrico especificado.", - "tooltip-query": "Devolve uma lista de resultados de consulta Prometheus para a consulta. Isto pode incluir funções Prometheus, ou seja,{{exampleQuery}}.", + "tooltip-query": "", "tooltip-query-type": "O plugin de origem de dados do Prometheus fornece os seguintes tipos de consulta para variáveis de modelo.", - "tooltip-series-query": "Introduza uma métrica com etiquetas, apenas uma métrica ou apenas etiquetas, ou seja, {{example1}}, {{example2}}, ou {{example3}}. Devolve uma lista de séries temporais associadas aos dados inseridos." + "tooltip-series-query": "" }, "selector-actions": { "aria-label-selector": "seletor", @@ -175,16 +175,16 @@ "label-scrape-interval": "Intervalo de raspagem", "label-series-limit": "Limite de série", "label-use-series-endpoint": "Utilizar ponto final da série", - "more-info": "Para obter mais informações sobre como configurar o tipo e a versão do Prometheus em origens de dados, consulte a <2>documentação de aprovisionamento.", + "more-info": "", "placeholder-example-maxsourceresolutionmtimeout": "Exemplo: {{example}}", "title-interval-behaviour": "Comportamento de intervalo", "title-other": "Outro", "title-performance": "Desempenho", "title-query-editor": "Editor de consultas", "tooltip-cache-level": "Definir o nível de cache do navegador para consultas do editor. São recomendadas definições de cache mais elevadas para origens de dados de elevada cardinalidade.", - "tooltip-custom-query-parameters": "Adicionar parâmetros personalizados ao URL de consulta do Prometheus. Por exemplo, {{example1}}, {{example2}}, {{example3}} ou {{example4}}. Os parâmetros múltiplos devem ser concatenados com {{concatenationChar}}.", + "tooltip-custom-query-parameters": "", "tooltip-default-editor": "Definir a opção de editor predefinida para todos os utilizadores desta origem de dados.", - "tooltip-disable-metrics-lookup": "Ao selecionar esta opção desativará o seletor de métricas e o suporte de métrica/etiqueta no preenchimento automático do campo de consulta. Isto ajuda se tiver problemas de desempenho com instâncias maiores do Prometheus. ", + "tooltip-disable-metrics-lookup": "", "tooltip-disable-recording-rules-beta": "Esta funcionalidade desativará as regras de gravação. Ative isto para melhorar o desempenho do painel de controlo", "tooltip-http-method": "Pode utilizar o método HTTP POST ou GET para consultar a sua origem de dados Prometheus. POST é o método recomendado, pois permite consultas maiores. Altere esta opção para GET se tiver uma versão do Prometheus anterior à 2.1 ou se os pedidos POST forem restritos na sua rede.", "tooltip-incremental-querying-beta": "Esta funcionalidade irá alterar o comportamento predefinido das consultas relativas para solicitar sempre dados novos da instância do Prometheus. Em vez disso, os resultados da consulta serão armazenados em cache e apenas serão solicitados novos registos. Ativar isto para diminuir a carga da base de dados e da rede.", @@ -479,7 +479,7 @@ "aria-label-selector": "seletor" }, "results-table": { - "content-descriptive-type": "Ao criar um {{descriptiveType}}, o Prometheus expõe várias séries com o contador de tipos. ", + "content-descriptive-type": "", "description": "Descrição", "message-expand-label-filters": "Não foram encontradas métricas. Tente expandir os seus filtros de etiquetas.", "message-expand-search": "Não foram encontradas métricas. Tente expandir a sua pesquisa e filtros.", diff --git a/packages/grafana-prometheus/src/locales/ru-RU/grafana-prometheus.json b/packages/grafana-prometheus/src/locales/ru-RU/grafana-prometheus.json index da73342e2e9..e4ff771a093 100644 --- a/packages/grafana-prometheus/src/locales/ru-RU/grafana-prometheus.json +++ b/packages/grafana-prometheus/src/locales/ru-RU/grafana-prometheus.json @@ -85,9 +85,9 @@ "tooltip-classic-query": "Оригинальная реализация редактора запросов переменных Prometheus. Введите строку с правильным типом запроса и параметрами, указанными в документации. Например, {{exampleQuery}}.", "tooltip-label": "Возвращает список значений для метки с соответствующим названием во всех метриках, если не указана конкретная метрика.", "tooltip-metric-regex": "Возвращает список названий меток, при необходимости фильтруя их по указанному регулярному выражению метрики.", - "tooltip-query": "Возвращает список результатов запросов Prometheus для текущего запроса. Сюда могут входить функции Prometheus, например {{exampleQuery}}.", + "tooltip-query": "", "tooltip-query-type": "Плагин источника данных Prometheus предоставляет следующие типы запросов для переменных шаблона.", - "tooltip-series-query": "Укажите метрику с метками, только метрику или только метки, например {{example1}}, {{example2}} или {{example3}}. Возвращает список временных рядов, связанных с введенными данными." + "tooltip-series-query": "" }, "selector-actions": { "aria-label-selector": "селектор", @@ -175,16 +175,16 @@ "label-scrape-interval": "Интервал опроса", "label-series-limit": "Лимит рядов", "label-use-series-endpoint": "Использовать конечную точку ряда", - "more-info": "Более подробную информацию о настройке типа и версии Prometheus в источниках данных см. в <2>документации по подготовке.", + "more-info": "", "placeholder-example-maxsourceresolutionmtimeout": "Пример: {{example}}", "title-interval-behaviour": "Поведение интервалов", "title-other": "Прочее", "title-performance": "Производительность", "title-query-editor": "Редактор запросов", "tooltip-cache-level": "Устанавливает уровень кэширования в браузере для запросов редактора. Для источников данных с высокой кардинальностью рекомендуются более высокие настройки кэша.", - "tooltip-custom-query-parameters": "Добавьте пользовательские параметры в URL-адрес запроса Prometheus. Например, {{example1}}, {{example2}}, {{example3}}, или {{example4}}. Несколько параметров следует объединить с {{concatenationChar}}.", + "tooltip-custom-query-parameters": "", "tooltip-default-editor": "Установите параметр редактора по умолчанию для всех пользователей этого источника данных.", - "tooltip-disable-metrics-lookup": "При включении этого параметра будут отключены выбор метрик и поддержка метрик/меток при автозаполнении поля запроса. Функция полезна, если вы испытываете проблемы с производительностью при использовании более крупных экземляров Prometheus. ", + "tooltip-disable-metrics-lookup": "", "tooltip-disable-recording-rules-beta": "Функция отключит правила записи. Включите, чтобы улучшить производительность дашборда", "tooltip-http-method": "Для отправки запросов в источник данных Prometheus можно использовать HTTP-методы POST или GET. POST является рекомендуемым методом, поскольку позволяет выполнять более крупные запросы. Измените метод на GET, если вы используете версию Prometheus старше 2.1 или в вашей сети запрещены запросы POST.", "tooltip-incremental-querying-beta": "Функция изменит поведение относительных запросов по умолчанию. Вместо запроса свежих данных из экземпляра Prometheus, результаты запросов будут кэшироваться, и запрашиваться будут только новые записи. Включите, чтобы уменьшить нагрузку на базу данных и сеть.", @@ -479,7 +479,7 @@ "aria-label-selector": "селектор" }, "results-table": { - "content-descriptive-type": "При создании {{descriptiveType}} Prometheus отображает несколько рядов со счетчиком типов. ", + "content-descriptive-type": "", "description": "Описание", "message-expand-label-filters": "Метрики не найдены. Попробуйте расширить фильтры меток.", "message-expand-search": "Метрики не найдены. Попробуйте расширить поиск и фильтры.", diff --git a/packages/grafana-prometheus/src/locales/sv-SE/grafana-prometheus.json b/packages/grafana-prometheus/src/locales/sv-SE/grafana-prometheus.json index e41b22075dd..8132d631384 100644 --- a/packages/grafana-prometheus/src/locales/sv-SE/grafana-prometheus.json +++ b/packages/grafana-prometheus/src/locales/sv-SE/grafana-prometheus.json @@ -85,9 +85,9 @@ "tooltip-classic-query": "Den ursprungliga implementeringen av Prometheus variabla frågeredigerare. Ange en sträng med rätt frågetyp och parametrar enligt beskrivningen i dessa dokument. Till exempel, {{exampleQuery}}.", "tooltip-label": "Returnerar en lista över etikettvärden för etikettnamnet för alla mätvärden om inte mätvärdet är angivet.", "tooltip-metric-regex": "Returnerar en lista över etikettnamn, eventuellt filtrering efter angiven måttregex.", - "tooltip-query": "Returnerar en lista över Prometheus frågeresultat för frågan. Detta kan inkludera Prometheus-funktioner, d.v.s. {{exampleQuery}}.", + "tooltip-query": "", "tooltip-query-type": "Prometheus-datakällans tillägg tillhandahåller följande frågetyper för mallvariabler.", - "tooltip-series-query": "Ange ett mätvärde med etiketter, endast ett mätvärde eller endast etiketter d.v.s. {{example1}}, {{example2}} eller {{example3}}. Returnerar en lista över tidsserier som är associerade med angivna data." + "tooltip-series-query": "" }, "selector-actions": { "aria-label-selector": "väljare", @@ -175,16 +175,16 @@ "label-scrape-interval": "Skrapningsintervall", "label-series-limit": "Seriegräns", "label-use-series-endpoint": "Använd serieändpunkt", - "more-info": "För mer information om hur du konfigurerar prometheustyp och -version i datakällor, se <2>provisioneringsdokumentationen.", + "more-info": "", "placeholder-example-maxsourceresolutionmtimeout": "Exempel: {{example}}", "title-interval-behaviour": "Intervallbeteende", "title-other": "Annat", "title-performance": "Performance", "title-query-editor": "Frågeredigerare", "tooltip-cache-level": "Anger webbläsarens cachelagringsnivå för redigeringsfrågor. Högre cacheinställningar rekommenderas för datakällor med hög kardinalitet.", - "tooltip-custom-query-parameters": "Lägg till anpassade parametrar i Prometheus fråge-URL. Till exempel {{example1}}, {{example2}}, {{example3}} eller {{example4}}. Flera parametrar ska sammanfogas med {{concatenationChar}}.", + "tooltip-custom-query-parameters": "", "tooltip-default-editor": "Ange standardalternativ för redigerare för alla användare av den här datakällan.", - "tooltip-disable-metrics-lookup": "Om du markerar det här alternativet inaktiveras metrikväljaren och stödet för automatisk komplettering av metrik/etikett i sökfältet. Detta hjälper om du har prestandaproblem med större Prometheus-instanser. ", + "tooltip-disable-metrics-lookup": "", "tooltip-disable-recording-rules-beta": "Denna funktion kommer att inaktivera inspelningsregler. Aktivera detta för att förbättra instrumentpanelens prestanda", "tooltip-http-method": "Du kan använda antingen HTTP-metoden POST eller GET för att fråga din Prometheus-datakälla. POST är den rekommenderade metoden eftersom den tillåter större frågor. Ändra detta till GET om du har en Prometheus-version som är äldre än 2.1 eller om POST-förfrågningar är begränsade i ditt nätverk.", "tooltip-incremental-querying-beta": "Denna funktion kommer att ändra standardbeteendet för relativa frågor till att alltid begära nya data från prometheus-instansen, istället kommer frågeresultat att cachelagras och endast nya poster begärs. Aktivera detta för att minska databas- och nätverksbelastningen.", @@ -479,7 +479,7 @@ "aria-label-selector": "väljare" }, "results-table": { - "content-descriptive-type": "När du skapar en {{descriptiveType}} visar Prometheus flera dataserier av typen räknare. ", + "content-descriptive-type": "", "description": "Beskrivning", "message-expand-label-filters": "Inga mätvärden hittades. Försök att utöka dina etikettfilter.", "message-expand-search": "Inga mätvärden hittades. Försök att utöka din sökning och dina filter.", diff --git a/packages/grafana-prometheus/src/locales/tr-TR/grafana-prometheus.json b/packages/grafana-prometheus/src/locales/tr-TR/grafana-prometheus.json index af4dea95932..4b918d3c61d 100644 --- a/packages/grafana-prometheus/src/locales/tr-TR/grafana-prometheus.json +++ b/packages/grafana-prometheus/src/locales/tr-TR/grafana-prometheus.json @@ -85,9 +85,9 @@ "tooltip-classic-query": "Prometheus değişken sorgu düzenleyicisinin orijinal uygulaması. Bu belgelerde açıklanan doğru sorgu türü ve parametrelerle bir dize girin. Örneğin {{exampleQuery}}.", "tooltip-label": "Bir metrik belirtilmedikçe tüm metriklerdeki etiket adı için etiket değerlerinin bir listesini döndürür.", "tooltip-metric-regex": "Belirtilen metrik düzenli ifadesine göre isteğe bağlı filtreleme yaparak etiket adlarının bir listesini döndürür.", - "tooltip-query": "Sorgu için Prometheus sorgu sonuçlarının bir listesini döndürür. Bu sorgular Prometheus işlevlerini içerebilir, örneğin {{exampleQuery}}.", + "tooltip-query": "", "tooltip-query-type": "Prometheus veri kaynağı eklentisi, şablon değişkenleri için aşağıdaki sorgu türlerini sağlar.", - "tooltip-series-query": "Bir metrik ve etiketlerle, yalnızca metrik ya da yalnızca etiketlerle birlikte bir değer girin. Örneğin {{example1}}, {{example2}} veya {{example3}}. Girilen verilerle ilişkili zaman serilerinin bir listesini döndürür." + "tooltip-series-query": "" }, "selector-actions": { "aria-label-selector": "seçici", @@ -175,16 +175,16 @@ "label-scrape-interval": "Kazıma aralığı", "label-series-limit": "Seri sınırı", "label-use-series-endpoint": "Seri uç noktasını kullan", - "more-info": "Prometheus türü ve sürümünü veri kaynaklarında yapılandırma hakkında daha fazla bilgi için <2>sağlama belgelerine bakın.", + "more-info": "", "placeholder-example-maxsourceresolutionmtimeout": "Örnek: {{example}}", "title-interval-behaviour": "Aralık davranışı", "title-other": "Diğer", "title-performance": "Performans", "title-query-editor": "Sorgu düzenleyicisi", "tooltip-cache-level": "Düzenleyici sorguları için tarayıcı önbelleğe alma düzeyini ayarlar. Yüksek ayırt ediciliğe sahip veri kaynakları için daha yüksek önbellek ayarları önerilir.", - "tooltip-custom-query-parameters": "Prometheus sorgu URL'sine özel parametreler ekleyin. Örneğin {{example1}}, {{example2}}, {{example3}} veya {{example4}}. Birden fazla parametre, {{concatenationChar}} karakteri ile birleştirilmelidir.", + "tooltip-custom-query-parameters": "", "tooltip-default-editor": "Bu veri kaynağının tüm kullanıcıları için varsayılan düzenleyici seçeneğini ayarlayın.", - "tooltip-disable-metrics-lookup": "Bu seçeneği işaretlemek, metrik seçicisini ve sorgu alanındaki metrik/etiket desteğini otomatik tamamlama özelliğinde devre dışı bırakır. Bu, büyük Prometheus örneklerinde yaşanan performans sorunlarına yardımcı olabilir. ", + "tooltip-disable-metrics-lookup": "", "tooltip-disable-recording-rules-beta": "Bu özellik, kayıt kurallarını devre dışı bırakacaktır. Pano performansını artırmak için bu seçeneği etkinleştirin", "tooltip-http-method": "Prometheus veri kaynağınızı sorgulamak için POST veya GET HTTP yöntemini kullanabilirsiniz. POST, daha büyük sorgulara izin verdiği için önerilen yöntemdir. Prometheus sürümünüz 2.1'den eskiyse ya da ağınızda POST istekleri kısıtlıysa bunu GET olarak değiştirin.", "tooltip-incremental-querying-beta": "Bu özellik, göreli sorguların varsayılan davranışını değiştirerek Prometheus örneğinden her zaman güncel veri istenmesini sağlar. Bunun yerine, sorgu sonuçları önbelleğe alınır ve yalnızca yeni kayıtlar istenir. Veri tabanı ve ağ yükünü azaltmak için bu özelliği etkinleştirin.", @@ -479,7 +479,7 @@ "aria-label-selector": "seçici" }, "results-table": { - "content-descriptive-type": "Bir {{descriptiveType}} oluşturulduğunda, Prometheus sayaç türünde birden fazla seri sunar. ", + "content-descriptive-type": "", "description": "Açıklama", "message-expand-label-filters": "Metrik bulunamadı. Etiket filtrelerinizi genişletmeyi deneyin.", "message-expand-search": "Metrik bulunamadı. Aramanızı ve filtrelerinizi genişletmeyi deneyin.", diff --git a/packages/grafana-prometheus/src/locales/zh-Hans/grafana-prometheus.json b/packages/grafana-prometheus/src/locales/zh-Hans/grafana-prometheus.json index 890add6aa2f..b8f110e9226 100644 --- a/packages/grafana-prometheus/src/locales/zh-Hans/grafana-prometheus.json +++ b/packages/grafana-prometheus/src/locales/zh-Hans/grafana-prometheus.json @@ -85,9 +85,9 @@ "tooltip-classic-query": "Prometheus 变量查询编辑器的原始执行操作。按照这些文档中所述,输入包含正确查询类型和参数的字符串。例如,{{exampleQuery}}。", "tooltip-label": "返回所有指标中标签名称的标签值列表,除非指定了指标。", "tooltip-metric-regex": "返回标签名称列表,可选择按指定的指标正则表达式进行筛选。", - "tooltip-query": "返回查询的 Prometheus 查询结果列表。这可以包含 Prometheus 函数,即 {{exampleQuery}}。", + "tooltip-query": "", "tooltip-query-type": "Prometheus 数据源插件为模板变量提供以下查询类型。", - "tooltip-series-query": "输入带有标签的指标、仅指标或仅标签,即 {{example1}}、{{example2}} 或 {{example3}}。返回与输入数据关联的时间序列列表。" + "tooltip-series-query": "" }, "selector-actions": { "aria-label-selector": "选择器", @@ -175,16 +175,16 @@ "label-scrape-interval": "抓取间隔", "label-series-limit": "序列限制", "label-use-series-endpoint": "使用序列端点", - "more-info": "有关在数据源中配置 prometheus 类型和版本的更多信息,请参阅<2>预配文档。", + "more-info": "", "placeholder-example-maxsourceresolutionmtimeout": "示例:{{example}}", "title-interval-behaviour": "间隔行为", "title-other": "其他", "title-performance": "性能", "title-query-editor": "查询编辑器", "tooltip-cache-level": "设置编辑器查询的浏览器缓存级别。对于高基数数据源,建议使用更高的缓存设置。", - "tooltip-custom-query-parameters": "将自定义参数添加到 Prometheus 查询网址。例如 {{example1}}、{{example2}}、{{example3}} 或 {{example4}}。多个参数应使用 {{concatenationChar}} 连接起来。", + "tooltip-custom-query-parameters": "", "tooltip-default-editor": "为此数据源的所有用户设置默认编辑器选项。", - "tooltip-disable-metrics-lookup": "选中此选项将禁用查询字段自动完成中的指标选择器和指标/标签支持。如果您在使用较大的 Prometheus 实例时遇到性能问题,这样做会有所帮助。", + "tooltip-disable-metrics-lookup": "", "tooltip-disable-recording-rules-beta": "此功能将禁用录制规则。开启此选项可提高数据面板性能", "tooltip-http-method": "您可以使用 POST 或 GET HTTP 方法来查询 Prometheus 数据源。POST 是推荐的方法,因为它允许更大的查询。如果您的 Prometheus 版本低于 2.1,或者您的网络中限制了 POST 请求,请将其更改为 GET。", "tooltip-incremental-querying-beta": "此功能将改变相对查询的默认行为,使其总是从 Prometheus 实例请求新数据,而不会缓存查询结果,且只请求新数据。开启此选项可减少数据库和网络负载。", @@ -479,7 +479,7 @@ "aria-label-selector": "选择器" }, "results-table": { - "content-descriptive-type": "创建 {{descriptiveType}} 时,Prometheus 会使用类型计数器公开多个序列。", + "content-descriptive-type": "", "description": "描述", "message-expand-label-filters": "未找到指标。尝试展开您的标签筛选条件。", "message-expand-search": "未找到指标。尝试展开您的搜索和筛选条件。", diff --git a/packages/grafana-prometheus/src/locales/zh-Hant/grafana-prometheus.json b/packages/grafana-prometheus/src/locales/zh-Hant/grafana-prometheus.json index 0f4fd89eaa2..c9b5b8bdd99 100644 --- a/packages/grafana-prometheus/src/locales/zh-Hant/grafana-prometheus.json +++ b/packages/grafana-prometheus/src/locales/zh-Hant/grafana-prometheus.json @@ -85,9 +85,9 @@ "tooltip-classic-query": "Prometheus 變數查詢編輯器的原始實作。輸入一個字串,其中包含如這些文件中所述正確的查詢類型和參數。例如:{{exampleQuery}}。", "tooltip-label": "除非有指定指標,否則會回傳所有指標中該標籤名稱的標籤值清單。", "tooltip-metric-regex": "回傳標籤名稱清單,選擇性地依據指定指標正規表達式篩選。", - "tooltip-query": "回傳此查詢的 Prometheus 查詢結果清單。這可能包括 Prometheus 功能,即{{exampleQuery}}。", + "tooltip-query": "", "tooltip-query-type": "Prometheus 資料來源外掛程式為範本變數提供以下查詢類型。", - "tooltip-series-query": "輸入帶有標籤的指標、僅有指標或僅標籤,即 {{example1}}、{{example2}} 或 {{example3}}。回傳與輸入資料相關的時間序列清單。" + "tooltip-series-query": "" }, "selector-actions": { "aria-label-selector": "選擇器", @@ -175,16 +175,16 @@ "label-scrape-interval": "抓取間隔", "label-series-limit": "序列限制", "label-use-series-endpoint": "使用序列端點", - "more-info": "如需更多在資料來源中設定 Prometheus 類型與版本的相關資訊,請參閱<2>佈建文件。", + "more-info": "", "placeholder-example-maxsourceresolutionmtimeout": "範例:{{example}}", "title-interval-behaviour": "間隔行為", "title-other": "其他", "title-performance": "成效", "title-query-editor": "查詢編輯器", "tooltip-cache-level": "設定編輯器查詢的瀏覽器快取層級。針對高基數資料來源,建議使用較高層級的快取設定。", - "tooltip-custom-query-parameters": "將自訂參數新增至 Prometheus 查詢網址。例如 {{example1}}、{{example2}}、{{example3}} 或 {{example4}}。多個參數應與{{concatenationChar}}串接在一起。", + "tooltip-custom-query-parameters": "", "tooltip-default-editor": "為此資料來源的所有使用者設定預設編輯器選項。", - "tooltip-disable-metrics-lookup": "勾選此選項將停用查詢欄位自動完成中的指標選擇器和指標/標籤支援。如果您在較大的 Prometheus 實例上遇到效能問題,這會有所幫助。", + "tooltip-disable-metrics-lookup": "", "tooltip-disable-recording-rules-beta": "此功能將停用錄製規則。開啟此功能以改善儀表板效能", "tooltip-http-method": "您可以使用 POST 或 GET HTTP 方法,來查詢您的 Prometheus 資料來源。POST 是建議的方法,因為它可以處理更大規模的查詢。如果您的 Prometheus 版本早於 2.1,或您的網路中限制了 POST 請求,請將此更改為 GET。", "tooltip-incremental-querying-beta": "此功能將變更相對時間查詢的預設行為,以便隨時從 Prometheus 實例要求新資料,而不會快取查詢結果,並且只會請求新紀錄。開啟此功能以減少資料庫和網路負載。", @@ -479,7 +479,7 @@ "aria-label-selector": "選擇器" }, "results-table": { - "content-descriptive-type": "建立{{descriptiveType}}時,Prometheus 會透過類型計數器顯示多個序列。", + "content-descriptive-type": "", "description": "說明", "message-expand-label-filters": "未找到指標。請嘗試展開標籤篩選條件。", "message-expand-search": "未找到指標。請嘗試擴大搜尋範圍和篩選條件。", diff --git a/packages/grafana-sql/src/locales/cs-CZ/grafana-sql.json b/packages/grafana-sql/src/locales/cs-CZ/grafana-sql.json index 68f1dd03de9..d908975dc53 100644 --- a/packages/grafana-sql/src/locales/cs-CZ/grafana-sql.json +++ b/packages/grafana-sql/src/locales/cs-CZ/grafana-sql.json @@ -11,10 +11,10 @@ }, "connection-limits": { "auto-max-idle": "Auto. max. nečinný", - "content-auto-max-idle": "Pokud je tato možnost povolena, automaticky nastaví počet <1>Maximálních nečinných připojení na stejnou hodnotu jako<3> Maximální otevřená připojení. Pokud není nastaven počet maximálních otevřených připojení, bude nastaven na výchozí hodnotu ({{defaultMaxIdle}}).", - "content-max-idle": "Maximální počet připojení v nečinném připojovacím souboru. Pokud je <1>Maximální počet otevřených připojení větší než 0, ale menší než <3>Maximální počet nečinných připojení, pak bude <5>Maximální počet nečinných připojení snížen tak, aby odpovídal limitu pro <8>Maximální počet otevřených připojení. Pokud je nastaveno na 0, nejsou zachována žádná nečinná připojení.", + "content-auto-max-idle": "", + "content-max-idle": "", "content-max-lifetime": "Maximální doba v sekundách, po kterou může být připojení znovu použito. Pokud je nastaveno na 0, připojení jsou znovu používána opakovaně.", - "content-max-open": "Maximální počet otevřených připojení k databázi. Pokud je <1>Maximální počet nečinných připojení větší než 0 a <3>Maximální počet otevřených připojení je menší než <5>Maximální počet nečinných připojení, pak bude <7>Maximální počet nečinných připojení snížen tak, aby odpovídal limitu pro <9>Maximální počet otevřených připojení. Pokud je nastaveno na 0, počet otevřených připojení není omezen.", + "content-max-open": "", "max-idle": "Max. nečinný", "max-lifetime": "Max. životnost", "max-open": "Max. otevřený", @@ -54,7 +54,7 @@ } }, "query-header": { - "content-invalid-query": "Váš dotaz je neplatný. Podrobnosti najdete níže. <1>Tento dotaz však můžete stále spustit.", + "content-invalid-query": "", "editor-modes": { "label-builder": "Nástroj pro tvorbu", "label-code": "Kód" @@ -76,7 +76,7 @@ "tooltip-format-query": "Formátovat dotaz" }, "query-validator": { - "query-will-process": "<0> Tento dotaz zpracuje <2>{{bytes}} při spuštění.", + "query-will-process": "", "validating-query": "Ověřování dotazu…" }, "raw-editor": { diff --git a/packages/grafana-sql/src/locales/de-DE/grafana-sql.json b/packages/grafana-sql/src/locales/de-DE/grafana-sql.json index 784acba470c..a8298401968 100644 --- a/packages/grafana-sql/src/locales/de-DE/grafana-sql.json +++ b/packages/grafana-sql/src/locales/de-DE/grafana-sql.json @@ -11,10 +11,10 @@ }, "connection-limits": { "auto-max-idle": "Auto. max. inaktiv", - "content-auto-max-idle": "Wenn dies aktiviert ist, wird die Anzahl der <1>Maximalen inaktiven Verbindungen automatisch auf den gleichen Wert der<3> Maximalen offenen Verbindungen festgelegt. Wenn die Anzahl der maximalen offenen Verbindungen nicht festgelegt ist, wird sie auf den Standardwert ({{defaultMaxIdle}}) eingestellt.", - "content-max-idle": "Die maximale Anzahl der Verbindungen im Pool der inaktiven Verbindungen. Wenn <1>Maximale offene Verbindungen größer ist als 0, aber kleiner als die Anzahl der <3>Maximalen inaktiven Verbindungen, werden die <5>Maximalen inaktiven Verbindungen verringert, um der Grenze für die Anzahl der <8>Maximalen offenen Verbindungen zu entsprechen. Wenn der Wert auf 0 eingestellt ist, werden keine inaktiven Verbindungen beibehalten.", + "content-auto-max-idle": "", + "content-max-idle": "", "content-max-lifetime": "Die maximale Zeitdauer der Wiederverwendung einer Verbindung in Sekunden. Bei einer Einstellung auf 0 werden Verbindungen immer wiederverwendet.", - "content-max-open": "Die maximale Anzahl offener Verbindungen zur Datenbank. Wenn <1>Maximale inaktive Verbindungen größer als 0 ist und die Anzahl der <3>Maximalen offenen Verbindungen kleiner als die Anzahl der <5>Maximalen inaktiven Verbindungen ist, werden die <7>Maximalen inaktiven Verbindungen bis zur Grenze für <9>Maximale offene Verbindungen verringert. Wenn 0 festgelegt ist, gibt es keine Begrenzung der Anzahl offener Verbindungen.", + "content-max-open": "", "max-idle": "Max. inaktiv", "max-lifetime": "Max. Lebensdauer", "max-open": "Max. offen", @@ -54,7 +54,7 @@ } }, "query-header": { - "content-invalid-query": "Ihre Abfrage ist ungültig. Weitere Informationen finden Sie unten. <1>Sie können diese Abfrage aber trotzdem ausführen.", + "content-invalid-query": "", "editor-modes": { "label-builder": "Builder", "label-code": "Code" @@ -76,7 +76,7 @@ "tooltip-format-query": "Formatabfrage" }, "query-validator": { - "query-will-process": "<0> Diese Abfrage verarbeitet <2>{{bytes}}, wenn sie ausgeführt wird.", + "query-will-process": "", "validating-query": "Abfrage wird validiert …" }, "raw-editor": { diff --git a/packages/grafana-sql/src/locales/es-ES/grafana-sql.json b/packages/grafana-sql/src/locales/es-ES/grafana-sql.json index 50762539f05..9937632d196 100644 --- a/packages/grafana-sql/src/locales/es-ES/grafana-sql.json +++ b/packages/grafana-sql/src/locales/es-ES/grafana-sql.json @@ -11,10 +11,10 @@ }, "connection-limits": { "auto-max-idle": "Inactividad máxima automática", - "content-auto-max-idle": "Si está habilitado, establece automáticamente el número de <1>Conexiones inactivas máximas en el mismo valor que<3> Conexiones abiertas máximas. Si no se establece el número de conexiones abiertas máximas, se establecerá en el valor predeterminado ({{defaultMaxIdle}}).", - "content-max-idle": "El número máximo de conexiones en el grupo de conexiones inactivas. Si <1>Conexiones abiertas máximas es mayor que 0 pero menor que <3>Conexiones inactivas máximas, entonces <5>Conexiones inactivas máximas se reducirá para que coincida con el límite de <8>Conexiones abiertas máximas. Si se establece en 0, no se conservan las conexiones inactivas.", + "content-auto-max-idle": "", + "content-max-idle": "", "content-max-lifetime": "La cantidad máxima de tiempo en segundos que se puede reutilizar una conexión. Si se establece en 0, las conexiones se reutilizan para siempre.", - "content-max-open": "El número máximo de conexiones abiertas a la base de datos. Si <1>Conexiones inactivas máximas es mayor que 0 y <3>Conexiones abiertas máximas es menor que <5>Conexiones inactivas máximas, entonces <7>Conexiones inactivas máximas se reducirá para que coincida con el límite de <9>Conexiones abiertas máximas. Si se establece en 0, no hay límite en el número de conexiones abiertas.", + "content-max-open": "", "max-idle": "Máx. inactivas", "max-lifetime": "Vida útil máxima", "max-open": "Máx. abiertas", @@ -54,7 +54,7 @@ } }, "query-header": { - "content-invalid-query": "Su consulta no es válida. A continuación podrá obtener más información. <1>En todo caso, puede ejecutar esta consulta.", + "content-invalid-query": "", "editor-modes": { "label-builder": "Constructor", "label-code": "Código" @@ -76,7 +76,7 @@ "tooltip-format-query": "Formatear consulta" }, "query-validator": { - "query-will-process": "<0> Esta consulta procesará <2>{{bytes}} cuando se ejecute.", + "query-will-process": "", "validating-query": "Validando consulta..." }, "raw-editor": { diff --git a/packages/grafana-sql/src/locales/fr-FR/grafana-sql.json b/packages/grafana-sql/src/locales/fr-FR/grafana-sql.json index f125322db6f..e24bc1fc4ec 100644 --- a/packages/grafana-sql/src/locales/fr-FR/grafana-sql.json +++ b/packages/grafana-sql/src/locales/fr-FR/grafana-sql.json @@ -11,10 +11,10 @@ }, "connection-limits": { "auto-max-idle": "Inactivité maximale automatique", - "content-auto-max-idle": "Si cette option est activée, le nombre de <1>connexions inactives maximales est automatiquement défini sur la même valeur que<3> Connexions ouvertes maximales. Si le nombre maximal de connexions ouvertes n’est pas défini, il sera défini sur la valeur par défaut ({{defaultMaxIdle}}).", - "content-max-idle": "Le nombre maximal de connexions dans le pool de connexions inactives. Si <1>Connexions ouvertes maximales est supérieur à 0, mais inférieur à <3>Connexions inactives maximales, alors <5>Connexions inactives maximales sera réduit pour correspondre à la limite de <8>Connexions ouvertes maximales. Si la valeur est 0, aucune connexion inactive n’est conservée.", + "content-auto-max-idle": "", + "content-max-idle": "", "content-max-lifetime": "La durée maximale en secondes pendant laquelle une connexion peut être réutilisée. Si la valeur est 0, les connexions sont réutilisées pour toujours.", - "content-max-open": "Le nombre maximal de connexions ouvertes à la base de données. Si <1>Connexions inactives maximales est supérieur à 0 et que <3>Connexions ouvertes maximales est inférieur à <5>Connexions inactives maximales, alors <7>Connexions inactives maximales sera réduit pour correspondre à la limite de <9>Connexions ouvertes maximales. Si la valeur est 0, il n’y a pas de limite quant au nombre de connexions ouvertes.", + "content-max-open": "", "max-idle": "Inactivité maximale", "max-lifetime": "Durée de vie maximale", "max-open": "Ouverture maximale", @@ -54,7 +54,7 @@ } }, "query-header": { - "content-invalid-query": "Votre requête n’est pas valide. Vérifiez ci-dessous pour en savoir plus. <1>Cependant, vous pouvez toujours exécuter cette requête.", + "content-invalid-query": "", "editor-modes": { "label-builder": "Builder", "label-code": "Code" @@ -76,7 +76,7 @@ "tooltip-format-query": "Requête de format" }, "query-validator": { - "query-will-process": "<0> Cette requête traitera <2>{{bytes}} lors de son exécution.", + "query-will-process": "", "validating-query": "Validation de la requête..." }, "raw-editor": { diff --git a/packages/grafana-sql/src/locales/hu-HU/grafana-sql.json b/packages/grafana-sql/src/locales/hu-HU/grafana-sql.json index 2f48efc048e..a5f7f0b2996 100644 --- a/packages/grafana-sql/src/locales/hu-HU/grafana-sql.json +++ b/packages/grafana-sql/src/locales/hu-HU/grafana-sql.json @@ -11,10 +11,10 @@ }, "connection-limits": { "auto-max-idle": "Inaktív automatikus maximális száma", - "content-auto-max-idle": "Ha engedélyezve van, automatikusan beállítja az <1>Inaktív kapcsolatok maximális száma értéket a <3>Megnyitott kapcsolatok maximális száma értékére. Ha a nyitott kapcsolatok maximális száma nincs beállítva, akkor az alapértelmezett értékre lesz beállítva ({{defaultMaxIdle}}).", - "content-max-idle": "Az inaktív kapcsolatok készletében lévő kapcsolatok maximális száma. Ha a <1>Megnyitott kapcsolatok maximális száma nagyobb, mint 0, de kisebb, mint az <3>Inaktív kapcsolatok maximális száma, akkor az <5>Inaktív kapcsolatok maximális száma csökken, hogy megfeleljen a <8>Megnyitott kapcsolatok maximális száma határértékének. Ha 0-ra van állítva, akkor egyetlen inaktív kapcsolat sem marad meg.", + "content-auto-max-idle": "", + "content-max-idle": "", "content-max-lifetime": "A csatlakozás újrafelhasználásának maximális időtartama másodpercben. Ha 0-ra van állítva, a kapcsolatok újrafelhasználása végtelen.", - "content-max-open": "Az adatbázishoz irányuló nyitott kapcsolatok maximális száma. Ha az <1>Inaktív kapcsolatok maximális száma nagyobb, mint 0, és a <3>Megnyitott kapcsolatok maximális száma kisebb, mint az <5>Inaktív kapcsolatok maximális száma, akkor az <7>Inaktív kapcsolatok maximális száma csökken, hogy megfeleljen a <9>Megnyitott kapcsolatok maximális száma határértékének. Ha 0-ra van állítva, akkor nincs korlátozva a nyitott kapcsolatok száma.", + "content-max-open": "", "max-idle": "Max. inaktív", "max-lifetime": "Max. élettartam", "max-open": "Max. nyitott", @@ -54,7 +54,7 @@ } }, "query-header": { - "content-invalid-query": "A lekérdezés érvénytelen. A részleteket tekintse meg alább. <1>Ezt a lekérdezést azonban továbbra is futtathatja.", + "content-invalid-query": "", "editor-modes": { "label-builder": "Építő", "label-code": "Kód" @@ -76,7 +76,7 @@ "tooltip-format-query": "Lekérdezés formázása" }, "query-validator": { - "query-will-process": "<0> Ez a lekérdezés <2>{{bytes}} feldolgozását végzi futtatáskor.", + "query-will-process": "", "validating-query": "Lekérdezés érvényesítése…" }, "raw-editor": { diff --git a/packages/grafana-sql/src/locales/id-ID/grafana-sql.json b/packages/grafana-sql/src/locales/id-ID/grafana-sql.json index 7d4256c43eb..e0233f65172 100644 --- a/packages/grafana-sql/src/locales/id-ID/grafana-sql.json +++ b/packages/grafana-sql/src/locales/id-ID/grafana-sql.json @@ -11,10 +11,10 @@ }, "connection-limits": { "auto-max-idle": "Nonaktif maksimum otomatis", - "content-auto-max-idle": "Jika diaktifkan, secara otomatis atur jumlah <1>Koneksi nonaktif maksimum ke nilai yang sama dengan<3> Koneksi terbuka maksimum. Jika jumlah maksimum koneksi terbuka tidak diatur, jumlah tersebut akan diatur ke default ({{defaultMaxIdle}}).", - "content-max-idle": "Jumlah maksimum koneksi dalam pool koneksi nonaktif. Jika <1>Koneksi terbuka maksimum lebih besar dari 0 tetapi kurang dari <3>Koneksi nonaktif maksimum, maka <5>Koneksi nonaktif maksimum akan dikurangi agar sesuai dengan batas <8>Koneksi terbuka maksimum. Jika diatur ke 0, tidak ada koneksi nonaktif yang dipertahankan.", + "content-auto-max-idle": "", + "content-max-idle": "", "content-max-lifetime": "Jumlah waktu maksimum dalam detik untuk menggunakan koneksi lagi. Jika diatur ke 0, koneksi digunakan kembali terus-menerus tanpa batas waktu.", - "content-max-open": "Jumlah koneksi terbuka maksimum ke basis data. Jika <1>Koneksi nonaktif maksimum lebih besar dari 0 dan <3>Koneksi terbuka maksimum kurang dari <5>Koneksi nonaktif maksimum, maka <7>Koneksi nonaktif maksimum akan dikurangi agar sesuai dengan batas <9>Koneksi terbuka maksimum. Jika diatur ke 0, tidak ada batasan jumlah koneksi terbuka.", + "content-max-open": "", "max-idle": "Nonaktif maks", "max-lifetime": "Periode maks", "max-open": "Terbuka maks", @@ -54,7 +54,7 @@ } }, "query-header": { - "content-invalid-query": "Kueri Anda tidak valid. Periksa di bawah ini untuk detailnya. <1>Namun, Anda masih dapat menjalankan kueri ini.", + "content-invalid-query": "", "editor-modes": { "label-builder": "Pembangun", "label-code": "Kode" @@ -76,7 +76,7 @@ "tooltip-format-query": "Format kueri" }, "query-validator": { - "query-will-process": "<0> Kueri ini akan memproses <2>{{bytes}} saat dijalankan.", + "query-will-process": "", "validating-query": "Memvalidasi kueri..." }, "raw-editor": { diff --git a/packages/grafana-sql/src/locales/it-IT/grafana-sql.json b/packages/grafana-sql/src/locales/it-IT/grafana-sql.json index 7197432881f..47e8e35fb00 100644 --- a/packages/grafana-sql/src/locales/it-IT/grafana-sql.json +++ b/packages/grafana-sql/src/locales/it-IT/grafana-sql.json @@ -11,10 +11,10 @@ }, "connection-limits": { "auto-max-idle": "Inattività massima automatica", - "content-auto-max-idle": "Se abilitato, imposta automaticamente il numero di <1>Connessioni inattive massime sullo stesso valore di <3> Connessioni aperte massime. Se il numero massimo di connessioni aperte non è impostato, verrà impostato sul valore predefinito ({{defaultMaxIdle}}).", - "content-max-idle": "Il numero massimo di connessioni nel pool di connessioni inattive. Se <1>Connessioni aperte massine è maggiore di 0 ma inferiore a <3>Connessioni inattive massime, le <5>Connessioni inattive massime verranno ridotte per corrispondere al limite di <8>Connessioni aperte massime. Se impostato su 0, non viene mantenuta alcuna connessione inattiva.", + "content-auto-max-idle": "", + "content-max-idle": "", "content-max-lifetime": "La quantità massima di tempo in secondi in cui una connessione può essere riutilizzata. Se impostato su 0, le connessioni vengono riutilizzate per sempre.", - "content-max-open": "Il numero massimo di connessioni aperte al database. Se <1>Connessioni inattive massime è maggiore di 0 e <3>Connessioni aperte massime è inferiore a <5>Connessioni inattive massime, <7>Connessioni inattive massime verrà ridotto affinché corrisponda al limite di <9>Connessioni aperte massime. Se impostato su 0, non vi è alcun limite al numero di connessioni aperte.", + "content-max-open": "", "max-idle": "Inattive massime", "max-lifetime": "Durata massima", "max-open": "Aperte massime", @@ -54,7 +54,7 @@ } }, "query-header": { - "content-invalid-query": "Query non valida. Controlla qui sotto per i dettagli. <1>Tuttavia, puoi comunque eseguire questa query.", + "content-invalid-query": "", "editor-modes": { "label-builder": "Builder", "label-code": "Codice" @@ -76,7 +76,7 @@ "tooltip-format-query": "Formato query" }, "query-validator": { - "query-will-process": "<0> Questa query elabora <2>{{bytes}} quando viene eseguita.", + "query-will-process": "", "validating-query": "Convalida della query in corso..." }, "raw-editor": { diff --git a/packages/grafana-sql/src/locales/ja-JP/grafana-sql.json b/packages/grafana-sql/src/locales/ja-JP/grafana-sql.json index 5aaeb7a6783..8ddb12b79d9 100644 --- a/packages/grafana-sql/src/locales/ja-JP/grafana-sql.json +++ b/packages/grafana-sql/src/locales/ja-JP/grafana-sql.json @@ -11,10 +11,10 @@ }, "connection-limits": { "auto-max-idle": "自動最大アイドル", - "content-auto-max-idle": "有効にすると、<1>最大アイドル接続数が<3>最大オープン接続数と同じ値に自動設定されます。最大オープン接続数が設定されていない場合、デフォルト({{defaultMaxIdle}})に設定されます。", - "content-max-idle": "アイドル接続プールの最大接続数。<1>最大オープン接続数が0より大きく<3>最大アイドル接続数より小さい場合、<5>最大アイドル接続数は<8>最大オープン接続数の制限に合わせて削減されます。0に設定すると、アイドル接続は保持されません。", + "content-auto-max-idle": "", + "content-max-idle": "", "content-max-lifetime": "接続を再利用できる最大時間(秒)。0に設定すると、接続は永続的に再利用されます。", - "content-max-open": "データベースへの最大オープン接続数。<1>最大アイドル接続数が0より大きく<3>最大オープン接続数が<5>最大アイドル接続数より小さい場合、<7>最大アイドル接続数は<9>最大オープン接続数の制限に合わせて削減されます。0に設定すると、オープン接続数に制限はありません。", + "content-max-open": "", "max-idle": "最大アイドル", "max-lifetime": "最大有効期間", "max-open": "最大オープン", @@ -54,7 +54,7 @@ } }, "query-header": { - "content-invalid-query": "クエリが無効です。詳細は下記をご確認ください。<1>ただし、このクエリは引き続き実行できます。", + "content-invalid-query": "", "editor-modes": { "label-builder": "ビルダー", "label-code": "コード" @@ -76,7 +76,7 @@ "tooltip-format-query": "クエリをフォーマット" }, "query-validator": { - "query-will-process": "<0>このクエリは実行時に<2>{{bytes}}を処理します。", + "query-will-process": "", "validating-query": "クエリを検証中..." }, "raw-editor": { diff --git a/packages/grafana-sql/src/locales/ko-KR/grafana-sql.json b/packages/grafana-sql/src/locales/ko-KR/grafana-sql.json index 61248514907..564cb59dc6b 100644 --- a/packages/grafana-sql/src/locales/ko-KR/grafana-sql.json +++ b/packages/grafana-sql/src/locales/ko-KR/grafana-sql.json @@ -11,10 +11,10 @@ }, "connection-limits": { "auto-max-idle": "자동 최대 유휴", - "content-auto-max-idle": "활성화하면, <1>유휴 연결 수 최대 한도를 <3>열린 연결 수 최대 한도와 동일한 값으로 자동 설정합니다. 열린 연결 수 최대 한도를 설정하지 않으면, 기본값({{defaultMaxIdle}})으로 설정됩니다.", - "content-max-idle": "유휴 연결 풀의 연결 최대 한도입니다. <1>열린 연결 최대 한도가 0보다 크지만 <3>유휴 연결 최대 한도보다 작으면, <5>유휴 연결 최대 한도가 <8>열린 연결 최대 한도에 맞춰 감소합니다. 0으로 설정된 경우, 유휴 연결이 유지되지 않습니다.", + "content-auto-max-idle": "", + "content-max-idle": "", "content-max-lifetime": "연결을 재사용할 수 있는 최대 시간(초)입니다. 0으로 설정하면, 연결이 영구적으로 재사용됩니다.", - "content-max-open": "데이터베이스에 대한 열린 연결 최대 한도입니다. <1>유휴 연결 최대 한도가 0보다 크고 <3>열린 연결 최대 한도가 <5>유휴 연결 최대 한도보다 작으면, <7>유휴 연결 최대 한도가 <9>열린 연결 최대 한도와 일치하도록 감소합니다. 0으로 설정하면, 열린 연결 수에 제한이 없습니다.", + "content-max-open": "", "max-idle": "유휴 최대 한도", "max-lifetime": "최대 수명 기간", "max-open": "열 한도", @@ -54,7 +54,7 @@ } }, "query-header": { - "content-invalid-query": "쿼리가 유효하지 않습니다. 자세한 내용은 아래에서 확인하세요. <1>하지만 이 쿼리는 계속 실행할 수 있습니다.", + "content-invalid-query": "", "editor-modes": { "label-builder": "빌더", "label-code": "코드" @@ -76,7 +76,7 @@ "tooltip-format-query": "형식 쿼리" }, "query-validator": { - "query-will-process": "<0> 이 쿼리는 실행 시 <2>{{bytes}}를 처리합니다.", + "query-will-process": "", "validating-query": "쿼리 유효성 검사 중..." }, "raw-editor": { diff --git a/packages/grafana-sql/src/locales/nl-NL/grafana-sql.json b/packages/grafana-sql/src/locales/nl-NL/grafana-sql.json index 4860e9bd054..a13866b5e35 100644 --- a/packages/grafana-sql/src/locales/nl-NL/grafana-sql.json +++ b/packages/grafana-sql/src/locales/nl-NL/grafana-sql.json @@ -11,10 +11,10 @@ }, "connection-limits": { "auto-max-idle": "Automatisch maximaal inactief", - "content-auto-max-idle": "Indien ingeschakeld, stel je het aantal <1>Maximale inactieve verbindingen automatisch in op dezelfde waarde als<3> Max open verbindingen. Als het aantal maximale open verbindingen niet is ingesteld, wordt dit ingesteld op de standaardwaarde ({{defaultMaxIdle}}).", - "content-max-idle": "Het maximale aantal verbindingen in de inactieve verbindingspool. Als <1>Max open verbindingen groter is dan 0 maar kleiner dan de <3>Max inactieve verbindingen, dan worden de <5>Max inactieve verbindingen verminderd om overeen te komen met de limiet <8>Max open verbindingen. Indien ingesteld op 0, blijven er geen inactieve verbindingen behouden.", + "content-auto-max-idle": "", + "content-max-idle": "", "content-max-lifetime": "De maximale hoeveelheid tijd in seconden dat een verbinding opnieuw kan worden gebruikt. Indien ingesteld op 0, worden verbindingen voor altijd hergebruikt.", - "content-max-open": "Het maximale aantal open verbindingen met de database. Als <1>Max inactieve verbindingen groter is dan 0 en de <3>Max open verbindingen kleiner is dan <5>Max inactieve verbindingen, dan wordt <7>Max inactieve verbindingen verminderd om overeen te komen met de limiet <9>Max open verbindingen. Indien ingesteld op 0, is er geen limiet op het aantal open verbindingen.", + "content-max-open": "", "max-idle": "Max. inactief", "max-lifetime": "Max. levensduur", "max-open": "Max. open", @@ -54,7 +54,7 @@ } }, "query-header": { - "content-invalid-query": "Je query is ongeldig. Kijk hieronder voor meer informatie. <1>Je kunt deze query echter nog steeds uitvoeren.", + "content-invalid-query": "", "editor-modes": { "label-builder": "Bouwer", "label-code": "Code" @@ -76,7 +76,7 @@ "tooltip-format-query": "Query-formaat" }, "query-validator": { - "query-will-process": "<0> Deze query zal <2>{{bytes}} verwerken wanneer deze wordt uitgevoerd.", + "query-will-process": "", "validating-query": "Query valideren..." }, "raw-editor": { diff --git a/packages/grafana-sql/src/locales/pl-PL/grafana-sql.json b/packages/grafana-sql/src/locales/pl-PL/grafana-sql.json index 677637715ce..96338ff59d8 100644 --- a/packages/grafana-sql/src/locales/pl-PL/grafana-sql.json +++ b/packages/grafana-sql/src/locales/pl-PL/grafana-sql.json @@ -11,10 +11,10 @@ }, "connection-limits": { "auto-max-idle": "Automatyczny maksymalny czas bezczynności", - "content-auto-max-idle": "Jeśli ta opcja jest włączona, automatycznie ustawia <1>maksymalną liczbę bezczynnych połączeń na tę samą wartość, co <3>maksymalna liczba otwartych połączeń. Jeśli maksymalna liczba otwartych połączeń nie jest określona, zostanie ustawiona wartość domyślna ({{defaultMaxIdle}}).", - "content-max-idle": "Maksymalna liczba połączeń w puli bezczynnych połączeń. Jeśli <1>maksymalna liczba otwartych połączeń jest większa niż 0, ale mniejsza niż <3>maksymalna liczba bezczynnych połączeń, to <5>maksymalna liczba bezczynnych połączeń zostanie zmniejszona, aby dopasować ją do limitu <8>maksymalnej liczby otwartych połączeń. Jeśli ustawiono wartość 0, nie są zachowywane żadne bezczynne połączenia.", + "content-auto-max-idle": "", + "content-max-idle": "", "content-max-lifetime": "Maksymalny czas w sekundach, przez który połączenie może być ponownie użyte. Jeśli ustawiono wartość 0, połączenia są ponownie wykorzystywane bez daty zakończenia.", - "content-max-open": "Maksymalna liczba otwartych połączeń z bazą danych. Jeśli <1>maksymalna liczba bezczynnych połączeń jest większa niż 0, a <3>maksymalna liczba otwartych połączeń jest mniejsza niż <5>maksymalna liczba bezczynnych połączeń, to <7>maksymalna liczba bezczynnych połączeń zostanie zmniejszona, aby dopasować ją do limitu <9>maksymalnej liczby otwartych połączeń. Jeśli ustawiono wartość 0, liczba otwartych połączeń nie jest ograniczona.", + "content-max-open": "", "max-idle": "Maks. czas bezczynności", "max-lifetime": "Maks. czas istnienia", "max-open": "Maks. czas otwarcia", @@ -54,7 +54,7 @@ } }, "query-header": { - "content-invalid-query": "Zapytanie jest nieprawidłowe. Szczegóły znajdziesz poniżej. <1>Nadal jednak możesz uruchomić to zapytanie.", + "content-invalid-query": "", "editor-modes": { "label-builder": "Konstruktor", "label-code": "Kod" @@ -76,7 +76,7 @@ "tooltip-format-query": "Formatuj zapytanie" }, "query-validator": { - "query-will-process": "<0> To zapytanie przetworzy <2>{{bytes}} po uruchomieniu.", + "query-will-process": "", "validating-query": "Sprawdzanie poprawności zapytania…" }, "raw-editor": { diff --git a/packages/grafana-sql/src/locales/pt-BR/grafana-sql.json b/packages/grafana-sql/src/locales/pt-BR/grafana-sql.json index d897588a416..d36a0b4868a 100644 --- a/packages/grafana-sql/src/locales/pt-BR/grafana-sql.json +++ b/packages/grafana-sql/src/locales/pt-BR/grafana-sql.json @@ -11,10 +11,10 @@ }, "connection-limits": { "auto-max-idle": "Inatividade máxima automática", - "content-auto-max-idle": "Se ativado, define automaticamente o número <1>Máximo de conexões ociosas para o mesmo valor que o<3> Máximo de conexões abertas. Se o número máximo de conexões abertas não estiver definido, ele será definido de acordo com o padrão ({{defaultMaxIdle}}).", - "content-max-idle": "O número máximo de conexões no grupo de conexões ociosas. Se o <1>Máximo de conexões abertas for maior que 0, mas menor que o <3>Máximo de conexões ociosas, o <5>Máximo de conexões ociosas será reduzido para corresponder ao limite do <8>Máximo de conexões abertas. Se estiver definido como 0, nenhuma conexão ociosa será mantida.", + "content-auto-max-idle": "", + "content-max-idle": "", "content-max-lifetime": "A quantidade máxima de tempo em segundos que uma conexão pode ser reutilizada. Se estiver definido como 0, as conexões serão reutilizadas indefinidamente.", - "content-max-open": "O número máximo de conexões abertas com o banco de dados. Se o <1>Máximo de conexões ociosas for maior que 0 e o <3>Máximo de conexões abertas for menor que o <5>Máximo de conexões ociosas, o <7>Máximo de conexões ociosas será reduzido para corresponder ao limite do <9>Máximo de conexões abertas. Se estiver definido como 0, não haverá limite para o número de conexões abertas.", + "content-max-open": "", "max-idle": "Máximo de ociosidade", "max-lifetime": "Tempo de vida máximo", "max-open": "Máximo de aberturas", @@ -54,7 +54,7 @@ } }, "query-header": { - "content-invalid-query": "Sua consulta é inválida. Confira abaixo para saber mais. <1>No entanto, você ainda pode executar esta consulta.", + "content-invalid-query": "", "editor-modes": { "label-builder": "Construtor", "label-code": "Código" @@ -76,7 +76,7 @@ "tooltip-format-query": "Formatar consulta" }, "query-validator": { - "query-will-process": "<0> Esta consulta processará <2>{{bytes}} ao ser executada.", + "query-will-process": "", "validating-query": "Validando consulta…" }, "raw-editor": { diff --git a/packages/grafana-sql/src/locales/pt-PT/grafana-sql.json b/packages/grafana-sql/src/locales/pt-PT/grafana-sql.json index ced6291980a..0f33de74f02 100644 --- a/packages/grafana-sql/src/locales/pt-PT/grafana-sql.json +++ b/packages/grafana-sql/src/locales/pt-PT/grafana-sql.json @@ -11,10 +11,10 @@ }, "connection-limits": { "auto-max-idle": "Ralenti máximo automático", - "content-auto-max-idle": "Se ativado, defina automaticamente o número de <1>Ligações de ralenti máximas para o mesmo valor que<3> Ligações abertas máximas. Se o número de ligações abertas máximas não estiver definido, será definido para a predefinição ({{defaultMaxIdle}}).", - "content-max-idle": "O número máximo de ligações no conjunto de ligações de ralenti. Se <1>Ligações abertas máximas for maior que 0, mas menor que as <3>Ligações de ralenti máximas, então as <5>Ligações de ralenti máximas serão reduzidas para corresponder ao limite de <8>Ligações abertas máximas. Se definido para 0, nenhuma ligação de ralenti será retida.", + "content-auto-max-idle": "", + "content-max-idle": "", "content-max-lifetime": "A quantidade máxima de tempo em segundos que uma ligação pode ser reutilizada. Se definido para 0, as ligações serão reutilizadas para sempre.", - "content-max-open": "O número máximo de ligações abertas à base de dados. Se <1>Ligações de ralenti máximas for maior que 0 e as <3>Ligações abertas máximas for menor que <5>Ligações de ralenti máximas, então <7>Ligações de ralenti máximas serão reduzidas para corresponder ao limite de <9>Ligações abertas máximas. Se definido para 0, não há limite para o número de ligações abertas.", + "content-max-open": "", "max-idle": "Ralenti máx.", "max-lifetime": "Tempo de vida máximo", "max-open": "Aberturas máx.", @@ -54,7 +54,7 @@ } }, "query-header": { - "content-invalid-query": "A sua consulta é inválida. Verifique abaixo para obter detalhes. <1>No entanto, ainda pode executar esta consulta.", + "content-invalid-query": "", "editor-modes": { "label-builder": "Construtor", "label-code": "Cód." @@ -76,7 +76,7 @@ "tooltip-format-query": "Formatar consulta" }, "query-validator": { - "query-will-process": "<0> Esta consulta processará <2>{{bytes}} quando for executada.", + "query-will-process": "", "validating-query": "A validar consulta..." }, "raw-editor": { diff --git a/packages/grafana-sql/src/locales/ru-RU/grafana-sql.json b/packages/grafana-sql/src/locales/ru-RU/grafana-sql.json index 3e71d2e580d..00b5a7fdd64 100644 --- a/packages/grafana-sql/src/locales/ru-RU/grafana-sql.json +++ b/packages/grafana-sql/src/locales/ru-RU/grafana-sql.json @@ -11,10 +11,10 @@ }, "connection-limits": { "auto-max-idle": "Автоматический максимум неактивных подключений", - "content-auto-max-idle": "Если этот параметр включен, параметр <1>Макс. кол-во неактивных подключений автоматически устанавливается на значение параметра <3> Макс. кол-во открытых подключений. Если максимальное количество открытых подключений не установлено, используется значение по умолчанию ({{defaultMaxIdle}}).", - "content-max-idle": "Максимальное количество подключений в пуле неактивных подключений. Если значение параметра <1>Макс. кол-во открытых подключений больше 0, но меньше значения <3>Макс. кол-во неактивных подключений, то значение <5>Макс. кол-во неактивных подключений уменьшается, чтобы соответствовать предельному значению параметра <8>Макс. кол-во открытых подключений. Если установлено значение 0, неактивные подключения не сохраняются.", + "content-auto-max-idle": "", + "content-max-idle": "", "content-max-lifetime": "Максимальное время (в секундах), в течение которого подключение может быть использовано повторно. Если установлено значение 0, подключения всегда используются повторно.", - "content-max-open": "Максимальное количество открытых подключений к базе данных. Если значение параметра <1>Макс. кол-во неактивных подключений больше 0, а значение параметра <3>Макс. кол-во открытых подключений меньше значения <5>Макс. кол-во неактивных подключений, то значение <7>Макс. кол-во неактивных подключений уменьшается, чтобы соответствовать предельному значению параметра <9>Макс. кол-во открытых подключений. Если установлено значение 0, количество открытых подключений не ограничено.", + "content-max-open": "", "max-idle": "Макс. кол-во неактивных подключений", "max-lifetime": "Макс. время жизни", "max-open": "Макс. кол-во открытых подключений", @@ -54,7 +54,7 @@ } }, "query-header": { - "content-invalid-query": "Недействительный запрос. См. подробности ниже. <1>Однако вы всё равно можете выполнить этот запрос.", + "content-invalid-query": "", "editor-modes": { "label-builder": "Конструктор", "label-code": "Код" @@ -76,7 +76,7 @@ "tooltip-format-query": "Форматировать запрос" }, "query-validator": { - "query-will-process": "<0> При выполнении запрос обработает <2>{{bytes}}.", + "query-will-process": "", "validating-query": "Проверка запроса..." }, "raw-editor": { diff --git a/packages/grafana-sql/src/locales/sv-SE/grafana-sql.json b/packages/grafana-sql/src/locales/sv-SE/grafana-sql.json index 9533bd6afc4..b334629c2cb 100644 --- a/packages/grafana-sql/src/locales/sv-SE/grafana-sql.json +++ b/packages/grafana-sql/src/locales/sv-SE/grafana-sql.json @@ -11,10 +11,10 @@ }, "connection-limits": { "auto-max-idle": "Automatisk max. inaktiv", - "content-auto-max-idle": "Om det är aktiverat ställer du automatiskt in antalet <1>Maximalt antal inaktiva anslutningar till samma värde som<3> Max öppna anslutningar. Om antalet maximala öppna anslutningar inte är inställt kommer det att ställas in på standard ({{defaultMaxIdle}}).", - "content-max-idle": "Det maximala antalet anslutningar i den inaktiva anslutningspoolen. Om <1>Max öppna anslutningar är större än 0 men mindre än <3>Max inaktiva anslutningar kommer <5>Max inaktiva anslutningar att reduceras för att matcha gränsen för <8>Max öppna anslutningar. Om inställningen är 0 behålls inga inaktiva anslutningar.", + "content-auto-max-idle": "", + "content-max-idle": "", "content-max-lifetime": "Den maximala tiden i sekunder som en anslutning kan återanvändas. Om inställningen är 0 återanvänds anslutningarna för evigt.", - "content-max-open": "Det maximala antalet öppna anslutningar till databasen. Om <1>Max inaktiva anslutningar är större än 0 och <3>Max öppna anslutningar är mindre än <5>Max inaktiva anslutningar kommer <7>Max inaktiva anslutningar att reduceras för att matcha gränsen för <9>Max öppna anslutningar. Om inställningen är 0 finns det ingen gräns för antalet öppna anslutningar.", + "content-max-open": "", "max-idle": "Max inaktiv", "max-lifetime": "Max livstid", "max-open": "Max öppen", @@ -54,7 +54,7 @@ } }, "query-header": { - "content-invalid-query": "Din fråga är ogiltig. Se nedan för mer information. <1>Du kan däremot fortfarande köra denna fråga.", + "content-invalid-query": "", "editor-modes": { "label-builder": "Builder", "label-code": "Kod" @@ -76,7 +76,7 @@ "tooltip-format-query": "Formatera fråga" }, "query-validator": { - "query-will-process": "<0> Den här frågan kommer att behandla <2>{{bytes}} när den körs.", + "query-will-process": "", "validating-query": "Validerar frågan …" }, "raw-editor": { diff --git a/packages/grafana-sql/src/locales/tr-TR/grafana-sql.json b/packages/grafana-sql/src/locales/tr-TR/grafana-sql.json index 873565bc5d1..79a6c8bf2dd 100644 --- a/packages/grafana-sql/src/locales/tr-TR/grafana-sql.json +++ b/packages/grafana-sql/src/locales/tr-TR/grafana-sql.json @@ -11,10 +11,10 @@ }, "connection-limits": { "auto-max-idle": "Otomatik maksimum boşta bağlantı sayısı", - "content-auto-max-idle": "Etkinleştirilirse <1>Maksimum boşta bağlantı sayısı, <3>Maksimum açık bağlantı sayısıyla aynı değere otomatik olarak ayarlanır. Maksimum açık bağlantı sayısı ayarlanmamışsa varsayılan değere ayarlanır ({{defaultMaxIdle}}).", - "content-max-idle": "Bu, boşta bağlantı havuzundaki maksimum bağlantı sayısını belirtir. <1>Maksimum açık bağlantı değeri 0'dan büyük ancak <3>Maksimum boşta bağlantı değerinden küçükse <5>Maksimum boşta bağlantı sayısı, <8>Maksimum açık bağlantı sınırına uyacak şekilde azaltılır. 0 olarak ayarlanırsa boşta bağlantılar tutulmaz.", + "content-auto-max-idle": "", + "content-max-idle": "", "content-max-lifetime": "Saniye cinsinden bir bağlantının yeniden kullanılabileceği maksimum süre. 0 olarak ayarlanırsa bağlantılar süresiz olarak yeniden kullanılır.", - "content-max-open": "Veri tabanına açılabilecek maksimum açık bağlantı sayısı. <1>Maksimum boşta bağlantı sayısı 0'dan büyük ve <3>Maksimum açık bağlantı sayısı <5>Maksimum boşta bağlantı sayısından küçükse <7>Maksimum boşta bağlantı değeri, <9>Maksimum açık bağlantı sınırına uyacak şekilde azaltılır. 0 olarak ayarlanırsa açık bağlantı sayısı için bir sınır yoktur.", + "content-max-open": "", "max-idle": "Maks. boşta", "max-lifetime": "Maksimum kullanım süresi", "max-open": "Maks. açık", @@ -54,7 +54,7 @@ } }, "query-header": { - "content-invalid-query": "Sorgunuz geçersiz. Ayrıntılar için aşağıya bakın. <1>Ancak yine de bu sorguyu çalıştırabilirsiniz.", + "content-invalid-query": "", "editor-modes": { "label-builder": "Oluşturucu", "label-code": "Kod" @@ -76,7 +76,7 @@ "tooltip-format-query": "Sorguyu biçimlendir" }, "query-validator": { - "query-will-process": "<0> Bu sorgu çalıştırıldığında <2>{{bytes}} işlenecek.", + "query-will-process": "", "validating-query": "Sorgu doğrulanıyor..." }, "raw-editor": { diff --git a/packages/grafana-sql/src/locales/zh-Hans/grafana-sql.json b/packages/grafana-sql/src/locales/zh-Hans/grafana-sql.json index 296562625e3..0bc830cb365 100644 --- a/packages/grafana-sql/src/locales/zh-Hans/grafana-sql.json +++ b/packages/grafana-sql/src/locales/zh-Hans/grafana-sql.json @@ -11,10 +11,10 @@ }, "connection-limits": { "auto-max-idle": "自动最大空闲", - "content-auto-max-idle": "如果启用,则自动将<1>最大空闲连接数的数字设置为与<3>最大打开连接数相同的值。如果未设置最大打开连接数的数字,则将其设置为默认值 ({{defaultMaxIdle}})。", - "content-max-idle": "空闲连接池中的最大连接数。如果<1>最大打开连接数大于 0 但小于<3>最大空闲连接数,则<5>最大空闲连接数将减少以匹配<8>最大打开连接数限制。如果设置为 0,则不保留任何空闲连接。", + "content-auto-max-idle": "", + "content-max-idle": "", "content-max-lifetime": "连接可以重复使用的最长时间(秒)。如果设置为 0,则连接将永久重复使用。", - "content-max-open": "数据库的最大打开连接数。如果<1>最大空闲连接数大于 0 且<3>最大打开连接数小于<5>最大空闲连接数,则<7>最大空闲连接数将减少以匹配<9>最大打开连接数限制。如果设置为 0,则对打开的连接数没有限制。", + "content-max-open": "", "max-idle": "最大空闲", "max-lifetime": "最大生命周期", "max-open": "最大打开", @@ -54,7 +54,7 @@ } }, "query-header": { - "content-invalid-query": "您的查询无效。请查看下方详情。<1>但是,您仍然可以运行此查询。", + "content-invalid-query": "", "editor-modes": { "label-builder": "构建器", "label-code": "代码" @@ -76,7 +76,7 @@ "tooltip-format-query": "格式化查询" }, "query-validator": { - "query-will-process": "<0> 此查询将在运行时处理 <2>{{bytes}}。", + "query-will-process": "", "validating-query": "正在验证查询..." }, "raw-editor": { diff --git a/packages/grafana-sql/src/locales/zh-Hant/grafana-sql.json b/packages/grafana-sql/src/locales/zh-Hant/grafana-sql.json index f09f0f3dcfd..e093a0c927f 100644 --- a/packages/grafana-sql/src/locales/zh-Hant/grafana-sql.json +++ b/packages/grafana-sql/src/locales/zh-Hant/grafana-sql.json @@ -11,10 +11,10 @@ }, "connection-limits": { "auto-max-idle": "自動最大閒置時間", - "content-auto-max-idle": "若啟用,<1>最大閒置連線數的數量將會自動設定為與<3>最大開啟連線數相同的數值。如果未設定最大開啟連線數,則將設定為預設值 ({{defaultMaxIdle}})。", - "content-max-idle": "閒置連線池中的最大連線數。若<1>最大開啟連線數大於 0,但小於 <3>最大閒置連線數,則<5>最大閒置連線數將會縮減,以符合<8>最大開啟連線數限制。若設定為 0,則不會保留任何閒置連線。", + "content-auto-max-idle": "", + "content-max-idle": "", "content-max-lifetime": "可以重複使用連線的最長時間(秒)。若設定為 0,則會永遠重複使用連線。", - "content-max-open": "資料庫的最大開啟連線數。若<1>最大閒置連線數大於 0,且<3>最大開啟連線數小於<5>最大閒置連線數,則<7>最大閒置連線數將會縮減,以符合<9>最大開啟連線數限制。若設定為 0,則不會限制開啟連線數。", + "content-max-open": "", "max-idle": "最大閒置", "max-lifetime": "最大存活期", "max-open": "最大開啟數量", @@ -54,7 +54,7 @@ } }, "query-header": { - "content-invalid-query": "您的查詢無效。請參閱下方詳細資訊。<1>不過,您仍然可以執行此查詢。", + "content-invalid-query": "", "editor-modes": { "label-builder": "建立器", "label-code": "代碼" @@ -76,7 +76,7 @@ "tooltip-format-query": "格式化查詢" }, "query-validator": { - "query-will-process": "<0>此查詢將在執行時處理 <2>{{bytes}}。", + "query-will-process": "", "validating-query": "正在驗證查詢…" }, "raw-editor": { diff --git a/public/app/plugins/datasource/azuremonitor/locales/cs-CZ/grafana-azure-monitor-datasource.json b/public/app/plugins/datasource/azuremonitor/locales/cs-CZ/grafana-azure-monitor-datasource.json index 0a0c7eafbba..c894f2b6066 100644 --- a/public/app/plugins/datasource/azuremonitor/locales/cs-CZ/grafana-azure-monitor-datasource.json +++ b/public/app/plugins/datasource/azuremonitor/locales/cs-CZ/grafana-azure-monitor-datasource.json @@ -13,11 +13,11 @@ "label-resource-group": "Skupina zdrojů", "label-resource-name": "Název zdroje", "label-resource-number": "Zdroj {{resourceNum}}", - "label-resource-uri": "URI zdroje ", + "label-resource-uri": "", "label-subscription": "Předplatné", "placeholder-resource-name": "název", "tooltip-region": "Oblast kódu zdroje. Volitelné pro jeden zdroj, ale povinné při výběru více zdrojů.", - "tooltip-resource-uri": "Ručně upravte <2>identifikátor URI zdroje. Podporuje použití více proměnných šablony (např.: /subscriptions/$subId/resourceGroups/$rg)" + "tooltip-resource-uri": "" }, "aggregate-item": { "aria-label-aggregate-function": "Funkce agregování", @@ -68,7 +68,7 @@ }, "basic-logs-toggle": { "aria-label-enable-basic-logs": "Základní protokoly", - "description-basic-logs": "Povolení této funkce zapříčiní vznik nákladů Azure Monitor na dotaz na panelech nástěnek, které dotazují tabulky nakonfigurované pro <2>základní protokoly.", + "description-basic-logs": "", "label-enable-basic-logs": "Povolit základní protokoly" }, "config-editor": { diff --git a/public/app/plugins/datasource/azuremonitor/locales/de-DE/grafana-azure-monitor-datasource.json b/public/app/plugins/datasource/azuremonitor/locales/de-DE/grafana-azure-monitor-datasource.json index c4d4d8b375a..9c4d21c9645 100644 --- a/public/app/plugins/datasource/azuremonitor/locales/de-DE/grafana-azure-monitor-datasource.json +++ b/public/app/plugins/datasource/azuremonitor/locales/de-DE/grafana-azure-monitor-datasource.json @@ -13,11 +13,11 @@ "label-resource-group": "Ressourcengruppe", "label-resource-name": "Ressourcenname", "label-resource-number": "Ressource {{resourceNum}}", - "label-resource-uri": "Ressourcen-URI(s) ", + "label-resource-uri": "", "label-subscription": "Abonnement", "placeholder-resource-name": "Name", "tooltip-region": "Die Code-Region der Ressource. Optional für eine Ressource, aber zwingend notwendig bei der Auswahl mehrerer Ressourcen.", - "tooltip-resource-uri": "Bearbeiten Sie die <2>Ressourcen-URI manuell. Unterstützt die Verwendung mehrerer Vorlagenvariablen (Beispiel: /subscriptions/$subId/resourceGroups/$rg)" + "tooltip-resource-uri": "" }, "aggregate-item": { "aria-label-aggregate-function": "Aggregatfunktion", @@ -68,7 +68,7 @@ }, "basic-logs-toggle": { "aria-label-enable-basic-logs": "Basis-Logs", - "description-basic-logs": "Wenn Sie diese Funktion aktivieren, fallen pro Abfrage Azure Monitor-Kosten für Dashboard-Panels an, die Tabellen abfragen, die für <2>Basis-Logs konfiguriert sind.", + "description-basic-logs": "", "label-enable-basic-logs": "Basis-Logs aktivieren" }, "config-editor": { diff --git a/public/app/plugins/datasource/azuremonitor/locales/es-ES/grafana-azure-monitor-datasource.json b/public/app/plugins/datasource/azuremonitor/locales/es-ES/grafana-azure-monitor-datasource.json index ca3dbf0f01d..34239be4c38 100644 --- a/public/app/plugins/datasource/azuremonitor/locales/es-ES/grafana-azure-monitor-datasource.json +++ b/public/app/plugins/datasource/azuremonitor/locales/es-ES/grafana-azure-monitor-datasource.json @@ -13,11 +13,11 @@ "label-resource-group": "Grupo de recursos", "label-resource-name": "Nombre del recurso", "label-resource-number": "Recurso {{resourceNum}}", - "label-resource-uri": "URI(s) de recursos ", + "label-resource-uri": "", "label-subscription": "Suscripción", "placeholder-resource-name": "nombre", "tooltip-region": "La región de código del recurso. Opcional para un recurso, pero obligatorio al seleccionar varios.", - "tooltip-resource-uri": "Edite manualmente el <2>URI del recurso. Admite el uso de múltiples variables de plantilla (por ejemplo: /subscriptions/$subId/resourceGroups/$rg)" + "tooltip-resource-uri": "" }, "aggregate-item": { "aria-label-aggregate-function": "Función de agregación", @@ -68,7 +68,7 @@ }, "basic-logs-toggle": { "aria-label-enable-basic-logs": "Logs básicos", - "description-basic-logs": "Habilitar esta función conlleva costes por consulta de Azure Monitor en los paneles del dashboard que consultan tablas configuradas para <2>logs básicos.", + "description-basic-logs": "", "label-enable-basic-logs": "Habilitar logs básicos" }, "config-editor": { diff --git a/public/app/plugins/datasource/azuremonitor/locales/fr-FR/grafana-azure-monitor-datasource.json b/public/app/plugins/datasource/azuremonitor/locales/fr-FR/grafana-azure-monitor-datasource.json index 07d3a18af33..d5db7927d85 100644 --- a/public/app/plugins/datasource/azuremonitor/locales/fr-FR/grafana-azure-monitor-datasource.json +++ b/public/app/plugins/datasource/azuremonitor/locales/fr-FR/grafana-azure-monitor-datasource.json @@ -13,11 +13,11 @@ "label-resource-group": "Groupe de ressources", "label-resource-name": "Nom de la ressource", "label-resource-number": "Ressource {{resourceNum}}", - "label-resource-uri": "URI(s) de ressource ", + "label-resource-uri": "", "label-subscription": "Abonnement", "placeholder-resource-name": "nom", "tooltip-region": "La région de code de la ressource. Facultatif pour une ressource, mais obligatoire lors de la sélection de plusieurs ressources.", - "tooltip-resource-uri": "Modifiez manuellement l’<2>URI de la ressource. Prend en charge l’utilisation de plusieurs variables de modèle (par exemple : /subscriptions/$subId/resourceGroups/$rg)" + "tooltip-resource-uri": "" }, "aggregate-item": { "aria-label-aggregate-function": "Fonction d’agrégation", @@ -68,7 +68,7 @@ }, "basic-logs-toggle": { "aria-label-enable-basic-logs": "Journaux de base", - "description-basic-logs": "L’activation de cette fonctionnalité entraîne des coûts Azure Monitor par requête sur les panneaux du tableau de bord qui interrogent les tables configurées pour les <2>journaux de base.", + "description-basic-logs": "", "label-enable-basic-logs": "Activer les journaux de base" }, "config-editor": { diff --git a/public/app/plugins/datasource/azuremonitor/locales/hu-HU/grafana-azure-monitor-datasource.json b/public/app/plugins/datasource/azuremonitor/locales/hu-HU/grafana-azure-monitor-datasource.json index c349c475221..41afe3e235e 100644 --- a/public/app/plugins/datasource/azuremonitor/locales/hu-HU/grafana-azure-monitor-datasource.json +++ b/public/app/plugins/datasource/azuremonitor/locales/hu-HU/grafana-azure-monitor-datasource.json @@ -13,11 +13,11 @@ "label-resource-group": "Erőforráscsoport", "label-resource-name": "Erőforrásnév", "label-resource-number": "Erőforrás {{resourceNum}}", - "label-resource-uri": "Erőforrás-URI-k ", + "label-resource-uri": "", "label-subscription": "Előfizetés", "placeholder-resource-name": "név", "tooltip-region": "Az erőforrás kódterülete. Egy erőforrás esetén nem kötelező, de több erőforrás kiválasztásakor kötelező.", - "tooltip-resource-uri": "Az <2>erőforrás-uri manuálisan szerkesztendő. Több sablonváltozó használatát támogatja (pl.: /subscriptions/$subId/resourceGroups/$rg)" + "tooltip-resource-uri": "" }, "aggregate-item": { "aria-label-aggregate-function": "Összesítési függvény", @@ -68,7 +68,7 @@ }, "basic-logs-toggle": { "aria-label-enable-basic-logs": "Alapvető naplók", - "description-basic-logs": "A funkció engedélyezése esetén lekérdezésenkénti Azure Monitor-költségek merülnek fel azon irányítópult-paneleken, amelyek lekérdezik az <2>Alapvető naplókhoz konfigurált táblákat.", + "description-basic-logs": "", "label-enable-basic-logs": "Alapvető naplók engedélyezése" }, "config-editor": { diff --git a/public/app/plugins/datasource/azuremonitor/locales/id-ID/grafana-azure-monitor-datasource.json b/public/app/plugins/datasource/azuremonitor/locales/id-ID/grafana-azure-monitor-datasource.json index 5c0ab3e813a..b11a7098cc6 100644 --- a/public/app/plugins/datasource/azuremonitor/locales/id-ID/grafana-azure-monitor-datasource.json +++ b/public/app/plugins/datasource/azuremonitor/locales/id-ID/grafana-azure-monitor-datasource.json @@ -13,11 +13,11 @@ "label-resource-group": "Kelompok Sumber Daya", "label-resource-name": "Nama Sumber Daya", "label-resource-number": "Sumber Daya {{resourceNum}}", - "label-resource-uri": "URI Sumber Daya ", + "label-resource-uri": "", "label-subscription": "Berlangganan", "placeholder-resource-name": "nama", "tooltip-region": "Wilayah kode sumber daya. Opsional untuk satu sumber daya tetapi wajib saat memilih beberapa sumber daya.", - "tooltip-resource-uri": "Edit <2>uri sumber daya secara manual. Mendukung penggunaan beberapa variabel templat (misalnya: /subscriptions/$subId/resourceGroups/$rg)" + "tooltip-resource-uri": "" }, "aggregate-item": { "aria-label-aggregate-function": "Fungsi agregat", @@ -68,7 +68,7 @@ }, "basic-logs-toggle": { "aria-label-enable-basic-logs": "Log Dasar", - "description-basic-logs": "Jika Anda mengaktifkan fitur ini, Azure Monitor akan dikenakan biaya per kueri untuk panel dasbor yang melakukan kueri pada tabel yang dikonfigurasi untuk <2>Log Dasar.", + "description-basic-logs": "", "label-enable-basic-logs": "Aktifkan Log Dasar" }, "config-editor": { diff --git a/public/app/plugins/datasource/azuremonitor/locales/it-IT/grafana-azure-monitor-datasource.json b/public/app/plugins/datasource/azuremonitor/locales/it-IT/grafana-azure-monitor-datasource.json index 107524c96af..0b5ffcdac4c 100644 --- a/public/app/plugins/datasource/azuremonitor/locales/it-IT/grafana-azure-monitor-datasource.json +++ b/public/app/plugins/datasource/azuremonitor/locales/it-IT/grafana-azure-monitor-datasource.json @@ -13,11 +13,11 @@ "label-resource-group": "Gruppi risorse", "label-resource-name": "Nome risorsa", "label-resource-number": "Risorsa {{resourceNum}}", - "label-resource-uri": "URI risorsa/e ", + "label-resource-uri": "", "label-subscription": "Abbonamento", "placeholder-resource-name": "nome", "tooltip-region": "La parte di codice della risorsa. Facoltativo per una risorsa ma obbligatorio quando se ne selezionano più di una.", - "tooltip-resource-uri": "Modifica manualmente l'<2>URI della risorsa. Supporta l'uso di più variabili di modello (ad esempio: /subscriptions/$subId/resourceGroups/$rg)" + "tooltip-resource-uri": "" }, "aggregate-item": { "aria-label-aggregate-function": "Funzione aggregata", @@ -68,7 +68,7 @@ }, "basic-logs-toggle": { "aria-label-enable-basic-logs": "Registri di base", - "description-basic-logs": "L'abilitazione di questa funzione comporta i costi per query di Azure Monitor sui pannelli della dashboard che eseguono query su tabelle configurate per <2>Registri di base.", + "description-basic-logs": "", "label-enable-basic-logs": "Abilita registri di base" }, "config-editor": { diff --git a/public/app/plugins/datasource/azuremonitor/locales/ja-JP/grafana-azure-monitor-datasource.json b/public/app/plugins/datasource/azuremonitor/locales/ja-JP/grafana-azure-monitor-datasource.json index cbeea159a4d..cdd23e444af 100644 --- a/public/app/plugins/datasource/azuremonitor/locales/ja-JP/grafana-azure-monitor-datasource.json +++ b/public/app/plugins/datasource/azuremonitor/locales/ja-JP/grafana-azure-monitor-datasource.json @@ -13,11 +13,11 @@ "label-resource-group": "リソースグループ", "label-resource-name": "リソース名", "label-resource-number": "リソース {{resourceNum}}", - "label-resource-uri": "リソースURI", + "label-resource-uri": "", "label-subscription": "サブスクリプション", "placeholder-resource-name": "名前", "tooltip-region": "リソースのコード領域。単一のリソースの場合はオプションですが、複数のリソースを選択する場合は必須です。", - "tooltip-resource-uri": "<2>リソースURIを手動で編集します。複数のテンプレート変数の使用をサポートしています(例:/subscriptions/$subId/resourceGroups/$rg)" + "tooltip-resource-uri": "" }, "aggregate-item": { "aria-label-aggregate-function": "集計関数", @@ -68,7 +68,7 @@ }, "basic-logs-toggle": { "aria-label-enable-basic-logs": "基本ログ", - "description-basic-logs": "この機能を有効にすると、<2>基本ログ用に設定されたテーブルをクエリするダッシュボードパネルで、Azure Monitorのクエリごとのコストが発生します。", + "description-basic-logs": "", "label-enable-basic-logs": "基本ログを有効にする" }, "config-editor": { diff --git a/public/app/plugins/datasource/azuremonitor/locales/ko-KR/grafana-azure-monitor-datasource.json b/public/app/plugins/datasource/azuremonitor/locales/ko-KR/grafana-azure-monitor-datasource.json index a111b996063..8b855a130bd 100644 --- a/public/app/plugins/datasource/azuremonitor/locales/ko-KR/grafana-azure-monitor-datasource.json +++ b/public/app/plugins/datasource/azuremonitor/locales/ko-KR/grafana-azure-monitor-datasource.json @@ -13,11 +13,11 @@ "label-resource-group": "리소스 그룹", "label-resource-name": "리소스 이름", "label-resource-number": "리소스 {{resourceNum}}개", - "label-resource-uri": "리소스 URI ", + "label-resource-uri": "", "label-subscription": "구독", "placeholder-resource-name": "이름", "tooltip-region": "리소스의 코드 리전입니다. 하나의 리소스에 대해서는 선택 사항이지만 여러 리소스를 선택할 때는 필수입니다.", - "tooltip-resource-uri": "<2>리소스 URI를 수동으로 편집합니다. 여러 템플릿 변수 사용 지원(예: /subscriptions/$subId/resourceGroups/$rg)" + "tooltip-resource-uri": "" }, "aggregate-item": { "aria-label-aggregate-function": "집계 함수", @@ -68,7 +68,7 @@ }, "basic-logs-toggle": { "aria-label-enable-basic-logs": "기본 로그", - "description-basic-logs": "이 기능을 활성화하면 <2>기본 로그에 구성된 테이블을 쿼리하는 대시보드 패널에서 Azure Monitor 쿼리당 비용이 발생합니다.", + "description-basic-logs": "", "label-enable-basic-logs": "기본 로그 활성화" }, "config-editor": { diff --git a/public/app/plugins/datasource/azuremonitor/locales/nl-NL/grafana-azure-monitor-datasource.json b/public/app/plugins/datasource/azuremonitor/locales/nl-NL/grafana-azure-monitor-datasource.json index 1ab2fb7f85d..ad53fde6477 100644 --- a/public/app/plugins/datasource/azuremonitor/locales/nl-NL/grafana-azure-monitor-datasource.json +++ b/public/app/plugins/datasource/azuremonitor/locales/nl-NL/grafana-azure-monitor-datasource.json @@ -13,11 +13,11 @@ "label-resource-group": "Brongroep", "label-resource-name": "Naam van het object", "label-resource-number": "Bron {{resourceNum}}", - "label-resource-uri": "Bron-URI('s) ", + "label-resource-uri": "", "label-subscription": "Abonnement", "placeholder-resource-name": "naam", "tooltip-region": "Het codegebied van de bron. Optioneel voor één bron, maar verplicht bij het selecteren van meerdere bronnen.", - "tooltip-resource-uri": "Bewerk de <2>bron-uri handmatig. Ondersteunt het gebruik van meerdere sjabloonvariabelen (bijv.: /subscriptions/$subId/resourceGroups/$rg)" + "tooltip-resource-uri": "" }, "aggregate-item": { "aria-label-aggregate-function": "Totaal van de functie", @@ -68,7 +68,7 @@ }, "basic-logs-toggle": { "aria-label-enable-basic-logs": "Basislogs", - "description-basic-logs": "Als je deze functie inschakelt, worden Azure Monitor-kosten per query gemaakt op dashboardpanelen die tabellen opvragen die zijn geconfigureerd voor <2>Basislogboeken.", + "description-basic-logs": "", "label-enable-basic-logs": "Basislogboeken inschakelen" }, "config-editor": { diff --git a/public/app/plugins/datasource/azuremonitor/locales/pl-PL/grafana-azure-monitor-datasource.json b/public/app/plugins/datasource/azuremonitor/locales/pl-PL/grafana-azure-monitor-datasource.json index 3602cc8352f..808baffda64 100644 --- a/public/app/plugins/datasource/azuremonitor/locales/pl-PL/grafana-azure-monitor-datasource.json +++ b/public/app/plugins/datasource/azuremonitor/locales/pl-PL/grafana-azure-monitor-datasource.json @@ -13,11 +13,11 @@ "label-resource-group": "Grupa zasobów", "label-resource-name": "Nazwa zasobu", "label-resource-number": "Zasób {{resourceNum}}", - "label-resource-uri": "Identyfikatory URI zasobów ", + "label-resource-uri": "", "label-subscription": "Subskrypcja", "placeholder-resource-name": "nazwa", "tooltip-region": "Kod regionu zasobu. Opcjonalny w przypadku jednego zasobu, ale wymagany przy wielu zasobach.", - "tooltip-resource-uri": "Edytuj ręcznie <2>identyfikator URI zasobu. Obsługuje korzystanie z wielu zmiennych szablonu (np. /subscriptions/$subId/resourceGroups/$rg)" + "tooltip-resource-uri": "" }, "aggregate-item": { "aria-label-aggregate-function": "Funkcja agregująca", @@ -68,7 +68,7 @@ }, "basic-logs-toggle": { "aria-label-enable-basic-logs": "Podstawowe dzienniki", - "description-basic-logs": "Włączenie tej funkcji wiąże się z opłatami Azure Monitor za każde zapytanie w przypadku paneli pulpitu, które wysyłają zapytania do tabel skonfigurowanych dla <2>podstawowych dzienników.", + "description-basic-logs": "", "label-enable-basic-logs": "Włącz podstawowe dzienniki" }, "config-editor": { diff --git a/public/app/plugins/datasource/azuremonitor/locales/pt-BR/grafana-azure-monitor-datasource.json b/public/app/plugins/datasource/azuremonitor/locales/pt-BR/grafana-azure-monitor-datasource.json index 236618cf01d..232fdcb80c4 100644 --- a/public/app/plugins/datasource/azuremonitor/locales/pt-BR/grafana-azure-monitor-datasource.json +++ b/public/app/plugins/datasource/azuremonitor/locales/pt-BR/grafana-azure-monitor-datasource.json @@ -13,11 +13,11 @@ "label-resource-group": "Grupo de recursos", "label-resource-name": "Nome do recurso", "label-resource-number": "Recurso {{resourceNum}}", - "label-resource-uri": "URI(s) de recurso ", + "label-resource-uri": "", "label-subscription": "Assinatura", "placeholder-resource-name": "nome", "tooltip-region": "A região de código do recurso. Opcional para um recurso, mas obrigatório ao selecionar vários.", - "tooltip-resource-uri": "Edite o <2>URI do recurso manualmente. Compatível com o uso de múltiplas variáveis de modelo (por exemplo: /subscriptions/$subId/resourceGroups/$rg)" + "tooltip-resource-uri": "" }, "aggregate-item": { "aria-label-aggregate-function": "Função de agregação", @@ -68,7 +68,7 @@ }, "basic-logs-toggle": { "aria-label-enable-basic-logs": "Logs básicos", - "description-basic-logs": "A ativação deste recurso incorre em custos por consulta do Azure Monitor em painéis que consultam tabelas configuradas para <2>logs básicos.", + "description-basic-logs": "", "label-enable-basic-logs": "Ativar logs básicos" }, "config-editor": { diff --git a/public/app/plugins/datasource/azuremonitor/locales/pt-PT/grafana-azure-monitor-datasource.json b/public/app/plugins/datasource/azuremonitor/locales/pt-PT/grafana-azure-monitor-datasource.json index 9eca6d90191..16e63fa3e55 100644 --- a/public/app/plugins/datasource/azuremonitor/locales/pt-PT/grafana-azure-monitor-datasource.json +++ b/public/app/plugins/datasource/azuremonitor/locales/pt-PT/grafana-azure-monitor-datasource.json @@ -13,11 +13,11 @@ "label-resource-group": "Grupo de recursos", "label-resource-name": "Nome do recurso", "label-resource-number": "Recurso {{resourceNum}}", - "label-resource-uri": "URI de recurso ", + "label-resource-uri": "", "label-subscription": "Subscrição", "placeholder-resource-name": "nome", "tooltip-region": "A região de código do recurso. Opcional para um recurso, mas obrigatório ao selecionar vários.", - "tooltip-resource-uri": "Edite manualmente o <2>URI do recurso. Suporta a utilização de múltiplas variáveis de modelo (p. ex: /subscriptions/$subId/resourceGroups/$rg)" + "tooltip-resource-uri": "" }, "aggregate-item": { "aria-label-aggregate-function": "Função agregada", @@ -68,7 +68,7 @@ }, "basic-logs-toggle": { "aria-label-enable-basic-logs": "Registos básicos", - "description-basic-logs": "A ativação desta funcionalidade incorre em custos por consulta do Azure Monitor em painéis que consultam tabelas configuradas para <2>Registos básicos.", + "description-basic-logs": "", "label-enable-basic-logs": "Ativar registos básicos" }, "config-editor": { diff --git a/public/app/plugins/datasource/azuremonitor/locales/ru-RU/grafana-azure-monitor-datasource.json b/public/app/plugins/datasource/azuremonitor/locales/ru-RU/grafana-azure-monitor-datasource.json index 54f9a1b3a29..3d3e4a2be3a 100644 --- a/public/app/plugins/datasource/azuremonitor/locales/ru-RU/grafana-azure-monitor-datasource.json +++ b/public/app/plugins/datasource/azuremonitor/locales/ru-RU/grafana-azure-monitor-datasource.json @@ -13,11 +13,11 @@ "label-resource-group": "Группа ресурсов", "label-resource-name": "Имя ресурса", "label-resource-number": "Ресурс {{resourceNum}}", - "label-resource-uri": "URI ресурса ", + "label-resource-uri": "", "label-subscription": "Подписка", "placeholder-resource-name": "имя", "tooltip-region": "Область кода ресурса. Необязательно для одного ресурса, но обязательно при выборе нескольких.", - "tooltip-resource-uri": "Вручную измените <2>URI ресурса. Поддерживает использование нескольких переменных шаблона (например, /subscriptions/$subId/resourceGroups/$rg)" + "tooltip-resource-uri": "" }, "aggregate-item": { "aria-label-aggregate-function": "Агрегатная функция", @@ -68,7 +68,7 @@ }, "basic-logs-toggle": { "aria-label-enable-basic-logs": "Базовые журналы", - "description-basic-logs": "Включение этой функции влечет за собой затраты на каждый запрос Azure Monitor на панелях дашбордов, связанный с таблицами для <2>базовых журналов.", + "description-basic-logs": "", "label-enable-basic-logs": "Включить базовые журналы" }, "config-editor": { diff --git a/public/app/plugins/datasource/azuremonitor/locales/sv-SE/grafana-azure-monitor-datasource.json b/public/app/plugins/datasource/azuremonitor/locales/sv-SE/grafana-azure-monitor-datasource.json index 4766600cc2a..07021e81d59 100644 --- a/public/app/plugins/datasource/azuremonitor/locales/sv-SE/grafana-azure-monitor-datasource.json +++ b/public/app/plugins/datasource/azuremonitor/locales/sv-SE/grafana-azure-monitor-datasource.json @@ -13,11 +13,11 @@ "label-resource-group": "Resursgrupp", "label-resource-name": "Rättigheter", "label-resource-number": "Resurs {{resourceNum}}", - "label-resource-uri": "Resurs-URI ", + "label-resource-uri": "", "label-subscription": "Prenumeration", "placeholder-resource-name": "namn", "tooltip-region": "Resursens kodregion. Valfritt för en enskild resurs men obligatoriskt vid val av flera.", - "tooltip-resource-uri": "Redigera <2>resursens URI manuellt. Stöder användning av flera mallvariabler (t.ex.: /subscriptions/$subId/resourceGroups/$rg)" + "tooltip-resource-uri": "" }, "aggregate-item": { "aria-label-aggregate-function": "Aggregeringsfunktion", @@ -68,7 +68,7 @@ }, "basic-logs-toggle": { "aria-label-enable-basic-logs": "Grundläggande loggar", - "description-basic-logs": "Om den här funktionen aktiveras medför det Azure Monitor-kostnader per fråga för instrumentpanelspaneler som frågar tabeller konfigurerade för <2>basloggar.", + "description-basic-logs": "", "label-enable-basic-logs": "Aktivera basloggar" }, "config-editor": { diff --git a/public/app/plugins/datasource/azuremonitor/locales/tr-TR/grafana-azure-monitor-datasource.json b/public/app/plugins/datasource/azuremonitor/locales/tr-TR/grafana-azure-monitor-datasource.json index 378d8377411..1b46578214b 100644 --- a/public/app/plugins/datasource/azuremonitor/locales/tr-TR/grafana-azure-monitor-datasource.json +++ b/public/app/plugins/datasource/azuremonitor/locales/tr-TR/grafana-azure-monitor-datasource.json @@ -13,11 +13,11 @@ "label-resource-group": "Kaynak Grubu", "label-resource-name": "Kaynak Adı", "label-resource-number": "Kaynak {{resourceNum}}", - "label-resource-uri": "Kaynak URI'leri ", + "label-resource-uri": "", "label-subscription": "Abonelik", "placeholder-resource-name": "ad", "tooltip-region": "Kaynağın kod bölgesi. Bir kaynak için isteğe bağlıdır ancak birden fazla kaynak seçildiğinde zorunludur.", - "tooltip-resource-uri": "<2>Kaynak URI'sini manuel olarak düzenleyin. Birden fazla şablon değişkeni kullanımını destekler (örnek: /subscriptions/$subId/resourceGroups/$rg)" + "tooltip-resource-uri": "" }, "aggregate-item": { "aria-label-aggregate-function": "Toplama işlevi", @@ -68,7 +68,7 @@ }, "basic-logs-toggle": { "aria-label-enable-basic-logs": "Temel Günlükler", - "description-basic-logs": "Bu özelliğin etkinleştirilmesi, <2>Temel Günlükler için yapılandırılmış tabloları sorgulayan pano panellerinde Azure Monitor sorgu başına maliyetlerinin oluşmasına neden olur.", + "description-basic-logs": "", "label-enable-basic-logs": "Temel Günlükleri Etkinleştir" }, "config-editor": { diff --git a/public/app/plugins/datasource/azuremonitor/locales/zh-Hans/grafana-azure-monitor-datasource.json b/public/app/plugins/datasource/azuremonitor/locales/zh-Hans/grafana-azure-monitor-datasource.json index 97701ed7f11..eb5e45aaa73 100644 --- a/public/app/plugins/datasource/azuremonitor/locales/zh-Hans/grafana-azure-monitor-datasource.json +++ b/public/app/plugins/datasource/azuremonitor/locales/zh-Hans/grafana-azure-monitor-datasource.json @@ -13,11 +13,11 @@ "label-resource-group": "资源组", "label-resource-name": "资源名称", "label-resource-number": "资源 {{resourceNum}}", - "label-resource-uri": "资源 URI ", + "label-resource-uri": "", "label-subscription": "订阅", "placeholder-resource-name": "姓名", "tooltip-region": "资源的代码区域。对于一个资源来说是可选的,但在选择多个资源时则是必须的。", - "tooltip-resource-uri": "手动编辑<2>资源 uri。支持使用多个模板变量(例如:/subscriptions/$subId/resourceGroups/$rg)" + "tooltip-resource-uri": "" }, "aggregate-item": { "aria-label-aggregate-function": "汇总功能", @@ -68,7 +68,7 @@ }, "basic-logs-toggle": { "aria-label-enable-basic-logs": "基本日志", - "description-basic-logs": "启用此功能后,在查询表配置为<2>基本日志的数据面板上,Azure Monitor 会产生每次查询的费用。", + "description-basic-logs": "", "label-enable-basic-logs": "启用基本日志" }, "config-editor": { diff --git a/public/app/plugins/datasource/azuremonitor/locales/zh-Hant/grafana-azure-monitor-datasource.json b/public/app/plugins/datasource/azuremonitor/locales/zh-Hant/grafana-azure-monitor-datasource.json index 9bbdc75b9c6..29f2a139657 100644 --- a/public/app/plugins/datasource/azuremonitor/locales/zh-Hant/grafana-azure-monitor-datasource.json +++ b/public/app/plugins/datasource/azuremonitor/locales/zh-Hant/grafana-azure-monitor-datasource.json @@ -13,11 +13,11 @@ "label-resource-group": "資源群組", "label-resource-name": "資源名稱", "label-resource-number": "資源 {{resourceNum}}", - "label-resource-uri": "資源 URI", + "label-resource-uri": "", "label-subscription": "訂閱", "placeholder-resource-name": "名稱", "tooltip-region": "資源的代碼區域。對於單一資源為選填,但選取多個資源時為必填。", - "tooltip-resource-uri": "手動編輯<2>資源 URI。支援使用多個範本變數(例如:/subscriptions/$subId/resourceGroups/$rg)" + "tooltip-resource-uri": "" }, "aggregate-item": { "aria-label-aggregate-function": "彙總函式", @@ -68,7 +68,7 @@ }, "basic-logs-toggle": { "aria-label-enable-basic-logs": "基本紀錄", - "description-basic-logs": "啟用此功能會導致 Azure Monitor 在查詢為<2>基本記錄設定的表格之儀表板面板上,產生每次查詢成本。", + "description-basic-logs": "", "label-enable-basic-logs": "啟用基本紀錄" }, "config-editor": { diff --git a/public/app/plugins/datasource/mssql/locales/cs-CZ/mssql.json b/public/app/plugins/datasource/mssql/locales/cs-CZ/mssql.json index ab93432674a..198e7a85804 100644 --- a/public/app/plugins/datasource/mssql/locales/cs-CZ/mssql.json +++ b/public/app/plugins/datasource/mssql/locales/cs-CZ/mssql.json @@ -41,7 +41,7 @@ "fillvalue": "Nastavením hodnoty „fillvalue“ Grafana vyplní chybějící hodnoty podle intervalu. Hodnota „fillvalue“ může být buď doslovná hodnota, {{null}} nebo {{previous}}. {{previous}} vyplní předchozí zobrazenou hodnotu nebo {{null}}, pokud dosud nebyla zobrazená žádná.", "macros": "Makra:", "optional": "Volitelné:", - "optional-tip": "vrátit sloupec s názvem <1>{{columnName}} pro zobrazení názvu řady.", + "optional-tip": "", "optional-tip-2": "Pokud je vráceno více sloupců s hodnotami, sloupec {{columnName}} se použije jako předpona.", "optional-tip-3": "Pokud není nalezen žádný sloupec s názvem {{columnName}}, použije se název sloupce hodnoty jako název řady", "resultsets-time-sorted": "Výsledkové sady dotazů časových řad musí být seřazeny podle času.", @@ -56,20 +56,20 @@ "configuration-editor": { "body-user-permission": "Uživateli databáze by měla být udělena pouze oprávnění typu {{permissionType}} pro specifikovanou databázi a tabulky, které chcete dotazovat. Grafana neověřuje, zda jsou dotazy bezpečné, takže dotazy mohou obsahovat jakýkoli SQL příkaz. Například budou provedeny příkazy jako <3>{{example1}} a <5>{{example2}}. Pokud tomu chcete zabránit, <7>důrazně doporučujeme vytvořit konkrétního uživatele MS SQL s omezenými oprávněními. Další informace najdete v <10>dokumentaci k datovému zdroji Microsoft SQL Server.", "description-additional-settings": "Další nastavení jsou volitelná nastavení, která lze nakonfigurovat pro větší kontrolu nad zdrojem dat. To zahrnuje limity připojení, časový limit připojení, časový interval skupiny a zabezpečený proxy server Socks.", - "description-auth-type-azure-auth": "<0>Ověření Azure Bezpečně ověřujte a přistupujte ke zdrojům a aplikacím Azure pomocí přihlašovacích údajů Azure AD – podporovány jsou identita spravované služby a tajné přihlašovací údaje klienta.", - "description-auth-type-credential-cache": "<0>Windows AD: Vyrovnávací paměť pověření Windows Active Directory – přihlášení pro uživatele domény prostřednictvím vyrovnávací paměti pověření.", - "description-auth-type-credential-cache-file": "<0>Windows AD: Soubor vyrovnávací paměti pověření Windows Active Directory – přihlášení pro uživatele domény prostřednictvím souboru vyrovnávací paměti pověření.", - "description-auth-type-keytab": "<0>Windows AD: Keytab Windows Active Directory – přihlášení pro uživatele domény prostřednictvím souboru keytab.", - "description-auth-type-sql-server": "<0>Ověření serveru SQL Toto je výchozí mechanismus pro připojení k MS SQL Serveru. Zadejte přihlašovací údaje pro ověření serveru SQL nebo přihlašovací údaje pro ověření systému Windows ve formátu DOMÉNA\\Uživatel.", - "description-auth-type-username-password": "<0>Windows AD: Uživatelské jméno + heslo Windows Active Directory – přihlášení pro uživatele domény prostřednictvím uživatelského jména / hesla.", - "description-auth-type-windows-auth": "<0>Ověřování systému Windows Integrované zabezpečení Windows – jednotné přihlášení pro uživatele, kteří jsou již přihlášeni do systému Windows a povolili tuto možnost pro MS SQL Server.", + "description-auth-type-azure-auth": "", + "description-auth-type-credential-cache": "", + "description-auth-type-credential-cache-file": "", + "description-auth-type-keytab": "", + "description-auth-type-sql-server": "", + "description-auth-type-username-password": "", + "description-auth-type-windows-auth": "", "description-connection-timeout": "Počet sekund, po které se čeká před zrušením požadavku při připojování k databázi. Výchozí hodnota je <1>{{defaultTimeout}}, což znamená žádný časový limit.", "description-encrypt": "Určuje, zda nebo do jaké míry bude se serverem vyjednáno zabezpečené připojení SSL TCP/IP.", - "description-encrypt-disable": "<0>{{encryptionValue}} – data odesílaná mezi klientem a serverem nejsou šifrována.", - "description-encrypt-false": "<0>{{encryptionValue}} – data odesílaná mezi klientem a serverem nejsou šifrována nad rámec přihlašovacího balíčku. (výchozí)", + "description-encrypt-disable": "", + "description-encrypt-false": "", "description-encrypt-older-version": "Pokud používáte starší verzi Microsoft SQL Server, jako je 2008 a 2008R2, možná budete muset zakázat šifrování, abyste se mohli připojit.", - "description-encrypt-true": "<0>{{encryptionValue}} – data odesílaná mezi klientem a serverem jsou šifrována.", - "description-min-interval": "Dolní limit pro automatické seskupení podle časového intervalu. Doporučuje se nastavit frekvenci zápisu, například <1>{{exampleInterval}}, pokud jsou data zapisována každou minutu.", + "description-encrypt-true": "", + "description-min-interval": "", "description-tls-cert": "Cesta k souboru obsahujícímu certifikát veřejného klíče CA, který podepsal certifikát SQL Server. Nutné, když je certifikát serveru podepsán sám sebou.", "label-auth-settings": "Nastavení ověření Azure", "label-auth-type": "Typ ověření", @@ -104,7 +104,7 @@ }, "kerberos-advanced-settings": { "description-dns-lookup-kdc": "Uveďte, zda by měly být k vyhledání KDC a dalších serverů pro oblast použity záznamy DNS „SRV“. Výchozí hodnota je <1>{{default}}.", - "description-krb5-config-file-path": "Cesta ke konfiguračnímu souboru pro <2>balíček MIT krb5. Výchozí hodnota je <4>{{default}}.", + "description-krb5-config-file-path": "", "description-udp-preference-limit": "Výchozí hodnota je <1>{{default}} (vždy použít TCP) a je volitelná.", "label-dns-lookup-kdc": "DNS pro vyhledání KDC", "label-krb5-config-file-path": "Cesta ke konfiguračnímu souboru krb5", diff --git a/public/app/plugins/datasource/mssql/locales/de-DE/mssql.json b/public/app/plugins/datasource/mssql/locales/de-DE/mssql.json index 2027cb95ff1..b1308275e22 100644 --- a/public/app/plugins/datasource/mssql/locales/de-DE/mssql.json +++ b/public/app/plugins/datasource/mssql/locales/de-DE/mssql.json @@ -41,7 +41,7 @@ "fillvalue": "durch Einstellung von fillvalue füllt Grafana fehlende Werte entsprechend dem Intervall aus. fillvalue kann entweder ein Literalwert, {{null}} oder {{previous}} sein; {{previous}} trägt den vorher gesehenen Wert ein oder {{null}} wenn bisher noch kein Wert gesehen wurde", "macros": "Makros:", "optional": "Optional:", - "optional-tip": "Rückgabe der Spalte namens <1>{{columnName}} zur Darstellung des Reihennamens.", + "optional-tip": "", "optional-tip-2": "Wenn mehrere Wertspalten zurückgegeben werden, wird die Spalte {{columnName}} als Präfix verwendet.", "optional-tip-3": "Wenn keine Spalte namens {{columnName}} gefunden wird, wird der Spaltenname der Wertspalte als Reihenname verwendet", "resultsets-time-sorted": "Ergebnismengen von Zeitreihenabfragen müssen nach Zeit sortiert werden.", @@ -56,20 +56,20 @@ "configuration-editor": { "body-user-permission": "Dem Datenbanknutzer sollten nur {{permissionType}}-Berechtigungen für die angegebene Datenbank und die Tabellen erteilt werden, die Sie abfragen möchten. Grafana überprüft die Sicherheit von Abfragen nicht, daher können Abfragen jede beliebige SQL-Anweisung enthalten. Beispielsweise würden Anweisungen wie <3>{{example1}} und <5>{{example2}} ausgeführt werden. Damit Sie sich davor schützen können, empfehlen wir Ihnen <7>dringend, einen bestimmten MS-SQL-Nutzer mit eingeschränkten Berechtigungen zu erstellen. Weitere Informationen finden Sie in der <10>Dokumentation zu den Microsoft-SQL-Server-Datenquellen.", "description-additional-settings": "Zusätzliche Einstellungen sind optionale Einstellungen, die für mehr Kontrolle über Ihre Datenquelle konfiguriert werden können. Dazu gehören Verbindungslimits, Verbindungs-Timeout, das Gruppieren nach Zeitintervall und sichere SOCKS-Proxys.", - "description-auth-type-azure-auth": "<0>Azure-Authentifizierung Authentifizieren Sie Azure-Ressourcen und -Anwendungen auf sichere Weise und greifen Sie mit den Anmeldedaten für Azure AD darauf zu – Managed Service Identity und Client Secret Credentials werden unterstützt.", - "description-auth-type-credential-cache": "<0>Windows AD: Anmeldedaten-Cache Windows Active Directory – Anmeldung für Domänen-Nutzer über Anmeldedaten-Cache.", - "description-auth-type-credential-cache-file": "<0>Windows AD: Anmeldedaten-Cache-Datei Windows Active Directory – Anmeldung für Domänen-Nutzer über Anmeldedaten-Cache-Datei.", - "description-auth-type-keytab": "<0>Windows AD: Keytab Windows Active Directory – Anmeldung für Domänen-Nutzer über Keytab-Datei.", - "description-auth-type-sql-server": "<0>SQL-Server-Authentifizierung Dies ist der Standardmechanismus für die Verbindung mit MS SQL Server. Gehen Sie zum Login der SQL-Server-Authentifizierung oder rufen Sie den Login der Windows-Authentifizierung im Format DOMAIN\\User auf.", - "description-auth-type-username-password": "<0>Windows AD: Benutzername + Passwort Windows Active Directory – Anmeldung für Domänen-Nutzer über Benutzername/Passwort.", - "description-auth-type-windows-auth": "<0>Windows-Authentifizierung Windows Integrated Security – Einmalanmeldung für Nutzer, die bereits bei Windows angemeldet sind und diese Option für MS SQL Server aktiviert haben.", + "description-auth-type-azure-auth": "", + "description-auth-type-credential-cache": "", + "description-auth-type-credential-cache-file": "", + "description-auth-type-keytab": "", + "description-auth-type-sql-server": "", + "description-auth-type-username-password": "", + "description-auth-type-windows-auth": "", "description-connection-timeout": "Die Anzahl der Sekunden, die gewartet wird, bevor die Anfrage während der Verbindung zur Datenbank abgebrochen wird. Der Standardwert ist <1>{{defaultTimeout}}, also kein Timeout.", "description-encrypt": "Bestimmt, ob oder in welchem Umfang eine sichere SSL-TCP/IP-Verbindung mit dem Server vereinbart wird.", - "description-encrypt-disable": "<0>{{encryptionValue}} – Daten, die zwischen Client und Server gesendet werden, sind nicht verschlüsselt.", - "description-encrypt-false": "<0>{{encryptionValue}} – Daten, die zwischen Client und Server gesendet werden, sind über das Login-Paket hinaus nicht verschlüsselt. (Standard)", + "description-encrypt-disable": "", + "description-encrypt-false": "", "description-encrypt-older-version": "Wenn Sie eine ältere Version von Microsoft SQL Server wie 2008 und 2008R2 nutzen, müssen Sie möglicherweise die Verschlüsselung deaktivieren, um eine Verbindung herstellen zu können.", - "description-encrypt-true": "<0>{{encryptionValue}} – Daten, die zwischen Client und Server gesendet werden, sind verschlüsselt.", - "description-min-interval": "Eine Untergrenze für die automatische Gruppierung je nach Zeitintervall. Es wird empfohlen, die Schreibfrequenz einzustellen, zum Beispiel <1>{{exampleInterval}}, wenn Ihre Daten jede Minute geschrieben werden.", + "description-encrypt-true": "", + "description-min-interval": "", "description-tls-cert": "Pfad zu einer Datei, die das öffentliche Schlüsselzertifikat der Zertifizierungsstelle enthält, die das SQL Server-Zertifikat signiert hat. Wird benötigt, wenn es sich um ein selbstsigniertes Serverzertifikat handelt.", "label-auth-settings": "Einstellungen für Azure Authentication", "label-auth-type": "Authentifizierungstyp", @@ -104,7 +104,7 @@ }, "kerberos-advanced-settings": { "description-dns-lookup-kdc": "Geben Sie an, ob DNS-`SRV`-Einträge verwendet werden sollen, um die KDCs und andere Server für einen Bereich zu lokalisieren. Der Standardwert ist <1>{{default}}.", - "description-krb5-config-file-path": "Der Pfad zur Konfigurationsdatei für das <2>Paket MIT krb5. Der Standardwert ist <4>{{default}}.", + "description-krb5-config-file-path": "", "description-udp-preference-limit": "Der Standardwert ist <1>{{default}} und bedeutet, dass immer TCP verwendet wird. Dies ist optional.", "label-dns-lookup-kdc": "DNS-Suche KDC", "label-krb5-config-file-path": "Konfigurationsdateipfad für krb5", diff --git a/public/app/plugins/datasource/mssql/locales/es-ES/mssql.json b/public/app/plugins/datasource/mssql/locales/es-ES/mssql.json index db5488e0ad0..a3beb6a86f4 100644 --- a/public/app/plugins/datasource/mssql/locales/es-ES/mssql.json +++ b/public/app/plugins/datasource/mssql/locales/es-ES/mssql.json @@ -41,7 +41,7 @@ "fillvalue": "al configurar «fillvalue», Grafana rellenará los valores que falten de acuerdo con el intervalo. «fillvalue» puede ser un valor literal, {{null}} o {{previous}}; {{previous}} rellenará el valor visto anteriormente o {{null}} si aún no se ha visto ninguno", "macros": "Macros:", "optional": "Opcional:", - "optional-tip": "devuelve la columna denominada <1>{{columnName}} para representar el nombre de la serie.", + "optional-tip": "", "optional-tip-2": "Si se devuelven varias columnas de valores, la columna {{columnName}} se utiliza como prefijo.", "optional-tip-3": "Si no se encuentra ninguna columna llamada {{columnName}}, el nombre de la columna de valores se utiliza como nombre de la serie", "resultsets-time-sorted": "Los conjuntos de resultados de las consultas de series temporales deben ordenarse por tiempo.", @@ -56,20 +56,20 @@ "configuration-editor": { "body-user-permission": "Al usuario de la base de datos solo se le deben conceder permisos {{permissionType}} en la base de datos especificada y en las tablas que desee consultar. Grafana no valida la seguridad de las consultas, por lo que las consultas pueden contener cualquier instrucción SQL. Por ejemplo, se ejecutarían sentencias como <3>{{example1}} y <5>{{example2}}. Como protección, es <7>muy recomendable que cree un usuario específico de MS SQL con permisos restringidos. Consulte la <10>documentación de la fuente de datos de Microsoft SQL Server para obtener más información.", "description-additional-settings": "Los ajustes adicionales son ajustes opcionales que se pueden configurar para tener un mayor control sobre su fuente de datos. Esto incluye los límites de conexión, el tiempo de espera de la conexión, el intervalo de tiempo de agrupación y el proxy SOCKS seguro.", - "description-auth-type-azure-auth": "<0>Autenticación de Azure Autentique los recursos y las aplicaciones de Azure y acceda de forma segura a ellos mediante las credenciales de Azure AD: se admiten la identidad de servicio administrado y las credenciales secretas del cliente.", - "description-auth-type-credential-cache": "<0>Windows AD: caché de credenciales Windows Active Directory: inicio de sesión para el usuario del dominio a través de la caché de credenciales.", - "description-auth-type-credential-cache-file": "<0>Windows AD: archivo de caché de credenciales Windows Active Directory: inicio de sesión para el usuario del dominio a través del archivo de caché de credenciales.", - "description-auth-type-keytab": "<0>Windows AD: Keytab Windows Active Directory: inicio de sesión para el usuario del dominio a través del archivo keytab.", - "description-auth-type-sql-server": "<0>Autenticación de SQL Server Este es el mecanismo predeterminado para conectarse a MS SQL Server. Introduzca el inicio de sesión de autenticación de SQL Server o el inicio de sesión de autenticación de Windows en el formato DOMINIO\\Usuario.", - "description-auth-type-username-password": "<0>Windows AD: nombre de usuario + contraseña Windows Active Directory: inicio de sesión para el usuario del dominio mediante nombre de usuario/contraseña.", - "description-auth-type-windows-auth": "<0>Autenticación de Windows Seguridad integrada de Windows: inicio de sesión único para los usuarios que ya han iniciado sesión en Windows y han habilitado esta opción para MS SQL Server.", + "description-auth-type-azure-auth": "", + "description-auth-type-credential-cache": "", + "description-auth-type-credential-cache-file": "", + "description-auth-type-keytab": "", + "description-auth-type-sql-server": "", + "description-auth-type-username-password": "", + "description-auth-type-windows-auth": "", "description-connection-timeout": "El número de segundos que se debe esperar antes de cancelar la solicitud al conectarse a la base de datos. El valor predeterminado es <1>{{defaultTimeout}}, lo que significa que no hay tiempo de espera.", "description-encrypt": "Determina si se negociará una conexión TCP/IP SSL segura con el servidor y con qué alcance.", - "description-encrypt-disable": "<0>{{encryptionValue}}: los datos enviados entre el cliente y el servidor no están cifrados.", - "description-encrypt-false": "<0>{{encryptionValue}}: los datos enviados entre el cliente y el servidor no están cifrados más allá del paquete de inicio de sesión (predeterminado).", + "description-encrypt-disable": "", + "description-encrypt-false": "", "description-encrypt-older-version": "Si está utilizando una versión anterior de Microsoft SQL Server, como 2008 y 2008R2, es posible que deba desactivar el cifrado para poder conectarse.", - "description-encrypt-true": "<0>{{encryptionValue}}: los datos enviados entre el cliente y el servidor están cifrados.", - "description-min-interval": "Un límite inferior para el grupo automático por intervalo de tiempo. Se recomienda configurar la frecuencia de escritura, por ejemplo<1>{{exampleInterval}}, si sus datos se escriben cada minuto.", + "description-encrypt-true": "", + "description-min-interval": "", "description-tls-cert": "Ruta al archivo que contiene el certificado de clave pública de la CA que firmó el certificado de SQL Server. Necesario cuando el certificado del servidor está autofirmado.", "label-auth-settings": "Configuración de autenticación de Azure", "label-auth-type": "Tipo de autenticación", @@ -104,7 +104,7 @@ }, "kerberos-advanced-settings": { "description-dns-lookup-kdc": "Indique si los registros DNS «SRV» deben utilizarse para localizar los KDC y otros servidores de un dominio. El valor predeterminado es <1>{{default}}.", - "description-krb5-config-file-path": "La ruta del archivo de configuración para el <2>paquete MIT krb5. El valor predeterminado es <4>{{default}}.", + "description-krb5-config-file-path": "", "description-udp-preference-limit": "El valor predeterminado es <1>{{default}} y significa que siempre se utiliza TCP y es opcional.", "label-dns-lookup-kdc": "KDC de búsqueda de DNS", "label-krb5-config-file-path": "Ruta del archivo de configuración krb5", diff --git a/public/app/plugins/datasource/mssql/locales/fr-FR/mssql.json b/public/app/plugins/datasource/mssql/locales/fr-FR/mssql.json index 8bd1d935603..8e706658691 100644 --- a/public/app/plugins/datasource/mssql/locales/fr-FR/mssql.json +++ b/public/app/plugins/datasource/mssql/locales/fr-FR/mssql.json @@ -41,7 +41,7 @@ "fillvalue": "en définissant fillvalue, Grafana remplira les valeurs manquantes en fonction de l’intervalle. fillvalue peut être une valeur littérale, {{null}} ou {{previous}} ; {{previous}} remplira la valeur précédente ou {{null}} si aucune n’a encore été vue", "macros": "Macros :", "optional": "En option :", - "optional-tip": "renvoie la colonne nommée <1>{{columnName}} pour représenter le nom de la série.", + "optional-tip": "", "optional-tip-2": "Si plusieurs colonnes de valeurs sont renvoyées, la colonne  {{columnName}} est utilisée comme préfixe.", "optional-tip-3": "Si aucune colonne nommée {{columnName}} n’est trouvée, le nom de la colonne de valeurs est utilisé comme nom de série", "resultsets-time-sorted": "Les ensembles de résultats des requêtes de séries chronologiques doivent être triés par heure.", @@ -56,20 +56,20 @@ "configuration-editor": { "body-user-permission": "L’utilisateur de la base de données ne doit disposer que des autorisations {{permissionType}} sur la base de données et les tableaux spécifiques que vous souhaitez interroger. Grafana ne garantit pas la sûreté des requêtes ; ainsi, elles peuvent contenir n’importe quelle instruction SQL. Par exemple, des instructions telles que <3>{{example1}} et <5>{{example2}} seraient exécutées. Pour vous protéger, nous vous recommandons <7>fortement de créer un utilisateur MS SQL spécifique avec des autorisations restreintes. Consultez les <10>documents sur les sources de données Microsoft SQL Server pour en savoir plus.", "description-additional-settings": "Les paramètres supplémentaires sont des paramètres facultatifs qui peuvent être configurés pour un meilleur contrôle de votre source de données. Cela inclut les limites de connexion, le délai d’expiration de la connexion, l’intervalle de temps de regroupement et le proxy Socks sécurisé.", - "description-auth-type-azure-auth": "<0>Authentification Azure Vérifiez de manière sécurisée l’authenticité et accédez aux ressources et applications Azure à l’aide des identifiants Azure AD. L’identité de service gérée et les identifiants secrets du client sont pris en charge.", - "description-auth-type-credential-cache": "<0>Windows AD : cache d’identifiant/0> Windows Active Directory - Connexion pour l’utilisateur du domaine via le cache d’identifiant.", - "description-auth-type-credential-cache-file": "<0>Windows AD : fichier de cache d’identifiant Windows Active Directory - Connexion pour l’utilisateur du domaine via le fichier de cache d’identifiant.", - "description-auth-type-keytab": "<0>Windows AD : keytab Windows Active Directory - Connexion pour l’utilisateur du domaine via le fichier keytab.", - "description-auth-type-sql-server": "<0>Authentification SQL Server Il s’agit du mécanisme par défaut pour se connecter à MS SQL Server. Saisissez l’identifiant d’authentification SQL Server ou l’identifiant d’authentification Windows au format DOMAIN\\User.", - "description-auth-type-username-password": "<0>Windows AD : nom d’utilisateur + mot de passe Windows Active Directory - Connexion pour l’utilisateur du domaine via le nom d’utilisateur/mot de passe.", - "description-auth-type-windows-auth": "<0>Authentification Windows Sécurité intégrée Windows - Authentification unique pour les utilisateurs qui sont déjà connectés à Windows et qui ont activé cette option pour MS SQL Server.", + "description-auth-type-azure-auth": "", + "description-auth-type-credential-cache": "", + "description-auth-type-credential-cache-file": "", + "description-auth-type-keytab": "", + "description-auth-type-sql-server": "", + "description-auth-type-username-password": "", + "description-auth-type-windows-auth": "", "description-connection-timeout": "Le nombre de secondes à attendre avant d’annuler la demande lors de la connexion à la base de données. La valeur par défaut est <1>{{defaultTimeout}}, ce qui signifie qu’il n’y a pas de délai d’expiration.", "description-encrypt": "Détermine si ou dans quelle mesure une connexion TCP/IP SSL sécurisée sera négociée avec le serveur.", - "description-encrypt-disable": "<0>{{encryptionValue}} - Les données envoyées entre le client et le serveur ne sont pas chiffrées.", - "description-encrypt-false": "<0>{{encryptionValue}} - Les données envoyées entre le client et le serveur ne sont pas chiffrées au-delà du paquet de connexion. (par défaut)", + "description-encrypt-disable": "", + "description-encrypt-false": "", "description-encrypt-older-version": "Si vous utilisez une ancienne version de Microsoft SQL Server, comme 2008 et 2008R2, vous devrez peut-être désactiver le chiffrement pour pouvoir vous connecter.", - "description-encrypt-true": "<0>{{encryptionValue}} - Les données envoyées entre le client et le serveur sont chiffrées.", - "description-min-interval": "Une limite inférieure pour le groupe automatique par intervalle de temps. Il est recommandé de définir la fréquence d’écriture, par exemple<1>{{exampleInterval}} si vos données sont écrites toutes les minutes.", + "description-encrypt-true": "", + "description-min-interval": "", "description-tls-cert": "Chemin d’accès au fichier contenant le certificat de clé publique de l’autorité de certification qui a signé le certificat SQL Server. Nécessaire lorsque le certificat du serveur est auto-signé.", "label-auth-settings": "Paramètres d’authentification Azure", "label-auth-type": "Type d’authentification", @@ -104,7 +104,7 @@ }, "kerberos-advanced-settings": { "description-dns-lookup-kdc": "Indiquez si les enregistrements DNS « SRV » doivent être utilisés pour localiser les KDC et d’autres serveurs pour un domaine. La valeur par défaut est <1>{{default}}.", - "description-krb5-config-file-path": "Le chemin d’accès au fichier de configuration pour le <2>paquet MIT krb5. La valeur par défaut est <4>{{default}}.", + "description-krb5-config-file-path": "", "description-udp-preference-limit": "La valeur par défaut est <1>{{default}} et signifie toujours utiliser TCP et est facultative.", "label-dns-lookup-kdc": "Recherche DNS KDC", "label-krb5-config-file-path": "chemin du fichier de configuration krb5", diff --git a/public/app/plugins/datasource/mssql/locales/hu-HU/mssql.json b/public/app/plugins/datasource/mssql/locales/hu-HU/mssql.json index 9721d3dde6b..d742078e2af 100644 --- a/public/app/plugins/datasource/mssql/locales/hu-HU/mssql.json +++ b/public/app/plugins/datasource/mssql/locales/hu-HU/mssql.json @@ -41,7 +41,7 @@ "fillvalue": "a fillvalue beállításával a Grafana az intervallumnak megfelelően kitölti a hiányzó értékeket. A fillvalue lehet tényleges érték, {{null}} vagy {{previous}}; a(z) {{previous}} az előzőleg látott értéket használja a kitöltéshez, vagy a {{null}} értéket, ha nem volt korábbi látható érték", "macros": "Makrók:", "optional": "Választható:", - "optional-tip": "a sorozat nevét jelölő <1>{{columnName}} nevű oszlop visszaadása.", + "optional-tip": "", "optional-tip-2": "Ha több értékoszlopot ad vissza, a(z) {{columnName}} oszlopot használja előtagként.", "optional-tip-3": "Ha nem található {{columnName}} nevű oszlop, akkor az értékoszlop oszlopneve lesz a sorozat neve", "resultsets-time-sorted": "Az idősor-lekérdezések eredményeit idő szerint kell rendezni.", @@ -56,20 +56,20 @@ "configuration-editor": { "body-user-permission": "Az adatbázis-felhasználó csak a megadott adatbázisra és a lekérdezni kívánt táblákra vonatkozóan kaphat {{permissionType}} engedélyeket. A Grafana nem ellenőrzi, hogy a lekérdezések biztonságosak-e, így a lekérdezések bármilyen SQL-utasítást tartalmazhatnak. Végrehajtja például az olyan utasításokat, mint a(z) <3>{{example1}} és <5>{{example2}}. Ennek elkerülése érdekében <7>határozottan javasoljuk, hogy hozzon létre egy külön MS SQL-felhasználót korlátozott engedélyekkel. További információért tekintse meg a <10>Microsoft SQL Server adatforrásdokumentumait.", "description-additional-settings": "A további beállítások olyan opcionális beállítások, amelyek konfigurálhatók az adatforrás nagyobb mértékű ellenőrzése érdekében. Ez magában foglalja a kapcsolati korlátokat, a kapcsolati időtúllépést, a csoportosítási időintervallumot és a Secure Socks Proxyt.", - "description-auth-type-azure-auth": "<0>Azure-hitelesítés Biztonságosan hitelesítheti és érheti el az Azure-erőforrásokat és -alkalmazásokat az Azure AD-hitelesítőadatok használatával – a felügyelt szolgáltatásidentitás és a klienstitkot használó hitelesítő adatok támogatottak.", - "description-auth-type-credential-cache": "<0>Windows AD: hitelesítőadat-gyorsítótár Windows Active Directory – bejelentkezés a tartományfelhasználó számára a hitelesítőadat-gyorsítótáron keresztül.", - "description-auth-type-credential-cache-file": "<0>Windows AD: hitelesítőadat-gyorsítótárfájl Windows Active Directory – bejelentkezés a tartományfelhasználó számára a hitelesítőadat-gyorsítótárfájlon keresztül.", - "description-auth-type-keytab": "<0>Windows AD: keytab Windows Active Directory – bejelentkezés a tartományfelhasználó számára a keytab fájlon keresztül.", - "description-auth-type-sql-server": "<0>SQL Server-hitelesítés Ez az alapértelmezett mechanizmus az MS SQL Serverhez való csatlakozáshoz. Adja meg az SQL Server-hitelesítés bejelentkezési adatait vagy a Windows-hitelesítés bejelentkezési adatait TARTOMÁNY\\felhasználó formátumban.", - "description-auth-type-username-password": "<0>Windows AD: felhasználónév + jelszó Windows Active Directory – bejelentkezés a tartományfelhasználó számára felhasználónévvel/jelszóval.", - "description-auth-type-windows-auth": "<0>Windows-hitelesítés Windows Integrated Security – egyszeri bejelentkezés azon felhasználók számára, akik már bejelentkeztek a Windows rendszerbe, és engedélyezték ezt a lehetőséget az MS SQL Server számára.", + "description-auth-type-azure-auth": "", + "description-auth-type-credential-cache": "", + "description-auth-type-credential-cache-file": "", + "description-auth-type-keytab": "", + "description-auth-type-sql-server": "", + "description-auth-type-username-password": "", + "description-auth-type-windows-auth": "", "description-connection-timeout": "A kérelem visszavonása előtti várakozási idő másodpercben az adatbázishoz való csatlakozáskor. Az alapértelmezett érték <1>{{defaultTimeout}}, ami azt jelenti, hogy nincs időtúllépés.", "description-encrypt": "Meghatározza, hogy a kiszolgálóval biztonságos SSL TCP/IP-kapcsolat jöjjön-e létre, és ha igen, milyen mértékben.", - "description-encrypt-disable": "<0>{{encryptionValue}} – a kliens és a kiszolgáló között küldött adatok nem titkosítottak.", - "description-encrypt-false": "<0>{{encryptionValue}} – a kliens és a kiszolgáló között küldött adatok a bejelentkezési csomagon túl nem titkosítottak. (alapértelmezett)", + "description-encrypt-disable": "", + "description-encrypt-false": "", "description-encrypt-older-version": "Ha a Microsoft SQL Server régebbi verzióját használja, például a 2008-at vagy a 2008R2-t, akkor előfordulhat, hogy le kell tiltania a titkosítást, hogy csatlakozhasson.", - "description-encrypt-true": "<0>{{encryptionValue}} – a kliens és a kiszolgáló között küldött adatok titkosítottak.", - "description-min-interval": "Az automatikus csoportosítás időintervallumának alsó határa. Javasoljuk, hogy az írási gyakoriságra állítsa be, például <1>{{exampleInterval}} értékre, ha az adatait percenként írja.", + "description-encrypt-true": "", + "description-min-interval": "", "description-tls-cert": "Az SQL Server-tanúsítványt aláíró hitelesítésszolgáltató nyilvános kulcsos tanúsítványát tartalmazó fájl elérési útvonala. Akkor szükséges, ha a kiszolgáló tanúsítványa saját aláírású.", "label-auth-settings": "Azure-hitelesítési beállítások", "label-auth-type": "Hitelesítés típusa", @@ -104,7 +104,7 @@ }, "kerberos-advanced-settings": { "description-dns-lookup-kdc": "Jelölje meg, hogy a DNS „SRV” rekordjait kell-e használni a KDC-k és más kiszolgálók keresésére egy tartományban. Az alapértelmezett érték <1>{{default}}.", - "description-krb5-config-file-path": "A <2>MIT krb5 csomag konfigurációs fájljának elérési útvonala. Az alapértelmezett érték <4>{{default}}.", + "description-krb5-config-file-path": "", "description-udp-preference-limit": "Az alapértelmezett érték <1>{{default}}, ami azt jelenti, hogy mindig TCP-t használ, és opcionális.", "label-dns-lookup-kdc": "DNS-keresés – KDC", "label-krb5-config-file-path": "krb5 konfigurációs fájl útvonala", diff --git a/public/app/plugins/datasource/mssql/locales/id-ID/mssql.json b/public/app/plugins/datasource/mssql/locales/id-ID/mssql.json index b2d3972769f..e61a202f711 100644 --- a/public/app/plugins/datasource/mssql/locales/id-ID/mssql.json +++ b/public/app/plugins/datasource/mssql/locales/id-ID/mssql.json @@ -41,7 +41,7 @@ "fillvalue": "dengan mengatur fillvalue, Grafana akan mengisi nilai yang kosong sesuai dengan interval. Fillvalue dapat berupa nilai literal, {{null}} atau {{previous}}; {{previous}} akan mengisi dengan nilai yang terlihat sebelumnya atau {{null}} jika belum ada yang terlihat", "macros": "Makro:", "optional": "Opsional:", - "optional-tip": "mengembalikan kolom bernama <1>{{columnName}} untuk mewakili nama deret waktu (series).", + "optional-tip": "", "optional-tip-2": "Jika beberapa kolom nilai dikembalikan, kolom {{columnName}} digunakan sebagai awalan.", "optional-tip-3": "Jika tidak ada kolom bernama {{columnName}} yang ditemukan, nama kolom dari kolom nilai digunakan sebagai nama deret waktu (series)", "resultsets-time-sorted": "Kumpulan hasil kueri yang berurutan perlu diurutkan berdasarkan waktu.", @@ -56,20 +56,20 @@ "configuration-editor": { "body-user-permission": "Pengguna basis data hanya boleh diberikan izin {{permissionType}} pada basis data dan tabel tertentu yang ingin Anda minta. Grafana tidak memvalidasi bahwa kueri aman sehingga kueri dapat berisi pernyataan SQL apa pun. Misalnya, pernyataan seperti <3>{{example1}} dan <5>{{example2}} akan dijalankan. Agar terlindung dari hal ini, kami <7>sangat menyarankan Anda membuat pengguna MS SQL tertentu dengan izin terbatas. Lihat <10>Dokumen Sumber Data Microsoft SQL Server untuk informasi selengkapnya.", "description-additional-settings": "Pengaturan tambahan adalah pengaturan opsional yang dapat dikonfigurasi agar memiliki kendali lebih besar atas sumber data Anda. Ini mencakup batas koneksi, batas waktu koneksi, interval waktu grup, dan Secure Socks Proxy.", - "description-auth-type-azure-auth": "<0>Autentikasi Azure Mengautentikasi dan mengakses sumber daya dan aplikasi Azure dengan aman menggunakan kredensial Azure AD - Identitas Layanan Terkelola dan Kredensial Rahasia Klien didukung.", - "description-auth-type-credential-cache": "<0>Windows AD: Cache kredensial Windows Active Directory - Masuk untuk pengguna domain melalui cache kredensial.", - "description-auth-type-credential-cache-file": "<0>Windows AD: File cache kredensial Windows Active Directory - Masuk untuk pengguna domain melalui file cache kredensial.", - "description-auth-type-keytab": "<0>Windows AD: Keytab Windows Active Directory - Masuk untuk pengguna domain melalui file keytab.", - "description-auth-type-sql-server": "<0>Autentikasi SQL Server Ini adalah mekanisme default untuk terhubung ke MS SQL Server. Masukkan login Autentikasi SQL Server atau login Autentikasi Windows dalam format DOMAIN\\Pengguna.", - "description-auth-type-username-password": "<0>Windows AD: Nama pengguna + kata sandi Windows Active Directory - Masuk untuk pengguna domain melalui nama pengguna/kata sandi.", - "description-auth-type-windows-auth": "<0>Autentikasi Windows Keamanan Terintegrasi Windows - SSO (masuk tunggal) untuk pengguna yang sudah masuk ke Windows dan telah mengaktifkan opsi ini untuk MS SQL Server.", + "description-auth-type-azure-auth": "", + "description-auth-type-credential-cache": "", + "description-auth-type-credential-cache-file": "", + "description-auth-type-keytab": "", + "description-auth-type-sql-server": "", + "description-auth-type-username-password": "", + "description-auth-type-windows-auth": "", "description-connection-timeout": "Jumlah detik untuk menunggu sebelum membatalkan permintaan saat terhubung ke basis data. Defaultnya adalah <1>{{defaultTimeout}}, yang berarti tidak ada batas waktu.", "description-encrypt": "Menentukan apakah atau sejauh mana koneksi SSL TCP/IP yang aman akan dinegosiasikan dengan server.", - "description-encrypt-disable": "<0>{{encryptionValue}} - Data yang dikirim antara klien dan server tidak dienkripsi.", - "description-encrypt-false": "<0>{{encryptionValue}} - Data yang dikirim antara klien dan server tidak dienkripsi di luar paket login. (default)", + "description-encrypt-disable": "", + "description-encrypt-false": "", "description-encrypt-older-version": "Jika Anda menggunakan Microsoft SQL Server versi lama seperti 2008 dan 2008R2, Anda mungkin perlu menonaktifkan enkripsi untuk dapat terhubung.", - "description-encrypt-true": "<0>{{encryptionValue}} - Data yang dikirim antara klien dan server tidak dienkripsi.", - "description-min-interval": "Batas bawah untuk grup otomatis berdasarkan interval waktu. Direkomendasikan untuk diatur ke frekuensi tulis, misalnya <1>{{exampleInterval}} jika data Anda ditulis setiap menit.", + "description-encrypt-true": "", + "description-min-interval": "", "description-tls-cert": "Jalur ke file yang berisi sertifikat kunci publik CA yang menandatangani sertifikat SQL Server. Diperlukan ketika sertifikat server ditandatangani sendiri.", "label-auth-settings": "Pengaturan Autentikasi Azure", "label-auth-type": "Jenis Autentikasi", @@ -104,7 +104,7 @@ }, "kerberos-advanced-settings": { "description-dns-lookup-kdc": "Tunjukkan apakah catatan DNS 'SRV' harus digunakan untuk menemukan KDC dan server lain untuk suatu realm. Defaultnya adalah <1>{{default}}.", - "description-krb5-config-file-path": "Jalur ke file konfigurasi untuk <2>paket MIT krb5. Defaultnya adalah <4>{{default}}.", + "description-krb5-config-file-path": "", "description-udp-preference-limit": "Defaultnya adalah <1>{{default}} dan berarti selalu menggunakan TCP dan bersifat opsional.", "label-dns-lookup-kdc": "KDC Pencarian DNS", "label-krb5-config-file-path": "jalur file konfigurasi krb5", diff --git a/public/app/plugins/datasource/mssql/locales/it-IT/mssql.json b/public/app/plugins/datasource/mssql/locales/it-IT/mssql.json index 9cc954ddba2..13291c7e524 100644 --- a/public/app/plugins/datasource/mssql/locales/it-IT/mssql.json +++ b/public/app/plugins/datasource/mssql/locales/it-IT/mssql.json @@ -41,7 +41,7 @@ "fillvalue": "impostando fillvalue Grafana compilerà i valori mancanti in base all'intervallo. fillvalue può essere un valore letterale, {{null}} o {{previous}}; {{previous}} compilerà il valore visto in precedenza oppure {{null}} se non ne è stato ancora visto nessuno", "macros": "Macro:", "optional": "Facoltativo:", - "optional-tip": "restituisce la colonna denominata <1>{{columnName}} per rappresentare il nome della serie.", + "optional-tip": "", "optional-tip-2": "Se vengono restituite più colonne di valori, la colonna {{columnName}} viene utilizzata come prefisso.", "optional-tip-3": "Se non viene trovata alcuna colonna denominata {{columnName}}, il nome della colonna di valori viene utilizzato come nome della serie", "resultsets-time-sorted": "I set di risultati delle query delle serie temporali devono essere ordinati per tempo.", @@ -56,20 +56,20 @@ "configuration-editor": { "body-user-permission": "All'utente del database devono essere concesse solo le autorizzazioni {{permissionType}} sul database e sulle tabelle specificate che desideri interrogare. Grafana non convalida che le query siano sicure, quindi le query possono contenere qualsiasi istruzione SQL. Ad esempio, verrebbero eseguite istruzioni come <3>{{example1}} e <5>{{example2}}. Per proteggerti da questo, ti consigliamo <7>vivamente di creare un utente MS SQL specifico con autorizzazioni limitate. Consulta la <10>Documentazione sull'origine dei dati di Microsoft SQL Server per ulteriori informazioni.", "description-additional-settings": "Le impostazioni aggiuntive sono impostazioni facoltative che possono essere configurate per un maggiore controllo sull'origine dei dati. Ciò include i limiti di connessione, il timeout di connessione, l'intervallo di tempo di raggruppamento e il proxy Secure Socks.", - "description-auth-type-azure-auth": "<0>Autenticazione di Azure Autentica e accedi in modo sicuro alle risorse e alle applicazioni di Azure utilizzando le credenziali di Azure AD: sono supportate le Credenziali di identità del servizio gestito e segreto del client.", - "description-auth-type-credential-cache": "<0>Windows AD: cache delle credenziali Windows Active Directory – Accesso per l'utente del dominio tramite la cache delle credenziali.", - "description-auth-type-credential-cache-file": "<0>Windows AD: file della cache delle credenziali Windows Active Directory – Accesso per l'utente del dominio tramite il file della cache delle credenziali.", - "description-auth-type-keytab": "<0>Windows AD: keytab Windows Active Directory – Accesso per l'utente del dominio tramite il file keytab.", - "description-auth-type-sql-server": "<0>Autenticazione di SQL Server Questo è il meccanismo predefinito per connettersi a MS SQL Server. Inserisci l'accesso di autenticazione di SQL Server o l'accesso di autenticazione di Windows nel formato DOMINIO\\Utente.", - "description-auth-type-username-password": "<0>Windows AD: nome utente + password Windows Active Directory – Accesso per l'utente del dominio tramite nome utente/password.", - "description-auth-type-windows-auth": "<0>Autenticazione di Windows Sicurezza integrata di Windows – Single Sign-On per gli utenti che hanno già effettuato l'accesso a Windows e hanno abilitato questa opzione per MS SQL Server.", + "description-auth-type-azure-auth": "", + "description-auth-type-credential-cache": "", + "description-auth-type-credential-cache-file": "", + "description-auth-type-keytab": "", + "description-auth-type-sql-server": "", + "description-auth-type-username-password": "", + "description-auth-type-windows-auth": "", "description-connection-timeout": "Il numero di secondi di attesa prima di annullare la richiesta durante la connessione al database. Il valore predefinito è <1>{{defaultTimeout}}, ovvero nessun timeout.", "description-encrypt": "Determina se o in che misura verrà negoziata una connessione TCP/IP SSL sicura con il server.", - "description-encrypt-disable": "<0>{{encryptionValue}} – I dati inviati tra client e server non sono crittografati.", - "description-encrypt-false": "<0>{{encryptionValue}} – I dati inviati tra client e server non sono crittografati oltre il pacchetto di accesso. (predefinito)", + "description-encrypt-disable": "", + "description-encrypt-false": "", "description-encrypt-older-version": "Se utilizzi una versione precedente di Microsoft SQL Server come 2008 e 2008R2, potrebbe essere necessario disabilitare la crittografia per potersi connettere.", - "description-encrypt-true": "<0>{{encryptionValue}} – I dati inviati tra client e server non sono crittografati.", - "description-min-interval": "Un limite inferiore per il raggruppamento automatico per intervallo di tempo. Si consiglia di impostare la frequenza di scrittura, ad esempio <1>{{exampleInterval}} se i dati vengono scritti ogni minuto.", + "description-encrypt-true": "", + "description-min-interval": "", "description-tls-cert": "Percorso al file contenente il certificato di chiave pubblica della CA che ha firmato il certificato di SQL Server. Necessario quando il certificato del server è autofirmato.", "label-auth-settings": "Impostazioni di autenticazione di Azure", "label-auth-type": "Tipo di autenticazione", @@ -104,7 +104,7 @@ }, "kerberos-advanced-settings": { "description-dns-lookup-kdc": "Indica se i record DNS \"SRV\" devono essere utilizzati per individuare i KDC e altri server per un'area di autenticazione. Il valore predefinito è <1>{{default}}.", - "description-krb5-config-file-path": "Il percorso al file di configurazione per il <2>pacchetto MIT krb5. Il valore predefinito è <4>{{default}}.", + "description-krb5-config-file-path": "", "description-udp-preference-limit": "Il valore predefinito è <1>{{default}} e significa che si utilizza sempre TCP ed è facoltativo.", "label-dns-lookup-kdc": "KDC di ricerca DNS", "label-krb5-config-file-path": "percorso del file di configurazione krb5", diff --git a/public/app/plugins/datasource/mssql/locales/ja-JP/mssql.json b/public/app/plugins/datasource/mssql/locales/ja-JP/mssql.json index 0b628d8d783..71971ae17ea 100644 --- a/public/app/plugins/datasource/mssql/locales/ja-JP/mssql.json +++ b/public/app/plugins/datasource/mssql/locales/ja-JP/mssql.json @@ -41,7 +41,7 @@ "fillvalue": "fillvalueを設定すると、Grafanaは間隔に応じて欠落値を埋めます。fillvalueには、リテラル値、{{null}}または{{previous}}のいずれかを設定できます。{{previous}}の場合、以前に表示された値が入り、まだ何も表示されていない場合は{{null}}になります", "macros": "マクロ:", "optional": "オプション:", - "optional-tip": "系列名を表す<1>{{columnName}}という名前の列を返します。", + "optional-tip": "", "optional-tip-2": "複数の値列が返される場合、{{columnName}}列はプレフィックスとして使用されます。", "optional-tip-3": "{{columnName}}という名前の列が見つからない場合、値列の列名が系列名として使用されます", "resultsets-time-sorted": "時系列クエリの結果セットは、時間で並べ替える必要があります。", @@ -56,20 +56,20 @@ "configuration-editor": { "body-user-permission": "データベースユーザーには、クエリを実行する特定のデータベースとテーブルに対する{{permissionType}}権限のみを付与する必要があります。Grafanaはクエリが安全であることを検証しないため、クエリには任意のSQLステートメントを含めることができます。例えば、<3>{{example1}}や <5>{{example2}}のようなステートメントも実行可能です。対策として、制限されたアクセス許可を持つ特定のMS SQLユーザーを作成することを<7>強くお勧めします。詳細については、<10>Microsoft SQL Serverデータソースドキュメントをご覧ください。", "description-additional-settings": "追加設定は、データソースをよりきめ細かく制御するために設定できるオプション設定です。これには、接続制限、接続タイムアウト、グループ化時間間隔、およびSocket Secureプロキシ(SOCKS)が含まれます。", - "description-auth-type-azure-auth": "<0>Azure認証 Azure AD認証情報を使用してAzureリソースとアプリケーションを安全に認証してアクセスできるようにします。マネージドサービスIDとクライアントシークレット認証情報がサポートされています。", - "description-auth-type-credential-cache": " <0>Windows AD:認証情報キャッシュ Windows Active Directory - 認証情報キャッシュを介してドメインユーザーがサインオンします。", - "description-auth-type-credential-cache-file": "<0>Windows AD:認証情報キャッシュファイル Windows Active Directory - 認証情報キャッシュファイルを介してドメインユーザーがサインオンします。", - "description-auth-type-keytab": "<0>Windows AD:Keytab Windows Active Directory - keytabファイルを介してドメインユーザーがサインオンします。", - "description-auth-type-sql-server": "<0>SQL Server認証 これは、MS SQL Serverに接続するためのデフォルトメカニズムです。SQL Server認証ログインまたはWindows認証ログインをDOMAIN\\User形式で入力します。", - "description-auth-type-username-password": "<0>Windows AD:ユーザー名+パスワード Windows Active Directory - ユーザー名/パスワードを介してドメインユーザーがサインオンします。", - "description-auth-type-windows-auth": "<0>Windows認証 Windows統合セキュリティ - すでにWindowsにログオンしており、MS SQL Serverでこのオプションを有効にしているユーザーのシングルサインオン。", + "description-auth-type-azure-auth": "", + "description-auth-type-credential-cache": "", + "description-auth-type-credential-cache-file": "", + "description-auth-type-keytab": "", + "description-auth-type-sql-server": "", + "description-auth-type-username-password": "", + "description-auth-type-windows-auth": "", "description-connection-timeout": "データベースへの接続時にリクエストをキャンセルする前に待機する秒数。デフォルトは<1>{{defaultTimeout}}で、タイムアウトなしを意味します。", "description-encrypt": "サーバーとセキュアなSSL TCP/IP接続をネゴシエートするかどうか、またはどの程度ネゴシエートするかを決定します。", - "description-encrypt-disable": "<0>{{encryptionValue}} - クライアントとサーバー間で送信されるデータは暗号化されません。", - "description-encrypt-false": "<0>{{encryptionValue}} - クライアントとサーバー間で送信されるデータは、ログインパケットを超えて暗号化されません。(デフォルト)", + "description-encrypt-disable": "", + "description-encrypt-false": "", "description-encrypt-older-version": "2008や2008R2などの古いバージョンのMicrosoft SQL Serverを使用している場合、接続できるようにするためには、暗号化を無効にする必要がある場合があります。", - "description-encrypt-true": "<0>{{encryptionValue}} - クライアントとサーバー間で送信されるデータは暗号化されます。", - "description-min-interval": "時間間隔による自動グループ化の下限。データが毎分書き込まれる場合は、書き込み頻度に合わせて<1>{{exampleInterval}}のようにに設定することをお勧めします。", + "description-encrypt-true": "", + "description-min-interval": "", "description-tls-cert": "SQL Server証明書に署名したCAの公開鍵証明書を含むファイルへのパス。サーバー証明書が自己署名されている場合に必要です。", "label-auth-settings": "Azure認証設定", "label-auth-type": "認証タイプ", @@ -104,7 +104,7 @@ }, "kerberos-advanced-settings": { "description-dns-lookup-kdc": "DNS「SRV」レコードを使用して、レルムのKDCやその他のサーバーを特定するかどうかを示します。デフォルトは<1>{{default}}です。", - "description-krb5-config-file-path": "<2>MIT krb5パッケージの設定ファイルへのパス。デフォルトは<4>{{default}}です。", + "description-krb5-config-file-path": "", "description-udp-preference-limit": "デフォルトは<1>{{default}}で、常にTCPを使用することを意味します。オプションです。", "label-dns-lookup-kdc": "DNS検索KDC", "label-krb5-config-file-path": "krb5設定ファイルパス", diff --git a/public/app/plugins/datasource/mssql/locales/ko-KR/mssql.json b/public/app/plugins/datasource/mssql/locales/ko-KR/mssql.json index a9e7416431e..d88f5e897f1 100644 --- a/public/app/plugins/datasource/mssql/locales/ko-KR/mssql.json +++ b/public/app/plugins/datasource/mssql/locales/ko-KR/mssql.json @@ -41,7 +41,7 @@ "fillvalue": "fillvalue를 설정하면 Grafana가 간격에 따라 누락된 값을 채웁니다. fillvalue는 리터럴 값, {{null}} 또는 {{previous}}이(가) 될 수 있습니다. {{previous}}의 경우 이전에 표시된 값으로 채우고, 이전에 표시된 값이 없는 경우 {{null}}을 채웁니다", "macros": "매크로:", "optional": "선택 사항: ", - "optional-tip": "시리즈 이름을 나타내는 <1>{{columnName}} 열을 반환합니다.", + "optional-tip": "", "optional-tip-2": "여러 값 열이 반환되면 {{columnName}} 열이 접두사로 사용됩니다.", "optional-tip-3": "이름이 {{columnName}}인 열이 없으면 값 열의 열 이름이 시리즈 이름으로 사용됩니다", "resultsets-time-sorted": "시계열 쿼리의 결과 집합은 시간별로 정렬해야 합니다.", @@ -56,20 +56,20 @@ "configuration-editor": { "body-user-permission": "데이터베이스 사용자에게는 지정된 데이터베이스와 쿼리할 테이블에 대한 {{permissionType}} 권한만 부여해야 합니다. Grafana는 쿼리의 안전성을 검증하지 않기 때문에 쿼리에는 모든 SQL 문이 포함될 수 있습니다. 예를 들어, <3>{{example1}} 및 <5>{{example2}}와(과) 같은 명령문도 실행될 수 있습니다. 이를 방지하기 위해 제한된 권한을 가진 특정 MS SQL 사용자를 생성할 것을 <7>적극 권장합니다. 자세한 내용은 <10>Microsoft SQL Server 데이터 소스 문서를 확인하세요.", "description-additional-settings": "추가 설정은 데이터 소스를 보다 세부적으로 제어하기 위해 구성할 수 있는 선택적 설정입니다. 여기에는 연결 제한, 연결 시간 초과, 그룹별 시간 간격 및 보안 SOCKS 프록시가 포함됩니다.", - "description-auth-type-azure-auth": "<0>Azure 인증 Azure AD 자격 증명을 사용하여 Azure 리소스 및 애플리케이션을 안전하게 인증하고 액세스합니다. 관리 서비스 ID 및 클라이언트 시크릿 자격 증명이 지원됩니다.", - "description-auth-type-credential-cache": "<0>Windows AD: 자격 증명 캐시 Windows Active Directory - 도메인 사용자가 자격 증명 캐시를 통해 로그인합니다.", - "description-auth-type-credential-cache-file": "<0>Windows AD: 자격 증명 캐시 파일 Windows Active Directory - 도메인 사용자가 자격 증명 캐시 파일을 통해 로그인합니다.", - "description-auth-type-keytab": "<0>Windows AD: 키탭 Windows Active Directory - 도메인 사용자가 키탭 파일을 통해 로그인합니다.", - "description-auth-type-sql-server": "<0>SQL 서버 인증 MS SQL 서버에 연결하는 기본 메커니즘입니다. SQL 서버 인증 로그인 또는 Windows 인증 로그인을 DOMAIN\\User 형식으로 입력합니다.", - "description-auth-type-username-password": "<0>Windows AD: 사용자 이름 + 비밀번호 Windows Active Directory - 도메인 사용자가 사용자 이름/비밀번호를 통해 로그인합니다.", - "description-auth-type-windows-auth": "<0>Windows 인증 Windows 통합 보안 - Windows에 이미 로그인되어 있고 MS SQL 서버에 대해 이 옵션을 활성화한 사용자가 이용할 수 있는 SSO 방식입니다.", + "description-auth-type-azure-auth": "", + "description-auth-type-credential-cache": "", + "description-auth-type-credential-cache-file": "", + "description-auth-type-keytab": "", + "description-auth-type-sql-server": "", + "description-auth-type-username-password": "", + "description-auth-type-windows-auth": "", "description-connection-timeout": "데이터베이스에 연결할 때 요청을 취소하기 전에 대기하는 시간(초)입니다. 기본값은 <1>{{defaultTimeout}}이며, 타임아웃이 없음을 의미합니다.", "description-encrypt": "서버와 보안 SSL TCP/IP 연결을 협상할지 여부 또는 어느 정도까지 협상할지 결정합니다.", - "description-encrypt-disable": "<0>{{encryptionValue}} - 클라이언트와 서버 사이에 전송되는 데이터가 암호화되지 않습니다.", - "description-encrypt-false": "<0>{{encryptionValue}} - 클라이언트와 서버 사이에 전송되는 데이터가 로그인 패킷 이후에는 암호화되지 않습니다. (기본값)", + "description-encrypt-disable": "", + "description-encrypt-false": "", "description-encrypt-older-version": "2008 및 2008R2와 같은 이전 버전의 Microsoft SQL Server를 사용하는 경우 연결을 위해 암호화를 비활성화해야 할 수 있습니다.", - "description-encrypt-true": "<0>{{encryptionValue}} - 클라이언트와 서버 사이에 전송되는 데이터가 암호화됩니다.", - "description-min-interval": "시간 간격을 기준으로 자동 그룹화할 때의 하한입니다. 데이터 기록 빈도에 맞춰 설정하는 것이 좋습니다. 예를 들어, 데이터가 1분마다 기록된다면 <1>{{exampleInterval}}으로 설정하세요. ", + "description-encrypt-true": "", + "description-min-interval": "", "description-tls-cert": "SQL 서버 인증서에 서명한 CA의 공개 키 인증서가 포함된 파일의 경로입니다. 서버 인증서가 자체 서명된 경우 필요합니다.", "label-auth-settings": "Azure 인증 설정", "label-auth-type": "인증 유형", @@ -104,7 +104,7 @@ }, "kerberos-advanced-settings": { "description-dns-lookup-kdc": "DNS `SRV` 레코드를 사용하여 Realm의 KDC 및 기타 서버를 찾을지 여부를 나타냅니다. 기본값은 <1>{{default}}입니다.", - "description-krb5-config-file-path": "<2>MIT krb5 패키지의 구성 파일에 대한 경로입니다. 기본값은 <4>{{default}}입니다.", + "description-krb5-config-file-path": "", "description-udp-preference-limit": "기본값은 <1>{{default}}(으)로 항상 TCP를 사용한다는 의미이며, 선택 사항입니다.", "label-dns-lookup-kdc": "DNS 조회 KDC", "label-krb5-config-file-path": "krb5 구성 파일 경로", diff --git a/public/app/plugins/datasource/mssql/locales/nl-NL/mssql.json b/public/app/plugins/datasource/mssql/locales/nl-NL/mssql.json index 42b3950a472..6f5631edda2 100644 --- a/public/app/plugins/datasource/mssql/locales/nl-NL/mssql.json +++ b/public/app/plugins/datasource/mssql/locales/nl-NL/mssql.json @@ -41,7 +41,7 @@ "fillvalue": "door fillvalue in te stellen, vult Grafana ontbrekende waarden in volgens het interval. fillvalue kan een letterlijke waarde zijn, {{null}} of {{previous}}; {{previous}} vult de vorige waarde in of {{null}} als er nog geen is gezien", "macros": "Macro's", "optional": "Optioneel:", - "optional-tip": "retourneer kolom met de naam <1>{{columnName}} om de serienaam weer te geven.", + "optional-tip": "", "optional-tip-2": "Als meerdere waardekolommen worden geretourneerd, wordt de kolom {{columnName}} gebruikt als voorvoegsel.", "optional-tip-3": "Als er geen kolom met de naam {{columnName}} wordt gevonden, wordt de kolomnaam van de waardekolom gebruikt als reeksnaam", "resultsets-time-sorted": "Resultsets van tijdreeksquery's moeten op tijd worden gesorteerd.", @@ -56,20 +56,20 @@ "configuration-editor": { "body-user-permission": "De databasegebruiker mag alleen {{permissionType}}machtigingen krijgen voor de opgegeven database en tabellen die je wilt opvragen. Grafana valideert niet dat query's veilig zijn, zodat query's elke SQL-instructie kunnen bevatten. Bijvoorbeeld, verklaringen zoals <3>{{example1}} en <5>{{example2}} zouden worden uitgevoerd. Om dit te voorkomen, raden we je <7>sterk aan om een specifieke MS SQL-gebruiker met beperkte machtigingen te maken. Bekijk de <10>Documenten voor de Microsoft SQL Server-gegevensbron voor meer informatie.", "description-additional-settings": "Aanvullende instellingen zijn optionele instellingen die kunnen worden geconfigureerd voor meer controle over je gegevensbron. Dit omvat verbindingslimieten, verbindingstime-out, groeperen op tijdsinterval en Secure Socks Proxy.", - "description-auth-type-azure-auth": "<0>Azure-verificatie Veilig verifiëren en toegang tot Azure-bronnen en -toepassingen met behulp van Azure AD-inloggegevens waarbij 'Beheerde service-identiteiten' en 'Inloggegevens voor clientgeheim' worden ondersteund.", - "description-auth-type-credential-cache": "<0>Windows AD: cache voor inloggegevens Windows Active Directory - Meld je aan voor domeingebruiker via cache voor inloggegevens.", - "description-auth-type-credential-cache-file": "<0>Windows AD: cachebestand voor inloggegevens Windows Active Directory - Meld je aan voor domeingebruiker via cachebestand voor inloggegevens.", - "description-auth-type-keytab": "<0>Windows AD: Keytab Windows Active Directory - Meld je aan voor domeingebruiker via keytab-bestand.", - "description-auth-type-sql-server": "<0>SQL Server-verificatie Dit is het standaardmechanisme om verbinding te maken met MS SQL Server. Voer de SQL Server-verificatie-login of de Windows-verificatie-login in de indeling DOMEIN\\Gebruiker in.", - "description-auth-type-username-password": "<0>Windows AD: gebruikersnaam + wachtwoord Windows Active Directory - Meld je aan voor domeingebruiker via gebruikersnaam/wachtwoord.", - "description-auth-type-windows-auth": "<0>Windows-verificatie Windows Ingebouwde beveiliging - eenmalige aanmelding voor gebruikers die al zijn aangemeld bij Windows en deze optie hebben ingeschakeld voor MS SQL Server.", + "description-auth-type-azure-auth": "", + "description-auth-type-credential-cache": "", + "description-auth-type-credential-cache-file": "", + "description-auth-type-keytab": "", + "description-auth-type-sql-server": "", + "description-auth-type-username-password": "", + "description-auth-type-windows-auth": "", "description-connection-timeout": "Het aantal seconden dat moet worden gewacht voordat het verzoek wordt geannuleerd bij het verbinden met de database. De standaardwaarde is <1>{{defaultTimeout}}, wat betekent dat er geen time-out is.", "description-encrypt": "Bepaalt of en in welke mate een beveiligde SSL TCP/IP-verbinding met de server wordt onderhandeld.", - "description-encrypt-disable": "<0>{{encryptionValue}}: gegevens die tussen client en server worden verzonden, worden niet gecodeerd.", - "description-encrypt-false": "<0>{{encryptionValue}}: gegevens die tussen client en server worden verzonden, worden niet gecodeerd buiten het inlogpakket. (standaard)", + "description-encrypt-disable": "", + "description-encrypt-false": "", "description-encrypt-older-version": "Als je een oudere versie van Microsoft SQL Server gebruikt, zoals 2008 en 2008R2, moet je mogelijk versleuteling uitschakelen om verbinding te kunnen maken.", - "description-encrypt-true": "<0>{{encryptionValue}}: gegevens die tussen client en server worden verzonden, worden niet gecodeerd.", - "description-min-interval": "Een ondergrens voor de automatische groepering op tijdsinterval. Aanbevolen om in te stellen op schrijffrequentie, bijvoorbeeld <1>{{exampleInterval}} als je gegevens elke minuut worden geschreven.", + "description-encrypt-true": "", + "description-min-interval": "", "description-tls-cert": "Pad naar bestand met het publieke sleutelcertificaat van de CA die het SQL Server-certificaat heeft ondertekend. Nodig wanneer het servercertificaat zelfondertekend is.", "label-auth-settings": "Azure-verificatie-instellingen", "label-auth-type": "Authenticatietype", @@ -104,7 +104,7 @@ }, "kerberos-advanced-settings": { "description-dns-lookup-kdc": "Geef aan of DNS 'SRV'-records moeten worden gebruikt om de KDC's en andere servers voor een realm te lokaliseren. De standaardwaarde is <1>{{default}}.", - "description-krb5-config-file-path": "Het pad naar het configuratiebestand voor het <2>MIT krb5-pakket. De standaardwaarde is <4>{{default}}.", + "description-krb5-config-file-path": "", "description-udp-preference-limit": "De standaardwaarde is <1>{{default}} en betekent altijd TCP gebruiken en is optioneel.", "label-dns-lookup-kdc": "DNS Lookup KDC", "label-krb5-config-file-path": "pad naar het krb5-config-bestand", diff --git a/public/app/plugins/datasource/mssql/locales/pl-PL/mssql.json b/public/app/plugins/datasource/mssql/locales/pl-PL/mssql.json index d3e053cf178..98329b765fb 100644 --- a/public/app/plugins/datasource/mssql/locales/pl-PL/mssql.json +++ b/public/app/plugins/datasource/mssql/locales/pl-PL/mssql.json @@ -41,7 +41,7 @@ "fillvalue": "w przypadku ustawienia wartości fillvalue Grafana wypełni brakujące wartości zgodnie z odstępem czasu. Wartością fillvalue może być literał, {{null}} lub {{previous}}. Wartość {{previous}} wprowadza poprzednio odnotowaną wartość lub {{null}}, jeśli żadna nie została jeszcze odnotowana", "macros": "Makra:", "optional": "Opcjonalnie:", - "optional-tip": "zwraca kolumnę o nazwie <1>{{columnName}} reprezentującą nazwę serii.", + "optional-tip": "", "optional-tip-2": "Jeśli zwróconych zostanie wiele kolumn wartości, kolumna {{columnName}} zostanie użyta jako prefiks.", "optional-tip-3": "Jeśli nie zostanie znaleziona żadna kolumna o nazwie {{columnName}}, nazwa kolumny wartości zostanie użyta jako nazwa serii", "resultsets-time-sorted": "Zestawy wyników zapytań o szeregi czasowe muszą być posortowane według czasu.", @@ -56,20 +56,20 @@ "configuration-editor": { "body-user-permission": "Użytkownik bazy danych powinien mieć tylko uprawnienia {{permissionType}} do określonej bazy danych i tabel, których dotyczy zapytanie. Grafana nie sprawdza, czy zapytania są bezpieczne, więc mogą one zawierać dowolne instrukcje SQL. Na przykład instrukcje takie jak <3>{{example1}} i <5>{{example2}} zostaną wykonane. Aby się przed tym zabezpieczyć, <7>zdecydowanie zalecamy utworzenie oddzielnego użytkownika MS SQL z ograniczonymi uprawnieniami. Więcej szczegółów znajdziesz w <10>dokumentacji źródła danych Microsoft SQL Server.", "description-additional-settings": "Dodatkowe ustawienia to opcje, które można skonfigurować, aby uzyskać większą kontrolę nad źródłem danych. Obejmuje to limity połączeń, limit czasu połączenia, odstęp czasu grupowania i bezpieczny serwer proxy SOCKS.", - "description-auth-type-azure-auth": "<0>Uwierzytelnianie Azure. Bezpieczne uwierzytelnianie i dostęp do zasobów i aplikacji Azure przy użyciu danych uwierzytelniających Azure AD – obsługiwane są opcje tożsamości usługi zarządzanej i klucza tajnego klienta.", - "description-auth-type-credential-cache": "<0>Windows AD: pamięć podręczna danych uwierzytelniających. Windows Active Directory – logowanie użytkowników w domenie za pośrednictwem pamięci podręcznej danych uwierzytelniających.", - "description-auth-type-credential-cache-file": "<0>Windows AD: plik pamięci podręcznej danych uwierzytelniających. Windows Active Directory – logowanie użytkownika w domenie za pośrednictwem pliku pamięci podręcznej danych uwierzytelniających.", - "description-auth-type-keytab": "<0>Windows AD: plik Keytab. Windows Active Directory – logowanie użytkowników w domenie za pośrednictwem pliku Keytab.", - "description-auth-type-sql-server": "<0>Uwierzytelnianie SQL Server. Jest to domyślny mechanizm łączenia się z MS SQL Server. Wprowadź login do uwierzytelniania SQL Server lub login do uwierzytelniania Windows w formacie DOMENA\\Użytkownik.", - "description-auth-type-username-password": "<0>Windows AD: nazwa użytkownika i hasło. Windows Active Directory – logowanie użytkowników w domenie za pomocą nazwy użytkownika i hasła.", - "description-auth-type-windows-auth": "<0>Uwierzytelnianie Windows. Zintegrowane zabezpieczenia systemu Windows – logowanie jednokrotne dla użytkowników, którzy są już zalogowani w systemie Windows i włączyli tę opcję dla MS SQL Server.", + "description-auth-type-azure-auth": "", + "description-auth-type-credential-cache": "", + "description-auth-type-credential-cache-file": "", + "description-auth-type-keytab": "", + "description-auth-type-sql-server": "", + "description-auth-type-username-password": "", + "description-auth-type-windows-auth": "", "description-connection-timeout": "Liczba sekund oczekiwania przed anulowaniem żądania podczas łączenia się z bazą danych. Domyślnie jest to <1>{{defaultTimeout}}, co oznacza brak limitu czasu.", "description-encrypt": "Określa, czy i w jakim stopniu bezpieczne połączenie SSL TCP/IP będzie negocjowane z serwerem.", - "description-encrypt-disable": "<0>{{encryptionValue}} – dane przesyłane między klientem i serwerem nie są szyfrowane.", - "description-encrypt-false": "<0>{{encryptionValue}} – dane przesyłane między klientem i serwerem nie są szyfrowane poza pakietem logowania (domyślnie).", + "description-encrypt-disable": "", + "description-encrypt-false": "", "description-encrypt-older-version": "Jeśli używasz starszej wersji Microsoft SQL Server, takiej jak 2008 lub 2008 R2, może być konieczne wyłączenie szyfrowania w celu nawiązania połączenia.", - "description-encrypt-true": "<0>{{encryptionValue}} – dane przesyłane między klientem i serwerem są szyfrowane.", - "description-min-interval": "Dolna granica automatycznego grupowania według odstępu czasu. Zalecane jest ustawienie częstotliwości zapisu, na przykład <1>{{exampleInterval}}, jeśli dane są zapisywane co minutę. ", + "description-encrypt-true": "", + "description-min-interval": "", "description-tls-cert": "Ścieżka do pliku zawierającego certyfikat klucza publicznego urzędu certyfikacji, który podpisał certyfikat SQL Server. Wymagane, gdy certyfikat serwera jest samodzielnie podpisany.", "label-auth-settings": "Ustawienia uwierzytelniania Azure", "label-auth-type": "Typ uwierzytelniania", @@ -104,7 +104,7 @@ }, "kerberos-advanced-settings": { "description-dns-lookup-kdc": "Określ, czy rekordy DNS „SRV” powinny być używane do lokalizowania KDC i innych serwerów dla domeny. Domyślnie jest to <1>{{default}}.", - "description-krb5-config-file-path": "Ścieżka do pliku konfiguracyjnego dla <2>pakietu MIT krb5. Domyślnie jest to <4>{{default}}.", + "description-krb5-config-file-path": "", "description-udp-preference-limit": "Domyślnie jest to <1>{{default}}, co oznacza „zawsze używaj TCP”. Jest to ustawienie opcjonalne.", "label-dns-lookup-kdc": "Wyszukiwanie DNS KDC", "label-krb5-config-file-path": "Ścieżka do pliku konfiguracyjnego krb5", diff --git a/public/app/plugins/datasource/mssql/locales/pt-BR/mssql.json b/public/app/plugins/datasource/mssql/locales/pt-BR/mssql.json index 5d82fac5d17..2c99bffee93 100644 --- a/public/app/plugins/datasource/mssql/locales/pt-BR/mssql.json +++ b/public/app/plugins/datasource/mssql/locales/pt-BR/mssql.json @@ -41,7 +41,7 @@ "fillvalue": "ao definir fillvalue, o Grafana adicionará os valores que estiverem faltando de acordo com o intervalo. O fillvalue pode ser um valor literal, {{null}} ou {{previous}}. O {{previous}} adicionará o valor encontrado anteriormente ou {{null}} se nenhum valor tiver sido encontrado ainda", "macros": "Macros:", "optional": "Opcional:", - "optional-tip": "retornar a coluna chamada <1>{{columnName}} para representar o nome da série.", + "optional-tip": "", "optional-tip-2": "Se várias colunas de valor forem retornadas, a coluna {{columnName}} será usada como prefixo.", "optional-tip-3": "Se nenhuma coluna chamada {{columnName}} for encontrada, o nome da coluna de valor será usado como nome da série", "resultsets-time-sorted": "Os conjuntos de resultados de consultas de séries temporais precisam ser ordenados por tempo.", @@ -56,20 +56,20 @@ "configuration-editor": { "body-user-permission": "O usuário do banco de dados só deve receber permissões {{permissionType}} no banco de dados especificado e nas tabelas que você deseja consultar. O Grafana não verifica se as consultas são seguras, portanto, as consultas podem conter qualquer instrução SQL. Por exemplo, instruções como <3>{{example1}} e <5>{{example2}} seriam executadas. Para se proteger contra isso, é <7>muito recomendável que você crie um usuário específico do MS SQL com permissões restritas. Consulte os <10>Documentos de fonte de dados do Microsoft SQL Server para obter mais informações.", "description-additional-settings": "As configurações adicionais são opcionais, e você pode defini-las para ter mais controle sobre sua fonte de dados. Isso inclui limites de conexão, tempo limite de conexão, intervalo de tempo de agrupamento e proxy SOCKS seguro.", - "description-auth-type-azure-auth": "<0>Autenticação do Azure: realize a autenticação e acesse os recursos e aplicativos do Azure com segurança usando credenciais do Azure AD. Há compatibilidade com identidade de serviço gerenciado e credenciais de segredo do cliente.", - "description-auth-type-credential-cache": "<0>Windows AD: cache de credenciais Windows Active Directory: login para o usuário do domínio por meio do cache de credenciais.", - "description-auth-type-credential-cache-file": "<0>Windows AD: arquivo de cache de credenciais Windows Active Directory: login para o usuário do domínio por meio do arquivo de cache de credenciais.", - "description-auth-type-keytab": "<0>Windows AD: Keytab Windows Active Directory: login para o usuário do domínio por meio do arquivo keytab.", - "description-auth-type-sql-server": "<0>Autenticação do SQL Server: este é o mecanismo padrão para se conectar ao MS SQL Server. Insira o login de autenticação do SQL Server ou o login de autenticação do Windows no formato DOMAIN\\User.", - "description-auth-type-username-password": "<0>Windows AD: nome de usuário + senha Windows Active Directory: login para o usuário do domínio por meio de nome de usuário/senha.", - "description-auth-type-windows-auth": "<0>Autenticação do Windows: segurança integrada do Windows: login único para usuários que já estão conectados ao Windows e ativaram esta opção para o MS SQL Server.", + "description-auth-type-azure-auth": "", + "description-auth-type-credential-cache": "", + "description-auth-type-credential-cache-file": "", + "description-auth-type-keytab": "", + "description-auth-type-sql-server": "", + "description-auth-type-username-password": "", + "description-auth-type-windows-auth": "", "description-connection-timeout": "A quantidade de segundos de espera antes de cancelar a solicitação ao se conectar ao banco de dados. O padrão é <1>{{defaultTimeout}}, o que significa que não há tempo limite.", "description-encrypt": "Determina se ou até que ponto uma conexão TCP/IP SSL segura será estabelecida com o servidor.", - "description-encrypt-disable": "<0>{{encryptionValue}}: os dados enviados entre o cliente e o servidor não são criptografados.", - "description-encrypt-false": "<0>{{encryptionValue}}: os dados enviados entre o cliente e o servidor não são criptografados além do pacote de login (padrão).", + "description-encrypt-disable": "", + "description-encrypt-false": "", "description-encrypt-older-version": "Se você estiver usando uma versão mais antiga do Microsoft SQL Server, como 2008 e 2008R2, talvez seja necessário desativar a criptografia para poder se conectar.", - "description-encrypt-true": "<0>{{encryptionValue}}: os dados enviados entre o cliente e o servidor são criptografados.", - "description-min-interval": "Um limite inferior para o grupo automático por intervalo de tempo. Recomendamos definir a frequência de gravação — por exemplo, <1>{{exampleInterval}}, se seus dados forem gravados a cada minuto.", + "description-encrypt-true": "", + "description-min-interval": "", "description-tls-cert": "Caminho para o arquivo que contém o certificado de chave pública da CA que assinou o certificado do SQL Server. Necessário quando o certificado do servidor é autoassinado.", "label-auth-settings": "Configurações de autenticação do Azure", "label-auth-type": "Tipo de autenticação", @@ -104,7 +104,7 @@ }, "kerberos-advanced-settings": { "description-dns-lookup-kdc": "Indique se os registros DNS \"SRV\" devem ser usados para localizar os KDCs e outros servidores de um domínio. O padrão é <1>{{default}}.", - "description-krb5-config-file-path": "O caminho para o arquivo de configuração do <2>pacote MIT krb5. O padrão é <4>{{default}}.", + "description-krb5-config-file-path": "", "description-udp-preference-limit": "O valor padrão é <1>{{default}}, indicando que o TCP será usado sempre e é opcional.", "label-dns-lookup-kdc": "KDC de pesquisa de DNS", "label-krb5-config-file-path": "Caminho do arquivo de configuração krb5", diff --git a/public/app/plugins/datasource/mssql/locales/pt-PT/mssql.json b/public/app/plugins/datasource/mssql/locales/pt-PT/mssql.json index f2e3dd55456..e41988ed380 100644 --- a/public/app/plugins/datasource/mssql/locales/pt-PT/mssql.json +++ b/public/app/plugins/datasource/mssql/locales/pt-PT/mssql.json @@ -41,7 +41,7 @@ "fillvalue": "ao definir fillvalue, o Grafana preencherá os valores em falta de acordo com o intervalo. fillvalue pode ser um valor literal, {{null}} ou {{previous}}; {{previous}} preencherá o valor visto anteriormente ou {{null}}, se ainda não tiver sido visto nenhum", "macros": "Macros:", "optional": "Opcional:", - "optional-tip": "devolver a coluna com o nome <1>{{columnName}} para representar o nome da série.", + "optional-tip": "", "optional-tip-2": "Se forem devolvidas várias colunas de valor, a coluna {{columnName}} é utilizada como prefixo.", "optional-tip-3": "Se não for encontrada qualquer coluna com o nome {{columnName}}, o nome da coluna de valor é utilizado como nome da série", "resultsets-time-sorted": "Os conjuntos de resultados de consultas de séries temporais têm de ser ordenados por hora.", @@ -56,20 +56,20 @@ "configuration-editor": { "body-user-permission": "O utilizador da base de dados apenas deve obter permissões {{permissionType}} na base de dados especificada e nas tabelas que pretende consultar. O Grafana não valida que as consultas são seguras, pelo que as consultas podem conter qualquer instrução SQL. Por exemplo, instruções como <3>{{example1}} e <5>{{example2}} seriam executadas. Para se proteger contra isto, recomendamos <7>vivamente que crie um utilizador MS SQL específico com permissões restritas. Consulte os <10>Documentos de fontes de dados do Microsoft SQL Server para obter mais informações.", "description-additional-settings": "As definições adicionais são definições opcionais que podem ser configuradas para obter mais controlo sobre a sua fonte de dados. Isto inclui limites de ligação, tempo limite de ligação, intervalo de tempo de agrupamento e proxy Socks seguro.", - "description-auth-type-azure-auth": "<0>Autenticação do Azure Autentique e aceda com segurança a recursos e aplicações do Azure através de credenciais do Azure AD - são suportadas a Identidade de Serviço Gerido e as Credenciais Secretas do Cliente.", - "description-auth-type-credential-cache": "<0>Windows AD: Cache de credenciais Windows Active Directory – Início de sessão para utilizador de domínio através da cache de credenciais.", - "description-auth-type-credential-cache-file": "<0>Windows AD: Ficheiro de cache de credenciais Windows Active Directory – Início de sessão para utilizador de domínio através do ficheiro de cache de credenciais.", - "description-auth-type-keytab": "<0>Windows AD: Keytab Windows Active Directory – Início de sessão para utilizador de domínio através do ficheiro keytab.", - "description-auth-type-sql-server": "<0>Autenticação do SQL Server Este é o mecanismo predefinido para estabelecer ligação ao MS SQL Server. Introduza os dados de início de sessão de autenticação do SQL Server ou os dados de início de sessão de autenticação do Windows no formato DOMAIN\\User.", - "description-auth-type-username-password": "<0>Windows AD: Nome de utilizador + palavra-passe Windows Active Directory – Início de sessão para utilizador de domínio através de nome de utilizador/palavra-passe.", - "description-auth-type-windows-auth": "<0>Autenticação do Windows Segurança Integrada do Windows – início de sessão único para utilizadores que já iniciaram sessão no Windows e ativaram esta opção para o MS SQL Server.", + "description-auth-type-azure-auth": "", + "description-auth-type-credential-cache": "", + "description-auth-type-credential-cache-file": "", + "description-auth-type-keytab": "", + "description-auth-type-sql-server": "", + "description-auth-type-username-password": "", + "description-auth-type-windows-auth": "", "description-connection-timeout": "O número de segundos a aguardar antes de cancelar o pedido ao estabelecer ligação à base de dados. A predefinição é <1>{{defaultTimeout}}, o que significa que não há tempo limite.", "description-encrypt": "Determina se ou até que ponto uma ligação SSL TCP/IP segura será negociada com o servidor.", - "description-encrypt-disable": "<0>{{encryptionValue}} - Os dados enviados entre o cliente e o servidor não estão encriptados.", - "description-encrypt-false": "<0>{{encryptionValue}} - Os dados enviados entre o cliente e o servidor não estão encriptados além do pacote de início de sessão. (predefinição)", + "description-encrypt-disable": "", + "description-encrypt-false": "", "description-encrypt-older-version": "Se estiver a utilizar uma versão mais antiga do Microsoft SQL Server, como 2008 e 2008R2, talvez tenha de desativar a encriptação para poder estabelecer ligação.", - "description-encrypt-true": "<0>{{encryptionValue}} - Os dados enviados entre o cliente e o servidor estão encriptados.", - "description-min-interval": "Um limite inferior para o agrupamento automático por intervalo de tempo. É recomendado que seja definido para frequência de escrita, por exemplo, <1>{{exampleInterval}} se os seus dados forem escritos a cada minuto.", + "description-encrypt-true": "", + "description-min-interval": "", "description-tls-cert": "Caminho para o ficheiro que contém o certificado de chave pública da AC que assinou o certificado do SQL Server. Necessário quando o certificado do servidor é assinado automaticamente.", "label-auth-settings": "Definições de autenticação do Azure", "label-auth-type": "Tipo de autenticação", @@ -104,7 +104,7 @@ }, "kerberos-advanced-settings": { "description-dns-lookup-kdc": "Indique se os registos DNS \"SRV\" devem ser utilizados para localizar os KDC e outros servidores para um âmbito. A predefinição é <1>{{default}}.", - "description-krb5-config-file-path": "O caminho para o ficheiro de configuração do <2>pacote MIT krb5. A predefinição é <4>{{default}}.", + "description-krb5-config-file-path": "", "description-udp-preference-limit": "A predefinição é <1>{{default}}, que significa utilizar sempre TCP, e é opcional.", "label-dns-lookup-kdc": "KDC de pesquisa de DNS", "label-krb5-config-file-path": "Caminho do ficheiro de configuração krb5", diff --git a/public/app/plugins/datasource/mssql/locales/ru-RU/mssql.json b/public/app/plugins/datasource/mssql/locales/ru-RU/mssql.json index cd8f4ea9b73..2a8cc95e103 100644 --- a/public/app/plugins/datasource/mssql/locales/ru-RU/mssql.json +++ b/public/app/plugins/datasource/mssql/locales/ru-RU/mssql.json @@ -41,7 +41,7 @@ "fillvalue": "установив значение fillvalue, Grafana заполнит отсутствующие значения в соответствии с интервалом. Значение fillvalue может быть литеральным, {{null}} либо {{previous}}. Если ничего не было найдено, {{previous}} будет использовано в качестве предыдущего найденного значение или {{null}}.", "macros": "Макрос:", "optional": "Необязательно:", - "optional-tip": "возвращает столбец с именем <1>{{columnName}} для отображения имени ряда.", + "optional-tip": "", "optional-tip-2": "Если возвращается несколько столбцов значений, столбец {{columnName}} используется в качестве префикса.", "optional-tip-3": "Если столбец с именем {{columnName}} не найден, имя столбца значения используется в качестве имени ряда.", "resultsets-time-sorted": "Наборы результатов, возвращаемых запросами временных рядов, должны сортироваться по времени.", @@ -56,20 +56,20 @@ "configuration-editor": { "body-user-permission": "Пользователю базы данных должны быть предоставлены только разрешения типа {{permissionType}} для указанной базы данных и таблиц, которые вы хотите запросить. Grafana не проверяет безопасность запросов, поэтому они могут содержать любые операторы SQL. Например, будут выполнены такие операторы, как <3>{{example1}} и <5>{{example2}}. Чтобы этого избежать, <7>настоятельно рекомендуем создать отдельного пользователя MS SQL с ограниченными разрешениями. Подробнее — в <10>документации по источникам данных Microsoft SQL Server.", "description-additional-settings": "Дополнительные параметры — это необязательные параметры, которые можно настроить для получения большего контроля над источником данных. Сюда входят ограничения на подключение, время ожидания подключения, группировка по временному интервалу и безопасный Socks-прокси.", - "description-auth-type-azure-auth": "<0>Аутентификация Azure. Безопасная аутентификация и доступ к ресурсам и приложениям Azure с использованием учетных данных Azure AD. Поддерживаются управляемые удостоверения службы и учетные данные секрета клиента.", - "description-auth-type-credential-cache": "<0>Windows AD: кэш учетных данных. Windows Active Directory — вход для пользователя домена через кэш учетных данных.", - "description-auth-type-credential-cache-file": "<0>Windows AD: файл кэша учетных данных. Windows Active Directory — вход для пользователя домена через файл кэша учетных данных.", - "description-auth-type-keytab": "<0>Windows AD: Keytab. Windows Active Directory — вход для пользователя домена через keytab-файл.", - "description-auth-type-sql-server": "<0>Аутентификация SQL Server. Механизм по умолчанию для подключения к MS SQL Server. Введите имя пользователя для аутентификации SQL Server или имя пользователя для аутентификации Windows в формате «ДОМЕН\\пользователь».", - "description-auth-type-username-password": "<0>Windows AD: имя пользователя + пароль. Windows Active Directory — вход для пользователя домена с помощью имени пользователя/пароля.", - "description-auth-type-windows-auth": "<0>Аутентификация Windows. Windows Integrated Security — единый вход для пользователей, которые уже вошли в Windows и включили эту опцию для MS SQL Server.", + "description-auth-type-azure-auth": "", + "description-auth-type-credential-cache": "", + "description-auth-type-credential-cache-file": "", + "description-auth-type-keytab": "", + "description-auth-type-sql-server": "", + "description-auth-type-username-password": "", + "description-auth-type-windows-auth": "", "description-connection-timeout": "Время ожидания (в секундах) перед отменой запроса при подключении к базе данных. Значение по умолчанию — <1>{{defaultTimeout}}, что означает отсутствие времени ожидания.", "description-encrypt": "Определяет, будет ли согласовываться с сервером безопасное соединение SSL TCP/IP и степень согласования.", - "description-encrypt-disable": "<0>{{encryptionValue}}: данные, передаваемые между клиентом и сервером, не шифруются.", - "description-encrypt-false": "<0>{{encryptionValue}}: данные, передаваемые между клиентом и сервером, не шифруются за пределами пакета входа в систему (по умолчанию).", + "description-encrypt-disable": "", + "description-encrypt-false": "", "description-encrypt-older-version": "Если вы используете более старую версию Microsoft SQL Server, например 2008 или 2008R2, для подключения может требоваться отключение шифрования.", - "description-encrypt-true": "<0>{{encryptionValue}}: данные, передаваемые между клиентом и сервером, шифруются.", - "description-min-interval": "Нижний предел для автоматической группировки по временному интервалу. Рекомендуется установить частоту записи, например <1>{{exampleInterval}}, если ваши данные записываются каждую минуту.", + "description-encrypt-true": "", + "description-min-interval": "", "description-tls-cert": "Путь к файлу, содержащему сертификат открытого ключа центра сертификации, который подписал сертификат SQL Server. Требуется, когда сертификат сервера является самозаверяющим.", "label-auth-settings": "Параметры аутентификации Azure", "label-auth-type": "Тип аутентификации", @@ -104,7 +104,7 @@ }, "kerberos-advanced-settings": { "description-dns-lookup-kdc": "Укажите, следует ли использовать служебные записи DNS для поиска KDC и других серверов для области. Значение по умолчанию — <1>{{default}}.", - "description-krb5-config-file-path": "Путь к файлу конфигурации для <2>пакета MIT krb5. Значение по умолчанию — <4>{{default}}.", + "description-krb5-config-file-path": "", "description-udp-preference-limit": "Значение по умолчанию — <1>{{default}}, что означает всегда использовать TCP (необязательно).", "label-dns-lookup-kdc": "DNS-поиск KDC", "label-krb5-config-file-path": "Путь к файлу конфигурации krb5", diff --git a/public/app/plugins/datasource/mssql/locales/sv-SE/mssql.json b/public/app/plugins/datasource/mssql/locales/sv-SE/mssql.json index 6ce25bc663a..f5fad3ac672 100644 --- a/public/app/plugins/datasource/mssql/locales/sv-SE/mssql.json +++ b/public/app/plugins/datasource/mssql/locales/sv-SE/mssql.json @@ -41,7 +41,7 @@ "fillvalue": "genom att ange fyllnadsvärde fyller Grafana i saknade värden enligt intervallet. Fyllnadsvärdet kan vara ett bokstavligt värde, {{null}} eller {{previous}}. {{previous}} fyller i det senast sedda värdet eller {{null}} om inget värde har setts ännu", "macros": "Makron:", "optional": "Valfritt:", - "optional-tip": "returnerar kolumn med namnet <1>{{columnName}} för att representera serienamnet.", + "optional-tip": "", "optional-tip-2": "Om flera värdekolumner returneras används kolumnen {{columnName}} som prefix.", "optional-tip-3": "Om ingen kolumn med namnet {{columnName}} hittas används kolumnnamnet för värdekolumnen som serienamn", "resultsets-time-sorted": "Resultatuppsättningar från tidsseriekörningar måste sorteras efter tid.", @@ -56,20 +56,20 @@ "configuration-editor": { "body-user-permission": "Databasens användare bör endast beviljas {{permissionType}}-behörigheter för den angivna databasen och de tabeller du vill fråga. Grafana validerar inte att frågor är säkra, så frågor kan innehålla vilken SQL-sats som helst. Till exempel skulle satser som <3>{{example1}} och <5>{{example2}} köras. För att skydda mot det rekommenderar vi <7>bestämt att du skapar en specifik MS SQL-användare med begränsade behörigheter. Se <10>dokumentationen för Microsoft SQL Server-datakällan för mer information.", "description-additional-settings": "Ytterligare inställningar är valfria inställningar som kan konfigureras för ökad kontroll över din datakälla. Detta inkluderar anslutningsgränser, anslutningstimeout, gruppering efter tidsintervall och säker SOCKS-proxy.", - "description-auth-type-azure-auth": "<0>Azure-autentisering Autentisera och få åtkomst till Azure-resurser och -program på ett säkert sätt med hjälp av Azure AD-autentiseringsuppgifter – hanterad tjänsteidentitet och hemliga klientautentiseringsuppgifter stöds.", - "description-auth-type-credential-cache": "<0>Windows AD: Autentiseringsuppgiftscache Windows Active Directory – Logga in som domänanvändare via autentiseringsuppgiftscache.", - "description-auth-type-credential-cache-file": "<0>Windows AD: Autentiseringsuppgiftscachefil Windows Active Directory – Logga in som domänanvändare via autentiseringsuppgiftscachefil.", - "description-auth-type-keytab": "<0>Windows AD: Keytab Windows Active Directory – Logga in som domänanvändare via keytab-fil.", - "description-auth-type-sql-server": "<0>SQL Server-autentisering Detta är standardmekanismen för anslutning till MS SQL Server. Ange inloggningen för SQL Server-autentisering eller Windows-autentisering i formatet DOMÄN\\Användare.", - "description-auth-type-username-password": "<0>Windows AD: Användarnamn + lösenord Windows Active Directory – Logga in som domänanvändare med användarnamn/lösenord.", - "description-auth-type-windows-auth": "<0>Windows-autentisering Windows Integrated Security – Enkel inloggning för användare som redan är inloggade i Windows och har aktiverat det här alternativet för MS SQL Server.", + "description-auth-type-azure-auth": "", + "description-auth-type-credential-cache": "", + "description-auth-type-credential-cache-file": "", + "description-auth-type-keytab": "", + "description-auth-type-sql-server": "", + "description-auth-type-username-password": "", + "description-auth-type-windows-auth": "", "description-connection-timeout": "Antalet sekunder att vänta innan begäran avbryts vid anslutning till databasen. Standard är <1>{{defaultTimeout}}, vilket innebär ingen timeout.", "description-encrypt": "Bestämmer om, och i vilken utsträckning, en säker SSL TCP/IP-anslutning ska förhandlas med servern.", - "description-encrypt-disable": "<0>{{encryptionValue}} – Data som skickas mellan klient och server är inte krypterade.", - "description-encrypt-false": "<0>{{encryptionValue}} – Data som skickas mellan klient och server är inte krypterade utöver inloggningspaketet. (standard)", + "description-encrypt-disable": "", + "description-encrypt-false": "", "description-encrypt-older-version": "Om du använder en äldre version av Microsoft SQL Server, exempelvis 2008 eller 2008R2, kan du behöva inaktivera kryptering för att kunna ansluta.", - "description-encrypt-true": "<0>{{encryptionValue}} – Data som skickas mellan klient och server är krypterade.", - "description-min-interval": "En nedre gräns för den automatiska grupperingen efter tidsintervall. Rekommenderas att ställas in på skrivfrekvens, till exempel<1>{{exampleInterval}} om data skrivs varje minut.", + "description-encrypt-true": "", + "description-min-interval": "", "description-tls-cert": "Sökväg till fil som innehåller det offentliga nyckelcertifikatet för den certifikatutfärdare som undertecknade SQL Server-certifikatet. Behövs när servercertifikatet är självsignerat.", "label-auth-settings": "Inställningar för Azure-autentisering", "label-auth-type": "Behörighetskontrolltyp", @@ -104,7 +104,7 @@ }, "kerberos-advanced-settings": { "description-dns-lookup-kdc": "Ange om DNS \"SRV\"-poster ska användas för att hitta KDC:er och andra servrar för en realm. Standard är <1>{{default}}.", - "description-krb5-config-file-path": "Sökvägen till konfigurationsfilen för <2>MIT krb5-paketet. Standard är <4>{{default}}.", + "description-krb5-config-file-path": "", "description-udp-preference-limit": "Standard är <1>{{default}} och innebär att alltid använda TCP och är valfritt.", "label-dns-lookup-kdc": "DNS-sökning KDC", "label-krb5-config-file-path": "Sökväg till krb5-konfigurationsfil", diff --git a/public/app/plugins/datasource/mssql/locales/tr-TR/mssql.json b/public/app/plugins/datasource/mssql/locales/tr-TR/mssql.json index 40467699fe0..585a8541064 100644 --- a/public/app/plugins/datasource/mssql/locales/tr-TR/mssql.json +++ b/public/app/plugins/datasource/mssql/locales/tr-TR/mssql.json @@ -41,7 +41,7 @@ "fillvalue": "fillvalue ayarlanarak Grafana, eksik değerleri belirtilen aralığa göre dolduracaktır. fillvalue bir sabit değer, {{null}} veya {{previous}} olabilir. {{previous}} ise daha önce görülen değeri doldurur; daha önce bir değer görülmemişse {{null}} ile doldurur.", "macros": "Makrolar:", "optional": "İsteğe Bağlı:", - "optional-tip": "Dönüş değeri olarak seri adını temsil etmesi için <1>{{columnName}} adlı sütunu kullanın.", + "optional-tip": "", "optional-tip-2": "Birden fazla değer sütunu döndürülürse {{columnName}} sütunu ön ek olarak kullanılır.", "optional-tip-3": "{{columnName}} adında bir sütun bulunamazsa değer sütununun adı seri adı olarak kullanılır.", "resultsets-time-sorted": "Zaman serisi sorgularının sonuç kümeleri zamana göre sıralanmalıdır.", @@ -56,20 +56,20 @@ "configuration-editor": { "body-user-permission": "Veritabanı kullanıcısına, yalnızca belirtilen veritabanı ve sorgulamak istediğiniz tablolar için {{permissionType}} izinleri verilmelidir. Grafana sorguların güvenli olduğunu doğrulamaz, bu nedenle sorgular herhangi bir SQL ifadesi içerebilir. Örneğin, <3>{{example1}} ve <5>{{example2}} gibi ifadeler yürütülür. Buna karşı korunmak için <7>kesinlikle kısıtlı izinlere sahip belirli bir MS SQL kullanıcısı oluşturmanızı öneririz. Daha fazla bilgi için <10>Microsoft SQL Server Veri Kaynağı Belgelerine göz atın.", "description-additional-settings": "Ek ayarlar, veri kaynağınız üzerinde daha fazla kontrol sağlamak için yapılandırılabilen isteğe bağlı ayarlardır. Bunlar bağlantı sınırları, bağlantı zaman aşımı, zamana göre gruplama aralığı ve Güvenli Socks Proxy'yi içerir.", - "description-auth-type-azure-auth": "<0>Azure Kimlik Doğrulaması Azure AD kimlik bilgilerini kullanarak Azure kaynaklarına ve uygulamalarına güvenli bir şekilde kimlik doğrulaması yapın ve erişin. Yönetilen Hizmet Kimliği ve İstemci Gizli Kimlik Bilgileri desteklenmektedir.", - "description-auth-type-credential-cache": "<0>Windows AD: Kimlik bilgileri önbelleği Windows Active Directory: Kimlik bilgileri ön belleği aracılığıyla alan adı kullanıcısı için giriş yapma.", - "description-auth-type-credential-cache-file": "<0>Windows AD: Kimlik bilgileri önbellek dosyası Windows Active Directory: Kimlik bilgileri ön bellek dosyası aracılığıyla alan adı kullanıcısı için giriş yapma.", - "description-auth-type-keytab": "<0>Windows AD: Keytab Windows Active Directory: Keytab dosyası aracılığıyla alan adı kullanıcısı için giriş yapma.", - "description-auth-type-sql-server": "<0>SQL Server Kimlik Doğrulaması Bu, MS SQL Server'a bağlanmak için varsayılan mekanizmadır. SQL Server Kimlik Doğrulama girişini veya Windows Kimlik Doğrulama girişini DOMAIN\\Kullanıcı biçiminde girin.", - "description-auth-type-username-password": "<0>Windows AD: Kullanıcı adı + parola Windows Active Directory: Kullanıcı adı/parola aracılığıyla alan adı kullanıcısı için giriş yapma.", - "description-auth-type-windows-auth": "<0>Windows Kimlik Doğrulaması Windows Entegre Güvenliği: Windows'a zaten giriş yapmış ve MS SQL Server için bu seçeneği etkinleştirmiş kullanıcılar için çoklu oturum yapma.", + "description-auth-type-azure-auth": "", + "description-auth-type-credential-cache": "", + "description-auth-type-credential-cache-file": "", + "description-auth-type-keytab": "", + "description-auth-type-sql-server": "", + "description-auth-type-username-password": "", + "description-auth-type-windows-auth": "", "description-connection-timeout": "Veritabanına bağlanırken isteği iptal etmeden önce beklenecek saniye sayısıdır. Varsayılan değer <1>{{defaultTimeout}} olduğu için zaman aşımı yoktur.", "description-encrypt": "Sunucuyla güvenli bir SSL TCP/IP bağlantısının kurulup kurulmayacağını veya ne ölçüde kurulacağını belirler.", - "description-encrypt-disable": "<0>{{encryptionValue}}: İstemci ve sunucu arasında gönderilen veriler şifrelenmez.", - "description-encrypt-false": "<0>{{encryptionValue}}: İstemci ve sunucu arasında gönderilen veriler, giriş paketi dışında şifrelenmez. (varsayılan)", + "description-encrypt-disable": "", + "description-encrypt-false": "", "description-encrypt-older-version": "Microsoft SQL Server'ın 2008 ve 2008R2 gibi eski bir sürümünü kullanıyorsanız bağlanabilmek için şifrelemeyi devre dışı bırakmanız gerekebilir.", - "description-encrypt-true": "<0>{{encryptionValue}}: İstemci ve sunucu arasında gönderilen veriler şifrelenir.", - "description-min-interval": "Otomatik gruplama zaman aralığı için alt sınır. Verileriniz her dakika yazılıyorsa (<1>{{exampleInterval}} gibi) yazma sıklığına ayarlanması önerilir.", + "description-encrypt-true": "", + "description-min-interval": "", "description-tls-cert": "SQL Server sertifikasını imzalayan Sertifika Yetkilisinin (CA) genel anahtar sertifikasını içeren dosyanın yolu. Sunucu sertifikası kendi kendine imzalanmışsa gereklidir.", "label-auth-settings": "Azure Kimlik Doğrulama Ayarları", "label-auth-type": "Kimlik Doğrulama Türü", @@ -104,7 +104,7 @@ }, "kerberos-advanced-settings": { "description-dns-lookup-kdc": "Bir alan için KDC'leri ve diğer sunucuları bulmak için DNS SRV kayıtlarının kullanılıp kullanılmayacağını belirtir. Varsayılan değer <1>{{default}}.", - "description-krb5-config-file-path": "<2>MIT krb5 paketi için yapılandırma dosyasının yolu. Varsayılan değer <4>{{default}}.", + "description-krb5-config-file-path": "", "description-udp-preference-limit": "Varsayılan değer <1>{{default}} olduğu için her zaman TCP kullanılır ve isteğe bağlıdır.", "label-dns-lookup-kdc": "DNS Arama KDC", "label-krb5-config-file-path": "krb5 yapılandırma dosyasının yolu", diff --git a/public/app/plugins/datasource/mssql/locales/zh-Hans/mssql.json b/public/app/plugins/datasource/mssql/locales/zh-Hans/mssql.json index 61c8f110405..e13b1998e93 100644 --- a/public/app/plugins/datasource/mssql/locales/zh-Hans/mssql.json +++ b/public/app/plugins/datasource/mssql/locales/zh-Hans/mssql.json @@ -41,7 +41,7 @@ "fillvalue": "通过设置 fillvalue,Grafana 将根据时间间隔填充缺失值。fillvalue 可以是字面值、{{null}} 或 {{previous}};{{previous}} 将填充上一个已查看值,如果尚未查看,则填充 {{null}}。", "macros": "宏:", "optional": "可选:", - "optional-tip": "返回名为 <1>{{columnName}} 的列,表示序列名称。", + "optional-tip": "", "optional-tip-2": "如果返回多个值列,则使用 {{columnName}} 列作为前缀。", "optional-tip-3": "如果未找到名为 {{columnName}} 的列,则使用值列的列名作为序列名称", "resultsets-time-sorted": "时间序列查询的结果集需要按时间排序。", @@ -56,20 +56,20 @@ "configuration-editor": { "body-user-permission": "数据库用户只能在指定的数据库和要查询的表上获得 {{permissionType}} 权限。Grafana 不会验证查询是否安全,因此查询可以包含任何 SQL 语句。例如,会执行 <3>{{example1}} 和 <5>{{example2}} 这样的语句。为防止出现这种情况,我们<7>强烈建议您创建一个具有受限权限的特定 MS SQL 用户。有关详细信息,请查看 <10>Microsoft SQL Server 数据源文档。", "description-additional-settings": "附加设置是可选设置,可通过配置对数据源进行更多控制。这包括连接限制、连接超时、分组时间间隔和安全 Socks 代理。", - "description-auth-type-azure-auth": "<0>Azure 身份验证 使用 Azure AD 凭证安全地验证和访问 Azure 资源和应用程序 - 支持托管服务身份和客户端密文凭证。", - "description-auth-type-credential-cache": "<0>Windows AD:凭证缓存 Windows Active Directory - 通过凭证缓存登录域用户。", - "description-auth-type-credential-cache-file": "<0>Windows AD:凭证缓存文件 Windows Active Directory - 通过凭证缓存文件登录域用户。", - "description-auth-type-keytab": "<0>Windows AD:Keytab Windows Active Directory - 通过 keytab 文件登录域用户。", - "description-auth-type-sql-server": "<0>SQL Server 身份验证 这是连接 MS SQL Server 的默认机制。以 DOMAIN\\User 格式输入 SQL Server 身份验证登录名或 Windows 身份验证登录名。", - "description-auth-type-username-password": "<0>Windows AD:用户名 + 密码 Windows 活动目录 - 通过用户名/密码登录域用户。", - "description-auth-type-windows-auth": "<0>Windows 身份验证 Windows 集成安全 - 为已登录到 Windows 并已为 MS SQL Server 启用此选项的用户提供单点登录。", + "description-auth-type-azure-auth": "", + "description-auth-type-credential-cache": "", + "description-auth-type-credential-cache-file": "", + "description-auth-type-keytab": "", + "description-auth-type-sql-server": "", + "description-auth-type-username-password": "", + "description-auth-type-windows-auth": "", "description-connection-timeout": "连接数据库时取消请求前的等待秒数。默认值为 <1>{{defaultTimeout}},表示不超时。", "description-encrypt": "用于确定是否与服务器协商建立安全的 SSL TCP/IP 连接,以及协商的程度。", - "description-encrypt-disable": "<0>{{encryptionValue}} - 客户端和服务器之间发送的数据未加密。", - "description-encrypt-false": "<0>{{encryptionValue}} - 客户端和服务器之间发送的数据除登录数据包外不加密。(默认值)", + "description-encrypt-disable": "", + "description-encrypt-false": "", "description-encrypt-older-version": "如果您使用的是 2008 和 2008R2 等旧版本的 Microsoft SQL Server,可能需要禁用加密才能连接。", - "description-encrypt-true": "<0>{{encryptionValue}} - 客户端和服务器之间发送的数据已加密。", - "description-min-interval": "按时间间隔划分的自动分组下限。如果数据每分钟写入一次,建议设置为写入频率,例如<1>{{exampleInterval}}。", + "description-encrypt-true": "", + "description-min-interval": "", "description-tls-cert": "包含签署 SQL Server 证书的 CA 的公钥证书的文件路径。服务器证书为自签名时需要。", "label-auth-settings": "Azure 身份验证设置", "label-auth-type": "身份验证类型", @@ -104,7 +104,7 @@ }, "kerberos-advanced-settings": { "description-dns-lookup-kdc": "指明是否应使用 DNS `SRV`记录来定位领域的 KDC 和其他服务器。默认值为 <1>{{default}}。", - "description-krb5-config-file-path": "<2>MIT krb5 软件包配置文件的路径。默认值为 <4>{{default}}。", + "description-krb5-config-file-path": "", "description-udp-preference-limit": "默认值为 <1>{{default}},表示始终使用 TCP,为可选项。", "label-dns-lookup-kdc": "DNS 查询 KDC", "label-krb5-config-file-path": "krb5 配置文件路径", diff --git a/public/app/plugins/datasource/mssql/locales/zh-Hant/mssql.json b/public/app/plugins/datasource/mssql/locales/zh-Hant/mssql.json index 2e30bf4f00d..bdcd2b1831b 100644 --- a/public/app/plugins/datasource/mssql/locales/zh-Hant/mssql.json +++ b/public/app/plugins/datasource/mssql/locales/zh-Hant/mssql.json @@ -41,7 +41,7 @@ "fillvalue": "透過設定 fillvalue,Grafana 將根據間隔填寫缺失的值。fillvalue 可以是文字值、{{null}} 或 {{previous}};如果尚未看到任何值,{{previous}} 將填先前看到的值或 {{null}}", "macros": "巨集:", "optional": "可選:", - "optional-tip": "傳回名為<1>{{columnName}}的欄位,以代表系列名稱。", + "optional-tip": "", "optional-tip-2": "如果傳回多個值的欄位,則「{{columnName}}」欄會用作前綴。", "optional-tip-3": "如果找不到名為「{{columnName}}」的欄,則值的欄位名稱會用作序列名稱", "resultsets-time-sorted": "時間序列查詢的結果集需要按時間排序。", @@ -56,20 +56,20 @@ "configuration-editor": { "body-user-permission": "資料庫使用者應僅獲授予您要查詢的指定資料庫和表格的{{permissionType}}權限。Grafana 不會驗證查詢是否安全,因此查詢可以包含任何 SQL 陳述式。例如,系統會執行 <3>{{example1}} 和 <5>{{example2}} 等陳述式。為了防止這種情況,<7>強烈建議您建立權限受限的特定 MS SQL 使用者。請參閱 <10>Microsoft SQL Server 資料來源文件,了解更多資訊。", "description-additional-settings": "附加設定為可選設定,可進行設定以便更妥善掌控您的資料來源,其中包括連線限制、連線逾時、按時間間隔分組和安全 Socks 代理。", - "description-auth-type-azure-auth": "<0>Azure 驗證使用 Azure AD 憑證安全地驗證和存取 Azure 資源和應用程式 - 支援受控服務身分識別和用戶端密碼憑證。", - "description-auth-type-credential-cache": "<0>Windows AD:憑證快取 Windows Active Directory - 透過憑證快取登入網域使用者。", - "description-auth-type-credential-cache-file": "<0>Windows AD:憑證快取檔案 Windows Active Directory - 透過憑證快取檔案登入網域使用者。", - "description-auth-type-keytab": "<0>Windows AD:金鑰表 Windows Active Directory - 透過金鑰表檔案登入網域使用者。", - "description-auth-type-sql-server": "<0>SQL Server 驗證 這是連接到 MS SQL Server 的預設機制。以 DOMAIN\\User 格式輸入 SQL Server 驗證登入或 Windows 驗證登入。", - "description-auth-type-username-password": "<0>Windows AD:使用者名稱 + 密碼 Windows Active Directory - 透過使用者名稱/密碼登入網域使用者。", - "description-auth-type-windows-auth": "<0>Windows 驗證 Windows 整合式安全性 - 為已登入 Windows 並已啟用 MS SQL Server 此選項的使用者提供單一登入。", + "description-auth-type-azure-auth": "", + "description-auth-type-credential-cache": "", + "description-auth-type-credential-cache-file": "", + "description-auth-type-keytab": "", + "description-auth-type-sql-server": "", + "description-auth-type-username-password": "", + "description-auth-type-windows-auth": "", "description-connection-timeout": "連接到資料庫時,取消請求之前要等待的秒數。預設值為 <1>{{defaultTimeout}},表示沒有逾時。", "description-encrypt": "決定是否或在多大程度上與伺服器協商安全的 SSL TCP/IP 連線。", - "description-encrypt-disable": "<0>{{encryptionValue}} - 用戶端和伺服器之間傳送的資料未加密。", - "description-encrypt-false": "<0>{{encryptionValue}} - 用戶端和伺服器之間傳送的資料不會在登入封包之外加密。(預設)", + "description-encrypt-disable": "", + "description-encrypt-false": "", "description-encrypt-older-version": "如果您使用的是舊版本的 Microsoft SQL Server(如 2008 和 2008R2),則可能需要停用加密才能連線。", - "description-encrypt-true": "<0>{{encryptionValue}} - 用戶端和伺服器之間傳送的資料已加密。", - "description-min-interval": "按時間間隔自動分組的下限。建議設定為寫入頻率,例如 <1>{{exampleInterval}},如果您的資料每分鐘寫入一次,則設定為 <1>1 分鐘。", + "description-encrypt-true": "", + "description-min-interval": "", "description-tls-cert": "包含簽署 SQL Server 憑證的 CA 之公開金鑰憑證的檔案路徑。伺服器憑證自行簽署時需要。", "label-auth-settings": "Azure 驗證設定", "label-auth-type": "身分驗證類型", @@ -104,7 +104,7 @@ }, "kerberos-advanced-settings": { "description-dns-lookup-kdc": "指明是否應使用 DNS「SRV」紀錄,來定位領域的 KDC 和其他伺服器。預設值為 <1>{{default}}。", - "description-krb5-config-file-path": "<2>MIT krb5 套件的設定檔案路徑。預設值為 <4>{{default}}。", + "description-krb5-config-file-path": "", "description-udp-preference-limit": "預設值為 <1>{{default}},表示一律使用 TCP,且為選用。", "label-dns-lookup-kdc": "DNS 查找 KDC", "label-krb5-config-file-path": "krb5 設定檔案路徑", diff --git a/public/locales/cs-CZ/grafana.json b/public/locales/cs-CZ/grafana.json index 670906c1906..5b9e80a4404 100644 --- a/public/locales/cs-CZ/grafana.json +++ b/public/locales/cs-CZ/grafana.json @@ -108,7 +108,7 @@ "dismiss": "Zamítnout", "heading": "Ověření Enterprise", "learn-more-link": "Další informace", - "text": "Spravujte uživatele, týmy a oprávnění automaticky pomocí <1>SAML, <3>SCIM, <6>LDAP a <8>RBAC – dostupné v Grafana Cloud a Enterprise." + "text": "" }, "feature-listing": { "title-auditing": "Provádění auditu", @@ -209,7 +209,7 @@ "title-delete": "Odstranit" }, "orgs": { - "delete-body": "Opravdu chcete odstranit organizaci „{{deleteOrgName}}“?<3> <5>Tímto odeberete všechny nástěnky pro tuto organizaci.", + "delete-body": "", "id-header": "ID", "name-header": "Název", "new-org-button": "Nová organizace" @@ -725,6 +725,7 @@ "title-annotations": "Vysvětlivky" }, "link-dashboard-and-panel": "Propojit nástěnku a panel", + "placeholder-value-input": "", "placeholder-value-input-default": "Zadejte obsah vlastní vysvětlivky…" }, "bulk-actions": { @@ -1154,7 +1155,7 @@ "title-something-wrong-trying-fetch-group-details": "Při pokusu o načtení podrobností o skupině se něco pokazilo" }, "evaluation-interval-limit-exceeded": { - "body-minimum-interval": "Minimální interval hodnocení <1>{{minInterval}} byl nakonfigurován v Grafaně.<3>Chcete-li nakonfigurovat nižší interval, obraťte se na správce.", + "body-minimum-interval": "", "title-global-evaluation-interval-limit-exceeded": "Byl překročen limit globálního intervalu hodnocení" }, "existing-rule-editor": { @@ -1302,7 +1303,7 @@ "resolved": "Vyřešeno" } }, - "review-alert-payload": " Zkontrolujte data výstrahy a přidejte je k datovému obsahu:", + "review-alert-payload": "", "title-add-custom-alerts": "Přidejte vlastní výstrahy" }, "get-alert-suggestions": { @@ -1426,7 +1427,7 @@ "title-add-folder-and-labels": "Přidat složku a štítky" }, "grafana-managed-rule-type": { - "description": "Podporuje více zdrojů dat jakéhokoli druhu.<1>Transformujte data pomocí výrazů." + "description": "" }, "grafana-modify-export": { "body-invalid-rule-id": "Pravidlo UID v adrese URL stránky je neplatné. Zkontrolujte adresu URL a zkuste to znovu.", @@ -1865,7 +1866,7 @@ "aria-label-new": "nové" }, "mimir-flavored-type": { - "description": "Použijte zdroj dat Mimir, Loki nebo Cortex.<1>Výrazy nejsou podporovány." + "description": "" }, "min-interval-option": { "label-interval": "Interval", @@ -2094,7 +2095,7 @@ "warning-1": "Odstraněním těchto zásad oznamování dojde k jejich trvalému odebrání.", "warning-2": "Určitě chcete zásady odstranit?" }, - "filter-description": "Filtrujte zásady oznamování pomocí seznamu odpovídajících osob oddělených čárkami, např.:<1>závažnost = kritická, region = EMEA", + "filter-description": "", "generated-policies": "Automaticky generované zásady", "matchers": "Srovnávače", "metadata": { @@ -2140,7 +2141,8 @@ "conflict": "Strom zásad oznamování byl aktualizován jiným uživatelem.", "error-code": "Chybová zpráva: „{{error}}“", "routes": { - "conflictingMatchers": "Nelze přidat nebo aktualizovat směrování: při sloučení matcherů {{-matchers}} dojde ke konfliktu s externím směrovacím stromem. To by způsobilo nedosažitelnost směrování." + "conflictingMatchers": "Nelze přidat nebo aktualizovat směrování: při sloučení matcherů {{-matchers}} dojde ke konfliktu s externím směrovacím stromem. To by způsobilo nedosažitelnost směrování.", + "unknownMatchers": "" }, "suffix": "Aktualizujte stránku a zkuste to znovu.", "title": "Nepodařilo se přidat nebo aktualizovat zásadu oznamování" @@ -2260,7 +2262,7 @@ "error-no-query-editor": "Nelze načíst editor dotazů, důvod: {{errorMessage}}" }, "recording-rule-type": { - "description": "Předpočítat výrazy.<1>Mělo by být kombinováno v pravidle výstrahy." + "description": "" }, "recording-rules": { "description-target-data-source": "Zdroj dat Prometheus, do kterého se uloží pravidla záznamu", @@ -2273,7 +2275,7 @@ }, "redirect-to-clone-rule": { "body-evaluation-group": "Pro zkopírované pravidlo budete muset nastavit novou hodnotící skupinu, protože původní skupina byla zajištěna a nelze ji použít pro pravidla vytvořená v uživatelském rozhraní.", - "body-not-provisioned": "Nové pravidlo <1>nebude označeno jako zajištěné pravidlo.", + "body-not-provisioned": "", "confirmText-copy": "Kopírovat", "title-copy-provisioned-alert-rule": "Kopírovat zajištěné pravidlo výstrahy" }, @@ -2308,13 +2310,13 @@ "routing-settings": { "aria-label-group-by": "Seřadit podle", "description-group-by": "Kombinujte více výstrah do jednoho oznámení jejich seskupením podle stejných hodnot štítku. Pokud není vyplněno, načte se z výchozí zásady oznamování.", - "group-interval": "Interval skupiny: <1>{{groupIntervalValue}}", - "group-wait": "Interval skupiny: <1>{{groupWaitValue}}", - "grouping": "Seskupení: <1>{{fields}}", + "group-interval": "", + "group-wait": "", + "grouping": "", "label-group-by": "Seřadit podle", "label-override-grouping": "Přepsat seskupení", "label-override-timings": "Přepsat časování", - "repeat-interval": "Interval opakování: <1>{{repeatIntervalValue}}" + "repeat-interval": "" }, "rule-actions-buttons": { "title-edit": "Upravit", @@ -2578,7 +2580,7 @@ "relative-with-to": "" }, "rule-type-picker": { - "grafana-managed": "Pokud nemáte zdroj dat Mimir, Loki nebo Cortex s povoleným rozhraním API pravidla, vyberte možnost „Spravováno Grafanou“." + "grafana-managed": "" }, "rule-view": { "query": { @@ -2911,7 +2913,7 @@ "test-contact-point-modal": { "custom-notification-message": "Odešlete zkušební oznámení, které používá níže definované vysvětlivky. Tato možnost je ideální, pokud používáte vlastní šablony a zprávy.", "notification-message": "Oznamovací zpráva", - "predefined-notification-message": "Odešlete zkušební oznámení, které používá předdefinovanou výstrahu. Pokud jste definovali vlastní šablonu nebo zprávu, pro lepší výsledky přepněte na <1>vlastní oznámení.", + "predefined-notification-message": "", "send-test-notification": "Odeslat testovací oznámení", "title-test-contact-point": "Otestovat kontaktní bod" }, @@ -2920,7 +2922,7 @@ }, "threshold-expression-viewer": { "input": "Vstup", - "stop-alerting-when": "Zastavit upozorňování (nebo čekající stav), když " + "stop-alerting-when": "" }, "time-interval": { "add-time-interval": "Přidat časový interval", @@ -3108,7 +3110,7 @@ "title-notification-policies": "Zásady oznamování" }, "yaml-content-info": { - "body": "Obsah YAML v editoru zahrnuje pouze konfiguraci pravidla výstrahy <1>Chcete-li nakonfigurovat Prometheus, musíte poskytnout zbytek <4>obsahu konfiguračního souboru." + "body": "" } }, "alertlist": { @@ -3184,7 +3186,7 @@ "no-annotations-found": "Nebyly nalezeny žádné vysvětlivky" }, "annotation-list-item": { - "tooltip-created-by": "Autor:<1> {{email}}" + "tooltip-created-by": "" }, "category-annotation-query": "Dotaz na vysvětlivky", "category-display": "Zobrazit", @@ -3222,7 +3224,7 @@ }, "empty-state": { "button-title": "Přidat dotaz na vysvětlivky", - "info-box-content": "<0>Vysvětlivky umožňují integraci údajů o události do vašich grafů. Jsou vizualizovány jako svislé čáry a ikony na všech panelech grafu. Po najetí kurzorem myši na ikonu vysvětlivek získáte text a tagy události. Události vysvětlivek můžete přidat přímo z Grafany podržením CTRL nebo CMD + kliknutím na graf (nebo přetažením oblasti). Ty budou uloženy v anotační databázi Grafany.", + "info-box-content": "", "info-box-content-2": "Další informace najdete v <2> dokumentaci k vysvětlivkám.", "title": "Nejsou k dispozici žádné vlastní dotazy s vysvětlivkami" }, @@ -3260,7 +3262,7 @@ "auth-settings": "Nastavení ověření" }, "auth-drawer-unconneced": { - "subtitle": "Konfigurovat nastavení ověření. Další informace najdete v naší <2>dokumentaci." + "subtitle": "" }, "auth-drawer-unconnected": { "advanced-auth": "Pokročilé ověření", @@ -3294,7 +3296,7 @@ "allowed-organizations-description": "Seznam organizací oddělených čárkou nebo mezerou. Uživatel musí být členem alespoň\njedné organizace, aby se mohl přihlásit.", "allowed-organizations-label": "Povolené organizace", "allowed-organizations-placeholder": "Zadejte organizace (my-team, myteam…) a stiskněte klávesu Enter pro přidání", - "api-url-description": "Koncový bod uživatelských informací vašeho poskytovatele OAuth2. Informace vrácené tímto koncovým bodem musí být kompatibilní s <2>OpenID UserInfo.", + "api-url-description": "", "api-url-required": "Toto pole musí být platná adresa URL, pokud je nastavena.", "auth-style-description": "Určuje způsob odesílání „{{ clientIDLabel }}“ a „{{ clientSecretLabel }}“ poskytovateli Oauth2. Výchozí hodnota je AutoDetect.", "auth-style-label": "Styl autorizace", @@ -3439,7 +3441,7 @@ } }, "auth-config-auth-config-page-unconnected": { - "subtitle": "Spravujte nastavení ověření a konfigurujte jednotné přihlašování. Další informace najdete v naší <2>dokumentaci." + "subtitle": "" }, "bar-chart": { "warn": { @@ -4173,7 +4175,7 @@ }, "scopes": { "apply-selected-scopes": "Použít", - "selected-scopes-label": "Rozsahy: " + "selected-scopes-label": "" }, "search-box": { "placeholder": "Hledat nebo přejít na…" @@ -4315,7 +4317,7 @@ "okay": "Ok" }, "not-found-datasource": { - "body": "Možná jste zadali nesprávnou adresu URL nebo plugin s ID <1> není k dispozici.<3>Chcete-li zobrazit seznam dostupných zdrojů dat, <5>klikněte sem." + "body": "" }, "oss": { "connections-home-page": { @@ -4358,8 +4360,8 @@ "versionHistory": { "comparison": { "header": { - "hide-json-diff": "Skrýt JSON diff ", - "show-json-diff": "Zobrazit JSON diff ", + "hide-json-diff": "", + "show-json-diff": "", "text": "Verze {{version}} byla aktualizována uživatelem {{createdBy}} ({{ageString}}) {{message}}" }, "select": "Vyberte dvě verze a začněte porovnávat" @@ -4386,7 +4388,7 @@ "label-label": "Štítek", "label-placeholder": "např. stopy Tempo", "label-required": "Toto pole je povinné.", - "sub-text": "<0>Definujte text, který bude popisovat korelaci.", + "sub-text": "", "title": "Definujte štítek korelace (krok 1 ze 3)" }, "configure-correlation-target-form": { @@ -4430,7 +4432,7 @@ }, "source-form": { "control-required": "Toto pole je povinné.", - "description": "Datový bod musí poskytnout hodnoty všem proměnným jako pole nebo jako výstup transformací, aby se tlačítko korelace zobrazilo ve vizualizaci.<1>Poznámka: Ne každá proměnná musí být výslovně definována níže. Transformace, jako je <4>logfmt, vytvoří proměnné pro každý pár klíče/hodnoty.", + "description": "", "description-external-pre": "V cílové adrese URL jste použili následující proměnné:", "description-query-pre": "V cílovém dotazu jste použili následující proměnné:", "external-title": "Nakonfigurujte zdroj dat, který bude používat adresu URL (krok 3 ze 3)", @@ -4442,12 +4444,12 @@ "results-required": "Toto pole je povinné.", "source-description": "Výsledky z vybraného zdroje dat mají odkazy zobrazené na panelu", "source-label": "Zdroj", - "sub-text": "<0>Definujte, jaký zdroj dat bude zobrazovat korelaci a jaká data nahradí dříve definované proměnné." + "sub-text": "" }, "sub-title": "Definujte, jak spolu souvisí data uložená v různých zdrojích dat. Další informace najdete v <2>dokumentaci", "target-form": { "control-rules": "Toto pole je povinné.", - "sub-text": "<0>Definujte, na co bude korelace odkazovat. S typem dotazu se dotaz spustí po kliknutí na korelaci. U externího typu se kliknutím na korelaci otevře adresa URL.", + "sub-text": "", "target-description-external": "Zadejte adresu URL, která se otevře po kliknutí na odkaz", "target-description-query": "Uveďte, na který zdroj dat se po kliknutí na odkaz má dotazovat", "target-label": "Cíl", @@ -4654,7 +4656,7 @@ } }, "confirm-plugin-dashboard-save-modal": { - "body-plugin-dashboard": "Aktualizací pluginu přijdete o změny.<1><2>Použijte <1>Uložit jako pro vytvoření vlastní verze.", + "body-plugin-dashboard": "", "cancel": "Zrušit", "overwrite": "Přepsat", "title-plugin-dashboard": "Plugin nástěnky" @@ -4871,7 +4873,7 @@ "add-visualization-body": "Vyberte zdroj dat a poté se dotazujte a vizualizujte data pomocí grafů, statistik a tabulek nebo vytvářejte seznamy, přehledy a další widgety.", "add-visualization-button": "Přidat vizualizaci", "add-visualization-header": "Začněte novou nástěnku přidáním vizualizace", - "import-a-dashboard-body": "Importujte nástěnky ze souborů nebo z <2>grafana.com.", + "import-a-dashboard-body": "", "import-a-dashboard-header": "Importovat nástěnku", "import-dashboard-button": "Importovat nástěnku", "show-less-dashboards": "", @@ -5331,8 +5333,8 @@ "title-provisioned": "Zajištěná nástěnka" }, "save-dashboard-error-proxy": { - "body-name-exists": "Ve vybrané složce už existuje nástěnka se stejným názvem.<1><2>Chcete přesto tuto nástěnku uložit?", - "body-version-mismatch": "Tuto nástěnku aktualizoval jiný uživatel<1><2>Chcete přesto tuto nástěnku uložit?", + "body-name-exists": "", + "body-version-mismatch": "", "confirmText-save-and-overwrite": "Uložit a přepsat", "title-name-exists": "Konflikt", "title-version-mismatch": "Konflikt" @@ -5350,7 +5352,7 @@ "cancel": "Zrušit", "cannot-be-saved": "Tuto nástěnku nelze uložit z uživatelského rozhraní Grafana, protože byla zajištěna z jiného zdroje. Zkopírujte JSON nebo ho uložte do souboru níže a následně aktualizujte nástěnku ve zdroji zajištění.", "copy-json-to-clipboard": "Kopírovat JSON do schránky", - "file-path": "<0>Cesta k souboru: {{filePath}}", + "file-path": "", "save-json-to-file": "Uložit JSON do souboru", "see-docs": "Další informace o zajištění najdete v <2>dokumentaci." }, @@ -5549,7 +5551,7 @@ "transformation-picker": { "info": "Transformace umožňují spojit, vypočítat, skrýt, přejmenovat a změnit pořadí výsledků dotazu před jejich vizualizací.", "info-graph-not-suitable": "Mnoho transformací není vhodných pro vizualizaci grafu, protože v současné době podporuje pouze data časových řad.", - "info-switch-to-table": "V takovém případě přepněte na vizualizaci tabulky. ", + "info-switch-to-table": "", "placeholder-search-for-transformation": "Hledat transformaci", "read-more": "Zjistěte víc", "title-transformations": "Transformace" @@ -5615,8 +5617,8 @@ "version-history-comparison": { "button-restore": "Obnovit na verzi {{version}}", "label-view-json-diff": "Zobrazit rozdíl JSON", - "new-updated-by": "<0>Verzi {{version}} aktualizoval uživatel {{editor}} {{timeAgo}}", - "old-updated-by": "<0>Verzi {{version}} aktualizoval uživatel {{editor}} {{timeAgo}}" + "new-updated-by": "", + "old-updated-by": "" }, "version-history-table": { "aria-label-toggle-selection": "Přepnout výběr verze {{version}}", @@ -6016,7 +6018,7 @@ "cancel": "Zrušit" }, "render-save-button-and-error": { - "body-plugin-dashboard": "Aktualizací pluginu přijdete o změny. Použijte <1>Uložit jako pro vytvoření vlastní verze.", + "body-plugin-dashboard": "", "title-failed-to-save-dashboard": "Nástěnku se nepodařilo uložit", "title-plugin-dashboard": "Plugin nástěnky", "title-someone-else-has-updated-this-dashboard": "Tuto nástěnku aktualizoval jiný uživatel", @@ -6025,7 +6027,7 @@ "save-and-overwrite": "Uložit a přepsat" }, "library-viz-panel-info": { - "last-edited": "{{timeAgo}} uživatelem ", + "last-edited": "", "usage-count_one": "Použito na {{count}} nástěnkách", "usage-count_few": "Použito na {{count}} nástěnkách", "usage-count_many": "Použito na {{count}} nástěnkách", @@ -6088,7 +6090,7 @@ }, "panel-data-queries-tab-rendered": { "add-query": "Přidat dotaz", - "expression": "Výraz " + "expression": "" }, "panel-data-transformations-tab": { "tab-label": "Transformace" @@ -6146,7 +6148,7 @@ "query": "Dotaz" }, "query-variable-editor-form": { - "description-examples": "Pojmenované skupiny zachycení lze použít k oddělení zobrazovaného textu a hodnoty (<1>viz příklady).", + "description-examples": "", "description-optional": "Volitelné, pokud chcete extrahovat část názvu řady nebo segmentu uzlu metriky.", "label-data-source": "Zdroj dat", "label-static-options-sort": "Statické možnosti třídění", @@ -6207,7 +6209,7 @@ "label-message": "Zpráva", "placeholder-describe-changes-optional": "Přidat poznámku k popisu změn (nepovinné).", "render-footer": { - "body-plugin-dashboard": "Aktualizací pluginu přijdete o změny. Použijte <1>Uložit jako pro vytvoření vlastní verze.", + "body-plugin-dashboard": "", "no-changes-to-save": "Žádné změny k uložení", "title-failed-to-save-dashboard": "Nástěnku se nepodařilo uložit", "title-plugin-dashboard": "Plugin nástěnky", @@ -6245,7 +6247,7 @@ "cancel": "Zrušit", "cannot-be-saved": "Tuto nástěnku nelze uložit z uživatelského rozhraní Grafana, protože byla zajištěna z jiného zdroje. Zkopírujte JSON nebo ho uložte do souboru níže a následně aktualizujte nástěnku ve zdroji zajištění.", "copy-json-to-clipboard": "Kopírovat JSON do schránky", - "file-path": "<0>Cesta k souboru: {{filePath}}", + "file-path": "", "label-description": "Popis", "label-target-folder": "Cílová složka", "label-title": "Název", @@ -6414,8 +6416,8 @@ }, "version-history-comparison": { "label-view-json-diff": "Zobrazit rozdíl JSON", - "new-version-updated": "<0>Verzi {{version}} aktualizoval uživatel {{editor}} {{timeAgo}}", - "old-version-updated": "<0>Verzi {{version}} aktualizoval uživatel {{editor}} {{timeAgo}}" + "new-version-updated": "", + "old-version-updated": "" }, "version-history-header": { "compare-versions": "Porovnání {{baseVersion}} <3> {{newVersion}}", @@ -6493,7 +6495,7 @@ "provisioned-delete-modal": { "confirm-button": "OK", "text-1": "Tuto nástěnka spravuje zajištění Grafana a nelze ji odstranit. Odebráním nástěnky z konfiguračního souboru ji odstraníte.", - "text-2": "Další informace o zajištění najdete v dokumentaci Grafany. ", + "text-2": "", "text-3": "Cesta k souboru: {{provisionedId}}", "text-link": "Přejít na stránku dokumentů", "title": "Zajištěnou nástěnku nelze odstranit" @@ -6571,7 +6573,7 @@ }, "data-source-testing-status-page": { "error-more-details-link": "Klikněte <2>tady a zjistěte víc o této chybě.", - "success-more-details-links": "Následně můžete začít vizualizovat data <2>vytvořením nástěnky nebo dotazováním na data v <5>Prozkoumat zobrazení." + "success-more-details-links": "" }, "data-sources": { "datasource-add-button": { @@ -6667,7 +6669,7 @@ "test": "Test" }, "cloud-info-box": { - "body-alert": "Nebo si to zjednodušte a získejte {{mainDS}} (a {{extraDS}}) – plně spravované, škálovatelné a hostované zdroje dat od Grafana Labs s <6>celoživotním bezplatným plánem Grafana Cloud.", + "body-alert": "", "title-alert": "Nakonfigurujte zdroje dat {{mainDS}} níže" }, "dashboards-table": { @@ -6795,18 +6797,18 @@ "no-events-yet": "Dosud žádné události" }, "render-info-viewer": { - "data-counter": "Data: {{numDataChanges}} ", + "data-counter": "", "elapsed-time": "Čas: {{elapsed}} ms", "field": "Pole", "last": "Poslední", - "render-counter": "Vykreslení: {{numRenders}} ", - "schema-counter": "Schéma: {{numSchemaChanges}} ", + "render-counter": "", + "schema-counter": "", "title-reset-counters": "Obnovit počítadla", "tooltip-step-back": "Krok zpět", "type": "Typ" }, "state-view": { - "current-value": "Aktuální hodnota: {{currentValue}} ", + "current-value": "", "label-state-name": "Název stavu" } }, @@ -7253,7 +7255,7 @@ }, "footer": { "learn-more": "Zjistěte víc", - "pro-tip-define-sources-through-configuration-files": " Pro tip: Zdroje dat můžete definovat také prostřednictvím konfiguračních souborů. " + "pro-tip-define-sources-through-configuration-files": "" } }, "pane": { @@ -7315,8 +7317,6 @@ "query-deleted": "Dotaz odstraněn" }, "rich-history-queries-tab": { - "displaying-partial-queries": "Zobrazování {{ count }} dotazů", - "displaying-queries": "Dotazy: {{ count }}", "filter-aria-label": "Filtrovat dotazy pro zdroje dat", "filter-history": "Filtrovat historii", "filter-placeholder": "Filtrovat dotazy pro zdroje dat", @@ -7326,7 +7326,15 @@ "search-placeholder": "Hledané dotazy", "showing-queries": "Zobrazuje se {{ shown }} z {{ total }} <0>Načíst další", "sort-aria-label": "Seřadit dotazy", - "sort-placeholder": "Seřadit dotazy podle" + "sort-placeholder": "Seřadit dotazy podle", + "displaying-partial-queries_one": "", + "displaying-partial-queries_few": "", + "displaying-partial-queries_many": "", + "displaying-partial-queries_other": "", + "displaying-queries_one": "", + "displaying-queries_few": "", + "displaying-queries_many": "", + "displaying-queries_other": "" }, "rich-history-settings-tab": { "alert-info": "Grafana bude uchovávat záznamy až do {{optionLabel}}.Záznamy označené hvězdičkou nebudou odstraněny.", @@ -7518,7 +7526,7 @@ "copy-shortened-link-menu": "Otevřít možnosti kopírování odkazu", "refresh-picker-cancel": "Zrušit", "refresh-picker-run": "Spustit dotaz", - "split-close": " Zavřít ", + "split-close": "", "split-close-tooltip": "Zavřít rozdělené podokno", "split-narrow": "Úzké podokno", "split-title": "Rozdělit", @@ -7648,8 +7656,8 @@ }, "math": { "available-math-functions": "Dostupné matematické funkce", - "run-math-operations": "Spustit matematické operace pro jeden nebo více dotazů. Odkazujete na dotaz podle {{refExample}}, např. {{ref1}}, {{ref2}}, {{ref3}} atd.<10>Příklad: <12>{{example}}", - "tooltip-footer": "Podívejte se na naši další dokumentaci o <2>matematických výrazech.", + "run-math-operations": "", + "tooltip-footer": "", "tooltip-title": "Matematický operátor", "tooltip-trigger": "Výraz" }, @@ -8708,7 +8716,7 @@ }, "data-source-http-settings": { "access-help": "Nápověda <1>", - "access-help-details": "Režim přístupu řídí, jak budou zpracovány požadavky na zdroj dat.<1> <1>Server by měl být preferovaným způsobem, pokud není uvedeno nic jiného.", + "access-help-details": "", "access-help-title": "Otevřít nápovědu", "access-label": "Otevřít", "allowed-cookies": "Povolené soubory cookie", @@ -8976,7 +8984,7 @@ "cell-inspect": "Zkontrolovat hodnotu", "cell-inspect-tooltip": "Zkontrolovat hodnotu", "copy": "Kopírovat do schránky", - "csv-counts": "Řádky:{{rows}}, sloupce:{{columns}} <5>", + "csv-counts": "", "csv-placeholder": "Zadej CSV tady…", "filter-placeholder": "Filtrovat hodnoty", "filter-popup-apply": "Ok", @@ -9261,7 +9269,6 @@ "name-line-width": "Šířka řádku", "name-stacking": "Stohování" }, - "inline-token-warning-badge-tooltip": "", "inspector": { "inspect-data-tab": { "loading": "Načítání", @@ -9429,7 +9436,7 @@ "error-fetching": "Chyba při načítání nastavení LDAP", "error-saving": "Chyba při ukládání nastavení LDAP", "error-validate-form": "Chyba při ověřování nastavení LDAP", - "feature-flag-disabled": "Tato stránka je přístupná pouze po povolení příznaku funkce <1>ssoSettingsLDAP.", + "feature-flag-disabled": "", "saved": "Nastavení LDAP bylo uloženo" }, "bind-dn": { @@ -9470,7 +9477,7 @@ "label": "Zásada vyhledávání DNS", "placeholder": "příklad: dc = grafana, dc = organizace" }, - "subtitle": "Integrace LDAP v Grafaně umožňuje uživatelům Grafany přihlásit se pomocí svých přihlašovacích údajů LDAP. Další informace najdete v naší <2><0>dokumentaci.", + "subtitle": "", "title": "Základní nastavení" }, "library-panel": { @@ -9514,7 +9521,7 @@ "dashboard-name": "Název nástěnky" }, "library-panel-info": { - "last-edited": "Naposledy upraveno {{timeAgo}} uživatelem ", + "last-edited": "", "usage-count_one": "Použito na {{count}} nástěnkách", "usage-count_few": "Použito na {{count}} nástěnkách", "usage-count_many": "Použito na {{count}} nástěnkách", @@ -9831,7 +9838,7 @@ "tooltip-unpin-line": "Odepnout řádek" }, "log-row-message": { - "ellipsis": "… ", + "ellipsis": "", "more": "další", "see-details": "Zobrazit podrobnosti protokolu", "tooltip-error": "Chyba: {{errorMessage}}" @@ -10227,7 +10234,7 @@ }, "resource-table": { "dashboard-load-error": "Nástěnku nelze načíst", - "error-library-element-sub": "Prvek knihovny {uid}", + "error-library-element-sub": "", "error-library-element-title": "Prvek knihovny nelze načíst", "unknown-datasource-title": "Zdroj dat {{datasourceUID}}", "unknown-datasource-type": "Neznámý zdroj dat" @@ -10881,10 +10888,10 @@ "placeholder-optional": "(volitelné)", "role": "Role", "submit": "Odeslat", - "tooltip": "Teď můžete vybrat možnost „Žádná základní role“ a přidat oprávnění k vlastním potřebám. Více informací najdete v <1>naší dokumentaci." + "tooltip": "" }, "user-invite-page": { - "sub-title": "Pošlete pozvánku nebo přidejte stávajícího uživatele Grafany do organizace.<1> {{orgName}}", + "sub-title": "", "text": { "invite-user": "Pozvat uživatele" } @@ -10973,7 +10980,7 @@ "switch-to-table": "Přepnout na tabulku" }, "panel-plugin-error": { - "text-load-error": "Další informace najdete ve spouštěcích protokolech serveru. <1>Pokud byl tento plugin načten z Gitu, ujistěte se, že byl zkompilován.", + "text-load-error": "", "title-load-error": "Chyba při načítání: {{panelId}}", "title-not-found": "Plugin panelu nebyl nalezen: {{id}}" }, @@ -11167,7 +11174,7 @@ }, "details": { "connections-tab": { - "description": "V současné době máte nakonfigurovány následující zdroje dat pro {{pluginName}}. Kliknutím na dlaždici zobrazíte podrobnosti konfigurace. Všechna připojení ke zdrojům dat najdete v <4><0>Připojení > <3> Zdroje dat. " + "description": "" }, "disabled-error": { "angular-deprecation-link": "Zjistěte víc o úhlovém odepisování", @@ -11184,7 +11191,7 @@ }, "labels": { "contactGrafanaLabs": "Kontaktovat Grafana Labs", - "customLinks": "Vlastní odkazy ", + "customLinks": "", "customLinksTooltip": "Tyto odkazy poskytuje vývojář pluginu, aby nabídl další zdroje a informace specifické pro vývojáře", "dependencies": "Závislosti", "documentation": "Dokumentace", @@ -11195,7 +11202,7 @@ "latestVersion": "Poslední verze", "license": "Licence", "raiseAnIssue": "Nahlásit problém", - "reportAbuse": "Nahlásit problém ", + "reportAbuse": "", "reportAbuseTooltip": "Nahlaste problémy související se škodlivými pluginy přímo společnosti Grafana Labs.", "repository": "Úložiště", "signature": "Podpis", @@ -11205,8 +11212,8 @@ "modal": { "cancel": "Zrušit", "copyEmail": "Kopírovat e-mailovou adresu", - "description": "Tato funkce slouží k nahlášení škodlivého chování v rámci pluginů. Pokud máte obavy ohledně pluginů, pošlete nám e-mail na adresu: ", - "node": "Poznámka: V případě obecných problémů s pluginem, jako jsou chyby nebo požadavky na funkce, kontaktujte autora pluginu pomocí poskytnutých odkazů. ", + "description": "", + "node": "", "title": "Nahlásit problém s pluginem" } }, @@ -11274,7 +11281,7 @@ "message": "Všechny pluginy jsou aktuální" }, "not-found-plugin": { - "body-plugin-not-found": "Tento plugin nebyl nalezen. Zkontrolujte správnost adresy URL nebo <1>přejděte do <3>katalogu pluginů.", + "body-plugin-not-found": "", "title-plugin-not-found": "Plugin nebyl nalezen" }, "plugin-actions": { @@ -11750,7 +11757,6 @@ "unsupported-repository-type": "" }, "inline-secure-values-warning": "", - "inline-token-warning-badge-text": "", "job-status": { "label-view-details": "Zobrazit podrobnosti", "loading-finished-job": "Načítání dokončené úlohy…", @@ -11927,6 +11933,17 @@ "label-current-step": "Aktuální krok", "label-pending-step": "Nevyřízený krok" }, + "status-badge": { + "automatic-pulling-disabled": "", + "deleting": "", + "error": "", + "pending": "", + "pulling": "", + "unknown": "", + "up-to-date": "", + "waiting-for-health-check": "", + "warning": "" + }, "success-title-default": "Úspěch", "sync-job": { "error-no-job-id": "Nepodařilo se spustit úlohu", @@ -12104,7 +12121,7 @@ "annotations-show-text": "Vysvětlivky = zobrazit", "time-range-picker-disabled-text": "Volič časového rozsahu = zakázán", "time-range-picker-enabled-text": "Volič časového rozsahu = povolen", - "time-range-text": "Časový rozsah = " + "time-range-text": "" }, "share": { "success-delete": "Vaši nástěnka už nejde sdílet" @@ -12143,7 +12160,7 @@ "revoke-user-access-modal-desc-line1": "Opravdu chcete odvolat přístup pro {{email}}?" }, "delete-user-shared-dashboards-modal": { - "revoke-user-access-modal-desc-line2": "Tato akce okamžitě odvolá přístup pro {{email}} ke všem sdíleným nástěnkám." + "revoke-user-access-modal-desc-line2": "" }, "modal": { "shared-dashboard-modal-title": "Sdílené nástěnky" @@ -12318,7 +12335,7 @@ }, "menu": { "clear-button": "Vymazat vše", - "tooltip": "Teď můžete vybrat možnost „Žádná základní role“ a přidat oprávnění k vlastním potřebám. Více informací najdete v <1>naší dokumentaci." + "tooltip": "" }, "menu-aria-label": "Nabídka voliče role", "menu-group-option-aria-label": "Možnost voliče role", @@ -12328,7 +12345,7 @@ }, "sub-menu-aria-label": "Podnabídka volič role", "title": { - "description": "Přiřaďte role uživatelům, abyste zajistili podrobnou kontrolu nad přístupem k funkcím a zdrojům Grafana. Další informace najdete v naší <2>dokumentaci." + "description": "" } }, "role-picker-drawer": { @@ -12451,7 +12468,7 @@ }, "select": { "select-menu": { - "selected-count": "Vybrané " + "selected-count": "" } }, "service-account-create-page": { @@ -12550,6 +12567,7 @@ "aria-label-role": "Role" }, "service-account-tokens-table": { + "aria-label-delete-button": "", "created": "Vytvořeno", "expires": "Vyprší", "last-used-at": "Naposledy použito v", @@ -12639,7 +12657,7 @@ "info-text": "Vytvořte přímý odkaz na tuto nástěnku nebo panel přizpůsobený možnostmi dole.", "link-url": "Odkaz adresy URL", "render-alert": "Plugin pro renderování obrázků není nainstalován", - "render-instructions": "Chcete-li vyrenderovat obrázek, musíte si nainstalovat <2>plugin Grafana pro renderování obrázků. Chcete-li nainstalovat plugin, obraťte se na správce Grafany.", + "render-instructions": "", "rendered-image": "Přímý odkaz na vyrenderovaný obrázek", "save-alert": "Nástěnka není uložena", "save-dashboard": "Chcete-li vyrenderovat obrázek panelu, musíte nejprve uložit nástěnku.", @@ -12663,7 +12681,7 @@ "info-text-1": "Snímek je okamžitý způsob, jak veřejně sdílet interaktivní nástěnku. Po vytvoření odstraníme citlivá data, jako jsou dotazy (metriky, šablony a vysvětlivky) a odkazy na panely, takže na nástěnce zůstanou pouze viditelné metriky dat a názvy sérií.", "info-text-2": "Upozorňujeme, že váš snímek <1>si může prohlédnout kdokoli, kdo má odkaz a má přístup k adrese URL. Před sdílením se prosím zamyslete.", "local-button": "Zveřejnit snímek", - "mistake-message": "Udělali jste chybu? ", + "mistake-message": "", "name": "Název snímku", "timeout": "Časový limit (sekundy)", "timeout-description": "Pokud načítání metrik nástěnky trvá dlouho, možná budete muset nakonfigurovat hodnotu časového limitu.", @@ -13277,7 +13295,7 @@ "forwards-time-aria-label": "Přesunout časový rozsah dopředu", "to": "do", "zoom-out-button": "Oddálit časový rozsah", - "zoom-out-tooltip": "Oddálení časového rozsahu <1> CTRL+Z" + "zoom-out-tooltip": "" }, "time-range": { "apply": "Použít časový rozsah", @@ -13402,7 +13420,7 @@ }, "transformations": { "empty": { - "add-transformation-body": "Transformace umožňují měnit data různými způsoby před zobrazením vaší vizualizace.<1>To zahrnuje spojování dat, přejmenování polí, provádění výpočtů, formátování dat pro zobrazení a další.", + "add-transformation-body": "", "add-transformation-header": "Spustit transformaci dat" } }, @@ -13669,7 +13687,7 @@ "label-format": "Formát", "label-set-timezone": "Nastavit časové pásmo", "label-time-field": "Pole času", - "tooltip-format": "Výstupní formát pro pole zadané jako <2>řetězec formátu Moment.js.", + "tooltip-format": "", "tooltip-timezone-manually": "Nastavit časové pásmo data manuálně" }, "format-time-transformer-editor": { @@ -14264,8 +14282,8 @@ "message": "Nebyli nalezeni žádní uživatelé" }, "token-revoked-modal": { - "auto-revoked": "Token relace byl automaticky zrušen, protože jste dosáhli <2>maximálního počtu {{numSessions}} souběžných relací pro svůj účet.", - "resume-message": "<0>Chcete-li pokračovat v relaci, přihlaste se znovu.Pokud jste opakovaně automaticky odhlášeni, obraťte se na správce nebo navštivte licenční stránku a zkontrolujte kvótu.", + "auto-revoked": "", + "resume-message": "", "sign-in": "Přihlášení", "title-you-have-been-automatically-signed-out": "Byli jste automaticky odhlášeni" }, diff --git a/public/locales/de-DE/grafana.json b/public/locales/de-DE/grafana.json index 38bb7627cff..bfeffc22032 100644 --- a/public/locales/de-DE/grafana.json +++ b/public/locales/de-DE/grafana.json @@ -108,7 +108,7 @@ "dismiss": "Schließen", "heading": "Enterprise-Authentifizierung", "learn-more-link": "Mehr erfahren", - "text": "Verwalten Sie Nutzer, Teams und Berechtigungen automatisch mit <1>SAML, <3>SCIM, <6>LDAP und <8>RBAC – verfügbar in Grafana Cloud und Grafana Enterprise." + "text": "" }, "feature-listing": { "title-auditing": "Auditing", @@ -209,7 +209,7 @@ "title-delete": "Löschen" }, "orgs": { - "delete-body": "Möchten Sie „{{deleteOrgName}}“ wirklich löschen?<3> <5>Alle Dashboards für diese Organisation werden entfernt!", + "delete-body": "", "id-header": "ID", "name-header": "Name", "new-org-button": "Neue Organisation" @@ -719,6 +719,7 @@ "title-annotations": "Anmerkungen" }, "link-dashboard-and-panel": "Dashboard und Panel verknüpfen", + "placeholder-value-input": "", "placeholder-value-input-default": "Inhalt der benutzerdefinierten Anmerkung eingeben …" }, "bulk-actions": { @@ -1144,7 +1145,7 @@ "title-something-wrong-trying-fetch-group-details": "Beim Versuch des Abrufs der Gruppendetails ist ein Fehler aufgetreten" }, "evaluation-interval-limit-exceeded": { - "body-minimum-interval": "Ein minimales Bewertungsintervall von <1>{{minInterval}} wurde in Grafana konfiguriert.<3>Bitte kontaktieren Sie den Administrator, um ein geringeres Intervall zu konfigurieren.", + "body-minimum-interval": "", "title-global-evaluation-interval-limit-exceeded": "Globales Bewertungsintervalllimit überschritten" }, "existing-rule-editor": { @@ -1292,7 +1293,7 @@ "resolved": "Gelöst" } }, - "review-alert-payload": " Überprüfen Sie Warnungsdaten, um sie der Nutzlast hinzuzufügen:", + "review-alert-payload": "", "title-add-custom-alerts": "Benutzerdefinierte Warnungen hinzufügen" }, "get-alert-suggestions": { @@ -1416,7 +1417,7 @@ "title-add-folder-and-labels": "Ordner und Labels hinzufügen" }, "grafana-managed-rule-type": { - "description": "Unterstützt mehrere Datenquellen jeder Art.<1>Transformieren Sie Daten mit Ausdrücken." + "description": "" }, "grafana-modify-export": { "body-invalid-rule-id": "Die Regel-UID in der Seiten-URL ist ungültig. Bitte überprüfen Sie den Link und versuchen Sie es erneut.", @@ -1853,7 +1854,7 @@ "aria-label-new": "neu" }, "mimir-flavored-type": { - "description": "Verwenden Sie eine Mimir-, Loki- oder Cortex-Datenquelle.<1>Ausdrücke werden nicht unterstützt." + "description": "" }, "min-interval-option": { "label-interval": "Intervall", @@ -2082,7 +2083,7 @@ "warning-1": "Wenn Sie diese Benachrichtigungsrichtlinie löschen, wird sie dauerhaft entfernt.", "warning-2": "Möchten Sie diese Richtlinie wirklich löschen?" }, - "filter-description": "Filtern Sie Benachrichtigungsrichtlinien und trennen Sie die Matchers durch Kommata, z. B.:<1>Schweregrad=kritisch, Region=EMEA", + "filter-description": "", "generated-policies": "Automatisch generierte Richtlinien", "matchers": "Matcher", "metadata": { @@ -2126,7 +2127,8 @@ "conflict": "Der Benachrichtigungsrichtlinienbaum wurde von einem anderen Benutzer aktualisiert.", "error-code": "Fehlermeldung: „{{error}}“", "routes": { - "conflictingMatchers": "Die Route kann nicht hinzugefügt oder aktualisiert werden: Wenn wir die Matcher {{-matchers}} verbinden, widersprechen Matcher einer externen Routing-Struktur. Dadurch wäre die Route nicht erreichbar." + "conflictingMatchers": "Die Route kann nicht hinzugefügt oder aktualisiert werden: Wenn wir die Matcher {{-matchers}} verbinden, widersprechen Matcher einer externen Routing-Struktur. Dadurch wäre die Route nicht erreichbar.", + "unknownMatchers": "" }, "suffix": "Bitte aktualisieren Sie die Seite und versuchen Sie es erneut.", "title": "Benachrichtigungsrichtlinie konnte nicht hinzugefügt oder aktualisiert werden" @@ -2244,7 +2246,7 @@ "error-no-query-editor": "Der Abfrage-Editor konnte nicht geladen werden wegen: {{errorMessage}}" }, "recording-rule-type": { - "description": "Ausdrücke vorausberechnen.<1>Sollte mit einer Warnregel kombiniert werden." + "description": "" }, "recording-rules": { "description-target-data-source": "Die Prometheus-Datenquelle zur Speicherung der Aufnahmeregeln", @@ -2257,7 +2259,7 @@ }, "redirect-to-clone-rule": { "body-evaluation-group": "Sie müssen eine neue Bewertungsgruppe für die kopierte Regel festlegen, da die ursprüngliche bereitgestellt wurde und nicht für Regeln genutzt werden kann, die in der Benutzeroberfläche erstellt werden.", - "body-not-provisioned": "Die neue Regel wird <1>nicht als bereitgestellte Regel gekennzeichnet.", + "body-not-provisioned": "", "confirmText-copy": "Kopieren", "title-copy-provisioned-alert-rule": "Bereitgestellte Warnregel kopieren" }, @@ -2292,13 +2294,13 @@ "routing-settings": { "aria-label-group-by": "Gruppieren nach", "description-group-by": "Kombinieren Sie mehrere Warnungen in einer einzigen Benachrichtigung, indem Sie sie nach denselben Label-Werten gruppieren. Wenn dies leer ist, erfolgt eine Übernahme von der standardmäßigen Benachrichtigungsrichtlinie.", - "group-interval": "Gruppenintervall: <1>{{groupIntervalValue}}", - "group-wait": "Gruppenwartezeit: <1>{{groupWaitValue}}", - "grouping": "Gruppierung: <1>{{fields}}", + "group-interval": "", + "group-wait": "", + "grouping": "", "label-group-by": "Gruppieren nach", "label-override-grouping": "Gruppierung überschreiben", "label-override-timings": "Zeitsteuerungen überschreiben", - "repeat-interval": "Wiederholungsintervall: <1>{{repeatIntervalValue}}" + "repeat-interval": "" }, "rule-actions-buttons": { "title-edit": "Bearbeiten", @@ -2554,7 +2556,7 @@ "relative-with-to": "" }, "rule-type-picker": { - "grafana-managed": "Wählen Sie “Grafana managed”, es sei denn, Sie verfügen über eine Mimir-, Loki- oder Cortex-Datenquelle mit aktivierter Ruler-API." + "grafana-managed": "" }, "rule-view": { "query": { @@ -2887,7 +2889,7 @@ "test-contact-point-modal": { "custom-notification-message": "Sie senden eine Testbenachrichtigung, die die unten festgelegten Anmerkungen verwendet. Dies ist eine gute Möglichkeit, wenn Sie benutzerdefinierte Vorlagen und Nachrichten verwenden.", "notification-message": "Benachrichtigungsnachricht", - "predefined-notification-message": "Sie senden eine Testbenachrichtigung, die eine vorgegebene Warnung verwendet. Wenn Sie eine benutzerdefinierte Vorlage oder Nachricht festgelegt haben, können Sie für bessere Ergebnisse auf <1>benutzerdefinierter Benachrichtigungstext umstellen (von oben).", + "predefined-notification-message": "", "send-test-notification": "Testbenachrichtigung senden", "title-test-contact-point": "Kontaktpunkt testen" }, @@ -2896,7 +2898,7 @@ }, "threshold-expression-viewer": { "input": "Eingabe", - "stop-alerting-when": "Warnung (oder ausstehenden Status) stoppen, wenn " + "stop-alerting-when": "" }, "time-interval": { "add-time-interval": "Zeitintervall hinzufügen", @@ -3084,7 +3086,7 @@ "title-notification-policies": "Benachrichtigungsrichtlinien" }, "yaml-content-info": { - "body": "Der YAML-Inhalt im Editor enthält nur die Warnregel-Konfiguration <1>Um Prometheus zu konfigurieren, müssen Sie den Rest des <4>Konfigurationsdatei-Inhalts angeben." + "body": "" } }, "alertlist": { @@ -3160,7 +3162,7 @@ "no-annotations-found": "Keine Anmerkungen gefunden" }, "annotation-list-item": { - "tooltip-created-by": "Erstellt von:<1> {{email}}" + "tooltip-created-by": "" }, "category-annotation-query": "Annotationsabfrage", "category-display": "Display", @@ -3198,7 +3200,7 @@ }, "empty-state": { "button-title": "Anmerkungsabfrage hinzufügen", - "info-box-content": "<0>Mit Anmerkungen können Sie Ereignisdaten in Ihre Grafiken integrieren. Sie werden als vertikale Linien und Symbole in allen Diagramm-Panels visualisiert. Wenn Sie mit der Maus über ein Anmerkungssymbol fahren, können Sie den Text und die Tags für das Ereignis abrufen. Sie können Anmerkungsereignisse direkt aus Grafana hinzufügen, indem Sie STRG oder CMD gedrückt halten + auf das Diagramm klicken (oder den Bereich ziehen). Sie werden dann in der Anmerkungsdatenbank von Grafana gespeichert.", + "info-box-content": "", "info-box-content-2": "Weitere Informationen finden Sie in der <2>Anmerkungs-Dokumentation.", "title": "Es wurden noch keine benutzerdefinierten Anmerkungsabfragen hinzugefügt" }, @@ -3236,7 +3238,7 @@ "auth-settings": "Authentifizierungseinstellungen" }, "auth-drawer-unconneced": { - "subtitle": "Konfigurieren Sie die Authentifizierungseinstellungen. Erfahren Sie mehr in unserer <2>Dokumentation." + "subtitle": "" }, "auth-drawer-unconnected": { "advanced-auth": "Erweiterte Authentifizierung", @@ -3270,7 +3272,7 @@ "allowed-organizations-description": "Durch Komma oder Leerzeichen getrennte Liste der Organisationen. Der Nutzer sollte Mitglied von mindestens\neiner Organisation sein, um sich anzumelden.", "allowed-organizations-label": "Erlaubte Organisationen", "allowed-organizations-placeholder": "Geben Sie Organisationen (my-team, myteam …) ein und drücken Sie zum Hinzufügen die Eingabetaste", - "api-url-description": "Der Endpunkt der Benutzerinformationen Ihres OAuth2-Anbieters. Informationen, die von diesem Endpunkt zurückgegeben werden, müssen mit <2>OpenID UserInfo kompatibel sein.", + "api-url-description": "", "api-url-required": "Dieses Feld muss – sofern festgelegt – eine gültige URL sein.", "auth-style-description": "Es bestimmt, wie „{{ clientIDLabel }}“ und „{{ clientSecretLabel }}“ an den Oauth2-Provider gesendet werden. Die Standardeinstellung ist AutoDetect.", "auth-style-label": "Authentifizierungsart", @@ -3415,7 +3417,7 @@ } }, "auth-config-auth-config-page-unconnected": { - "subtitle": "Verwalten Sie Ihre Authentifizierungseinstellungen und konfigurieren Sie einmalige Anmeldungen. Erfahren Sie mehr in unserer <2>Dokumentation." + "subtitle": "" }, "bar-chart": { "warn": { @@ -4133,7 +4135,7 @@ }, "scopes": { "apply-selected-scopes": "Anwenden", - "selected-scopes-label": "Bereiche: " + "selected-scopes-label": "" }, "search-box": { "placeholder": "Suche oder springe zu ..." @@ -4275,7 +4277,7 @@ "okay": "Okay" }, "not-found-datasource": { - "body": "Möglicherweise haben Sie die URL falsch eingegeben oder das Plugin mit der ID <1> ist nicht verfügbar.<3>Um eine Liste der verfügbaren Datenquellen anzuzeigen, <5>klicken Sie bitte hier." + "body": "" }, "oss": { "connections-home-page": { @@ -4318,8 +4320,8 @@ "versionHistory": { "comparison": { "header": { - "hide-json-diff": "JSON-Diff ausblenden ", - "show-json-diff": "JSON-Diff anzeigen ", + "hide-json-diff": "", + "show-json-diff": "", "text": "Version {{version}} aktualisiert von {{createdBy}} ({{ageString}}) {{message}}" }, "select": "Wählen Sie zwei Versionen aus, um den Vergleich zu starten" @@ -4346,7 +4348,7 @@ "label-label": "Label", "label-placeholder": "z.B. Tempospuren", "label-required": "Dieses Feld ist erforderlich.", - "sub-text": "<0>Definiere Text, der die Korrelation beschreibt.", + "sub-text": "", "title": "Korrelationsbezeichnung definieren (Schritt 1 von 3)" }, "configure-correlation-target-form": { @@ -4390,7 +4392,7 @@ }, "source-form": { "control-required": "Dieses Feld ist erforderlich.", - "description": "Ein Datenpunkt muss allen Variablen Werte als Felder oder als Transformationen zur Verfügung stellen, damit die Schaltfläche „Korrelation“ in der Visualisierung angezeigt wird.<1>Hinweis: Nicht jede Variable muss unten explizit definiert werden. Eine Transformation wie <4>logfmt erstellt Variablen für jedes Key-Wert-Paar.", + "description": "", "description-external-pre": "Sie haben folgende Variablen in der Ziel-URL verwendet:", "description-query-pre": "Sie haben folgende Variablen in der Zielabfrage verwendet:", "external-title": "Konfigurieren Sie die Datenquelle, die die URL verwenden soll (Schritt 3 von 3)", @@ -4402,12 +4404,12 @@ "results-required": "Dieses Feld ist erforderlich.", "source-description": "Die Ergebnisse aus der ausgewählten Quelldatenquelle verfügen über Links, die im Fenster angezeigt werden", "source-label": "Quelle", - "sub-text": "<0>Definieren, welche Datenquelle die Korrelation anzeigt und welche Daten die zuvor definierten Variablen ersetzen sollen. " + "sub-text": "" }, "sub-title": "Bestimmen Sie, wie Daten aus verschiedenen Datenquellen zueinander in Beziehung stehen. Lesen Sie mehr in der <2>Dokumentation", "target-form": { "control-rules": "Dieses Feld ist erforderlich.", - "sub-text": "<0>Definiere, wohin die Korrelation verlinken soll. Mit dem Typ „Abfrage“ wird eine Abfrage ausgeführt, wenn auf die Korrelation geklickt wird. Beim Typ „Extern“ wird durch Klicken auf die Korrelation eine URL geöffnet.", + "sub-text": "", "target-description-external": "Geben Sie die URL an, die geöffnet werden soll, wenn auf den Link geklickt wird", "target-description-query": "Geben Sie an, welche Datenquelle beim Anklicken des Links abgefragt wird", "target-label": "Ziel", @@ -4614,7 +4616,7 @@ } }, "confirm-plugin-dashboard-save-modal": { - "body-plugin-dashboard": "Ihre Änderungen gehen verloren, wenn Sie das Plugin aktualisieren.Verwenden Sie <1>Speichern unter, um eine benutzerdefinierte Version zu erstellen.", + "body-plugin-dashboard": "", "cancel": "Abbrechen", "overwrite": "Überschreiben", "title-plugin-dashboard": "Plugin-Dashboard" @@ -4831,7 +4833,7 @@ "add-visualization-body": "Wählen Sie eine Datenquelle aus und visualisieren und fragen Sie dann Ihre Daten mit Diagrammen, Statistiken und Tabellen ab oder erstellen Sie Listen, Markierungen und andere Widgets.", "add-visualization-button": "Visualisierung hinzufügen", "add-visualization-header": "Starten Sie Ihr neues Dashboard, indem Sie eine Visualisierung hinzufügen", - "import-a-dashboard-body": "Importieren Sie Dashboards aus Dateien oder von <2>grafana.com.", + "import-a-dashboard-body": "", "import-a-dashboard-header": "Dashboard importieren", "import-dashboard-button": "Dashboard importieren", "show-less-dashboards": "", @@ -5289,8 +5291,8 @@ "title-provisioned": "Bereitgestelltes Dashboard" }, "save-dashboard-error-proxy": { - "body-name-exists": "Ein Dashboard mit demselben Namen im ausgewählten Ordner existiert bereits.<1><2>Möchten Sie dieses Dashboard trotzdem speichern?", - "body-version-mismatch": "Eine andere Person hat dieses Dashboard aktualisiert<1><2>Möchten Sie dieses Dashboard trotzdem speichern?", + "body-name-exists": "", + "body-version-mismatch": "", "confirmText-save-and-overwrite": "Speichern und überschreiben", "title-name-exists": "Widerspruch", "title-version-mismatch": "Widerspruch" @@ -5308,7 +5310,7 @@ "cancel": "Abbrechen", "cannot-be-saved": "Dieses Dashboard kann nicht über die Grafana-Benutzeroberfläche gespeichert werden, da es von einer anderen Quelle bereitgestellt wurde. Kopieren Sie JSON oder speichern Sie es unten in einer Datei. Anschließend können Sie Ihr Dashboard in der Bereitstellungsquelle aktualisieren.", "copy-json-to-clipboard": "JSON in die Zwischenablage kopieren", - "file-path": "<0>Dateipfad: {{filePath}}", + "file-path": "", "save-json-to-file": "JSON in Datei speichern", "see-docs": "Weitere Informationen zur Bereitstellung finden Sie in der <2>Dokumentation." }, @@ -5507,7 +5509,7 @@ "transformation-picker": { "info": "Mit Transformationen können Sie Ihre Abfrageergebnisse vor ihrer Visualisierung verbinden, berechnen, neu anordnen, ausblenden und umbenennen.", "info-graph-not-suitable": "Viele Transformationen sind ungeeignet, wenn Sie die Graph-Visualisierung nutzen, da derzeit nur Zeitreihen-Daten unterstützt werden.", - "info-switch-to-table": "Es kann hilfreich sein, zur Tabellenvisualisierung zu wechseln, um besser nachzuvollziehen, was eine Transformation bewirkt. ", + "info-switch-to-table": "", "placeholder-search-for-transformation": "Nach Transformation suchen", "read-more": "Mehr erfahren", "title-transformations": "Transformationen" @@ -5573,8 +5575,8 @@ "version-history-comparison": { "button-restore": "Auf Version {{version}} wiederherstellen", "label-view-json-diff": "JSON-Diff anzeigen", - "new-updated-by": "<0>Version {{version}} aktualisiert von {{editor}} {{timeAgo}}", - "old-updated-by": "<0>Version {{version}} aktualisiert von {{editor}} {{timeAgo}}" + "new-updated-by": "", + "old-updated-by": "" }, "version-history-table": { "aria-label-toggle-selection": "Auswahl der Version {{version}} umschalten", @@ -5974,7 +5976,7 @@ "cancel": "Abbrechen" }, "render-save-button-and-error": { - "body-plugin-dashboard": "Ihre Änderungen gehen verloren, wenn Sie das Plugin aktualisieren. Verwenden Sie <1>Speichern unter, um eine benutzerdefinierte Version zu erstellen.", + "body-plugin-dashboard": "", "title-failed-to-save-dashboard": "Dashboard konnte nicht gespeichert werden", "title-plugin-dashboard": "Plugin-Dashboard", "title-someone-else-has-updated-this-dashboard": "Eine andere Person hat dieses Dashboard aktualisiert", @@ -5983,7 +5985,7 @@ "save-and-overwrite": "'Speichern und überschreiben'" }, "library-viz-panel-info": { - "last-edited": "{{timeAgo}} von", + "last-edited": "", "usage-count_one": "Verwendet bei {{count}} Dashboards", "usage-count_other": "Verwendet bei {{count}} Dashboards" }, @@ -6044,7 +6046,7 @@ }, "panel-data-queries-tab-rendered": { "add-query": "Abfrage hinzufügen", - "expression": "Ausdruck " + "expression": "" }, "panel-data-transformations-tab": { "tab-label": "Transformationen" @@ -6102,7 +6104,7 @@ "query": "Abfrage" }, "query-variable-editor-form": { - "description-examples": "Mithilfe von benannten Erfassungsgruppen können der Anzeigetext und der Wert getrennt werden (<1>siehe Beispiele).", + "description-examples": "", "description-optional": "Optional, wenn Sie einen Teil eines Reihennamens oder eines metrischen Knotensegments extrahieren möchten.", "label-data-source": "Datenquelle", "label-static-options-sort": "Sortierung der statischen Optionen", @@ -6163,7 +6165,7 @@ "label-message": "Nachricht", "placeholder-describe-changes-optional": "Fügen Sie eine Notiz hinzu, um Ihre Änderungen zu beschreiben (optional).", "render-footer": { - "body-plugin-dashboard": "Ihre Änderungen gehen verloren, wenn Sie das Plugin aktualisieren. Verwenden Sie <1>Speichern unter, um eine benutzerdefinierte Version zu erstellen.", + "body-plugin-dashboard": "", "no-changes-to-save": "Keine Änderungen speicherbar", "title-failed-to-save-dashboard": "Dashboard konnte nicht gespeichert werden", "title-plugin-dashboard": "Plugin-Dashboard", @@ -6199,7 +6201,7 @@ "cancel": "Abbrechen", "cannot-be-saved": "Dieses Dashboard kann nicht über die Grafana-Benutzeroberfläche gespeichert werden, da es von einer anderen Quelle bereitgestellt wurde. Kopieren Sie JSON oder speichern Sie es unten in einer Datei. Anschließend können Sie Ihr Dashboard in der Bereitstellungsquelle aktualisieren.", "copy-json-to-clipboard": "JSON in die Zwischenablage kopieren", - "file-path": "<0>Dateipfad: {{filePath}}", + "file-path": "", "label-description": "Beschreibung", "label-target-folder": "Zielordner", "label-title": "Titel", @@ -6368,8 +6370,8 @@ }, "version-history-comparison": { "label-view-json-diff": "JSON-Diff anzeigen", - "new-version-updated": "<0>Version {{version}} aktualisiert von {{editor}} {{timeAgo}}", - "old-version-updated": "<0>Version {{version}} aktualisiert von {{editor}} {{timeAgo}}" + "new-version-updated": "", + "old-version-updated": "" }, "version-history-header": { "compare-versions": "Vergleich von {{baseVersion}} <3> {{newVersion}}", @@ -6447,7 +6449,7 @@ "provisioned-delete-modal": { "confirm-button": "OK", "text-1": "Dieses Dashboard wird von der Grafana-Bereitstellung verwaltet und kann nicht gelöscht werden. Entfernen Sie das Dashboard aus der Konfigurationsdatei, um es zu löschen.", - "text-2": "Weitere Informationen zur Bereitstellung finden Sie in der Grafana-Dokumentation. ", + "text-2": "", "text-3": "Dateipfad: {{provisionedId}}", "text-link": "Zur Dokumentationsseite gehen", "title": "Das bereitgestellte Dashboard kann nicht gelöscht werden" @@ -6525,7 +6527,7 @@ }, "data-source-testing-status-page": { "error-more-details-link": "Klicken Sie <2>hier, um mehr über diesen Fehler zu erfahren.", - "success-more-details-links": "Als Nächstes können Sie damit beginnen, Daten zu visualisieren, indem Sie <2>ein Dashboard erstellen oder Daten in der <5>Explore-Ansicht abfragen." + "success-more-details-links": "" }, "data-sources": { "datasource-add-button": { @@ -6621,7 +6623,7 @@ "test": "Test" }, "cloud-info-box": { - "body-alert": "Oder sparen Sie sich den Aufwand und erhalten Sie {{mainDS}} (und {{extraDS}}) als vollständig verwaltete, skalierbare und gehostete Datenquellen von Grafana Labs – mit dem <6>jederzeit kostenlosen Grafana-Cloud-Plan.", + "body-alert": "", "title-alert": "Konfigurieren Sie unten Ihre {{mainDS}} Datenquelle" }, "dashboards-table": { @@ -6749,18 +6751,18 @@ "no-events-yet": "Bisher keine Ereignisse" }, "render-info-viewer": { - "data-counter": "Daten: {{numDataChanges}} ", + "data-counter": "", "elapsed-time": "Zeit: {{elapsed}} ms", "field": "Feld", "last": "Zuletzt", - "render-counter": "Rendern: {{numRenders}} ", - "schema-counter": "Schema: {{numSchemaChanges}} ", + "render-counter": "", + "schema-counter": "", "title-reset-counters": "Zähler zurücksetzen", "tooltip-step-back": "Schritt zurück", "type": "Typ" }, "state-view": { - "current-value": "Aktueller Wert: {{currentValue}} ", + "current-value": "", "label-state-name": "Statusname" } }, @@ -7207,7 +7209,7 @@ }, "footer": { "learn-more": "Mehr erfahren", - "pro-tip-define-sources-through-configuration-files": " Profi-Tipp: Sie können Datenquellen auch über Konfigurationsdateien festlegen. " + "pro-tip-define-sources-through-configuration-files": "" } }, "pane": { @@ -7269,8 +7271,6 @@ "query-deleted": "Abfrage gelöscht" }, "rich-history-queries-tab": { - "displaying-partial-queries": "{{ count }} Abfragen anzeigen", - "displaying-queries": "{{ count }} Abfragen", "filter-aria-label": "Filterabfragen nach Datenquelle(n)", "filter-history": "Filterverlauf", "filter-placeholder": "Filterabfragen nach Datenquelle(n)", @@ -7280,7 +7280,11 @@ "search-placeholder": "Suchabfragen", "showing-queries": "Zeige {{ shown }} von {{ total }} <0>Mehr laden", "sort-aria-label": "Abfragen sortieren", - "sort-placeholder": "Abfragen sortieren nach" + "sort-placeholder": "Abfragen sortieren nach", + "displaying-partial-queries_one": "", + "displaying-partial-queries_other": "", + "displaying-queries_one": "", + "displaying-queries_other": "" }, "rich-history-settings-tab": { "alert-info": "Grafana hält Einträge bis {{optionLabel}}. Markierte Einträge werden nicht gelöscht.", @@ -7472,7 +7476,7 @@ "copy-shortened-link-menu": "Optionen zum Kopieren des Links öffnen", "refresh-picker-cancel": "Abbrechen", "refresh-picker-run": "Abfrage ausführen", - "split-close": "Schließen ", + "split-close": "Schließen", "split-close-tooltip": "Teilbereich schließen", "split-narrow": "Schmaler Bereich", "split-title": "Teilen", @@ -7602,8 +7606,8 @@ }, "math": { "available-math-functions": "Verfügbare mathematische Funktionen", - "run-math-operations": "Führen Sie mathematische Operationen für eine oder mehrere Abfragen durch. Sie verweisen auf die Abfrage durch {{refExample}} d. h. {{ref1}}, {{ref2}}, {{ref3}} usw.<10>Beispiel: <12>{{example}}", - "tooltip-footer": "Siehe unsere zusätzliche Dokumentation zu <2>Mathematischen Ausdrücken.", + "run-math-operations": "", + "tooltip-footer": "", "tooltip-title": "Mathematik-Operator", "tooltip-trigger": "Ausdruck" }, @@ -8642,7 +8646,7 @@ }, "data-source-http-settings": { "access-help": "Hilfe <1>", - "access-help-details": "Der Zugriffsmodus steuert, wie Anfragen an die Datenquelle behandelt werden.<1> <1>Server sollte die bevorzugte Methode sein, wenn nichts anderes angegeben ist.", + "access-help-details": "", "access-help-title": "Hilfe öffnen", "access-label": "Zugang", "allowed-cookies": "Erlaubte Cookies ", @@ -8910,7 +8914,7 @@ "cell-inspect": "Wert prüfen", "cell-inspect-tooltip": "Wert prüfen", "copy": "In Zwischenablage kopieren", - "csv-counts": "Zeilen: {{rows}}, Spalten: {{columns}} <5>", + "csv-counts": "", "csv-placeholder": "CSV hier eingeben …", "filter-placeholder": "Filterwerte", "filter-popup-apply": "Ok", @@ -9195,7 +9199,6 @@ "name-line-width": "Linienbreite", "name-stacking": "Stapeln" }, - "inline-token-warning-badge-tooltip": "", "inspector": { "inspect-data-tab": { "loading": "Wird geladen", @@ -9359,7 +9362,7 @@ "error-fetching": "Fehler beim Abrufen der LDAP-Einstellungen", "error-saving": "Fehler beim Speichern der LDAP-Einstellungen", "error-validate-form": "Fehler beim Überprüfen der LDAP-Einstellungen", - "feature-flag-disabled": "Diese Seite ist nur zugänglich, wenn das <1>ssoSettingsLDAP-Feature-Flag aktiviert ist.", + "feature-flag-disabled": "", "saved": "LDAP-Einstellungen gespeichert" }, "bind-dn": { @@ -9400,7 +9403,7 @@ "label": "Suchbasis-DNS", "placeholder": "Beispiel: dc=grafana,dc=org" }, - "subtitle": "Die LDAP-Integration in Grafana ermöglicht es Ihren Grafana-Benutzern, sich mit ihren LDAP-Anmeldeinformationen anzumelden. Weitere Informationen finden Sie in unserer <2><0>Dokumentation.", + "subtitle": "", "title": "Grundeinstellungen" }, "library-panel": { @@ -9444,7 +9447,7 @@ "dashboard-name": "Dashboard-Name" }, "library-panel-info": { - "last-edited": "Zuletzt bearbeitet am {{timeAgo}} von", + "last-edited": "", "usage-count_one": "Verwendet bei {{count}} Dashboards", "usage-count_other": "Verwendet bei {{count}} Dashboards" }, @@ -9749,7 +9752,7 @@ "tooltip-unpin-line": "Zeile lösen" }, "log-row-message": { - "ellipsis": "… ", + "ellipsis": "", "more": "mehr", "see-details": "Protokolldetails anzeigen", "tooltip-error": "Fehler: {{errorMessage}}" @@ -10145,7 +10148,7 @@ }, "resource-table": { "dashboard-load-error": "Dashboard kann nicht geladen werden", - "error-library-element-sub": "Bibliothekselement {uid}", + "error-library-element-sub": "", "error-library-element-title": "Bibliothekselement kann nicht geladen werden", "unknown-datasource-title": "Datenquelle {{datasourceUID}}", "unknown-datasource-type": "Unbekannte Datenquelle" @@ -10793,10 +10796,10 @@ "placeholder-optional": "(optional)", "role": "Rolle", "submit": "Absenden", - "tooltip": "Sie können jetzt die Option „Keine Basisrolle“ auswählen und Berechtigungen zu Ihren benutzerdefinierten Anforderungen hinzufügen. Weitere Informationen finden Sie in <1>unserer Dokumentation." + "tooltip": "" }, "user-invite-page": { - "sub-title": "Versenden Sie eine Einladung oder fügen Sie einen bestehenden Grafana-Nutzer zur Organisation hinzu.<1> {{orgName}}", + "sub-title": "", "text": { "invite-user": "Nutzer einladen" } @@ -10885,7 +10888,7 @@ "switch-to-table": "Zur Tabelle wechseln" }, "panel-plugin-error": { - "text-load-error": "Weitere Informationen finden Sie in den Serverstart-Logs. <1>Wenn dieses Plugin von Git geladen wurde, achten Sie bitte darauf, dass es kompiliert wurde.", + "text-load-error": "", "title-load-error": "Fehler beim Laden: {{panelId}}", "title-not-found": "Panel-Plugin nicht gefunden: {{id}}" }, @@ -11079,7 +11082,7 @@ }, "details": { "connections-tab": { - "description": "Sie haben derzeit folgende Datenquellen für {{pluginName}} konfiguriert. Klicken Sie auf eine Kachel, um die Konfigurationsdetails anzuzeigen. Sie finden all Ihre Datenquellenverbindungen unter <4><0>Verbindungen - <3>Datenquellen." + "description": "" }, "disabled-error": { "angular-deprecation-link": "Erfahren Sie mehr über die Einstellung von Angular", @@ -11096,7 +11099,7 @@ }, "labels": { "contactGrafanaLabs": "Grafana Labs kontaktieren", - "customLinks": "Individuelle Links ", + "customLinks": "", "customLinksTooltip": "Diese Links werden vom Plugin-Entwickler bereitgestellt, um zusätzliche entwicklerspezifische Ressourcen und Informationen anzubieten", "dependencies": "Abhängigkeiten", "documentation": "Dokumentation", @@ -11107,7 +11110,7 @@ "latestVersion": "Aktuelle Version", "license": "Lizenz", "raiseAnIssue": "Ein Problem melden", - "reportAbuse": "Bedenken melden ", + "reportAbuse": "", "reportAbuseTooltip": "Melden Sie Probleme im Zusammenhang mit bösartigen oder schädlichen Plugins direkt an Grafana Labs.", "repository": "Repository", "signature": "Unterschrift", @@ -11117,8 +11120,8 @@ "modal": { "cancel": "Abbrechen", "copyEmail": "E-Mail-Adresse kopieren", - "description": "Mit dieser Funktion können Sie bösartiges oder schädliches Verhalten in Plugins melden. Bei Fragen zu Plugins senden Sie uns bitte eine E-Mail an: ", - "node": "Hinweis: Bei allgemeinen Plugin-Problemen wie Fehlern oder Funktionsanfragen wenden Sie sich bitte über die bereitgestellten Links an den Autor des Plugins. ", + "description": "", + "node": "", "title": "Ein Plugin-Problem melden" } }, @@ -11186,7 +11189,7 @@ "message": "Alle Plugins sind auf dem neuesten Stand" }, "not-found-plugin": { - "body-plugin-not-found": "Das Plugin kann nicht gefunden werden. Bitte überprüfen Sie, ob die URL korrekt ist oder <1>gehen Sie zum <3>Plugin-Katalog.", + "body-plugin-not-found": "", "title-plugin-not-found": "Plugin nicht gefunden" }, "plugin-actions": { @@ -11650,7 +11653,6 @@ "unsupported-repository-type": "" }, "inline-secure-values-warning": "", - "inline-token-warning-badge-text": "", "job-status": { "label-view-details": "Details anzeigen", "loading-finished-job": "Fertiger Auftrag wird geladen …", @@ -11827,6 +11829,17 @@ "label-current-step": "Aktueller Schritt", "label-pending-step": "Ausstehender Schritt" }, + "status-badge": { + "automatic-pulling-disabled": "", + "deleting": "", + "error": "", + "pending": "", + "pulling": "", + "unknown": "", + "up-to-date": "", + "waiting-for-health-check": "", + "warning": "" + }, "success-title-default": "Erfolg", "sync-job": { "error-no-job-id": "Auftrag konnte nicht gestartet werden", @@ -12004,7 +12017,7 @@ "annotations-show-text": "Anmerkungen = anzeigen", "time-range-picker-disabled-text": "Zeitraumauswahl = deaktiviert", "time-range-picker-enabled-text": "Zeitraumauswahl = aktiviert", - "time-range-text": "Zeitraum = " + "time-range-text": "" }, "share": { "success-delete": "Ihr Dashboard kann nicht mehr geteilt werden" @@ -12043,7 +12056,7 @@ "revoke-user-access-modal-desc-line1": "Sind Sie sicher, dass Sie den Zugriff für {{email}} widerrufen möchten?" }, "delete-user-shared-dashboards-modal": { - "revoke-user-access-modal-desc-line2": "Diese Aktion widerruft sofort den Zugang von {{email}} zu allen freigegebenen Dashboards." + "revoke-user-access-modal-desc-line2": "" }, "modal": { "shared-dashboard-modal-title": "Freigegebene Dashboards" @@ -12212,7 +12225,7 @@ }, "menu": { "clear-button": "Alles löschen", - "tooltip": "Sie können jetzt die Option „Keine Basisrolle“ auswählen und Berechtigungen zu Ihren benutzerdefinierten Anforderungen hinzufügen. Weitere Informationen finden Sie in <1>unserer Dokumentation." + "tooltip": "" }, "menu-aria-label": "Rollenauswahlmenü", "menu-group-option-aria-label": "Rollenauswahloption", @@ -12222,7 +12235,7 @@ }, "sub-menu-aria-label": "Rollenauswahl-Untermenü", "title": { - "description": "Weisen Sie den Benutzern Rollen zu, um eine granulare Kontrolle über den Zugriff auf die Funktionen und Ressourcen von Grafana zu gewährleisten. Weitere Informationen finden Sie in unserer <2>Dokumentation." + "description": "" } }, "role-picker-drawer": { @@ -12345,7 +12358,7 @@ }, "select": { "select-menu": { - "selected-count": "Ausgewählt " + "selected-count": "" } }, "service-account-create-page": { @@ -12444,6 +12457,7 @@ "aria-label-role": "Rolle" }, "service-account-tokens-table": { + "aria-label-delete-button": "", "created": "Erstellt", "expires": "Läuft ab", "last-used-at": "Zuletzt verwendet am", @@ -12531,7 +12545,7 @@ "info-text": "Erstelle einen direkten Link zu diesem Dashboard oder Panel mit den folgenden angepassten Optionen.", "link-url": "Link-URL", "render-alert": "Bild-Render-Plug-in nicht installiert", - "render-instructions": "Um ein Bild zu rendern, müssen Sie das <2>Grafana Image Renderer Plugin installieren. Bitte kontaktieren Sie Ihren Grafana-Administrator, um das Plugin zu installieren.", + "render-instructions": "", "rendered-image": "Direktlink zum gerenderten Bild", "save-alert": "Dashboard nicht gespeichert", "save-dashboard": "Um ein Panel-Bild zu rendern, muss zuerst das Dashboard gespeichert werden.", @@ -12555,7 +12569,7 @@ "info-text-1": "Ein Schnappschuss ist eine Möglichkeit, ein interaktives Dashboard sofort öffentlich zu teilen. Beim Erstellen entfernen wir sensible Daten wie Abfragen (Metriken, Vorlagen und Anmerkungen) und Panel-Links, sodass nur die sichtbaren Metrikdaten und die in dein Dashboard eingebetteten Seriennamen angezeigt werden.", "info-text-2": "Beachte, dass dein Schnappschuss <1>für jeden sichtbar ist, der den Link hat und auf die URL zugreifen kann. Teile Schnappschüsse daher mit Bedacht.", "local-button": "Snapshot veröffentlichen", - "mistake-message": "Hast du einen Fehler gemacht? ", + "mistake-message": "", "name": "Name des Schnappschusses", "timeout": "Timeout (Sekunden)", "timeout-description": "Wenn die Erfassung deiner Dashboard-Metriken lange dauert, musst du ggf. den Timeout-Wert anpassen.", @@ -13167,7 +13181,7 @@ "forwards-time-aria-label": "Zeitbereich nach vorne verschieben", "to": "bis", "zoom-out-button": "Zeitbereich verkleinern", - "zoom-out-tooltip": "Zeitbereich verkleinern <1> STRG +Z" + "zoom-out-tooltip": "" }, "time-range": { "apply": "Zeitbereich anwenden", @@ -13292,7 +13306,7 @@ }, "transformations": { "empty": { - "add-transformation-body": "Mithilfe von Transformationen können Daten auf verschiedene Arten geändert werden, bevor Ihre Visualisierung angezeigt wird.<1>Dies beinhaltet die Verknüpfung von Daten, das Umbenennen von Feldern, die Erstellung von Berechnungen, das Formatieren von Daten für die Anzeige und mehr.", + "add-transformation-body": "", "add-transformation-header": "Daten transformieren beginnen" } }, @@ -13559,7 +13573,7 @@ "label-format": "Format", "label-set-timezone": "Zeitzone festlegen", "label-time-field": "Zeitfeld", - "tooltip-format": "Das Ausgabeformat für das Feld, das als <2>Moment.js-Format-String angegeben ist.", + "tooltip-format": "", "tooltip-timezone-manually": "Stellen Sie die Zeitzone des Datums manuell ein" }, "format-time-transformer-editor": { @@ -14154,8 +14168,8 @@ "message": "Keine Benutzer gefunden" }, "token-revoked-modal": { - "auto-revoked": "Ihr Sitzungstoken wurde automatisch widerrufen, weil Sie <2>die maximale Anzahl von {{numSessions}} gleichzeitigen Sitzungen für Ihren Account erreicht haben.", - "resume-message": "<0>Melden Sie sich für die Fortsetzung Ihrer Sitzung erneut an.Kontaktieren Sie Ihren Administrator oder besuchen Sie die Lizenz-Seite, um Ihr Kontingent zu prüfen, wenn Sie wiederholt automatisch abgemeldet werden.", + "auto-revoked": "", + "resume-message": "", "sign-in": "Anmelden", "title-you-have-been-automatically-signed-out": "Sie wurden automatisch abgemeldet" }, diff --git a/public/locales/es-ES/grafana.json b/public/locales/es-ES/grafana.json index acd1c36de4b..6e99108c6d5 100644 --- a/public/locales/es-ES/grafana.json +++ b/public/locales/es-ES/grafana.json @@ -108,7 +108,7 @@ "dismiss": "Descartar", "heading": "Autenticación empresarial", "learn-more-link": "Más información", - "text": "Gestione usuarios, equipos y permisos automáticamente con <1>SAML, <3>SCIM, <6>LDAP y <8>RBAC, disponibles en Grafana Cloud y Enterprise." + "text": "" }, "feature-listing": { "title-auditing": "Auditoría", @@ -209,7 +209,7 @@ "title-delete": "Eliminar" }, "orgs": { - "delete-body": "¿Seguro que quieres eliminar «{{deleteOrgName}}»?<3> <5>Se eliminarán todos los paneles de control de esta organización.", + "delete-body": "", "id-header": "ID", "name-header": "Nombre", "new-org-button": "Nueva organización" @@ -719,6 +719,7 @@ "title-annotations": "Anotaciones" }, "link-dashboard-and-panel": "Vincular dashboard y panel", + "placeholder-value-input": "", "placeholder-value-input-default": "Introduce el contenido de la anotación personalizada..." }, "bulk-actions": { @@ -1144,7 +1145,7 @@ "title-something-wrong-trying-fetch-group-details": "Se ha producido un error al intentar obtener los detalles del grupo" }, "evaluation-interval-limit-exceeded": { - "body-minimum-interval": "Se ha configurado un intervalo de evaluación mínimo de <1>{{minInterval}} en Grafana.<3>Ponte en contacto con el administrador para configurar un intervalo más reducido.", + "body-minimum-interval": "", "title-global-evaluation-interval-limit-exceeded": "Se ha superado el límite del intervalo de evaluación global" }, "existing-rule-editor": { @@ -1292,7 +1293,7 @@ "resolved": "Resuelta" } }, - "review-alert-payload": "Revisar los datos de alerta para añadir a la carga útil:", + "review-alert-payload": "", "title-add-custom-alerts": "Añadir alertas personalizadas" }, "get-alert-suggestions": { @@ -1416,7 +1417,7 @@ "title-add-folder-and-labels": "Añadir carpeta y etiquetas" }, "grafana-managed-rule-type": { - "description": "Admite múltiples fuentes de datos de cualquier tipo.<1>Transformar datos con expresiones." + "description": "" }, "grafana-modify-export": { "body-invalid-rule-id": "El UID de la regla en la URL de la página no es válido. Comprueba la URL e inténtalo de nuevo.", @@ -1853,7 +1854,7 @@ "aria-label-new": "nuevo" }, "mimir-flavored-type": { - "description": "Utiliza una fuente de datos de Mimir, Loki o Cortex.<1>Las expresiones no son compatibles." + "description": "" }, "min-interval-option": { "label-interval": "Intervalo", @@ -2082,7 +2083,7 @@ "warning-1": "La eliminación de esta política de notificación la eliminará de forma permanente.", "warning-2": "¿Seguro que quieres eliminar esta política?" }, - "filter-description": "Filtra las políticas de notificación mediante una lista de buscadores de coincidencias separados por comas, por ejemplo:<1>severidad=crítica, región=EMEA", + "filter-description": "", "generated-policies": "Políticas generadas automáticamente", "matchers": "Buscadores de coincidencias", "metadata": { @@ -2126,7 +2127,8 @@ "conflict": "Otro usuario ha actualizado el árbol de políticas de notificación.", "error-code": "Mensaje de error: «{{error}}»", "routes": { - "conflictingMatchers": "No se puede añadir o actualizar la ruta: los comparadores entrarán en conflicto con un árbol de enrutamiento externo si fusionamos los comparadores {{-matchers}}. Esto haría que la ruta fuera inaccesible." + "conflictingMatchers": "No se puede añadir o actualizar la ruta: los comparadores entrarán en conflicto con un árbol de enrutamiento externo si fusionamos los comparadores {{-matchers}}. Esto haría que la ruta fuera inaccesible.", + "unknownMatchers": "" }, "suffix": "Actualiza la página y vuelve a intentarlo.", "title": "Error al añadir o actualizar la política de notificación" @@ -2244,7 +2246,7 @@ "error-no-query-editor": "No se ha podido cargar el editor de consultas debido a: {{errorMessage}}" }, "recording-rule-type": { - "description": "Precalcula las expresiones.<1>Debe combinarse con una regla de alerta." + "description": "" }, "recording-rules": { "description-target-data-source": "La fuente de datos de Prometheus para almacenar las reglas de registro en", @@ -2257,7 +2259,7 @@ }, "redirect-to-clone-rule": { "body-evaluation-group": "Deberás establecer un nuevo grupo de evaluación para la regla copiada porque el original se ha aprovisionado y no se puede usar para las reglas creadas en la interfaz de usuario.", - "body-not-provisioned": "La nueva regla <1>no se marcará como una regla aprovisionada.", + "body-not-provisioned": "", "confirmText-copy": "Copiar", "title-copy-provisioned-alert-rule": "Copiar regla de alerta aprovisionada" }, @@ -2292,13 +2294,13 @@ "routing-settings": { "aria-label-group-by": "Agrupar por", "description-group-by": "Combina varias alertas en una sola notificación agrupándolas por los mismos valores de etiqueta. Si el campo está vacío, se hereda de la política de notificación predeterminada.", - "group-interval": "Intervalo del grupo: <1>{{groupIntervalValue}}", - "group-wait": "Espera del grupo: <1>{{groupWaitValue}}", - "grouping": "Agrupación: <1>{{fields}}", + "group-interval": "", + "group-wait": "", + "grouping": "", "label-group-by": "Agrupar por", "label-override-grouping": "Anular agrupación", "label-override-timings": "Anular tiempos", - "repeat-interval": "Intervalo de repetición: <1>{{repeatIntervalValue}}" + "repeat-interval": "" }, "rule-actions-buttons": { "title-edit": "Editar", @@ -2554,7 +2556,7 @@ "relative-with-to": "" }, "rule-type-picker": { - "grafana-managed": "Selecciona «Gestionadas por Grafana» a menos que tengas una fuente de datos Mimir, Loki o Cortex con la API de Ruler habilitada." + "grafana-managed": "" }, "rule-view": { "query": { @@ -2887,7 +2889,7 @@ "test-contact-point-modal": { "custom-notification-message": "Enviarás una notificación de prueba que utiliza las anotaciones definidas a continuación. Esta es una buena opción si utilizas plantillas y mensajes personalizados.", "notification-message": "Mensaje de notificación", - "predefined-notification-message": "Enviarás una notificación de prueba que utiliza una alerta predefinida. Si has definido una plantilla o un mensaje personalizado cambia al mensaje de notificación <1>personalizado de arriba para obtener mejores resultados.", + "predefined-notification-message": "", "send-test-notification": "Enviar notificación de prueba", "title-test-contact-point": "Probar punto de contacto" }, @@ -2896,7 +2898,7 @@ }, "threshold-expression-viewer": { "input": "Entrada", - "stop-alerting-when": "Dejar de alertar (o estado pendiente) cuando " + "stop-alerting-when": "" }, "time-interval": { "add-time-interval": "Añadir intervalo de tiempo", @@ -3084,7 +3086,7 @@ "title-notification-policies": "Políticas de notificación" }, "yaml-content-info": { - "body": "El contenido YAML en el editor solo contiene la configuración de la regla de alerta <1>Para configurar Prometheus, debes proporcionar el resto del <4>contenido del archivo de configuración." + "body": "" } }, "alertlist": { @@ -3160,7 +3162,7 @@ "no-annotations-found": "No se han encontrado anotaciones" }, "annotation-list-item": { - "tooltip-created-by": "Creado por:<1> {{email}}" + "tooltip-created-by": "" }, "category-annotation-query": "Consulta de anotaciones", "category-display": "Mostrar", @@ -3198,7 +3200,7 @@ }, "empty-state": { "button-title": "Añadir consulta de anotación", - "info-box-content": "<0>Las anotaciones proporcionan una forma de integrar los datos de los eventos en tus gráficos. Se visualizan como líneas verticales e iconos en todos los paneles de gráficos. Al pasar el ratón por encima de un icono de anotación, puedes obtener el texto y las etiquetas del evento. Puedes añadir eventos de anotación directamente desde Grafana manteniendo pulsada la tecla CTRL o CMD y haciendo clic en el gráfico (o arrastrando la región). Estos se almacenarán en la base de datos de anotaciones de Grafana.", + "info-box-content": "", "info-box-content-2": "Consulta la <2>documentación de anotaciones para obtener más información.", "title": "Aún no se han añadido consultas de anotaciones personalizadas" }, @@ -3236,7 +3238,7 @@ "auth-settings": "Ajustes de autenticación" }, "auth-drawer-unconneced": { - "subtitle": "Configura los ajustes de autenticación. Encuentra más información en nuestra <2><0>documentación." + "subtitle": "" }, "auth-drawer-unconnected": { "advanced-auth": "Autenticación avanzada", @@ -3270,7 +3272,7 @@ "allowed-organizations-description": "Lista de organizaciones separadas por comas o espacios. El usuario debe ser miembro \nde al menos una organización para iniciar sesión.", "allowed-organizations-label": "Organizaciones permitidas", "allowed-organizations-placeholder": "Introduzca organizaciones (mi-equipo, miequipo...) y pulse Intro para añadirlas", - "api-url-description": "El punto final de información del usuario de tu proveedor de OAuth2. La información devuelta por este punto final debe ser compatible con <2>OpenID UserInfo.", + "api-url-description": "", "api-url-required": "Este campo debe ser una URL válida si se configura.", "auth-style-description": "Determina cómo se envían los valores de «{{ clientIDLabel }}» y «{{ clientSecretLabel }}» al proveedor de Oauth2. El valor predeterminado es «Detección automática».", "auth-style-label": "Estilo de autenticación", @@ -3415,7 +3417,7 @@ } }, "auth-config-auth-config-page-unconnected": { - "subtitle": "Gestiona tus ajustes de autenticación y configura el inicio de sesión único. Encuentra más información en nuestra <2><0>documentación." + "subtitle": "" }, "bar-chart": { "warn": { @@ -4133,7 +4135,7 @@ }, "scopes": { "apply-selected-scopes": "Aplicar", - "selected-scopes-label": "Alcances: " + "selected-scopes-label": "" }, "search-box": { "placeholder": "Buscar o saltar a..." @@ -4275,7 +4277,7 @@ "okay": "De acuerdo" }, "not-found-datasource": { - "body": "Tal vez escribiste mal la URL o el plugin con el ID <1> no está disponible.<3>Para ver una lista de las fuentes de datos disponibles, <5>haz clic aquí." + "body": "" }, "oss": { "connections-home-page": { @@ -4318,8 +4320,8 @@ "versionHistory": { "comparison": { "header": { - "hide-json-diff": "Ocultar diferencia de JSON ", - "show-json-diff": "Mostrar diferencia de JSON ", + "hide-json-diff": "", + "show-json-diff": "", "text": "Versión {{version}} actualizada por {{createdBy}} ({{ageString}}) {{message}}" }, "select": "Selecciona dos versiones para empezar a comparar" @@ -4346,7 +4348,7 @@ "label-label": "Etiqueta", "label-placeholder": "p. ej. seguimiento de Tempo", "label-required": "Este campo es obligatorio.", - "sub-text": "<0>Defina el texto que describirá la correlación.", + "sub-text": "", "title": "Definir la etiqueta de correlación (paso 1 de 3)" }, "configure-correlation-target-form": { @@ -4390,7 +4392,7 @@ }, "source-form": { "control-required": "Este campo es obligatorio.", - "description": "Un punto de datos debe proporcionar valores a todas las variables como campos o como salida de transformaciones para que el botón de correlación aparezca en la visualización.<1>Nota: No es necesario definir explícitamente todas las variables a continuación. Una transformación como <4>logfmt creará variables para cada par de clave/valor.", + "description": "", "description-external-pre": "Has utilizado las siguientes variables en la URL de destino:", "description-query-pre": "Has utilizado las siguientes variables en la consulta de destino:", "external-title": "Configura la fuente de datos que utilizará la URL (paso 3 de 3)", @@ -4402,12 +4404,12 @@ "results-required": "Este campo es obligatorio.", "source-description": "Los resultados de la fuente de datos seleccionada tienen enlaces que se muestran en el panel", "source-label": "Fuente", - "sub-text": "<0>Defina qué fuente de datos mostrará la correlación y qué datos reemplazarán a las variables previamente definidas." + "sub-text": "" }, "sub-title": "Define cómo se relacionan entre sí los datos alojados en diferentes fuentes de datos. Consulta la <2>documentación para obtener más información.", "target-form": { "control-rules": "Este campo es obligatorio.", - "sub-text": "<0>Define a qué elemento se vinculará la correlación. Con el tipo de consulta, se ejecutará una consulta cuando se haga clic en la correlación. Con el tipo externo, al hacer clic en la correlación se abrirá una URL.", + "sub-text": "", "target-description-external": "Especifica la URL que se abrirá al hacer clic en el enlace", "target-description-query": "Especifique qué fuente de datos se consulta cuando se hace clic en el enlace", "target-label": "Destino", @@ -4614,7 +4616,7 @@ } }, "confirm-plugin-dashboard-save-modal": { - "body-plugin-dashboard": "Los cambios se perderán al actualizar el plugin.<1><2>Utiliza <1>Guardar como para crear una versión personalizada.", + "body-plugin-dashboard": "", "cancel": "Cancelar", "overwrite": "Sobrescribir", "title-plugin-dashboard": "Dashboard del plugin" @@ -4831,7 +4833,7 @@ "add-visualization-body": "Selecciona una fuente de datos y luego consulta y visualiza tus datos con gráficos, estadísticas y tablas o cree listas, anotaciones y otros widgets.", "add-visualization-button": "Añadir visualización", "add-visualization-header": "Comienza tu nuevo panel de control añadiendo una visualización", - "import-a-dashboard-body": "Importa dashboards desde archivos o <2>grafana.com.", + "import-a-dashboard-body": "", "import-a-dashboard-header": "Importar un tablero", "import-dashboard-button": "Importar panel de control", "show-less-dashboards": "", @@ -5289,8 +5291,8 @@ "title-provisioned": "Dashboard aprovisionado" }, "save-dashboard-error-proxy": { - "body-name-exists": "Ya existe un dashboard con el mismo nombre en la carpeta seleccionada.<1><2>¿Seguro que quieres guardar este dashboard?", - "body-version-mismatch": "Otra persona ha actualizado este dashboard<1><2>¿Seguro que quieres guardar este dashboard?", + "body-name-exists": "", + "body-version-mismatch": "", "confirmText-save-and-overwrite": "Guardar y sobrescribir", "title-name-exists": "Conflicto", "title-version-mismatch": "Conflicto" @@ -5308,7 +5310,7 @@ "cancel": "Cancelar", "cannot-be-saved": "Este dashboard no se puede guardar desde la interfaz de usuario de Grafana porque se ha aprovisionado desde otra fuente. Copia el JSON o guárdalo en un archivo a continuación; luego puedes actualizar el dashboard en la fuente de aprovisionamiento.", "copy-json-to-clipboard": "Copiar JSON al portapapeles", - "file-path": "<0>Ruta del archivo: {{filePath}}", + "file-path": "", "save-json-to-file": "Guardar JSON en un archivo", "see-docs": "Consulta la <2>documentación para obtener más información sobre el aprovisionamiento." }, @@ -5507,7 +5509,7 @@ "transformation-picker": { "info": "Las transformaciones permiten unir, calcular, reordenar, ocultar y cambiar el nombre de los resultados de tu consulta antes de que se visualicen.", "info-graph-not-suitable": "Muchas transformaciones no son adecuadas si se utiliza la visualización de gráficos, ya que actualmente solo admite datos de series temporales.", - "info-switch-to-table": "Puede ser útil cambiar a la visualización de tabla para comprender lo que está haciendo una transformación. ", + "info-switch-to-table": "", "placeholder-search-for-transformation": "Buscar transformación", "read-more": "Leer más", "title-transformations": "Transformaciones" @@ -5573,8 +5575,8 @@ "version-history-comparison": { "button-restore": "Restaurar a la versión {{version}} ", "label-view-json-diff": "Ver diferencia de JSON", - "new-updated-by": "<0>Versión {{version}} actualizada por {{editor}} {{timeAgo}}", - "old-updated-by": "<0>Versión {{version}} actualizada por {{editor}} {{timeAgo}}" + "new-updated-by": "", + "old-updated-by": "" }, "version-history-table": { "aria-label-toggle-selection": "Alternar selección de versión {{version}}", @@ -5974,7 +5976,7 @@ "cancel": "Cancelar" }, "render-save-button-and-error": { - "body-plugin-dashboard": "Los cambios se perderán al actualizar el plugin. Utiliza <1>Guardar como para crear una versión personalizada.", + "body-plugin-dashboard": "", "title-failed-to-save-dashboard": "Error al guardar el dashboard", "title-plugin-dashboard": "Dashboard del plugin", "title-someone-else-has-updated-this-dashboard": "Otra persona ha actualizado este dashboard", @@ -5983,7 +5985,7 @@ "save-and-overwrite": "«Guardar y sobrescribir»" }, "library-viz-panel-info": { - "last-edited": "{{timeAgo}} por ", + "last-edited": "", "usage-count_one": "Utilizado en {{count}} dashboards", "usage-count_other": "Utilizado en {{count}} dashboards" }, @@ -6044,7 +6046,7 @@ }, "panel-data-queries-tab-rendered": { "add-query": "Añadir consulta", - "expression": "Expresión " + "expression": "" }, "panel-data-transformations-tab": { "tab-label": "Transformaciones" @@ -6102,7 +6104,7 @@ "query": "Consulta" }, "query-variable-editor-form": { - "description-examples": "Los grupos de captura con nombre se pueden utilizar para separar el texto y el valor de la pantalla (<1>consulta los ejemplos).", + "description-examples": "", "description-optional": "Es opcional si quieres extraer parte del nombre de una serie o segmento de nodo métrico.", "label-data-source": "Fuente de datos", "label-static-options-sort": "Ordenar opciones estáticas", @@ -6163,7 +6165,7 @@ "label-message": "Mensaje", "placeholder-describe-changes-optional": "Añade una nota para describir tus cambios (opcional).", "render-footer": { - "body-plugin-dashboard": "Los cambios se perderán al actualizar el plugin. Utiliza <1>Guardar como para crear una versión personalizada.", + "body-plugin-dashboard": "", "no-changes-to-save": "Sin cambios para guardar", "title-failed-to-save-dashboard": "Error al guardar el dashboard", "title-plugin-dashboard": "Dashboard del plugin", @@ -6199,7 +6201,7 @@ "cancel": "Cancelar", "cannot-be-saved": "Este dashboard no se puede guardar desde la interfaz de usuario de Grafana porque se ha aprovisionado desde otra fuente. Copia el JSON o guárdalo en un archivo a continuación; luego puedes actualizar el dashboard en la fuente de aprovisionamiento.", "copy-json-to-clipboard": "Copiar JSON al portapapeles", - "file-path": "<0>Ruta del archivo: {{filePath}}", + "file-path": "", "label-description": "Descripción", "label-target-folder": "Carpeta de destino", "label-title": "Título", @@ -6368,8 +6370,8 @@ }, "version-history-comparison": { "label-view-json-diff": "Ver diferencia de JSON", - "new-version-updated": "<0>Versión {{version}} actualizada por {{editor}} {{timeAgo}}", - "old-version-updated": "<0>Versión {{version}} actualizada por {{editor}} {{timeAgo}}" + "new-version-updated": "", + "old-version-updated": "" }, "version-history-header": { "compare-versions": "Comparando {{baseVersion}} <3> {{newVersion}}", @@ -6447,7 +6449,7 @@ "provisioned-delete-modal": { "confirm-button": "Aceptar", "text-1": "Este panel de control está gestionado por el aprovisionamiento de Grafana y no se puede eliminar. Elimina el panel de control del archivo de configuración para borrarlo.", - "text-2": "Consulta la documentación de Grafana para obtener más información sobre el aprovisionamiento. ", + "text-2": "", "text-3": "Ruta del archivo: {{provisionedId}}", "text-link": "Ir a la página de documentos", "title": "No se puede eliminar el panel de control aprovisionado" @@ -6525,7 +6527,7 @@ }, "data-source-testing-status-page": { "error-more-details-link": "Haz clic <2>aquí para obtener más información sobre este error.", - "success-more-details-links": "A continuación, puedes empezar a visualizar los datos <2>creando un panel de control o consultando los datos en la <5>vista Explorar." + "success-more-details-links": "" }, "data-sources": { "datasource-add-button": { @@ -6621,7 +6623,7 @@ "test": "Prueba" }, "cloud-info-box": { - "body-alert": "O ahórrate el esfuerzo y consigue {{mainDS}} (y{{extraDS}}) como fuentes de datos totalmente gestionadas, escalables y alojadas de Grafana Labs con el <6>plan Grafana Cloud gratuito para siempre.", + "body-alert": "", "title-alert": "Configura tu fuente de datos {{mainDS}} a continuación" }, "dashboards-table": { @@ -6749,18 +6751,18 @@ "no-events-yet": "Ningún evento todavía" }, "render-info-viewer": { - "data-counter": "Datos: {{numDataChanges}} ", + "data-counter": "", "elapsed-time": "Tiempo: {{elapsed}} ms", "field": "Campo", "last": "Últimos", - "render-counter": "Renderizar: {{numRenders}} ", - "schema-counter": "Esquema: {{numSchemaChanges}} ", + "render-counter": "", + "schema-counter": "", "title-reset-counters": "Reiniciar contadores", "tooltip-step-back": "Volver", "type": "Tipo" }, "state-view": { - "current-value": "Valor actual: {{currentValue}} ", + "current-value": "", "label-state-name": "Nombre del estado" } }, @@ -7207,7 +7209,7 @@ }, "footer": { "learn-more": "Más información", - "pro-tip-define-sources-through-configuration-files": " Un consejo: también puedes definir fuentes de datos a través de archivos de configuración. " + "pro-tip-define-sources-through-configuration-files": "" } }, "pane": { @@ -7269,8 +7271,6 @@ "query-deleted": "Consulta eliminada" }, "rich-history-queries-tab": { - "displaying-partial-queries": "Mostrando {{ count }} consultas", - "displaying-queries": "{{ count }} consultas", "filter-aria-label": "Filtrar consultas para la(s) fuente(s) de datos", "filter-history": "Filtrar historial", "filter-placeholder": "Filtrar consultas para la(s) fuente(s) de datos", @@ -7280,7 +7280,11 @@ "search-placeholder": "Buscar consultas", "showing-queries": "Mostrando {{ shown }} de {{ total }} <0>Cargar más", "sort-aria-label": "Ordenar consultas", - "sort-placeholder": "Ordenar consultas por" + "sort-placeholder": "Ordenar consultas por", + "displaying-partial-queries_one": "", + "displaying-partial-queries_other": "", + "displaying-queries_one": "", + "displaying-queries_other": "" }, "rich-history-settings-tab": { "alert-info": "Grafana mantendrá las entradas hasta {{optionLabel}}. Las entradas destacadas no se eliminarán.", @@ -7472,7 +7476,7 @@ "copy-shortened-link-menu": "Abrir opciones para copiar enlace", "refresh-picker-cancel": "Cancelar", "refresh-picker-run": "Ejecutar consulta", - "split-close": " Cerrar ", + "split-close": "Cerrar", "split-close-tooltip": "Cerrar panel dividido", "split-narrow": "Reducir panel", "split-title": "Dividir", @@ -7602,8 +7606,8 @@ }, "math": { "available-math-functions": "Funciones matemáticas disponibles", - "run-math-operations": "Ejecuta operaciones matemáticas en una o más consultas. Hace referencia a la consulta por {{refExample}} es decir: {{ref1}}, {{ref2}}, {{ref3}} etc.<10>Ejemplo: <12>{{example}}", - "tooltip-footer": "Consulta nuestra documentación adicional sobre <2>Expresiones matemáticas.", + "run-math-operations": "", + "tooltip-footer": "", "tooltip-title": "Operador matemático", "tooltip-trigger": "Expresión" }, @@ -8642,7 +8646,7 @@ }, "data-source-http-settings": { "access-help": "Ayuda <1>", - "access-help-details": "El modo de acceso controla cómo se gestionarán las solicitudes a la fuente de datos.<1> <1>Servidor debería ser la opción preferida si no se indica nada más.", + "access-help-details": "", "access-help-title": "Acceder a la ayuda", "access-label": "Acceder", "allowed-cookies": "Cookies permitidas", @@ -8910,7 +8914,7 @@ "cell-inspect": "Inspeccionar valor", "cell-inspect-tooltip": "Inspeccionar valor", "copy": "Copiar al portapapeles", - "csv-counts": "Filas: {{rows}}, columnas: {{columns}} <5>", + "csv-counts": "", "csv-placeholder": "Introducir CSV aquí...", "filter-placeholder": "Filtrar valores", "filter-popup-apply": "Aceptar", @@ -9195,7 +9199,6 @@ "name-line-width": "Espesor de la línea", "name-stacking": "Apilamiento" }, - "inline-token-warning-badge-tooltip": "", "inspector": { "inspect-data-tab": { "loading": "Cargando", @@ -9359,7 +9362,7 @@ "error-fetching": "Error al obtener los ajustes de LDAP", "error-saving": "Error al guardar los ajustes de LDAP", "error-validate-form": "Error al validar los ajustes de LDAP", - "feature-flag-disabled": "Solo se puede acceder a esta página habilitando el indicador de función <1>ssoSettingsLDAP.", + "feature-flag-disabled": "", "saved": "Ajustes de LDAP guardados" }, "bind-dn": { @@ -9400,7 +9403,7 @@ "label": "DNS de base de búsqueda", "placeholder": "ejemplo: dc=grafana,dc=org" }, - "subtitle": "La integración LDAP en Grafana permite a los usuarios de Grafana iniciar sesión con sus credenciales LDAP. Encuentra más información en nuestra <2><0>documentación.", + "subtitle": "", "title": "Ajustes básicos" }, "library-panel": { @@ -9444,7 +9447,7 @@ "dashboard-name": "Nombre del dashboard" }, "library-panel-info": { - "last-edited": "Última modificación el {{timeAgo}} por ", + "last-edited": "", "usage-count_one": "Utilizado en {{count}} dashboards", "usage-count_other": "Utilizado en {{count}} dashboards" }, @@ -9749,7 +9752,7 @@ "tooltip-unpin-line": "Desanclar línea" }, "log-row-message": { - "ellipsis": "… ", + "ellipsis": "", "more": "más", "see-details": "Ver detalles del registro", "tooltip-error": "Error: {{errorMessage}}" @@ -10145,7 +10148,7 @@ }, "resource-table": { "dashboard-load-error": "No se puede cargar el panel de control", - "error-library-element-sub": "Elemento de biblioteca {uid}", + "error-library-element-sub": "", "error-library-element-title": "No se puede cargar el elemento de la biblioteca", "unknown-datasource-title": "Fuente de datos {{datasourceUID}}", "unknown-datasource-type": "Fuente de datos desconocida" @@ -10793,10 +10796,10 @@ "placeholder-optional": "(opcional)", "role": "Rol", "submit": "Enviar", - "tooltip": "Ahora puedes seleccionar la opción «Sin función básica» y añadir permisos según tus necesidades específicas. Puedes encontrar más información en <1>nuestra documentación." + "tooltip": "" }, "user-invite-page": { - "sub-title": "Envía una invitación o añade un usuario de Grafana existente a la organización.<1> {{orgName}}", + "sub-title": "", "text": { "invite-user": "Invitar a usuario" } @@ -10885,7 +10888,7 @@ "switch-to-table": "Cambiar a tabla" }, "panel-plugin-error": { - "text-load-error": "Consulta los logs de inicio del servidor para obtener más información. <1>Si este plugin se cargó desde Git, asegúrate de que se haya compilado.", + "text-load-error": "", "title-load-error": "Error al cargar: {{panelId}}", "title-not-found": "No se ha encontrado el plugin del panel: {{id}}" }, @@ -11079,7 +11082,7 @@ }, "details": { "connections-tab": { - "description": "Actualmente tienes las siguientes fuentes de datos configuradas para {{pluginName}}. Haz clic en un mosaico para ver los detalles de la configuración. Puedes encontrar todas las conexiones de tus fuentes de datos en <4><0>Conexiones - <3>Fuentes de datos." + "description": "" }, "disabled-error": { "angular-deprecation-link": "Leer más sobre la depreciación angular", @@ -11096,7 +11099,7 @@ }, "labels": { "contactGrafanaLabs": "Contactar con Grafana Labs", - "customLinks": "Enlaces personalizados ", + "customLinks": "", "customLinksTooltip": "Estos enlaces los proporciona el desarrollador del complemento para ofrecer recursos e información adicionales específicos del desarrollador", "dependencies": "Dependencias", "documentation": "Documentación", @@ -11107,7 +11110,7 @@ "latestVersion": "Versión más reciente", "license": "Licencia", "raiseAnIssue": "Comunicar un problema", - "reportAbuse": "Comunicar un problema ", + "reportAbuse": "", "reportAbuseTooltip": "Informa de problemas relacionados con complementos maliciosos o dañinos directamente a Grafana Labs.", "repository": "Repositorio", "signature": "Firma", @@ -11117,8 +11120,8 @@ "modal": { "cancel": "Cancelar", "copyEmail": "Copiar dirección de correo electrónico", - "description": "Esta característica sirve para informar de comportamientos maliciosos o dañinos de los complementos. Si tienes alguna duda sobre los complementos, envíanos un correo electrónico a: ", - "node": "Nota: Para problemas generales de los complementos, como errores o solicitudes de funciones, ponte en contacto con el autor del complemento utilizando los enlaces proporcionados. ", + "description": "", + "node": "", "title": "Informar de un problema con el complemento" } }, @@ -11186,7 +11189,7 @@ "message": "Todos los plugins están actualizados" }, "not-found-plugin": { - "body-plugin-not-found": "No se puede encontrar ese plugin. Comprueba que la URL sea correcta o <1>ve al <3>catálogo de plugins.", + "body-plugin-not-found": "", "title-plugin-not-found": "Plugin no encontrado" }, "plugin-actions": { @@ -11650,7 +11653,6 @@ "unsupported-repository-type": "" }, "inline-secure-values-warning": "", - "inline-token-warning-badge-text": "", "job-status": { "label-view-details": "Ver detalles", "loading-finished-job": "Cargando trabajo finalizado...", @@ -11827,6 +11829,17 @@ "label-current-step": "Paso actual", "label-pending-step": "Paso pendiente" }, + "status-badge": { + "automatic-pulling-disabled": "", + "deleting": "", + "error": "", + "pending": "", + "pulling": "", + "unknown": "", + "up-to-date": "", + "waiting-for-health-check": "", + "warning": "" + }, "success-title-default": "Completado", "sync-job": { "error-no-job-id": "Error al iniciar el trabajo", @@ -12004,7 +12017,7 @@ "annotations-show-text": "Anotaciones = mostrar", "time-range-picker-disabled-text": "Selector de rango de tiempo = desactivado", "time-range-picker-enabled-text": "Selector de rango de tiempo = activado", - "time-range-text": "Rango de tiempo = " + "time-range-text": "" }, "share": { "success-delete": "Tu panel de control ya no se puede compartir" @@ -12043,7 +12056,7 @@ "revoke-user-access-modal-desc-line1": "¿Seguro que quieres revocar el acceso para {{email}}?" }, "delete-user-shared-dashboards-modal": { - "revoke-user-access-modal-desc-line2": "Esta acción revocará inmediatamente el acceso de {{email}} a todos los paneles de control compartidos." + "revoke-user-access-modal-desc-line2": "" }, "modal": { "shared-dashboard-modal-title": "Paneles de control compartidos" @@ -12212,7 +12225,7 @@ }, "menu": { "clear-button": "Borrar todo", - "tooltip": "Ahora puedes seleccionar la opción «Sin función básica» y añadir permisos según tus necesidades específicas. Puedes encontrar más información en <1>nuestra documentación." + "tooltip": "" }, "menu-aria-label": "Menú del selector de roles", "menu-group-option-aria-label": "Opción del selector de roles", @@ -12222,7 +12235,7 @@ }, "sub-menu-aria-label": "Submenú del selector de roles", "title": { - "description": "Asigna funciones a los usuarios para garantizar un control preciso sobre el acceso a las funciones y recursos de Grafana. Encuentra más información en nuestra <2><0>documentación." + "description": "" } }, "role-picker-drawer": { @@ -12345,7 +12358,7 @@ }, "select": { "select-menu": { - "selected-count": "Seleccionado " + "selected-count": "" } }, "service-account-create-page": { @@ -12444,6 +12457,7 @@ "aria-label-role": "Rol" }, "service-account-tokens-table": { + "aria-label-delete-button": "", "created": "Creado", "expires": "Caduca", "last-used-at": "Último uso el", @@ -12531,7 +12545,7 @@ "info-text": "Cree un enlace directo a este panel de control o panel, personalizado con las siguientes opciones.", "link-url": "URL del enlace", "render-alert": "Complemento de renderizador de imagen no instalado", - "render-instructions": "Para renderizar una imagen, debes instalar el <2>complemento de renderizado de imágenes Grafana. Ponte en contacto con tu administrador de Grafana para instalarlo.", + "render-instructions": "", "rendered-image": "Enlace directo a la imagen renderizada", "save-alert": "El panel de control no se ha guardado", "save-dashboard": "Para renderizar una imagen de panel, primero debe guardar el panel de control.", @@ -12555,7 +12569,7 @@ "info-text-1": "Una instantánea es una forma inmediata de compartir un panel interactivo públicamente. Cuando se crean, eliminamos datos confidenciales como consultas (métricas, plantilla y anotación) y enlaces de panel, dejando solo los datos de métricas visibles y los nombres de serie incrustados en el panel.", "info-text-2": "Tenga en cuenta que su instantánea <1>puede ser vista por cualquiera que tenga el enlace y pueda acceder a la URL. Comparta sus instantáneas con cautela.", "local-button": "Publicar instantánea", - "mistake-message": "¿Ha cometido un error? ", + "mistake-message": "", "name": "Nombre de la instantánea", "timeout": "Tiempo de espera (segundos)", "timeout-description": "Es posible que deba configurar el valor del tiempo de espera si se tarda mucho tiempo en recopilar las métricas del panel.", @@ -13167,7 +13181,7 @@ "forwards-time-aria-label": "Adelantar el intervalo de tiempo", "to": "hasta", "zoom-out-button": "Reducir el intervalo de tiempo", - "zoom-out-tooltip": "Reducir el intervalo de tiempo <1> CTRL+Z" + "zoom-out-tooltip": "" }, "time-range": { "apply": "Aplicar intervalo de tiempo", @@ -13292,7 +13306,7 @@ }, "transformations": { "empty": { - "add-transformation-body": "Las transformaciones permiten cambiar los datos de varias maneras antes de que se muestre su visualización.<1>Aquí se incluyen acciones como unir datos, renombrar campos, hacer cálculos, dar formato a los datos para mostrarlos, etc.", + "add-transformation-body": "", "add-transformation-header": "Empezar a transformar datos" } }, @@ -13559,7 +13573,7 @@ "label-format": "Formato", "label-set-timezone": "Establecer zona horaria", "label-time-field": "Campo de tiempo", - "tooltip-format": "El formato de salida para el campo especificado como una <2>cadena de formato Moment.js.", + "tooltip-format": "", "tooltip-timezone-manually": "Establecer la zona horaria de la fecha manualmente" }, "format-time-transformer-editor": { @@ -14154,8 +14168,8 @@ "message": "No se han encontrado usuarios" }, "token-revoked-modal": { - "auto-revoked": "Su token de sesión se ha revocado automáticamente porque ha alcanzado <2>el número máximo de {{numSessions}} sesiones concurrentes para su cuenta.", - "resume-message": "<0>Para reanudar la sesión, vuelve a iniciar sesión.Ponte en contacto con tu administrador o visita la página de licencias para revisar tu cuota si se cierra la sesión automáticamente en repetidas ocasiones.", + "auto-revoked": "", + "resume-message": "", "sign-in": "Iniciar sesión", "title-you-have-been-automatically-signed-out": "Se ha cerrado tu sesión automáticamente" }, diff --git a/public/locales/fr-FR/grafana.json b/public/locales/fr-FR/grafana.json index c22cc0025e3..8bdfac6e3a1 100644 --- a/public/locales/fr-FR/grafana.json +++ b/public/locales/fr-FR/grafana.json @@ -108,7 +108,7 @@ "dismiss": "Ignorer", "heading": "Authentification Enterprise", "learn-more-link": "En savoir plus", - "text": "Gérez automatiquement les utilisateurs, les équipes et les autorisations grâce à <1>SAML, <3>SCIM, <6>LDAP et <8>RBAC, disponibles dans Grafana Cloud et Grafana Enterprise." + "text": "" }, "feature-listing": { "title-auditing": "Auditer", @@ -209,7 +209,7 @@ "title-delete": "Supprimer" }, "orgs": { - "delete-body": "Voulez-vous vraiment supprimer « {{deleteOrgName}} » ?<3> <5>Tous les tableaux de bord de cette organisation seront supprimés !", + "delete-body": "", "id-header": "ID", "name-header": "Nom", "new-org-button": "Nouvelle organisation" @@ -719,6 +719,7 @@ "title-annotations": "Annotations" }, "link-dashboard-and-panel": "Lier le tableau de bord et le panneau", + "placeholder-value-input": "", "placeholder-value-input-default": "Saisir le contenu de l’annotation personnalisée..." }, "bulk-actions": { @@ -1144,7 +1145,7 @@ "title-something-wrong-trying-fetch-group-details": "Une erreur s’est produite lors de la récupération des détails du groupe" }, "evaluation-interval-limit-exceeded": { - "body-minimum-interval": "Un intervalle d’évaluation minimum de <1>{{minInterval}} a été configuré dans Grafana.<3>Veuillez contacter l’administrateur pour configurer un intervalle inférieur.", + "body-minimum-interval": "", "title-global-evaluation-interval-limit-exceeded": "Limite de l’intervalle d’évaluation globale dépassée" }, "existing-rule-editor": { @@ -1292,7 +1293,7 @@ "resolved": "Résolu" } }, - "review-alert-payload": " Examiner les données d’alerte à ajouter à la charge utile :", + "review-alert-payload": "", "title-add-custom-alerts": "Ajouter des alertes personnalisées" }, "get-alert-suggestions": { @@ -1416,7 +1417,7 @@ "title-add-folder-and-labels": "Ajouter un dossier et des étiquettes" }, "grafana-managed-rule-type": { - "description": "Prend en charge plusieurs sources de données de tout type.<1>Transformez les données avec des expressions." + "description": "" }, "grafana-modify-export": { "body-invalid-rule-id": "L’UID de règle dans l’URL de la page n’est pas valide. Veuillez vérifier l’URL et réessayer.", @@ -1853,7 +1854,7 @@ "aria-label-new": "nouveau" }, "mimir-flavored-type": { - "description": "Utilisez une source de données Mimir, Loki ou Cortex.<1>Les expressions ne sont pas prises en charge." + "description": "" }, "min-interval-option": { "label-interval": "Intervalle", @@ -2082,7 +2083,7 @@ "warning-1": "La suppression de cette politique de notification la supprimera définitivement.", "warning-2": "Voulez-vous vraiment supprimer cette politique ?" }, - "filter-description": "Filtrez les politiques de notification en utilisant une liste de correspondances séparées par des virgules, par exemple :<1>gravité=critique, région=EMEA", + "filter-description": "", "generated-policies": "Politiques générées automatiquement", "matchers": "Correspondants", "metadata": { @@ -2126,7 +2127,8 @@ "conflict": "L'arborescence des politiques de notification a été mise à jour par un autre utilisateur.", "error-code": "Message d'erreur : « {{error}} »", "routes": { - "conflictingMatchers": "Impossible d’ajouter ou de mettre à jour la route : des conflits de correspondance existent avec un arbre de routage externe si les correspondances {{-matchers}} sont fusionnées. Cela rendrait la route inaccessible." + "conflictingMatchers": "Impossible d’ajouter ou de mettre à jour la route : des conflits de correspondance existent avec un arbre de routage externe si les correspondances {{-matchers}} sont fusionnées. Cela rendrait la route inaccessible.", + "unknownMatchers": "" }, "suffix": "Actualisez la page, puis réessayez.", "title": "Échec lors de l’ajout ou de la mise à jour de la politique de notification" @@ -2244,7 +2246,7 @@ "error-no-query-editor": "Impossible de charger l’éditeur de requête en raison de : {{errorMessage}}" }, "recording-rule-type": { - "description": "Précalculez les expressions.<1>Doit être combiné avec une règle d’alerte." + "description": "" }, "recording-rules": { "description-target-data-source": "La source de données Prometheus dans laquelle stocker les règles d’enregistrement", @@ -2257,7 +2259,7 @@ }, "redirect-to-clone-rule": { "body-evaluation-group": "Vous devrez définir un nouveau groupe d’évaluation pour la règle copiée, car la règle d’origine a été mise en service et ne peut pas être utilisée pour les règles créées dans l’interface utilisateur.", - "body-not-provisioned": "La nouvelle règle <1>ne sera pas marquée comme une règle mise en service.", + "body-not-provisioned": "", "confirmText-copy": "Copier", "title-copy-provisioned-alert-rule": "Copier la règle d’alerte mise en service" }, @@ -2292,13 +2294,13 @@ "routing-settings": { "aria-label-group-by": "Regrouper par", "description-group-by": "Combinez plusieurs alertes en une seule notification en les regroupant avec les mêmes valeurs d’étiquette. Si elle est vide, elle est héritée de la politique de notification par défaut.", - "group-interval": "Intervalle de groupe : <1>{{groupIntervalValue}}", - "group-wait": "Attente de groupe : <1>{{groupWaitValue}}", - "grouping": "Regroupement : <1>{{fields}}", + "group-interval": "", + "group-wait": "", + "grouping": "", "label-group-by": "Regrouper par", "label-override-grouping": "Remplacer le regroupement", "label-override-timings": "Remplacer les horaires", - "repeat-interval": "Intervalle de répétition : <1>{{repeatIntervalValue}}" + "repeat-interval": "" }, "rule-actions-buttons": { "title-edit": "Modifier", @@ -2554,7 +2556,7 @@ "relative-with-to": "" }, "rule-type-picker": { - "grafana-managed": "Sélectionnez « Grafana géré » à moins que vous n’ayez une source de données Mimir, Loki ou Cortex avec l’API Ruler activée." + "grafana-managed": "" }, "rule-view": { "query": { @@ -2887,7 +2889,7 @@ "test-contact-point-modal": { "custom-notification-message": "Vous allez envoyer une notification de test qui utilise les annotations définies ci-dessous. C’est une bonne option si vous utilisez des modèles et des messages personnalisés.", "notification-message": "Message de notification", - "predefined-notification-message": "Vous allez envoyer une notification de test qui utilise une alerte prédéfinie. Si vous avez défini un modèle ou un message personnalisé, pour de meilleurs résultats, passez au message de notification <1>personnalisé, ci-dessus.", + "predefined-notification-message": "", "send-test-notification": "Envoyer une notification de test", "title-test-contact-point": "Tester le point de contact" }, @@ -2896,7 +2898,7 @@ }, "threshold-expression-viewer": { "input": "Entrée", - "stop-alerting-when": "Arrêter d’alerter (ou état en attente) lorsque " + "stop-alerting-when": "" }, "time-interval": { "add-time-interval": "Ajouter un intervalle de temps", @@ -3084,7 +3086,7 @@ "title-notification-policies": "Règles de notification" }, "yaml-content-info": { - "body": "Le contenu YAML dans l’éditeur ne contient que la configuration de la règle d’alerte <1>Pour configurer Prometheus, vous devez fournir le reste du <4>contenu du fichier de configuration." + "body": "" } }, "alertlist": { @@ -3160,7 +3162,7 @@ "no-annotations-found": "Aucune annotation trouvée" }, "annotation-list-item": { - "tooltip-created-by": "Créé par :<1> {{email}}" + "tooltip-created-by": "" }, "category-annotation-query": "Requête d’annotation", "category-display": "Affichage", @@ -3198,7 +3200,7 @@ }, "empty-state": { "button-title": "Ajouter une requête d'annotation", - "info-box-content": "<0>Les annotations permettent d'intégrer des données d'événements dans vos graphiques. Elles sont visualisées sous forme de lignes verticales et d'icônes sur tous les panneaux du graphique. Lorsque vous survolez une icône d'annotation, vous pouvez obtenir le texte et les balises de l'événement. Vous pouvez ajouter des événements d'annotation directement depuis Grafana en maintenant CTRL ou CMD + clic sur le graphique (ou en faisant glisser la région). Ces événements seront stockés dans la base de données d'annotations de Grafana.", + "info-box-content": "", "info-box-content-2": "Consultez la <2>documentation sur les annotations pour en savoir plus.", "title": "Aucune requête d'annotation personnalisée n'a encore été ajoutée" }, @@ -3236,7 +3238,7 @@ "auth-settings": "Paramètres d’authentification" }, "auth-drawer-unconneced": { - "subtitle": "Configurez les paramètres d’authentification. Pour en savoir plus, consultez notre <2>documentation." + "subtitle": "" }, "auth-drawer-unconnected": { "advanced-auth": "Authentification avancée", @@ -3270,7 +3272,7 @@ "allowed-organizations-description": "Liste des organisations séparées par des virgules ou des espaces. L’utilisateur doit être membre\nd’au moins une organisation pour se connecter.", "allowed-organizations-label": "Organisations autorisées", "allowed-organizations-placeholder": "Saisissez les organisations (my-team, myteam...) et appuyez sur Entrée pour ajouter", - "api-url-description": "Le point de terminaison des informations utilisateur de votre fournisseur OAuth2. Les informations renvoyées par ce point de terminaison doivent être compatibles avec <2>OpenID UserInfo.", + "api-url-description": "", "api-url-required": "Ce champ doit être une URL valide s’il est défini.", "auth-style-description": "Il détermine comment « {{ clientIDLabel }} » et « {{ clientSecretLabel }} » sont envoyés au fournisseur Oauth2. La valeur par défaut est AutoDetect.", "auth-style-label": "Style d’authentification", @@ -3415,7 +3417,7 @@ } }, "auth-config-auth-config-page-unconnected": { - "subtitle": "Gérez vos paramètres d’authentification et configurez l’authentification unique. Pour en savoir plus, consultez notre <2>documentation." + "subtitle": "" }, "bar-chart": { "warn": { @@ -4133,7 +4135,7 @@ }, "scopes": { "apply-selected-scopes": "Appliquer", - "selected-scopes-label": "Portées : " + "selected-scopes-label": "" }, "search-box": { "placeholder": "Rechercher ou aller à..." @@ -4275,7 +4277,7 @@ "okay": "Ok" }, "not-found-datasource": { - "body": "Vous avez peut-être mal saisi l’URL ou le plugin avec l’identifiant <1> n’est pas disponible.<3>Pour afficher la liste des sources de données disponibles, veuillez <5>cliquer ici." + "body": "" }, "oss": { "connections-home-page": { @@ -4318,8 +4320,8 @@ "versionHistory": { "comparison": { "header": { - "hide-json-diff": "Masquer JSON diff ", - "show-json-diff": "Afficher JSON diff ", + "hide-json-diff": "", + "show-json-diff": "", "text": "Version {{version}} mise à jour par {{createdBy}} ({{ageString}}) {{message}}" }, "select": "Sélectionnez deux versions pour commencer la comparaison" @@ -4346,7 +4348,7 @@ "label-label": "Étiquette", "label-placeholder": "par exemple les traces Tempo", "label-required": "Ce champ est obligatoire.", - "sub-text": "<0>Définissez le texte qui décrira la corrélation.", + "sub-text": "", "title": "Définir l'étiquette de corrélation (étape 1 sur 3)" }, "configure-correlation-target-form": { @@ -4390,7 +4392,7 @@ }, "source-form": { "control-required": "Ce champ est obligatoire.", - "description": "Un point de données doit fournir des valeurs à toutes les variables sous forme de champs ou de sorties de transformation pour que le bouton de corrélation apparaisse dans la visualisation.<1>Remarque : il n'est pas nécessaire de définir explicitement toutes les variables ci-dessous. Une transformation telle que <4>logfmt créera des variables pour chaque paire clé/valeur.", + "description": "", "description-external-pre": "Vous avez utilisé les variables suivantes dans l'URL cible :", "description-query-pre": "Vous avez utilisé les variables suivantes dans la requête cible :", "external-title": "Configurer la source de données qui utilisera l'URL (étape 3 sur 3)", @@ -4402,12 +4404,12 @@ "results-required": "Ce champ est obligatoire.", "source-description": "Les résultats de la source de données source sélectionnée ont des liens affichés dans le panneau", "source-label": "Source", - "sub-text": "<0>Définissez quelle source de données affichera la corrélation et quelles données remplaceront les variables précédemment définies." + "sub-text": "" }, "sub-title": "Définissez comment les données issues de différentes sources se relient entre elles. Pour en savoir plus, consultez la <2>documentation", "target-form": { "control-rules": "Ce champ est obligatoire.", - "sub-text": "<0>Définissez l'objet de la corrélation. Avec le type requête, une requête sera exécutée lorsque vous cliquerez sur la corrélation. Avec le type externe, un clic sur la corrélation ouvrira une URL.", + "sub-text": "", "target-description-external": "Spécifiez l'URL qui s'ouvrira lorsque vous cliquerez sur le lien", "target-description-query": "Spécifiez quelle source de données est requêtée lorsque vous cliquez sur le lien", "target-label": "Cible", @@ -4614,7 +4616,7 @@ } }, "confirm-plugin-dashboard-save-modal": { - "body-plugin-dashboard": "Vos modifications seront perdues lorsque vous mettrez à jour le plugin.<1><2>Utilisez <1>Enregistrer sous pour créer une version personnalisée.", + "body-plugin-dashboard": "", "cancel": "Annuler", "overwrite": "Écraser", "title-plugin-dashboard": "Tableau de bord du plugin" @@ -4831,7 +4833,7 @@ "add-visualization-body": "Sélectionnez une source de données, puis examinez et visualisez vos données avec des graphiques, des statistiques et des tableaux ou créez des listes, des markdowns et d'autres widgets.", "add-visualization-button": "Ajouter une visualisation", "add-visualization-header": "Commencez votre nouveau tableau de bord en ajoutant une visualisation", - "import-a-dashboard-body": "Importez des tableaux de bord à partir de fichiers ou du site <2>grafana.com.", + "import-a-dashboard-body": "", "import-a-dashboard-header": "Importer un tableau de bord", "import-dashboard-button": "Importer un tableau de bord", "show-less-dashboards": "", @@ -5289,8 +5291,8 @@ "title-provisioned": "Tableau de bord provisionné" }, "save-dashboard-error-proxy": { - "body-name-exists": "Un tableau de bord du même nom existe déjà dans le dossier sélectionné.<1><2>Voulez-vous vraiment enregistrer ce tableau de bord ?", - "body-version-mismatch": "Quelqu’un d’autre a mis à jour ce tableau de bord<1><2>Voulez-vous vraiment enregistrer ce tableau de bord ?", + "body-name-exists": "", + "body-version-mismatch": "", "confirmText-save-and-overwrite": "Enregistrer et écraser", "title-name-exists": "Conflits", "title-version-mismatch": "Conflits" @@ -5308,7 +5310,7 @@ "cancel": "Annuler", "cannot-be-saved": "Ce tableau de bord ne peut pas être enregistré à partir de l’interface utilisateur Grafana, car il a été mis en service à partir d’une autre source. Copiez le JSON ou enregistrez-le dans un fichier ci-dessous, puis vous pourrez mettre à jour votre tableau de bord dans la source de mise en service.", "copy-json-to-clipboard": "Copier JSON dans le presse-papiers", - "file-path": "<0>Chemin du fichier : {{filePath}}", + "file-path": "", "save-json-to-file": "Enregistrer le fichier JSON", "see-docs": "Consultez la <2>documentation pour en savoir plus sur la mise en service." }, @@ -5507,7 +5509,7 @@ "transformation-picker": { "info": "Les transformations vous permettent de joindre, calculer, réorganiser, masquer et renommer les résultats de votre requête avant qu’ils ne soient visualisés.", "info-graph-not-suitable": "De nombreuses transformations ne conviennent pas si vous utilisez la visualisation Graphique, car elle ne prend actuellement en charge que les données de séries chronologiques.", - "info-switch-to-table": "Il peut être utile de passer à la visualisation tabulaire pour comprendre ce que fait une transformation. ", + "info-switch-to-table": "", "placeholder-search-for-transformation": "Rechercher une transformation", "read-more": "En savoir plus", "title-transformations": "Transformations" @@ -5573,8 +5575,8 @@ "version-history-comparison": { "button-restore": "Restaurer la version {{version}}", "label-view-json-diff": "Afficher les différences du JSON", - "new-updated-by": "<0>Version {{version}} mise à jour par {{editor}} {{timeAgo}}", - "old-updated-by": "<0>Version {{version}} mise à jour par {{editor}} {{timeAgo}}" + "new-updated-by": "", + "old-updated-by": "" }, "version-history-table": { "aria-label-toggle-selection": "Basculer la sélection de la version {{version}}", @@ -5974,7 +5976,7 @@ "cancel": "Annuler" }, "render-save-button-and-error": { - "body-plugin-dashboard": "Vos modifications seront perdues lorsque vous mettrez à jour le plugin. Utilisez <1>Enregistrer sous pour créer une version personnalisée.", + "body-plugin-dashboard": "", "title-failed-to-save-dashboard": "Échec de l’enregistrement du tableau de bord", "title-plugin-dashboard": "Tableau de bord du plugin", "title-someone-else-has-updated-this-dashboard": "Quelqu’un d’autre a mis à jour ce tableau de bord", @@ -5983,7 +5985,7 @@ "save-and-overwrite": "« Enregistrer et écraser »" }, "library-viz-panel-info": { - "last-edited": "{{timeAgo}} par ", + "last-edited": "", "usage-count_one": "Utilisé sur {{count}} tableaux de bord", "usage-count_other": "Utilisé sur {{count}} tableaux de bord" }, @@ -6044,7 +6046,7 @@ }, "panel-data-queries-tab-rendered": { "add-query": "Ajouter une requête", - "expression": "Expression " + "expression": "" }, "panel-data-transformations-tab": { "tab-label": "Transformations" @@ -6102,7 +6104,7 @@ "query": "Requête" }, "query-variable-editor-form": { - "description-examples": "Les groupes de capture nommés peuvent être utilisés pour séparer le texte d’affichage et la valeur (<1>voir les exemples).", + "description-examples": "", "description-optional": "Facultatif, si vous souhaitez extraire une partie d’un nom de série ou d’un segment de nœud de métrique.", "label-data-source": "Source de données", "label-static-options-sort": "Tri des options statiques", @@ -6163,7 +6165,7 @@ "label-message": "Message", "placeholder-describe-changes-optional": "Ajoutez une note pour décrire vos modifications (facultatif).", "render-footer": { - "body-plugin-dashboard": "Vos modifications seront perdues lorsque vous mettrez à jour le plugin. Utilisez <1>Enregistrer sous pour créer une version personnalisée.", + "body-plugin-dashboard": "", "no-changes-to-save": "Aucun changement à enregistrer", "title-failed-to-save-dashboard": "Échec de l’enregistrement du tableau de bord", "title-plugin-dashboard": "Tableau de bord du plugin", @@ -6199,7 +6201,7 @@ "cancel": "Annuler", "cannot-be-saved": "Ce tableau de bord ne peut pas être enregistré à partir de l’interface utilisateur Grafana, car il a été mis en service à partir d’une autre source. Copiez le JSON ou enregistrez-le dans un fichier ci-dessous, puis vous pourrez mettre à jour votre tableau de bord dans la source de mise en service.", "copy-json-to-clipboard": "Copier JSON dans le presse-papiers", - "file-path": "<0>Chemin du fichier : {{filePath}}", + "file-path": "", "label-description": "Description", "label-target-folder": "Dossier cible", "label-title": "Titre", @@ -6368,8 +6370,8 @@ }, "version-history-comparison": { "label-view-json-diff": "Afficher les différences du JSON", - "new-version-updated": "<0>Version {{version}} mise à jour par {{editor}} {{timeAgo}}", - "old-version-updated": "<0>Version {{version}} mise à jour par {{editor}} {{timeAgo}}" + "new-version-updated": "", + "old-version-updated": "" }, "version-history-header": { "compare-versions": "Comparaison {{baseVersion}} <3> {{newVersion}}", @@ -6447,7 +6449,7 @@ "provisioned-delete-modal": { "confirm-button": "OK", "text-1": "Ce tableau de bord est géré par la mise en service Grafana et ne peut pas être supprimé. Supprimez le tableau de bord du fichier de configuration pour le supprimer.", - "text-2": "Consultez la documentation de Grafana pour en savoir plus sur la mise en service. ", + "text-2": "", "text-3": "Chemin du fichier : {{provisionedId}}", "text-link": "Aller à la page des documents", "title": "Impossible de supprimer le tableau de bord mis en service" @@ -6525,7 +6527,7 @@ }, "data-source-testing-status-page": { "error-more-details-link": "Cliquez <2>ici pour en savoir plus sur cette erreur.", - "success-more-details-links": "Ensuite, vous pouvez commencer à visualiser les données en <2>créant un tableau de bord ou en interrogeant les données dans la <5>vue Explorer." + "success-more-details-links": "" }, "data-sources": { "datasource-add-button": { @@ -6621,7 +6623,7 @@ "test": "Test" }, "cloud-info-box": { - "body-alert": "Ou simplifiez-vous la tâche et obtenez {{mainDS}} (et {{extraDS}}) sous forme de sources de données entièrement gérées, évolutives et hébergées par Grafana Labs avec le <6>plan Grafana Cloud gratuit à vie.", + "body-alert": "", "title-alert": "Configurer la source de données {{mainDS}} ci-dessous" }, "dashboards-table": { @@ -6749,18 +6751,18 @@ "no-events-yet": "Pas encore d’événements" }, "render-info-viewer": { - "data-counter": "Données : {{numDataChanges}} ", + "data-counter": "", "elapsed-time": "Temps : {{elapsed}} ms", "field": "Champ", "last": "Dernier", - "render-counter": "Rendu : {{numRenders}} ", - "schema-counter": "Schéma : {{numSchemaChanges}} ", + "render-counter": "", + "schema-counter": "", "title-reset-counters": "Réinitialiser les compteurs", "tooltip-step-back": "Étape précédente", "type": "Type" }, "state-view": { - "current-value": "Valeur actuelle : {{currentValue}} ", + "current-value": "", "label-state-name": "Nom de l’état" } }, @@ -7207,7 +7209,7 @@ }, "footer": { "learn-more": "En savoir plus", - "pro-tip-define-sources-through-configuration-files": " Conseil de pro : vous pouvez également définir des sources de données via des fichiers de configuration. " + "pro-tip-define-sources-through-configuration-files": "" } }, "pane": { @@ -7269,8 +7271,6 @@ "query-deleted": "Requête supprimée" }, "rich-history-queries-tab": { - "displaying-partial-queries": "Affichage de {{ count }} requêtes", - "displaying-queries": "{{ count }} requêtes", "filter-aria-label": "Filtrer les requêtes pour la ou les sources de données", "filter-history": "Filtrer l'historique", "filter-placeholder": "Filtrer les requêtes pour la ou les sources de données", @@ -7280,7 +7280,11 @@ "search-placeholder": "Rechercher des requêtes", "showing-queries": "Affichage de {{ shown }} sur {{ total }} <0>Charger plus", "sort-aria-label": "Trier les requêtes", - "sort-placeholder": "Trier les requêtes par" + "sort-placeholder": "Trier les requêtes par", + "displaying-partial-queries_one": "", + "displaying-partial-queries_other": "", + "displaying-queries_one": "", + "displaying-queries_other": "" }, "rich-history-settings-tab": { "alert-info": "Grafana gardera les entrées jusqu'à {{optionLabel}}. Les entrées en favori ne seront pas supprimées.", @@ -7472,7 +7476,7 @@ "copy-shortened-link-menu": "Ouvrir les options de lien de copie", "refresh-picker-cancel": "Annuler", "refresh-picker-run": "Exécuter la requête", - "split-close": " Fermer ", + "split-close": "Fermer", "split-close-tooltip": "Fermer le panneau scindé", "split-narrow": "Panneau étroit", "split-title": "Scinder", @@ -7602,8 +7606,8 @@ }, "math": { "available-math-functions": "Fonctions mathématiques disponibles", - "run-math-operations": "Exécute des opérations mathématiques sur une ou plusieurs requêtes. Vous référencez la requête par {{refExample}} ; c.-à-d. {{ref1}}, {{ref2}}, {{ref3}}, etc.<10>Exemple : <12>{{example}}", - "tooltip-footer": "Consultez notre documentation supplémentaire sur les <2>expressions mathématiques.", + "run-math-operations": "", + "tooltip-footer": "", "tooltip-title": "Opérateur mathématique", "tooltip-trigger": "Expression" }, @@ -8642,7 +8646,7 @@ }, "data-source-http-settings": { "access-help": "Aide <1>", - "access-help-details": "Le mode d'accès contrôle la façon dont les requêtes à la source de données seront traitées.<1> <1>Serveur doit être la méthode privilégiée si rien d'autre n'est indiqué.", + "access-help-details": "", "access-help-title": "Aide d'accès", "access-label": "Accès", "allowed-cookies": "Cookies autorisés", @@ -8910,7 +8914,7 @@ "cell-inspect": "Inspecter la valeur", "cell-inspect-tooltip": "Inspecter la valeur", "copy": "Copier dans le presse-papier", - "csv-counts": "Lignes :{{rows}}, Colonnes :{{columns}} <5>", + "csv-counts": "", "csv-placeholder": "Saisir le CSV ici…", "filter-placeholder": "Filtrer les valeurs", "filter-popup-apply": "Ok", @@ -9195,7 +9199,6 @@ "name-line-width": "Épaisseur de ligne", "name-stacking": "Empilement" }, - "inline-token-warning-badge-tooltip": "", "inspector": { "inspect-data-tab": { "loading": "Chargement en cours", @@ -9359,7 +9362,7 @@ "error-fetching": "Erreur lors de la récupération des paramètres LDAP", "error-saving": "Erreur lors de l'enregistrement des paramètres LDAP", "error-validate-form": "Erreur lors de la validation des paramètres LDAP", - "feature-flag-disabled": "Cette page est uniquement accessible en activant le marqueur de fonctionnalité <1>ssoSettingsLDAP.", + "feature-flag-disabled": "", "saved": "Paramètres LDAP enregistrés" }, "bind-dn": { @@ -9400,7 +9403,7 @@ "label": "Rechercher dans la base DNS", "placeholder": "exemple : dc=grafana,dc=org" }, - "subtitle": "L'intégration LDAP dans Grafana permet à vos utilisateurs Grafana de se connecter avec leurs identifiants LDAP. Pour en savoir plus, consultez notre <2><0>documentation.", + "subtitle": "", "title": "Paramètres de base" }, "library-panel": { @@ -9444,7 +9447,7 @@ "dashboard-name": "Nom du tableau de bord" }, "library-panel-info": { - "last-edited": "Dernière modification le {{timeAgo}} par ", + "last-edited": "", "usage-count_one": "Utilisé sur {{count}} tableaux de bord", "usage-count_other": "Utilisé sur {{count}} tableaux de bord" }, @@ -9749,7 +9752,7 @@ "tooltip-unpin-line": "Désépingler la ligne" }, "log-row-message": { - "ellipsis": "… ", + "ellipsis": "", "more": "plus", "see-details": "Voir les détails du journal", "tooltip-error": "Erreur : {{errorMessage}}" @@ -10145,7 +10148,7 @@ }, "resource-table": { "dashboard-load-error": "Impossible de charger le tableau de bord", - "error-library-element-sub": "Élément de bibliothèque {uid}", + "error-library-element-sub": "", "error-library-element-title": "Impossible de charger l'élément de bibliothèque", "unknown-datasource-title": "Source de données {{datasourceUID}}", "unknown-datasource-type": "Source de données inconnue" @@ -10793,10 +10796,10 @@ "placeholder-optional": "(facultatif)", "role": "Rôle", "submit": "Envoyer", - "tooltip": "Vous pouvez maintenant sélectionner l'option « Aucun rôle de base » et ajouter des autorisations à vos besoins personnalisés. Vous trouverez plus d'informations dans <1>notre documentation." + "tooltip": "" }, "user-invite-page": { - "sub-title": "Envoyez une invitation ou ajoutez un utilisateur Grafana existant à l’organisation.<1>{{orgName}}", + "sub-title": "", "text": { "invite-user": "Inviter un utilisateur" } @@ -10885,7 +10888,7 @@ "switch-to-table": "Affichage tabulaire" }, "panel-plugin-error": { - "text-load-error": "Consultez les journaux de démarrage du serveur pour en savoir plus. <1>Si ce plugin a été chargé à partir de Git, assurez-vous qu’il a été compilé.", + "text-load-error": "", "title-load-error": "Erreur lors du chargement : {{panelId}}", "title-not-found": "Plugin de panneau introuvable : {{id}}" }, @@ -11079,7 +11082,7 @@ }, "details": { "connections-tab": { - "description": "Les sources de données suivantes sont actuellement configurées pour {{pluginName}} ; cliquez sur une tuile pour afficher les détails de la configuration. Vous trouverez toutes vos connexions de sources de données dans <4><0>Connexions - <3>Sources de données." + "description": "" }, "disabled-error": { "angular-deprecation-link": "En savoir plus sur la dépréciation Angular", @@ -11096,7 +11099,7 @@ }, "labels": { "contactGrafanaLabs": "Contacter Grafana Labs", - "customLinks": "Liens personnalisés ", + "customLinks": "", "customLinksTooltip": "Ces liens sont fournis par le développeur du plugin pour offrir des ressources et des informations supplémentaires spécifiques au développeur", "dependencies": "Dépendances", "documentation": "Documentation", @@ -11107,7 +11110,7 @@ "latestVersion": "Dernière version", "license": "Licence", "raiseAnIssue": "Signaler un problème", - "reportAbuse": "Signaler une préoccupation ", + "reportAbuse": "", "reportAbuseTooltip": "Signalez les problèmes liés à des plugins malveillants ou nuisibles directement à Grafana Labs.", "repository": "Référentiel", "signature": "Signature", @@ -11117,8 +11120,8 @@ "modal": { "cancel": "Annuler", "copyEmail": "Copier l'adresse e-mail", - "description": "Cette fonctionnalité sert à signaler les comportements malveillants ou nuisibles dans les plugins. Pour toute question concernant les plugins, envoyez-nous un e-mail à l'adresse suivante : ", - "node": "Remarque : pour les problèmes généraux liés aux plugins, tels que les bugs ou les demandes de fonctionnalités, veuillez contacter l'auteur du plugin en utilisant les liens fournis. ", + "description": "", + "node": "", "title": "Signaler un problème de plugin" } }, @@ -11186,7 +11189,7 @@ "message": "Tous les plugins sont à jour" }, "not-found-plugin": { - "body-plugin-not-found": "Ce plugin est introuvable. Veuillez vérifier que l’URL est correcte ou <1>accédez au <3>catalogue de plugins.", + "body-plugin-not-found": "", "title-plugin-not-found": "Plugin introuvable" }, "plugin-actions": { @@ -11650,7 +11653,6 @@ "unsupported-repository-type": "" }, "inline-secure-values-warning": "", - "inline-token-warning-badge-text": "", "job-status": { "label-view-details": "Afficher les détails", "loading-finished-job": "Chargement de mission terminée…", @@ -11827,6 +11829,17 @@ "label-current-step": "Étape actuelle", "label-pending-step": "Étape en attente" }, + "status-badge": { + "automatic-pulling-disabled": "", + "deleting": "", + "error": "", + "pending": "", + "pulling": "", + "unknown": "", + "up-to-date": "", + "waiting-for-health-check": "", + "warning": "" + }, "success-title-default": "Succès", "sync-job": { "error-no-job-id": "Échec du démarrage de la tâche", @@ -12004,7 +12017,7 @@ "annotations-show-text": "Annotations = montrer", "time-range-picker-disabled-text": "Sélecteur de plage de temps = désactivé", "time-range-picker-enabled-text": "Sélecteur de plage de temps = activé", - "time-range-text": "Plage de temps = " + "time-range-text": "" }, "share": { "success-delete": "Votre tableau de bord n'est plus partageable" @@ -12043,7 +12056,7 @@ "revoke-user-access-modal-desc-line1": "Souhaitez-vous vraiment retirer l'accès pour {{email}} ?" }, "delete-user-shared-dashboards-modal": { - "revoke-user-access-modal-desc-line2": "Cette action révoquera immédiatement l'accès de {{email}}'s à tous les tableaux de bord partagés." + "revoke-user-access-modal-desc-line2": "" }, "modal": { "shared-dashboard-modal-title": "Tableaux de bord partagés" @@ -12212,7 +12225,7 @@ }, "menu": { "clear-button": "Tout effacer", - "tooltip": "Vous pouvez maintenant sélectionner l'option « Aucun rôle de base » et ajouter des autorisations à vos besoins personnalisés. Vous trouverez plus d'informations dans <1>notre documentation." + "tooltip": "" }, "menu-aria-label": "Menu du sélecteur de rôle", "menu-group-option-aria-label": "Option du sélecteur de rôle", @@ -12222,7 +12235,7 @@ }, "sub-menu-aria-label": "Sous-menu du sélecteur de rôle", "title": { - "description": "Attribuez des rôles aux utilisateurs pour assurer un contrôle granulaire sur l'accès aux fonctionnalités et aux ressources de Grafana. Pour en savoir plus, consultez notre <2>documentation." + "description": "" } }, "role-picker-drawer": { @@ -12345,7 +12358,7 @@ }, "select": { "select-menu": { - "selected-count": "Sélectionné " + "selected-count": "" } }, "service-account-create-page": { @@ -12444,6 +12457,7 @@ "aria-label-role": "Rôle" }, "service-account-tokens-table": { + "aria-label-delete-button": "", "created": "Créé", "expires": "Expire", "last-used-at": "Dernière utilisation le", @@ -12531,7 +12545,7 @@ "info-text": "Créez un lien direct vers ce tableau de bord ou ce panneau, personnalisé avec les options ci-dessous.", "link-url": "Lien URL", "render-alert": "Plugin de rendu d'image non installé", - "render-instructions": "Pour afficher une image, vous devez installer le <2>plugin de rendu d’images Grafana. Veuillez contacter votre administrateur Grafana pour installer le plugin.", + "render-instructions": "", "rendered-image": "Lien direct vers l'image dont il faut améliorer le rendu", "save-alert": "Le tableau de bord n'est pas enregistré", "save-dashboard": "Pour améliorer le rendu d'une image de panneau, vous devez d'abord enregistrer le tableau de bord.", @@ -12555,7 +12569,7 @@ "info-text-1": "Un instantané est un moyen instantané de partager publiquement un tableau de bord interactif. Lors de la création, nous supprimons les données sensibles telles que les requêtes (métrique, modèle et annotation) et les liens du panneau, pour ne laisser que les métriques visibles et les noms de séries intégrés dans votre tableau de bord.", "info-text-2": "N'oubliez pas que votre instantané <1>peut être consulté par une personne qui dispose du lien et qui peut accéder à l'URL. Partagez judicieusement.", "local-button": "Publier un instantané", - "mistake-message": "Avez-vous commis une erreur ? ", + "mistake-message": "", "name": "Nom de l'instantané", "timeout": "Délai d’expiration (secondes)", "timeout-description": "Vous devrez peut-être configurer la valeur du délai d'expiration si la collecte des métriques de votre tableau de bord prend beaucoup de temps.", @@ -13167,7 +13181,7 @@ "forwards-time-aria-label": "Avancer la plage de temps", "to": "à", "zoom-out-button": "Dézoomer la plage de temps", - "zoom-out-tooltip": "Dézoomer la plage de temps <1> CTRL+Z" + "zoom-out-tooltip": "" }, "time-range": { "apply": "Appliquer la plage temporelle", @@ -13292,7 +13306,7 @@ }, "transformations": { "empty": { - "add-transformation-body": "Les transformations permettent de modifier les données de différentes manières avant l'affichage de votre visualisation.<1>Vous pouvez notamment rassembler des données, renommer des champs, faire des calculs, formater les données à afficher, etc.", + "add-transformation-body": "", "add-transformation-header": "Commencer la transformation des données" } }, @@ -13559,7 +13573,7 @@ "label-format": "Format", "label-set-timezone": "Définir le fuseau horaire", "label-time-field": "Champ horaire", - "tooltip-format": "Le format de sortie pour le champ spécifié en tant que <2>chaîne de format Moment.js.", + "tooltip-format": "", "tooltip-timezone-manually": "Définir manuellement le fuseau horaire de la date" }, "format-time-transformer-editor": { @@ -14154,8 +14168,8 @@ "message": "Aucun utilisateur trouvé" }, "token-revoked-modal": { - "auto-revoked": "Votre jeton de session a été automatiquement révoqué, car vous avez atteint <2>le nombre maximum de {{numSessions}} sessions simultanées pour votre compte.", - "resume-message": "<0>Pour reprendre votre session, reconnectez-vous.Contactez votre administrateur ou consultez la page de licence pour vérifier votre quota si vous êtes déconnecté automatiquement à plusieurs reprises.", + "auto-revoked": "", + "resume-message": "", "sign-in": "Se connecter", "title-you-have-been-automatically-signed-out": "Vous avez été automatiquement déconnecté" }, diff --git a/public/locales/hu-HU/grafana.json b/public/locales/hu-HU/grafana.json index 967656853b4..4ab9bcb1678 100644 --- a/public/locales/hu-HU/grafana.json +++ b/public/locales/hu-HU/grafana.json @@ -108,7 +108,7 @@ "dismiss": "Elvetés", "heading": "Vállalati hitelesítés", "learn-more-link": "További információk", - "text": "Kezelje automatikusan a felhasználókat, a csapatokat és az engedélyeket a Grafana Cloud és az Enterprise szolgáltatásban elérhető <1>SAML, <3>SCIM, <6>LDAP és <8>RBAC segítségével." + "text": "" }, "feature-listing": { "title-auditing": "Auditálás", @@ -209,7 +209,7 @@ "title-delete": "Törlés" }, "orgs": { - "delete-body": "Biztosan törli a következőt: „{{deleteOrgName}}”?<3> <5>A szervezet összes irányítópultja el lesz távolítva.", + "delete-body": "", "id-header": "Azonosító", "name-header": "Név", "new-org-button": "Új szervezet" @@ -719,6 +719,7 @@ "title-annotations": "Jegyzetek" }, "link-dashboard-and-panel": "Irányítópult és panel összekapcsolása", + "placeholder-value-input": "", "placeholder-value-input-default": "Adja meg az egyéni jegyzet tartalmát…" }, "bulk-actions": { @@ -1144,7 +1145,7 @@ "title-something-wrong-trying-fetch-group-details": "Valami hiba történt a csoport részleteinek lekérése során" }, "evaluation-interval-limit-exceeded": { - "body-minimum-interval": "A Grafanában egy minimális értékelési intervallum van beállítva: <1>{{minInterval}}.<3>Lépjen kapcsolatba a rendszergazdával alacsonyabb intervallum beállításához.", + "body-minimum-interval": "", "title-global-evaluation-interval-limit-exceeded": "Globális értékelési intervallumkorlát túllépve" }, "existing-rule-editor": { @@ -1292,7 +1293,7 @@ "resolved": "Megoldott" } }, - "review-alert-payload": " A hasznos tartalomhoz hozzáadandó riasztási adatok áttekintése:", + "review-alert-payload": "", "title-add-custom-alerts": "Egyéni riasztások hozzáadása" }, "get-alert-suggestions": { @@ -1416,7 +1417,7 @@ "title-add-folder-and-labels": "Mappa és címkék hozzáadása" }, "grafana-managed-rule-type": { - "description": "Több, bármilyen típusú adatforrást támogat.<1>Adatok átalakítása kifejezésekkel." + "description": "" }, "grafana-modify-export": { "body-invalid-rule-id": "Érvénytelen szabály-UID az oldal URL-címében. Ellenőrizze az URL-t, és próbálkozzon újra.", @@ -1853,7 +1854,7 @@ "aria-label-new": "új" }, "mimir-flavored-type": { - "description": "Használjon Mimir-, Loki- vagy Cortex-adatforrást.<1>A kifejezések nem támogatottak." + "description": "" }, "min-interval-option": { "label-interval": "Intervallum", @@ -2082,7 +2083,7 @@ "warning-1": "Az értesítési házirendet a törlésével véglegesen eltávolítja.", "warning-2": "Biztosan törli ezt a házirendet?" }, - "filter-description": "Az értesítési házirendek szűrése az egyezések vesszővel elválasztott listájának használatával, pl.:<1>súlyosság=kritikus, régió=EMEA", + "filter-description": "", "generated-policies": "Automatikusan generált házirendek", "matchers": "Egyezések", "metadata": { @@ -2126,7 +2127,8 @@ "conflict": "Az értesítési házirendfáját egy másik felhasználó frissítette.", "error-code": "Hibaüzenet: „{{error}}”", "routes": { - "conflictingMatchers": "Nem lehet útvonalat hozzáadni vagy frissíteni: az illesztések ütköznek egy külső útválasztási fával, ha a(z) {{-matchers}} illesztéseket egyesítjük. Ez az útvonal elérhetetlenné válna." + "conflictingMatchers": "Nem lehet útvonalat hozzáadni vagy frissíteni: az illesztések ütköznek egy külső útválasztási fával, ha a(z) {{-matchers}} illesztéseket egyesítjük. Ez az útvonal elérhetetlenné válna.", + "unknownMatchers": "" }, "suffix": "Kérjük, frissítse az oldalt, és próbálkozzon újra.", "title": "Nem sikerült értesítési szabályzatot hozzáadni vagy frissíteni" @@ -2244,7 +2246,7 @@ "error-no-query-editor": "Nem sikerült betölteni a lekérdezésszerkesztőt a következők miatt: {{errorMessage}}" }, "recording-rule-type": { - "description": "Kifejezések előzetes kiszámítása.<1>Riasztási szabállyal kell kombinálni." + "description": "" }, "recording-rules": { "description-target-data-source": "A felvételi szabályok tárolására szolgáló Prometheus-adatforrás", @@ -2257,7 +2259,7 @@ }, "redirect-to-clone-rule": { "body-evaluation-group": "A másolt szabályhoz új értékelési csoportot kell beállítania, mert az eredeti ki van építve, és nem használható a felhasználói felületen létrehozott szabályokhoz.", - "body-not-provisioned": "Az új szabály <1>nem lesz kiépített szabályként megjelölve.", + "body-not-provisioned": "", "confirmText-copy": "Másolás", "title-copy-provisioned-alert-rule": "Kiépített riasztási szabály másolása" }, @@ -2292,13 +2294,13 @@ "routing-settings": { "aria-label-group-by": "Csoportosítási szempont", "description-group-by": "Ötvözhet több riasztást egyetlen értesítésben, azonos címkeértékek szerint csoportosítva őket. Ha üres, akkor az alapértelmezett értesítési házirendből öröklődik.", - "group-interval": "Csoportintervallum: <1>{{groupIntervalValue}}", - "group-wait": "Csoportvárakozás: <1>{{groupWaitValue}}", - "grouping": "Csoportosítás: <1>{{fields}}", + "group-interval": "", + "group-wait": "", + "grouping": "", "label-group-by": "Csoportosítási szempont", "label-override-grouping": "Csoportosítás felülbírálása", "label-override-timings": "Felülbírálási időzítések", - "repeat-interval": "Ismétlési időköz: <1>{{repeatIntervalValue}}" + "repeat-interval": "" }, "rule-actions-buttons": { "title-edit": "Szerkesztés", @@ -2554,7 +2556,7 @@ "relative-with-to": "" }, "rule-type-picker": { - "grafana-managed": "Válassza a „Grafana által felügyelt” lehetőséget, kivéve, ha Mimir-, Loki- vagy Cortex-adatforrása van engedélyezett Ruler API-val." + "grafana-managed": "" }, "rule-view": { "query": { @@ -2887,7 +2889,7 @@ "test-contact-point-modal": { "custom-notification-message": "Az alábbiakban meghatározott jegyzeteket használó tesztértesítést fog küldeni. Ez egy jó lehetőség, ha egyéni sablonokat és üzeneteket használ.", "notification-message": "Értesítési üzenet", - "predefined-notification-message": "Előre meghatározott riasztást használó tesztértesítést fog küldeni. Ha egyéni sablont vagy üzenetet határozott meg, a jobb eredmény érdekében váltson a fenti <1>egyéni értesítési üzenetre.", + "predefined-notification-message": "", "send-test-notification": "Tesztértesítés küldése", "title-test-contact-point": "Kapcsolattartási pont tesztelése" }, @@ -2896,7 +2898,7 @@ }, "threshold-expression-viewer": { "input": "Bemenet", - "stop-alerting-when": "Riasztás (vagy függőben lévő állapot) leállítása ekkor: " + "stop-alerting-when": "" }, "time-interval": { "add-time-interval": "Időintervallum hozzáadása", @@ -3084,7 +3086,7 @@ "title-notification-policies": "Értesítési irányelvek" }, "yaml-content-info": { - "body": "A szerkesztő YAML-tartalma csak riasztásiszabály-konfigurációt tartalmaz <1>A Prometheus konfigurálásához meg kell adnia a <4>konfigurációs fájl többi tartalmát." + "body": "" } }, "alertlist": { @@ -3160,7 +3162,7 @@ "no-annotations-found": "Nem található jegyzet" }, "annotation-list-item": { - "tooltip-created-by": "Létrehozta:<1> {{email}}" + "tooltip-created-by": "" }, "category-annotation-query": "Jegyzetlekérdezés", "category-display": "Megjelenítés", @@ -3198,7 +3200,7 @@ }, "empty-state": { "button-title": "Jegyzetlekérdezés hozzáadása", - "info-box-content": "<0>A jegyzetek lehetővé teszik az eseményadatok integrálását a grafikonokba. Ezek függőleges vonalakként és ikonokként jelennek meg minden grafikonpanelen. Ha az egérmutatót egy jegyzetikon fölé viszi, megjelenítheti az esemény szövegét és címkéit. Jegyzeteseményeket közvetlenül a Grafanából adhat hozzá, ha lenyomva tartja a CTRL vagy a CMD billentyűt, és rákattint a grafikonra (vagy áthúzza a régiót). Ezeket a rendszer a Grafana jegyzet-adatbázisában tárolja.", + "info-box-content": "", "info-box-content-2": "További információért tekintse meg a <2>Jegyzetek dokumentációját.", "title": "Még nincsenek hozzáadva egyéni jegyzetlekérdezések" }, @@ -3236,7 +3238,7 @@ "auth-settings": "Hitelesítési beállítások" }, "auth-drawer-unconneced": { - "subtitle": "Hitelesítési beállítások konfigurálása. További információkat a <2>dokumentációnkban talál." + "subtitle": "" }, "auth-drawer-unconnected": { "advanced-auth": "Speciális hitelesítés", @@ -3270,7 +3272,7 @@ "allowed-organizations-description": "Vesszővel vagy szóközzel elválasztott szervezetek listája. A bejelentkezéshez a felhasználónak legalább \negy szervezet tagjának kell lennie.", "allowed-organizations-label": "Engedélyezett szervezetek", "allowed-organizations-placeholder": "Adja meg a szervezeteket (my-team, myteam…), és nyomja le az Enter billentyűt a hozzáadáshoz", - "api-url-description": "Az OAuth2-szolgáltató felhasználói információs végpontja. Az ezen végpont által visszaadott információknak kompatibilisnek kell lenniük az <2>OpenID UserInfóval.", + "api-url-description": "", "api-url-required": "Ennek a mezőnek érvényes URL-címnek kell lennie, ha be van állítva.", "auth-style-description": "Ez határozza meg, hogy a(z) „{{ clientIDLabel }}” és a(z) „{{ clientSecretLabel }}” hogyan lesz elküldve az Oauth2-szolgáltatónak. Az alapértelmezett beállítás az AutoDetect (Automatikus észlelés).", "auth-style-label": "Hitelesítési stílus", @@ -3415,7 +3417,7 @@ } }, "auth-config-auth-config-page-unconnected": { - "subtitle": "Saját hitelesítési beállítások kezelése és az egyszeri bejelentkezés konfigurálása. További információkat a <2>dokumentációnkban talál." + "subtitle": "" }, "bar-chart": { "warn": { @@ -4133,7 +4135,7 @@ }, "scopes": { "apply-selected-scopes": "Alkalmaz", - "selected-scopes-label": "Hatókörök: " + "selected-scopes-label": "" }, "search-box": { "placeholder": "Keresés vagy ugrás ide:" @@ -4275,7 +4277,7 @@ "okay": "Rendben" }, "not-found-datasource": { - "body": "Lehet, hogy elgépelte az URL-címet, vagy a(z) <1> azonosítójú bővítmény nem érhető el.<3>Az elérhető adatforrások listájának megtekintéséhez <5>kattintson ide." + "body": "" }, "oss": { "connections-home-page": { @@ -4318,8 +4320,8 @@ "versionHistory": { "comparison": { "header": { - "hide-json-diff": "JSON-különbség elrejtése ", - "show-json-diff": "JSON-különbség megjelenítése ", + "hide-json-diff": "", + "show-json-diff": "", "text": "A(z) {{version}} verziót frissítette: {{createdBy}} ({{ageString}}) {{message}}" }, "select": "Válasszon ki két verziót az összehasonlítás megkezdéséhez" @@ -4346,7 +4348,7 @@ "label-label": "Címke", "label-placeholder": "pl. Tempo-nyomkövetések", "label-required": "A mező kitöltése kötelező.", - "sub-text": "<0>Határozza meg a korrelációt leíró szöveget.", + "sub-text": "", "title": "Korrelációs címke meghatározása (3/1. lépés)" }, "configure-correlation-target-form": { @@ -4390,7 +4392,7 @@ }, "source-form": { "control-required": "A mező kitöltése kötelező.", - "description": "Az adatpontnak értékeket kell biztosítania minden változóhoz mezőként vagy transzformációs kimenetként, hogy a korreláció gomb megjelenjen a vizualizációban.<1>Megjegyzés: Nem kell minden változót explicit módon definiálni az alábbiakban. Egy olyan transzformáció, mint a <4>logfmt változókat hoz létre minden kulcs/érték párhoz.", + "description": "", "description-external-pre": "A következő változókat használta a cél-URL-ben:", "description-query-pre": "A következő változókat használta a céllekérdezésben:", "external-title": "Az URL-címet használó adatforrás konfigurálása (3/3. lépés)", @@ -4402,12 +4404,12 @@ "results-required": "A mező kitöltése kötelező.", "source-description": "A kijelölt forrásadatforrásból származó eredmények hivatkozásai megjelennek a panelen", "source-label": "Forrás", - "sub-text": "<0>Határozza meg, hogy melyik adatforrás jeleníti meg a korrelációt, és mely adatok helyettesítik a korábban meghatározott változókat." + "sub-text": "" }, "sub-title": "Határozza meg, hogy a különböző adatforrásokban élő adatok hogyan kapcsolódnak egymáshoz. További információ a <2>dokumentációban található", "target-form": { "control-rules": "A mező kitöltése kötelező.", - "sub-text": "<0>Határozza meg, hogy mihez kapcsolódik a korreláció. A lekérdezéstípusnál egy lekérdezés akkor fut le, amikor a korrelációra kattintanak. A külső típusnál a korrelációra kattintva megnyílik egy URL-cím.", + "sub-text": "", "target-description-external": "Adja meg azt az URL-címet, amely akkor nyílik meg, amikor a hivatkozásra kattintanak", "target-description-query": "Adja meg, hogy melyik adatforrást kérdezi le a rendszer, amikor a hivatkozásra kattintanak", "target-label": "Cél", @@ -4614,7 +4616,7 @@ } }, "confirm-plugin-dashboard-save-modal": { - "body-plugin-dashboard": "A módosítások elvesznek a bővítmény frissítésekor.<1><2>Egyéni verzió létrehozásához használja a <1>Mentés másként lehetőséget.", + "body-plugin-dashboard": "", "cancel": "Mégse", "overwrite": "Felülírás", "title-plugin-dashboard": "Bővítmény-irányítópult" @@ -4831,7 +4833,7 @@ "add-visualization-body": "Válasszon ki egy adatforrást, majd kérdezze le és jelenítse meg az adatait diagramokkal, statisztikákkal és táblázatokkal, vagy hozzon létre listákat, Markdown-elemeket és egyéb widgeteket.", "add-visualization-button": "Vizualizáció hozzáadása", "add-visualization-header": "Indítsa el az új irányítópultot vizualizáció hozzáadásával", - "import-a-dashboard-body": "Irányítópultok importálása fájlokból vagy a <2>grafana.com webhelyről.", + "import-a-dashboard-body": "", "import-a-dashboard-header": "Irányítópult importálása", "import-dashboard-button": "Irányítópult importálása", "show-less-dashboards": "", @@ -5289,8 +5291,8 @@ "title-provisioned": "Kiépített irányítópult" }, "save-dashboard-error-proxy": { - "body-name-exists": "Egy irányítópult már létezik ugyanazzal a névvel a kijelölt mappában.<1><2>Biztosan menti ezt az irányítópultot?", - "body-version-mismatch": "Valaki más frissítette ezt az irányítópultot<1><2>Biztosan menti ezt az irányítópultot?", + "body-name-exists": "", + "body-version-mismatch": "", "confirmText-save-and-overwrite": "Mentés és felülírás", "title-name-exists": "Ütközés", "title-version-mismatch": "Ütközés" @@ -5308,7 +5310,7 @@ "cancel": "Mégse", "cannot-be-saved": "Ez az irányítópult nem menthető a Grafana kezelőfelületéből, mert egy másik forrásból van kiépítve. Másolja a JSON-t, vagy mentse fájlba az alábbiakban, majd frissítheti az irányítópultot a kiépítési forrásban.", "copy-json-to-clipboard": "JSON másolása a vágólapra", - "file-path": "<0>Fájl útvonala: {{filePath}}", + "file-path": "", "save-json-to-file": "JSON mentése fájlba", "see-docs": "A kiépítéssel kapcsolatos további információkért tekintse meg a <2>dokumentációt." }, @@ -5507,7 +5509,7 @@ "transformation-picker": { "info": "Az átalakítások lehetővé teszik a lekérdezési eredmények egyesítését, kiszámítását, átrendezését, elrejtését és átnevezését a vizualizációjuk előtt.\n", "info-graph-not-suitable": "Sok átalakítás nem megfelelő, ha a Grafikon vizualizációt használja, mivel az jelenleg csak az idősoros adatokat támogatja.", - "info-switch-to-table": "Segíthet, ha átvált a Táblázat vizualizációra, hogy megértse, mit csinál egy transzformáció. ", + "info-switch-to-table": "", "placeholder-search-for-transformation": "Transzformáció keresése", "read-more": "További információk", "title-transformations": "Transzformációk" @@ -5573,8 +5575,8 @@ "version-history-comparison": { "button-restore": "Visszaállítás erre a verzióra: {{version}}", "label-view-json-diff": "JSON-diff megtekintése", - "new-updated-by": "<0>{{version}} verzió, frissítette: {{editor}}, {{timeAgo}}", - "old-updated-by": "<0>{{version}} verzió, frissítette: {{editor}}, {{timeAgo}}" + "new-updated-by": "", + "old-updated-by": "" }, "version-history-table": { "aria-label-toggle-selection": "Verzió kijelölésének ki- és bekapcsolása: {{version}}", @@ -5974,7 +5976,7 @@ "cancel": "Mégse" }, "render-save-button-and-error": { - "body-plugin-dashboard": "A módosítások elvesznek a bővítmény frissítésekor. Egyéni verzió létrehozásához használja a <1>Mentés másként lehetőséget.", + "body-plugin-dashboard": "", "title-failed-to-save-dashboard": "Az irányítópult mentése sikertelen volt", "title-plugin-dashboard": "Bővítmény-irányítópult", "title-someone-else-has-updated-this-dashboard": "Valaki más frissítette ezt az irányítópultot", @@ -5983,7 +5985,7 @@ "save-and-overwrite": "„Mentés és felülírás”" }, "library-viz-panel-info": { - "last-edited": "{{timeAgo}}, ", + "last-edited": "", "usage-count_one": "{{count}} irányítópulton használatos", "usage-count_other": "{{count}} irányítópulton használatos" }, @@ -6044,7 +6046,7 @@ }, "panel-data-queries-tab-rendered": { "add-query": "Lekérdezés hozzáadása", - "expression": "Kifejezés " + "expression": "" }, "panel-data-transformations-tab": { "tab-label": "Transzformációk" @@ -6102,7 +6104,7 @@ "query": "Lekérdezés" }, "query-variable-editor-form": { - "description-examples": "Az elnevezett rögzítési csoportok felhasználhatók a megjelenített szöveg és érték elválasztására (<1>lásd a példákat).", + "description-examples": "", "description-optional": "Opcionális, ha egy sorozatnév vagy metrikai csomópontszegmens egy részét szeretné kinyerni.", "label-data-source": "Adatforrás", "label-static-options-sort": "Statikus opciók rendezése", @@ -6163,7 +6165,7 @@ "label-message": "Üzenet", "placeholder-describe-changes-optional": "Megjegyzés hozzáadása a módosítások leírásához (nem kötelező).", "render-footer": { - "body-plugin-dashboard": "A módosítások elvesznek a bővítmény frissítésekor. Egyéni verzió létrehozásához használja a <1>Mentés másként lehetőséget.", + "body-plugin-dashboard": "", "no-changes-to-save": "Nincs menthető módosítás", "title-failed-to-save-dashboard": "Az irányítópult mentése sikertelen volt", "title-plugin-dashboard": "Bővítmény-irányítópult", @@ -6199,7 +6201,7 @@ "cancel": "Mégse", "cannot-be-saved": "Ez az irányítópult nem menthető a Grafana kezelőfelületéből, mert egy másik forrásból van kiépítve. Másolja a JSON-t, vagy mentse fájlba az alábbiakban, majd frissítheti az irányítópultot a kiépítési forrásban.", "copy-json-to-clipboard": "JSON másolása a vágólapra", - "file-path": "<0>Fájl útvonala: {{filePath}}", + "file-path": "", "label-description": "Leírás", "label-target-folder": "Célmappa", "label-title": "Cím", @@ -6368,8 +6370,8 @@ }, "version-history-comparison": { "label-view-json-diff": "JSON-diff megtekintése", - "new-version-updated": "<0>{{version}} verzió, frissítette: {{editor}}, {{timeAgo}}", - "old-version-updated": "<0>{{version}} verzió, frissítette: {{editor}}, {{timeAgo}}" + "new-version-updated": "", + "old-version-updated": "" }, "version-history-header": { "compare-versions": "{{baseVersion}} <3> {{newVersion}} összehasonlítása", @@ -6447,7 +6449,7 @@ "provisioned-delete-modal": { "confirm-button": "OK", "text-1": "Ezt az irányítópultot a Grafana-kiépítés kezeli, és nem törölhető. A törléshez távolítsa el az irányítópultot a konfigurációs fájlból.", - "text-2": "A kiépítéssel kapcsolatos további információkért tekintse meg a Grafana dokumentációját. ", + "text-2": "", "text-3": "Fájl elérési útja: {{provisionedId}}", "text-link": "Ugrás a dokumentáció oldalára", "title": "Nem lehet törölni a kiépített irányítópultot" @@ -6525,7 +6527,7 @@ }, "data-source-testing-status-page": { "error-more-details-link": "Ha többet szeretne megtudni erről a hibáról, kattintson <2>ide.", - "success-more-details-links": "Ezután < 2 >létrehozhat egy irányítópultot, vagy lekérdezheti az adatokat az <5>Explore nézetben." + "success-more-details-links": "" }, "data-sources": { "datasource-add-button": { @@ -6621,7 +6623,7 @@ "test": "Teszt" }, "cloud-info-box": { - "body-alert": "Vagy hagyja ki a próbálkozást, és szerezze be a(z) {{mainDS}} adatforrást (és {{extraDS}}) a Grafana Labs teljes körűen felügyelt, skálázható és hosztolt adatforrásait az <6>örökre ingyenes Grafana Cloud-előfizetéssel.", + "body-alert": "", "title-alert": "Konfigurálja {{mainDS}} adatforrását alább" }, "dashboards-table": { @@ -6749,18 +6751,18 @@ "no-events-yet": "Még nincs esemény" }, "render-info-viewer": { - "data-counter": "Adatok: {{numDataChanges}} ", + "data-counter": "", "elapsed-time": "Idő: {{elapsed}} mp.", "field": "Mező", "last": "Legutóbbi", - "render-counter": "Leképzés: {{numRenders}} ", - "schema-counter": "Séma: {{numSchemaChanges}} ", + "render-counter": "", + "schema-counter": "", "title-reset-counters": "Számlálók nullázása", "tooltip-step-back": "Visszalépés", "type": "Típus" }, "state-view": { - "current-value": "Jelenlegi érték: {{currentValue}} ", + "current-value": "", "label-state-name": "Állapot neve" } }, @@ -7207,7 +7209,7 @@ }, "footer": { "learn-more": "További információk", - "pro-tip-define-sources-through-configuration-files": " Tipp: Adatforrásokat konfigurációs fájlokon keresztül is definiálhat. " + "pro-tip-define-sources-through-configuration-files": "" } }, "pane": { @@ -7269,8 +7271,6 @@ "query-deleted": "Lekérdezés törölve" }, "rich-history-queries-tab": { - "displaying-partial-queries": "{{ count }} lekérdezés megjelenítése", - "displaying-queries": "{{ count }} lekérdezés", "filter-aria-label": "Adatforrás(ok)hoz tartozó lekérdezések szűrése", "filter-history": "Szűrési előzmények", "filter-placeholder": "Adatforrás(ok)hoz tartozó lekérdezések szűrése", @@ -7280,7 +7280,11 @@ "search-placeholder": "Lekérdezések keresése", "showing-queries": "{{ total }}/{{ shown }} megjelenítése <0>Továbbiak betöltése", "sort-aria-label": "Lekérdezések rendezése", - "sort-placeholder": "Lekérdezések rendezési módja" + "sort-placeholder": "Lekérdezések rendezési módja", + "displaying-partial-queries_one": "", + "displaying-partial-queries_other": "", + "displaying-queries_one": "", + "displaying-queries_other": "" }, "rich-history-settings-tab": { "alert-info": "A Grafana megőrzi a bejegyzéseket eddig: {{optionLabel}}.A csillagozott bejegyzések nem törlődnek.", @@ -7472,7 +7476,7 @@ "copy-shortened-link-menu": "Hivatkozás másolási beállításainak megnyitása", "refresh-picker-cancel": "Mégse", "refresh-picker-run": "Lekérdezés", - "split-close": " Bezárás ", + "split-close": "", "split-close-tooltip": "Osztott ablaktábla bezárása", "split-narrow": "Keskeny ablaktábla", "split-title": "Osztott", @@ -7602,8 +7606,8 @@ }, "math": { "available-math-functions": "Elérhető matematikai függvények", - "run-math-operations": "Matematikai műveletek futtatása egy vagy több lekérdezésen. A lekérdezésre a következőkkel hivatkozhat: {{refExample}}, azaz {{ref1}}, {{ref2}}, {{ref3}} stb.<10>Példa: <12>{{example}}", - "tooltip-footer": "Lásd a további dokumentációt a <2>matematikai kifejezésekről.", + "run-math-operations": "", + "tooltip-footer": "", "tooltip-title": "Matematikai operátor", "tooltip-trigger": "Kifejezés" }, @@ -8642,7 +8646,7 @@ }, "data-source-http-settings": { "access-help": "Súgó <1>", - "access-help-details": "A hozzáférési mód vezérli az adatforráshoz intézett kérelmek kezelésének módját.Eltérő rendelkezés hiányában a < 1>< 1>kiszolgálónak kell lennie az előnyben részesített módnak.", + "access-help-details": "", "access-help-title": "Hozzáférés a súgóhoz", "access-label": "Hozzáférés", "allowed-cookies": "Engedélyezett cookie-k", @@ -8910,7 +8914,7 @@ "cell-inspect": "Érték ellenőrzése", "cell-inspect-tooltip": "Érték ellenőrzése", "copy": "Másolás a vágólapra", - "csv-counts": "Sorok:{{rows}}, Oszlopok:{{columns}} <5>", + "csv-counts": "", "csv-placeholder": "Itt adja meg a CSV-t...", "filter-placeholder": "Értékek szűrése", "filter-popup-apply": "OK", @@ -9195,7 +9199,6 @@ "name-line-width": "Vonal szélessége", "name-stacking": "Egymásra helyezés" }, - "inline-token-warning-badge-tooltip": "", "inspector": { "inspect-data-tab": { "loading": "Betöltés", @@ -9359,7 +9362,7 @@ "error-fetching": "Hiba történt az LDAP-beállítások lekérése során", "error-saving": "Hiba az LDAP-beállítások mentésekor", "error-validate-form": "Hiba történt az LDAP-beállítások érvényesítése során", - "feature-flag-disabled": "Ez az oldal csak az <1>ssoSettingsLDAP funkciójelző engedélyezésével érhető el.", + "feature-flag-disabled": "", "saved": "LDAP-beállítások mentve" }, "bind-dn": { @@ -9400,7 +9403,7 @@ "label": "Keresési alap DNS", "placeholder": "példa: dc=grafana,dc=org" }, - "subtitle": "A Grafana LDAP-integrációja lehetővé teszi a Grafana-felhasználók számára, hogy LDAP hitelesítő adataikkal jelentkezzenek be. Tudjon meg többet a <2><0>dokumentációnkból.", + "subtitle": "", "title": "Alapbeállítások" }, "library-panel": { @@ -9444,7 +9447,7 @@ "dashboard-name": "Irányítópult neve" }, "library-panel-info": { - "last-edited": "Legutóbbi szerkesztés: {{timeAgo}}, ", + "last-edited": "", "usage-count_one": "{{count}} irányítópulton használatos", "usage-count_other": "{{count}} irányítópulton használatos" }, @@ -9749,7 +9752,7 @@ "tooltip-unpin-line": "Sor rögzítésének feloldása" }, "log-row-message": { - "ellipsis": "… ", + "ellipsis": "", "more": "továbbiak", "see-details": "A napló részleteinek megtekintése", "tooltip-error": "Hiba: {{errorMessage}}" @@ -10145,7 +10148,7 @@ }, "resource-table": { "dashboard-load-error": "Nem lehet betölteni az irányítópultot", - "error-library-element-sub": "Könyvtárelem {uid}", + "error-library-element-sub": "", "error-library-element-title": "Nem lehet betölteni a könyvtárelemet", "unknown-datasource-title": "Adatforrás: {{datasourceUID}}", "unknown-datasource-type": "Ismeretlen adatforrás" @@ -10793,10 +10796,10 @@ "placeholder-optional": "(opcionális)", "role": "Szerepkör", "submit": "Küldés", - "tooltip": "Most kiválaszthatja a „Nincs alapvető szerepkör” opciót, és az egyéni igényeinek megfelelő engedélyeket adhat hozzá. További információt a <1>dokumentációnkban talál." + "tooltip": "" }, "user-invite-page": { - "sub-title": "Meghívó küldése vagy meglévő Grafana-felhasználó hozzáadása a szervezethez.<1>{{orgName}}", + "sub-title": "", "text": { "invite-user": "Felhasználó meghívása" } @@ -10885,7 +10888,7 @@ "switch-to-table": "Váltás táblázatra" }, "panel-plugin-error": { - "text-load-error": "További információért ellenőrizze a kiszolgáló indítási naplóit. <1>Ha ezt a bővítményt a Gitről töltötték be, akkor győződjön meg róla, hogy lefordították.", + "text-load-error": "", "title-load-error": "Hiba történt a(z) {{panelId}} betöltésekor", "title-not-found": "A panelbővítmény nem található: {{id}}" }, @@ -11079,7 +11082,7 @@ }, "details": { "connections-tab": { - "description": "Jelenleg a következő adatforrások vannak konfigurálva ehhez: {{pluginName}}. Kattintson egy csempére a konfiguráció részleteinek megtekintéséhez. Az összes adatforrás-kapcsolatát a <4><0>Kapcsolatok – <3>Adatforrások menüpontban találja." + "description": "" }, "disabled-error": { "angular-deprecation-link": "További információ az Angular kivezetéséről", @@ -11096,7 +11099,7 @@ }, "labels": { "contactGrafanaLabs": "Kapcsolatfelvétel a Grafana Labs vállalattal", - "customLinks": "Egyéni hivatkozások ", + "customLinks": "", "customLinksTooltip": "Ezeket a hivatkozásokat a bővítmény fejlesztője biztosítja, hogy további, fejlesztőspecifikus erőforrásokat és információkat tegyen elérhetővé", "dependencies": "Függőségek", "documentation": "Dokumentáció", @@ -11107,7 +11110,7 @@ "latestVersion": "Legújabb verzió", "license": "Licenc", "raiseAnIssue": "Probléma felvetése", - "reportAbuse": "Probléma bejelentése ", + "reportAbuse": "", "reportAbuseTooltip": "A rosszindulatú vagy kártékony bővítményekkel kapcsolatos problémák jelentése közvetlenül a Grafana Labs vállalatnak.", "repository": "Adattár", "signature": "Aláírás", @@ -11117,8 +11120,8 @@ "modal": { "cancel": "Mégse", "copyEmail": "E-mail-cím másolása", - "description": "Ez a funkció a bővítményeken belüli rosszindulatú vagy kártékony viselkedés jelentésére szolgál. A bővítménnyel kapcsolatos aggályok esetén írjon nekünk e-mailt a következő címre: ", - "node": "Megjegyzés: Általános bővítményproblémák, például hibák vagy funkciókérések esetén vegye fel a kapcsolatot a bővítmény szerzőjével a megadott hivatkozások segítségével. ", + "description": "", + "node": "", "title": "Probléma bejelentése a bővítménnyel kapcsolatban" } }, @@ -11186,7 +11189,7 @@ "message": "Minden bővítmény naprakész" }, "not-found-plugin": { - "body-plugin-not-found": "A bővítmény nem található. Ellenőrizze, hogy helyes-e az URL-cím, vagy <1>lépjen a <3>bővítménykatalógusba.", + "body-plugin-not-found": "", "title-plugin-not-found": "Nem található bővítmény" }, "plugin-actions": { @@ -11650,7 +11653,6 @@ "unsupported-repository-type": "" }, "inline-secure-values-warning": "", - "inline-token-warning-badge-text": "", "job-status": { "label-view-details": "Részletek megtekintése", "loading-finished-job": "Befejezett feladat betöltése…", @@ -11827,6 +11829,17 @@ "label-current-step": "Jelenlegi lépés", "label-pending-step": "Függőben lévő lépés" }, + "status-badge": { + "automatic-pulling-disabled": "", + "deleting": "", + "error": "", + "pending": "", + "pulling": "", + "unknown": "", + "up-to-date": "", + "waiting-for-health-check": "", + "warning": "" + }, "success-title-default": "Sikerült", "sync-job": { "error-no-job-id": "A feladat indítása nem sikerült", @@ -12004,7 +12017,7 @@ "annotations-show-text": "Jegyzetek = megjelenítés", "time-range-picker-disabled-text": "Időtartomány-választó = letiltva", "time-range-picker-enabled-text": "Időtartomány-választó = engedélyezve", - "time-range-text": "Időtartomány = " + "time-range-text": "" }, "share": { "success-delete": "Az irányítópult már nem osztható meg" @@ -12043,7 +12056,7 @@ "revoke-user-access-modal-desc-line1": "Biztosan visszavonja {{email}} hozzáférését?" }, "delete-user-shared-dashboards-modal": { - "revoke-user-access-modal-desc-line2": "Ez a művelet azonnal visszavonja {{email}} hozzáférését az összes megosztott irányítópulthoz." + "revoke-user-access-modal-desc-line2": "" }, "modal": { "shared-dashboard-modal-title": "Megosztott irányítópultok" @@ -12212,7 +12225,7 @@ }, "menu": { "clear-button": "Összes törlése", - "tooltip": "Most kiválaszthatja a „Nincs alapvető szerepkör” opciót, és az egyéni igényeinek megfelelő engedélyeket adhat hozzá. További információt a <1>dokumentációnkban talál." + "tooltip": "" }, "menu-aria-label": "Szerepkörválasztó menü", "menu-group-option-aria-label": "Szerepkörválasztási beállítás", @@ -12222,7 +12235,7 @@ }, "sub-menu-aria-label": "Szerepkörválasztó almenü", "title": { - "description": "Rendeljen szerepköröket a felhasználókhoz, hogy biztosítsa a Grafana funkcióihoz és erőforrásaihoz való hozzáférés részletes ellenőrzését. További információkat a <2>dokumentációnkban talál." + "description": "" } }, "role-picker-drawer": { @@ -12345,7 +12358,7 @@ }, "select": { "select-menu": { - "selected-count": "Kijelölve " + "selected-count": "" } }, "service-account-create-page": { @@ -12444,6 +12457,7 @@ "aria-label-role": "Szerepkör" }, "service-account-tokens-table": { + "aria-label-delete-button": "", "created": "Létrehozva", "expires": "Lejárat", "last-used-at": "Legutóbbi használat", @@ -12531,7 +12545,7 @@ "info-text": "Létrehozhat egy közvetlen hivatkozást ehhez az irányítópulthoz vagy panelhez, az alábbi lehetőségekkel testreszabva.", "link-url": "Hivatkozás URL-címe", "render-alert": "Az Image Renderer bővítmény nincs telepítve", - "render-instructions": "Képek rendereléséhez telepítenie kell a <2>Grafana Image Renderer bővítményt. Kérjük, vegye fel a kapcsolatot Grafana-rendszergazdájával a bővítmény telepítéséhez.", + "render-instructions": "", "rendered-image": "Renderelt kép közvetlen hivatkozása", "save-alert": "Az irányítópult nincs mentve", "save-dashboard": "Panelkép rendereléséhez először mentenie kell az irányítópultot.", @@ -12555,7 +12569,7 @@ "info-text-1": "A pillanatfelvétel azonnali módja az interaktív irányítópult nyilvános megosztásának. Létrehozásakor eltávolítjuk a bizalmas adatokat, például a lekérdezéseket (metrika, sablon és jegyzetek) és a panelhivatkozásokat, így csak a látható metrikaadatok és az irányítópultba ágyazott sorozatnevek maradnak.", "info-text-2": "Ne feledje, hogy az Ön pillanatképét <1> bárki megtekintheti, aki rendelkezik a hivatkozással és hozzáférhet az URL-címhez. Körültekintően ossza meg.", "local-button": "Pillanatkép közzététele", - "mistake-message": "Hibázott? ", + "mistake-message": "", "name": "Pillanatkép neve", "timeout": "Időtúllépés (másodpercben)", "timeout-description": "Előfordulhat, hogy konfigurálnia kell az időtúllépés értékét, ha hosszú időt vesz igénybe az irányítópult-metrikák összegyűjtése.", @@ -13167,7 +13181,7 @@ "forwards-time-aria-label": "Időtartomány mozgatása előre", "to": "vége", "zoom-out-button": "Időtartomány kicsinyítése", - "zoom-out-tooltip": "Időtartomány kicsinyítése <1> CTRL+Z" + "zoom-out-tooltip": "" }, "time-range": { "apply": "Időtartomány alkalmazása", @@ -13292,7 +13306,7 @@ }, "transformations": { "empty": { - "add-transformation-body": "A transzformációk lehetővé teszik az adatok különböző módon történő megváltoztatását a vizualizáció megjelenítése előtt.<1>Ez magában foglalja az adatok egyesítését, a mezők átnevezését, a számítások elvégzését, az adatok formázását a megjelenítéshez stb.", + "add-transformation-body": "", "add-transformation-header": "Adatok átalakításának megkezdése" } }, @@ -13559,7 +13573,7 @@ "label-format": "Formátum", "label-set-timezone": "Időzóna beállítása", "label-time-field": "Időmező", - "tooltip-format": "A <2>Moment.js formátumú karakterlánc mező kimeneti formátuma.", + "tooltip-format": "", "tooltip-timezone-manually": "A dátum időzónájának manuális beállítása" }, "format-time-transformer-editor": { @@ -14154,8 +14168,8 @@ "message": "Nincsenek felhasználók" }, "token-revoked-modal": { - "auto-revoked": "A munkameneti tokent a rendszer automatikusan visszavonta, mert elérte <2>a(z) {{numSessions}} egyidejű munkamenet maximális számát a fiókjában.", - "resume-message": "<0>A munkamenet folytatásához jelentkezzen be újra.Vegye fel a kapcsolatot a rendszergazdával, vagy látogasson el a licencoldalra a kvóta áttekintéséhez, ha ismételten automatikusan kijelentkezteti a rendszer.", + "auto-revoked": "", + "resume-message": "", "sign-in": "Bejelentkezés", "title-you-have-been-automatically-signed-out": "A rendszer automatikusan kijelentkeztette" }, diff --git a/public/locales/id-ID/grafana.json b/public/locales/id-ID/grafana.json index 70e14895802..17825673bbd 100644 --- a/public/locales/id-ID/grafana.json +++ b/public/locales/id-ID/grafana.json @@ -108,7 +108,7 @@ "dismiss": "Tutup", "heading": "Autentikasi perusahaan", "learn-more-link": "Pelajari lebih lanjut", - "text": "Kelola pengguna, tim, dan izin secara otomatis dengan <1>SAML, <3>SCIM, <6>LDAP, dan <8>RBAC — tersedia di Grafana Cloud dan Enterprise." + "text": "" }, "feature-listing": { "title-auditing": "Audit", @@ -209,7 +209,7 @@ "title-delete": "Hapus" }, "orgs": { - "delete-body": "Apa Anda yakin ingin menghapus '{{deleteOrgName}}'?<3> <5>Semua dasbor untuk organisasi ini akan dihapus!", + "delete-body": "", "id-header": "ID", "name-header": "Nama", "new-org-button": "Org baru" @@ -716,6 +716,7 @@ "title-annotations": "Anotasi" }, "link-dashboard-and-panel": "Tautkan dasbor dan panel", + "placeholder-value-input": "", "placeholder-value-input-default": "Masukkan konten anotasi kustom..." }, "bulk-actions": { @@ -1139,7 +1140,7 @@ "title-something-wrong-trying-fetch-group-details": "Terjadi kesalahan saat mencoba mengambil detail grup" }, "evaluation-interval-limit-exceeded": { - "body-minimum-interval": "Interval evaluasi minimum dari <1>{{minInterval}} telah dikonfigurasi di Grafana.<3>Hubungi administrator untuk mengonfigurasi interval yang lebih rendah.", + "body-minimum-interval": "", "title-global-evaluation-interval-limit-exceeded": "Batas interval evaluasi global terlampaui" }, "existing-rule-editor": { @@ -1287,7 +1288,7 @@ "resolved": "Diselesaikan" } }, - "review-alert-payload": " Tinjau data peringatan untuk ditambahkan ke payload:", + "review-alert-payload": "", "title-add-custom-alerts": "Tambah peringatan kustom" }, "get-alert-suggestions": { @@ -1411,7 +1412,7 @@ "title-add-folder-and-labels": "Tambahkan folder dan label" }, "grafana-managed-rule-type": { - "description": "Mendukung beberapa sumber data dalam bentuk apa pun.<1>Ubah data dengan pola." + "description": "" }, "grafana-modify-export": { "body-invalid-rule-id": "UID aturan di URL halaman tidak valid. Harap periksa URL dan coba lagi.", @@ -1847,7 +1848,7 @@ "aria-label-new": "baru" }, "mimir-flavored-type": { - "description": "Gunakan sumber data Mimir, Loki, atau Cortex.<1>Pola tidak didukung." + "description": "" }, "min-interval-option": { "label-interval": "Interval", @@ -2076,7 +2077,7 @@ "warning-1": "Menghapus kebijakan pemberitahuan ini akan menghapusnya secara permanen.", "warning-2": "Apa Anda yakin ingin menghapus kebijakan ini?" }, - "filter-description": "Filter kebijakan pemberitahuan menggunakan daftar pencocok yang dipisahkan koma, misalnya:<1>severity=critical, region=EMEA", + "filter-description": "", "generated-policies": "Kebijakan yang dibuat otomatis", "matchers": "Pencocok", "metadata": { @@ -2119,7 +2120,8 @@ "conflict": "Pohon kebijakan pemberitahuan telah diperbarui oleh pengguna lain.", "error-code": "Pesan kesalahan: \"{{error}}\"", "routes": { - "conflictingMatchers": "Tidak dapat menambahkan atau memperbarui rute: pencocok bertentangan dengan pohon perutean eksternal jika kami menggabungkan pencocok {{-matchers}}. Ini akan membuat rute tidak dapat dijangkau." + "conflictingMatchers": "Tidak dapat menambahkan atau memperbarui rute: pencocok bertentangan dengan pohon perutean eksternal jika kami menggabungkan pencocok {{-matchers}}. Ini akan membuat rute tidak dapat dijangkau.", + "unknownMatchers": "" }, "suffix": "Muat ulang halaman untuk mencoba lagi.", "title": "Gagal menambahkan atau memperbarui kebijakan pemberitahuan" @@ -2236,7 +2238,7 @@ "error-no-query-editor": "Tidak dapat memuat editor kueri karena: {{errorMessage}}" }, "recording-rule-type": { - "description": "Prakomputasi pola.<1>Harus dikombinasikan dengan aturan peringatan." + "description": "" }, "recording-rules": { "description-target-data-source": "Sumber data Prometheus untuk menyimpan aturan perekaman", @@ -2249,7 +2251,7 @@ }, "redirect-to-clone-rule": { "body-evaluation-group": "Anda perlu mengatur grup evaluasi baru untuk aturan yang disalin karena grup evaluasi awal telah disediakan dan tidak dapat digunakan untuk aturan yang dibuat di UI.", - "body-not-provisioned": "Aturan baru tidak <1>akan ditandai sebagai aturan yang disediakan.", + "body-not-provisioned": "", "confirmText-copy": "Salin", "title-copy-provisioned-alert-rule": "Salin aturan peringatan yang disediakan" }, @@ -2284,13 +2286,13 @@ "routing-settings": { "aria-label-group-by": "Kelompokkan berdasarkan", "description-group-by": "Gabungkan beberapa peringatan menjadi satu pemberitahuan dengan mengelompokkannya berdasarkan nilai label yang sama. Jika kosong, pengaturan ini akan mengikuti pengaturan kebijakan pemberitahuan default.", - "group-interval": "Interval grup: <1>{{groupIntervalValue}}", - "group-wait": "Periode tunggu grup: <1>{{groupWaitValue}}", - "grouping": "Pengelompokan: <1>{{fields}}", + "group-interval": "", + "group-wait": "", + "grouping": "", "label-group-by": "Kelompokkan berdasarkan", "label-override-grouping": "Timpa pengelompokan", "label-override-timings": "Timpa pengaturan waktu", - "repeat-interval": "Interval pengulangan: <1>{{repeatIntervalValue}}" + "repeat-interval": "" }, "rule-actions-buttons": { "title-edit": "Edit", @@ -2542,7 +2544,7 @@ "relative-with-to": "" }, "rule-type-picker": { - "grafana-managed": "Pilih “dikelola Grafana” kecuali Anda memiliki sumber data Mimir, Loki, atau Cortex yang mengaktifkan API Ruler." + "grafana-managed": "" }, "rule-view": { "query": { @@ -2875,7 +2877,7 @@ "test-contact-point-modal": { "custom-notification-message": "Anda akan mengirim pemberitahuan tes yang menggunakan anotasi yang ditentukan di bawah ini. Ini adalah opsi yang baik jika Anda menggunakan templat dan pesan kustom.", "notification-message": "Pesan pemberitahuan", - "predefined-notification-message": "Anda akan mengirim pemberitahuan tes yang menggunakan peringatan yang telah ditentukan. Jika Anda telah menentukan templat atau pesan kustom, untuk hasil yang lebih baik, beralihlah ke pesan pemberitahuan <1>kustom dari atas.", + "predefined-notification-message": "", "send-test-notification": "Kirim pemberitahuan tes", "title-test-contact-point": "Uji titik kontak" }, @@ -2884,7 +2886,7 @@ }, "threshold-expression-viewer": { "input": "Input", - "stop-alerting-when": "Hentikan peringatan (atau status tertunda) jika " + "stop-alerting-when": "" }, "time-interval": { "add-time-interval": "Tambahkan interval waktu", @@ -3072,7 +3074,7 @@ "title-notification-policies": "Kebijakan pemberitahuan" }, "yaml-content-info": { - "body": "Konten YAML di editor hanya berisi konfigurasi aturan peringatan <1>Untuk mengonfigurasi Prometheus, Anda perlu memberikan bagian lain dalam <4>konten file konfigurasi." + "body": "" } }, "alertlist": { @@ -3148,7 +3150,7 @@ "no-annotations-found": "Tidak ada anotasi yang ditemukan" }, "annotation-list-item": { - "tooltip-created-by": "Dibuat oleh:<1> {{email}}" + "tooltip-created-by": "" }, "category-annotation-query": "Kueri anotasi", "category-display": "Tampilan", @@ -3186,7 +3188,7 @@ }, "empty-state": { "button-title": "Tambahkan kueri anotasi", - "info-box-content": "<0>Anotasi menyediakan cara untuk mengintegrasikan data kejadian ke dalam grafik Anda. Anotasi divisualisasikan sebagai garis vertikal dan ikon pada semua panel grafik. Saat mengarahkan kursor ke ikon anotasi, Anda bisa mendapatkan teks & tag kejadian untuk kejadian tersebut. Anda dapat menambahkan kejadian anotasi langsung dari grafana dengan menahan Ctrl atau CMD + klik pada grafik (atau seret wilayah). Ini akan disimpan dalam database anotasi Grafana.", + "info-box-content": "", "info-box-content-2": "Lihat <2>Dokumentasi anotasi untuk informasi selengkapnya.", "title": "Belum ada kueri anotasi kustom yang ditambahkan" }, @@ -3224,7 +3226,7 @@ "auth-settings": "Pengaturan autentikasi" }, "auth-drawer-unconneced": { - "subtitle": "Konfigurasikan pengaturan autentikasi. Cari tahu selengkapnya di <2>dokumentasi kami." + "subtitle": "" }, "auth-drawer-unconnected": { "advanced-auth": "Autentikasi Lanjutan", @@ -3258,7 +3260,7 @@ "allowed-organizations-description": "Daftar organisasi yang dipisahkan koma atau spasi. Pengguna harus menjadi anggota\ndari setidaknya satu organisasi untuk masuk.", "allowed-organizations-label": "Organisasi yang diizinkan", "allowed-organizations-placeholder": "Masukkan organisasi (my-team, myteam...) dan tekan Enter untuk menambahkan", - "api-url-description": "Endpoint informasi pengguna penyedia OAuth2 Anda. Informasi yang dikembalikan oleh endpoint ini harus kompatibel dengan <2>OpenID UserInfo.", + "api-url-description": "", "api-url-required": "Bidang ini harus berupa URL yang valid jika ditetapkan.", "auth-style-description": "Ini menentukan cara \"{{ clientIDLabel }}\" dan \"{{ clientSecretLabel }}\" dikirim ke penyedia Oauth2. Default adalah AutoDetect.", "auth-style-label": "Metode autentikasi", @@ -3403,7 +3405,7 @@ } }, "auth-config-auth-config-page-unconnected": { - "subtitle": "Kelola pengaturan autentikasi Anda dan konfigurasikan single sign-on. Cari tahu selengkapnya di <2>dokumentasi kami." + "subtitle": "" }, "bar-chart": { "warn": { @@ -4113,7 +4115,7 @@ }, "scopes": { "apply-selected-scopes": "Terapkan", - "selected-scopes-label": "Lingkup: " + "selected-scopes-label": "" }, "search-box": { "placeholder": "Cari atau lompat ke..." @@ -4255,7 +4257,7 @@ "okay": "Oke" }, "not-found-datasource": { - "body": "Anda mungkin salah mengetik URL atau plugin dengan id <1> tidak tersedia.<3>Untuk melihat daftar sumber data yang tersedia, silakan <5>klik di sini." + "body": "" }, "oss": { "connections-home-page": { @@ -4298,8 +4300,8 @@ "versionHistory": { "comparison": { "header": { - "hide-json-diff": "Sembunyikan selisih JSON ", - "show-json-diff": "Tampilkan selisih JSON ", + "hide-json-diff": "", + "show-json-diff": "", "text": "Versi {{version}} diperbarui oleh {{createdBy}} ({{ageString}}) {{message}}" }, "select": "Pilih dua versi untuk mulai membandingkan" @@ -4326,7 +4328,7 @@ "label-label": "Label", "label-placeholder": "misalnya, jejak Tempo", "label-required": "Bidang ini wajib diisi.", - "sub-text": "<0>Tentukan teks yang akan menggambarkan korelasi.", + "sub-text": "", "title": "Tentukan label korelasi (Langkah 1 dari 3)" }, "configure-correlation-target-form": { @@ -4370,7 +4372,7 @@ }, "source-form": { "control-required": "Bidang ini wajib diisi.", - "description": "Titik data perlu memberikan nilai kepada semua variabel sebagai bidang atau sebagai output transformasi untuk membuat tombol korelasi muncul dalam visualisasi.<1>Catatan: Tidak setiap variabel perlu ditentukan secara eksplisit di bawah ini. Transformasi seperti <4>logfmt akan membuat variabel untuk setiap pasangan kunci/nilai.", + "description": "", "description-external-pre": "Anda telah menggunakan variabel berikut di URL target:", "description-query-pre": "Anda telah menggunakan variabel berikut di kueri target:", "external-title": "Konfigurasikan sumber data yang akan menggunakan URL (Langkah 3 dari 3)", @@ -4382,12 +4384,12 @@ "results-required": "Bidang ini wajib diisi.", "source-description": "Hasil dari sumber data yang dipilih memiliki tautan yang ditampilkan di panel", "source-label": "Sumber", - "sub-text": "<0>Tentukan sumber data apa yang akan menampilkan korelasi, dan data yang akan menggantikan variabel yang ditentukan sebelumnya." + "sub-text": "" }, "sub-title": "Tentukan cara data yang berada di sumber data yang berbeda saling berhubungan. Baca selengkapnya di <2>dokumentasi", "target-form": { "control-rules": "Bidang ini wajib diisi.", - "sub-text": "<0>Tentukan korelasi yang akan ditautkan. Dengan jenis kueri, kueri akan berjalan saat korelasi diklik. Dengan jenis eksternal, mengklik korelasi akan membuka URL.", + "sub-text": "", "target-description-external": "Tentukan URL yang akan terbuka saat tautan diklik", "target-description-query": "Tentukan sumber data yang dikueri saat tautan diklik", "target-label": "Target", @@ -4594,7 +4596,7 @@ } }, "confirm-plugin-dashboard-save-modal": { - "body-plugin-dashboard": "Perubahan Anda akan hilang saat Anda memperbarui plugin.<1><2>Gunakan <1>Simpan Sebagai untuk membuat versi kustom.", + "body-plugin-dashboard": "", "cancel": "Batalkan", "overwrite": "Timpa", "title-plugin-dashboard": "Dasbor plugin" @@ -4811,7 +4813,7 @@ "add-visualization-body": "Pilih sumber data, kemudian kueri dan visualisasikan data Anda dengan bagan, statistik, dan tabel atau buat daftar, markdown, dan widget lainnya.", "add-visualization-button": "Tambahkan visualisasi", "add-visualization-header": "Mulai dasbor baru Anda dengan menambahkan visualisasi", - "import-a-dashboard-body": "Impor dasbor dari file atau <2>grafana.com.", + "import-a-dashboard-body": "", "import-a-dashboard-header": "Impor dasbor", "import-dashboard-button": "Impor dasbor", "show-less-dashboards": "", @@ -5268,8 +5270,8 @@ "title-provisioned": "Dasbor yang disediakan" }, "save-dashboard-error-proxy": { - "body-name-exists": "Dasbor dengan nama yang sama di folder yang dipilih sudah ada.<1><2>Apa Anda masih ingin menyimpan dasbor ini?", - "body-version-mismatch": "Orang lain telah memperbarui dasbor ini<1><2>Apa Anda masih ingin menyimpan dasbor ini?", + "body-name-exists": "", + "body-version-mismatch": "", "confirmText-save-and-overwrite": "Simpan dan timpa", "title-name-exists": "Konflik", "title-version-mismatch": "Konflik" @@ -5287,7 +5289,7 @@ "cancel": "Batalkan", "cannot-be-saved": "Dasbor ini tidak dapat disimpan dari UI Grafana karena telah disediakan dari sumber lain. Salin JSON atau simpan ke file di bawah ini, lalu Anda dapat memperbarui dasbor Anda di sumber penyediaan.", "copy-json-to-clipboard": "Salin JSON ke papan klip", - "file-path": "<0>Jalur file: {{filePath}}", + "file-path": "", "save-json-to-file": "Simpan JSON ke file", "see-docs": "Lihat <2>dokumentasi untuk informasi selengkapnya tentang penyediaan." }, @@ -5486,7 +5488,7 @@ "transformation-picker": { "info": "Transformasi memungkinkan Anda bergabung, menghitung, menyusun ulang, menyembunyikan, dan mengubah nama hasil kueri Anda sebelum divisualisasikan.", "info-graph-not-suitable": "Banyak transformasi yang tidak cocok jika Anda menggunakan visualisasi Grafik, karena saat ini visualisasi ini hanya mendukung data deret waktu.", - "info-switch-to-table": "Ini dapat membantu untuk beralih ke visualisasi Tabel untuk memahami operasi transformasi. ", + "info-switch-to-table": "", "placeholder-search-for-transformation": "Cari transformasi", "read-more": "Baca selengkapnya", "title-transformations": "Transformasi" @@ -5552,8 +5554,8 @@ "version-history-comparison": { "button-restore": "Pulihkan ke versi {{version}}", "label-view-json-diff": "Lihat diff JSON", - "new-updated-by": "<0>Versi {{version}} diperbarui oleh {{editor}} {{timeAgo}}", - "old-updated-by": "<0>Versi {{version}} diperbarui oleh {{editor}} {{timeAgo}}" + "new-updated-by": "", + "old-updated-by": "" }, "version-history-table": { "aria-label-toggle-selection": "Alihkan tombol pemilihan versi {{version}}", @@ -5953,7 +5955,7 @@ "cancel": "Batalkan" }, "render-save-button-and-error": { - "body-plugin-dashboard": "Perubahan Anda akan hilang saat Anda memperbarui plugin. Gunakan <1>Simpan sebagai untuk membuat versi kustom.", + "body-plugin-dashboard": "", "title-failed-to-save-dashboard": "Gagal menyimpan dasbor", "title-plugin-dashboard": "Dasbor plugin", "title-someone-else-has-updated-this-dashboard": "Orang lain telah memperbarui dasbor ini", @@ -5962,7 +5964,7 @@ "save-and-overwrite": "'Simpan dan timpa'" }, "library-viz-panel-info": { - "last-edited": "{{timeAgo}} oleh", + "last-edited": "", "usage-count_other": "Digunakan pada {{count}} dasbor" }, "managed-badge": { @@ -6022,7 +6024,7 @@ }, "panel-data-queries-tab-rendered": { "add-query": "Tambahkan kueri", - "expression": "Pola " + "expression": "" }, "panel-data-transformations-tab": { "tab-label": "Transformasi" @@ -6080,7 +6082,7 @@ "query": "Kueri" }, "query-variable-editor-form": { - "description-examples": "Grup tangkapan bernama dapat digunakan untuk memisahkan teks tampilan dan nilai (<1>lihat contoh).", + "description-examples": "", "description-optional": "Opsional, jika Anda ingin mengekstrak bagian dari nama seri atau segmen node metrik.", "label-data-source": "Sumber data", "label-static-options-sort": "Urutan opsi statis", @@ -6141,7 +6143,7 @@ "label-message": "Pesan", "placeholder-describe-changes-optional": "Tambahkan catatan untuk menjelaskan perubahan Anda (opsional).", "render-footer": { - "body-plugin-dashboard": "Perubahan Anda akan hilang saat Anda memperbarui plugin. Gunakan <1>Simpan sebagai untuk membuat versi kustom.", + "body-plugin-dashboard": "", "no-changes-to-save": "Tidak ada perubahan untuk disimpan", "title-failed-to-save-dashboard": "Gagal menyimpan dasbor", "title-plugin-dashboard": "Dasbor plugin", @@ -6176,7 +6178,7 @@ "cancel": "Batalkan", "cannot-be-saved": "Dasbor ini tidak dapat disimpan dari UI Grafana karena telah disediakan dari sumber lain. Salin JSON atau simpan ke file di bawah ini, lalu Anda dapat memperbarui dasbor Anda di sumber penyediaan.", "copy-json-to-clipboard": "Salin JSON ke papan klip", - "file-path": "<0>Jalur file: {{filePath}}", + "file-path": "", "label-description": "Deskripsi", "label-target-folder": "Folder target", "label-title": "Judul", @@ -6345,8 +6347,8 @@ }, "version-history-comparison": { "label-view-json-diff": "Lihat diff JSON", - "new-version-updated": "<0>Versi {{version}} diperbarui oleh {{editor}} {{timeAgo}}", - "old-version-updated": "<0>Versi {{version}} diperbarui oleh {{editor}} {{timeAgo}}" + "new-version-updated": "", + "old-version-updated": "" }, "version-history-header": { "compare-versions": "Membandingkan {{baseVersion}} <3> {{newVersion}}", @@ -6424,7 +6426,7 @@ "provisioned-delete-modal": { "confirm-button": "OK", "text-1": "Dasbor ini dikelola oleh penyediaan Grafana dan tidak dapat dihapus. Hapus dasbor dari file konfigurasi untuk menghapusnya.", - "text-2": "Lihat dokumentasi grafana untuk informasi selengkapnya tentang penyediaan. ", + "text-2": "", "text-3": "Jalur file: {{provisionedId}}", "text-link": "Buka halaman dokumen", "title": "Tidak dapat menghapus dasbor yang disediakan" @@ -6502,7 +6504,7 @@ }, "data-source-testing-status-page": { "error-more-details-link": "Klik <2>di sini untuk mempelajari selengkapnya tentang kesalahan ini.", - "success-more-details-links": "Selanjutnya, Anda dapat mulai memvisualisasikan data dengan <2>membuat dasbor, atau dengan melakukan kueri data di <5>tampilan Explore." + "success-more-details-links": "" }, "data-sources": { "datasource-add-button": { @@ -6598,7 +6600,7 @@ "test": "Tes" }, "cloud-info-box": { - "body-alert": "Atau lewati proses dan dapatkan {{mainDS}} (dan {{extraDS}}) sebagai sumber data yang dikelola sepenuhnya, dapat diskalakan, dan di-host dari Grafana Labs dengan <6>paket Grafana Cloud gratis selamanya.", + "body-alert": "", "title-alert": "Konfigurasikan sumber data {{mainDS}} Anda di bawah ini" }, "dashboards-table": { @@ -6726,18 +6728,18 @@ "no-events-yet": "Belum ada peristiwa" }, "render-info-viewer": { - "data-counter": "Data: {{numDataChanges}} ", + "data-counter": "", "elapsed-time": "Waktu: {{elapsed}} md", "field": "Bidang", "last": "Terakhir", - "render-counter": "Render: {{numRenders}} ", - "schema-counter": "Skema: {{numSchemaChanges}} ", + "render-counter": "", + "schema-counter": "", "title-reset-counters": "Atur ulang penghitung", "tooltip-step-back": "Mundurlah", "type": "Jenis" }, "state-view": { - "current-value": "Nilai saat ini: {{currentValue}} ", + "current-value": "", "label-state-name": "Nama status" } }, @@ -7184,7 +7186,7 @@ }, "footer": { "learn-more": "Pelajari lebih lanjut", - "pro-tip-define-sources-through-configuration-files": " ProTip: Anda juga dapat menentukan sumber data melalui file konfigurasi. " + "pro-tip-define-sources-through-configuration-files": "" } }, "pane": { @@ -7246,8 +7248,6 @@ "query-deleted": "Kueri dihapus" }, "rich-history-queries-tab": { - "displaying-partial-queries": "Menampilkan {{ count }} kueri", - "displaying-queries": "{{ count }} kueri", "filter-aria-label": "Filter kueri untuk sumber data", "filter-history": "Riwayat filter", "filter-placeholder": "Filter kueri untuk sumber data", @@ -7257,7 +7257,9 @@ "search-placeholder": "Kueri pencarian", "showing-queries": "Menampilkan {{ shown }} dari {{ total }} <0>Muat lebih banyak", "sort-aria-label": "Urutkan kueri", - "sort-placeholder": "Urutkan kueri menurut" + "sort-placeholder": "Urutkan kueri menurut", + "displaying-partial-queries_other": "", + "displaying-queries_other": "" }, "rich-history-settings-tab": { "alert-info": "Grafana akan menyimpan entri hingga {{optionLabel}}.Entri yang dibintangi tidak akan dihapus.", @@ -7449,7 +7451,7 @@ "copy-shortened-link-menu": "Buka opsi salin tautan", "refresh-picker-cancel": "Batalkan", "refresh-picker-run": "Jalankan kueri", - "split-close": " Tutup ", + "split-close": "", "split-close-tooltip": "Tutup panel terpisah", "split-narrow": "Panel sempit", "split-title": "Pisah", @@ -7579,8 +7581,8 @@ }, "math": { "available-math-functions": "Fungsi matematika yang tersedia", - "run-math-operations": "Jalankan operasi matematika pada satu atau beberapa kueri. Anda mereferensikan kueri berdasarkan {{refExample}}, yaitu {{ref1}}, {{ref2}}, {{ref3}}, dll.<10>Contoh: <12>{{example}}", - "tooltip-footer": "Lihat dokumentasi tambahan kami di <2>Pola matematika.", + "run-math-operations": "", + "tooltip-footer": "", "tooltip-title": "Operator matematika", "tooltip-trigger": "Ekspresi" }, @@ -8609,7 +8611,7 @@ }, "data-source-http-settings": { "access-help": "Bantuan <1>", - "access-help-details": "Mode akses mengendalikan cara permintaan ke sumber data akan ditangani.<1> <1>Server harus menjadi cara pilihan jika tidak ada hal lain yang dinyatakan.", + "access-help-details": "", "access-help-title": "Akses bantuan", "access-label": "Akses", "allowed-cookies": "Cookie yang diizinkan", @@ -8877,7 +8879,7 @@ "cell-inspect": "Periksa nilai", "cell-inspect-tooltip": "Periksa nilai", "copy": "Salin ke Papan Klip", - "csv-counts": "Baris:{{rows}}, Kolom:{{columns}} <5>", + "csv-counts": "", "csv-placeholder": "Masukkan CSV di sini...", "filter-placeholder": "Filter nilai", "filter-popup-apply": "Oke", @@ -9162,7 +9164,6 @@ "name-line-width": "Lebar garis", "name-stacking": "Tumpukan" }, - "inline-token-warning-badge-tooltip": "", "inspector": { "inspect-data-tab": { "loading": "Memuat", @@ -9324,7 +9325,7 @@ "error-fetching": "Kesalahan saat mengambil pengaturan LDAP", "error-saving": "Kesalahan saat menyimpan pengaturan LDAP", "error-validate-form": "Kesalahan saat memvalidasi pengaturan LDAP", - "feature-flag-disabled": "Halaman ini hanya dapat diakses dengan mengaktifkan bendera fitur <1>ssoSettingsLDAP.", + "feature-flag-disabled": "", "saved": "Pengaturan LDAP tersimpan" }, "bind-dn": { @@ -9365,7 +9366,7 @@ "label": "Basis pencarian DNS", "placeholder": "contoh: dc=grafana,dc=org" }, - "subtitle": "Integrasi LDAP di Grafana memungkinkan pengguna Grafana Anda untuk login dengan kredensial LDAP mereka. Cari tahu selengkapnya di <2><0>dokumentasi kami.", + "subtitle": "", "title": "Pengaturan Dasar" }, "library-panel": { @@ -9409,7 +9410,7 @@ "dashboard-name": "Nama dasbor" }, "library-panel-info": { - "last-edited": "Terakhir diedit {{timeAgo}} oleh", + "last-edited": "", "usage-count_other": "Digunakan pada {{count}} dasbor" }, "library-panels-search": { @@ -9708,7 +9709,7 @@ "tooltip-unpin-line": "Batal sematkan baris" }, "log-row-message": { - "ellipsis": "… ", + "ellipsis": "", "more": "lainnya", "see-details": "Lihat detail log", "tooltip-error": "Kesalahan: {{errorMessage}}" @@ -10104,7 +10105,7 @@ }, "resource-table": { "dashboard-load-error": "Tidak dapat memuat dasbor", - "error-library-element-sub": "Elemen Pustaka {uid}", + "error-library-element-sub": "", "error-library-element-title": "Tidak dapat memuat elemen pustaka", "unknown-datasource-title": "Sumber data {{datasourceUID}}", "unknown-datasource-type": "Sumber data tidak diketahui" @@ -10749,10 +10750,10 @@ "placeholder-optional": "(opsional)", "role": "Peran", "submit": "Kirim", - "tooltip": "Anda sekarang dapat memilih opsi \"Tidak ada peran dasar\" dan menambahkan izin ke kebutuhan kustom Anda. Anda dapat menemukan informasi lebih lanjut di <1> dokumentasi kami ." + "tooltip": "" }, "user-invite-page": { - "sub-title": "Kirim undangan atau tambahkan pengguna Grafana yang ada ke organisasi.<1> {{orgName}}", + "sub-title": "", "text": { "invite-user": "Undang pengguna" } @@ -10841,7 +10842,7 @@ "switch-to-table": "Alihkan ke tabel" }, "panel-plugin-error": { - "text-load-error": "Periksa log startup server untuk informasi selengkapnya. <1>Jika plugin ini dimuat dari Git, pastikan plugin dikompilasi.", + "text-load-error": "", "title-load-error": "Kesalahan saat memuat: {{panelId}}", "title-not-found": "Plugin panel tidak ditemukan: {{id}}" }, @@ -11035,7 +11036,7 @@ }, "details": { "connections-tab": { - "description": "Saat ini Anda memiliki sumber data berikut yang dikonfigurasi untuk {{pluginName}}, klik kotak untuk melihat detail konfigurasi. Anda dapat menemukan semua koneksi sumber data Anda di <4><0>Koneksi - <3>Sumber data." + "description": "" }, "disabled-error": { "angular-deprecation-link": "Baca selengkapnya tentang penghentian sudut", @@ -11052,7 +11053,7 @@ }, "labels": { "contactGrafanaLabs": "Hubungi Grafana Labs", - "customLinks": "Tautan kustom ", + "customLinks": "", "customLinksTooltip": "Tautan ini disediakan oleh pengembang plugin untuk menawarkan sumber daya dan informasi tambahan khusus pengembang", "dependencies": "Dependensi", "documentation": "Dokumentasi", @@ -11063,7 +11064,7 @@ "latestVersion": "Versi Terbaru", "license": "Lisensi", "raiseAnIssue": "Kemukakan masalah", - "reportAbuse": "Laporkan masalah ", + "reportAbuse": "", "reportAbuseTooltip": "Laporkan masalah yang terkait dengan plugin jahat atau berbahaya langsung ke Grafana Labs.", "repository": "Repositori", "signature": "Tanda Tangan", @@ -11073,8 +11074,8 @@ "modal": { "cancel": "Batalkan", "copyEmail": "Salin alamat email", - "description": "Fitur ini untuk melaporkan perilaku jahat atau berbahaya dalam plugin. Untuk masalah plugin, kirim email kepada kami di: ", - "node": "Catatan: Untuk masalah plugin umum seperti bug atau permintaan fitur, hubungi penulis plugin menggunakan tautan yang disediakan. ", + "description": "", + "node": "", "title": "Laporkan masalah plugin" } }, @@ -11142,7 +11143,7 @@ "message": "Semua plugin sudah diperbarui" }, "not-found-plugin": { - "body-plugin-not-found": "Plugin tersebut tidak dapat ditemukan. Silakan periksa apakah url sudah benar atau <1>buka <3>katalog plugin.", + "body-plugin-not-found": "", "title-plugin-not-found": "Plugin tidak ditemukan" }, "plugin-actions": { @@ -11600,7 +11601,6 @@ "unsupported-repository-type": "" }, "inline-secure-values-warning": "", - "inline-token-warning-badge-text": "", "job-status": { "label-view-details": "Lihat detail", "loading-finished-job": "Memuat pekerjaan yang sudah selesai...", @@ -11777,6 +11777,17 @@ "label-current-step": "Langkah saat ini", "label-pending-step": "Langkah tertunda" }, + "status-badge": { + "automatic-pulling-disabled": "", + "deleting": "", + "error": "", + "pending": "", + "pulling": "", + "unknown": "", + "up-to-date": "", + "waiting-for-health-check": "", + "warning": "" + }, "success-title-default": "Berhasil", "sync-job": { "error-no-job-id": "Gagal memulai pekerjaan", @@ -11954,7 +11965,7 @@ "annotations-show-text": "Anotasi = tampilkan", "time-range-picker-disabled-text": "Pemilih rentang waktu = dinonaktifkan", "time-range-picker-enabled-text": "Pemilih rentang waktu = diaktifkan", - "time-range-text": "Rentang waktu = " + "time-range-text": "" }, "share": { "success-delete": "Dasbor Anda tidak lagi dapat dibagikan" @@ -11993,7 +12004,7 @@ "revoke-user-access-modal-desc-line1": "Apa Anda yakin ingin mencabut akses untuk {{email}}?" }, "delete-user-shared-dashboards-modal": { - "revoke-user-access-modal-desc-line2": "Tindakan ini akan segera mencabut akses {{email}}'s ke semua dasbor bersama." + "revoke-user-access-modal-desc-line2": "" }, "modal": { "shared-dashboard-modal-title": "Dasbor bersama" @@ -12159,7 +12170,7 @@ }, "menu": { "clear-button": "Hapus semua", - "tooltip": "Anda sekarang dapat memilih opsi \"Tidak ada peran dasar\" dan menambahkan izin ke kebutuhan kustom Anda. Anda dapat menemukan informasi lebih lanjut di <1> dokumentasi kami ." + "tooltip": "" }, "menu-aria-label": "Menu pemilih peran", "menu-group-option-aria-label": "Opsi pemilih peran", @@ -12169,7 +12180,7 @@ }, "sub-menu-aria-label": "Submenu pemilih peran", "title": { - "description": "Tetapkan peran ke pengguna untuk memastikan kontrol terperinci atas akses ke fitur dan sumber daya Grafana. Cari tahu selengkapnya di <2>dokumentasi kami." + "description": "" } }, "role-picker-drawer": { @@ -12292,7 +12303,7 @@ }, "select": { "select-menu": { - "selected-count": "Dipilih " + "selected-count": "" } }, "service-account-create-page": { @@ -12391,6 +12402,7 @@ "aria-label-role": "Peran" }, "service-account-tokens-table": { + "aria-label-delete-button": "", "created": "Dibuat", "expires": "Kedaluwarsa", "last-used-at": "Terakhir digunakan pada", @@ -12477,7 +12489,7 @@ "info-text": "Buat tautan langsung ke dasbor atau panel ini, disesuaikan dengan opsi di bawah ini.", "link-url": "Tautkan URL", "render-alert": "Plugin perender gambar belum diinstal", - "render-instructions": "Untuk merender gambar, Anda harus menginstal <2>plugin perender gambar Grafana. Hubungi administrator Grafana Anda untuk menginstal plugin.", + "render-instructions": "", "rendered-image": "Tautan langsung gambar yang dirender", "save-alert": "Dasbor tidak disimpan", "save-dashboard": "Untuk merender gambar panel, Anda harus menyimpan dasbor terlebih dahulu.", @@ -12501,7 +12513,7 @@ "info-text-1": "Snapshot adalah cara instan untuk membagikan dasbor interaktif secara publik. Saat dibuat, kami menghapus data sensitif seperti kueri (metrik, templat, dan anotasi) dan tautan panel, hanya menyisakan data metrik dan nama seri yang terlihat yang disematkan di dasbor Anda.", "info-text-2": "Perlu diingat, snapshot Anda <1>dapat dilihat oleh siapa saja yang memiliki tautan dan dapat mengakses URL. Bagikan dengan bijak.", "local-button": "Publikasikan Snapshot", - "mistake-message": "Apakah Anda melakukan kesalahan? ", + "mistake-message": "", "name": "Nama snapshot", "timeout": "Waktu habis (detik)", "timeout-description": "Anda mungkin perlu mengonfigurasi nilai batas waktu jika membutuhkan waktu lama untuk mengumpulkan metrik dasbor.", @@ -13112,7 +13124,7 @@ "forwards-time-aria-label": "Pindahkan rentang waktu ke depan", "to": "ke", "zoom-out-button": "Perkecil rentang waktu", - "zoom-out-tooltip": "Perkecil rentang waktu <1> CTRL+Z" + "zoom-out-tooltip": "" }, "time-range": { "apply": "Gunakan rentang waktu", @@ -13237,7 +13249,7 @@ }, "transformations": { "empty": { - "add-transformation-body": "Transformasi memungkinkan data diubah dengan berbagai cara sebelum visualisasi Anda ditampilkan.<1>Ini termasuk menggabungkan data bersama, mengubah nama bidang, membuat perhitungan, memformat data untuk ditampilkan, dan banyak lagi.", + "add-transformation-body": "", "add-transformation-header": "Mulai ubah data" } }, @@ -13504,7 +13516,7 @@ "label-format": "Format", "label-set-timezone": "Atur zona waktu", "label-time-field": "Bidang waktu", - "tooltip-format": "Format output untuk bidang yang ditentukan sebagai <2>string format Moment.js.", + "tooltip-format": "", "tooltip-timezone-manually": "Atur zona waktu tanggal secara manual" }, "format-time-transformer-editor": { @@ -14099,8 +14111,8 @@ "message": "Pengguna tidak ditemukan" }, "token-revoked-modal": { - "auto-revoked": "Token sesi Anda dicabut secara otomatis karena Anda telah mencapai <2>jumlah maksimum {{numSessions}} sesi bersamaan untuk akun Anda.", - "resume-message": "<0>Untuk melanjutkan sesi Anda, masuk lagi.Hubungi administrator Anda atau kunjungi halaman lisensi untuk meninjau kuota Anda jika Anda berulang kali keluar secara otomatis.", + "auto-revoked": "", + "resume-message": "", "sign-in": "Masuk", "title-you-have-been-automatically-signed-out": "Anda telah keluar secara otomatis" }, diff --git a/public/locales/it-IT/grafana.json b/public/locales/it-IT/grafana.json index ae7ad603e9e..a7d095fffc8 100644 --- a/public/locales/it-IT/grafana.json +++ b/public/locales/it-IT/grafana.json @@ -108,7 +108,7 @@ "dismiss": "Chiudi", "heading": "Autenticazione aziendale", "learn-more-link": "Scopri di più", - "text": "Gestisci automaticamente utenti, team e autorizzazioni con <1>SAML, <3>SCIM, <6>LDAP e <8>RBAC, disponibili in Grafana Cloud ed Enterprise." + "text": "" }, "feature-listing": { "title-auditing": "Verifiche", @@ -209,7 +209,7 @@ "title-delete": "Elimina" }, "orgs": { - "delete-body": "Vuoi davvero eliminare \"{{deleteOrgName}}\"?<3> <5>Tutti i dashboard per questa organizzazione saranno rimossi!", + "delete-body": "", "id-header": "ID", "name-header": "Nome", "new-org-button": "Nuova organizzazione" @@ -719,6 +719,7 @@ "title-annotations": "Annotazioni" }, "link-dashboard-and-panel": "Collega dashboard e pannello", + "placeholder-value-input": "", "placeholder-value-input-default": "Inserisci il contenuto dell'annotazione personalizzata..." }, "bulk-actions": { @@ -1144,7 +1145,7 @@ "title-something-wrong-trying-fetch-group-details": "Si è verificato un errore durante il recupero dei dettagli del gruppo" }, "evaluation-interval-limit-exceeded": { - "body-minimum-interval": "Un intervallo di valutazione minimo di <1>{{minInterval}} è stato configurato in Grafana.<3>Contatta l'amministratore per configurare un intervallo inferiore.", + "body-minimum-interval": "", "title-global-evaluation-interval-limit-exceeded": "Limite dell'intervallo di valutazione globale superato" }, "existing-rule-editor": { @@ -1292,7 +1293,7 @@ "resolved": "Risolto" } }, - "review-alert-payload": " Esamina i dati di avviso da aggiungere al carico utile:", + "review-alert-payload": "", "title-add-custom-alerts": "Aggiungi avvisi personalizzati" }, "get-alert-suggestions": { @@ -1416,7 +1417,7 @@ "title-add-folder-and-labels": "Aggiungi cartella ed etichette" }, "grafana-managed-rule-type": { - "description": "Supporta più origini dei dati di qualsiasi tipo.<1>Trasforma i dati con le espressioni." + "description": "" }, "grafana-modify-export": { "body-invalid-rule-id": "L'UID della regola nell'URL della pagina non è valido. Controlla l'URL e riprova.", @@ -1853,7 +1854,7 @@ "aria-label-new": "nuovo" }, "mimir-flavored-type": { - "description": "Utilizza un'origine dei dati Mimir, Loki o Cortex.<1>Le espressioni non sono supportate." + "description": "" }, "min-interval-option": { "label-interval": "Intervallo", @@ -2082,7 +2083,7 @@ "warning-1": "L'eliminazione di questo criterio di notifica lo rimuoverà in modo permanente.", "warning-2": "Vuoi davvero eliminare questo criterio?" }, - "filter-description": "Filtra i criteri di notifica utilizzando un elenco di corrispondenti separati da virgole, ad esempio:<1>gravità=critica, regione=EMEA", + "filter-description": "", "generated-policies": "Criteri generati automaticamente", "matchers": "Corrispondenze", "metadata": { @@ -2126,7 +2127,8 @@ "conflict": "L'albero di accesso alle notifiche è stato aggiornato da un altro utente.", "error-code": "Messaggio di errore: \"{{error}}\"", "routes": { - "conflictingMatchers": "Impossibile aggiungere o aggiornare il percorso: i matcher sono in conflitto con una struttura di routing esterna se abbiamo unito i matcher {{-matchers}}. Ciò renderebbe il percorso irraggiungibile." + "conflictingMatchers": "Impossibile aggiungere o aggiornare il percorso: i matcher sono in conflitto con una struttura di routing esterna se abbiamo unito i matcher {{-matchers}}. Ciò renderebbe il percorso irraggiungibile.", + "unknownMatchers": "" }, "suffix": "Aggiorna la pagina e riprova.", "title": "Impossibile aggiungere o aggiornare i criteri di notifica" @@ -2244,7 +2246,7 @@ "error-no-query-editor": "Impossibile caricare l'editor di query a causa di: {{errorMessage}}" }, "recording-rule-type": { - "description": "Precalcola le espressioni.<1>Dovrebbe essere combinato con una regola di avviso." + "description": "" }, "recording-rules": { "description-target-data-source": "L'origine dei dati di Prometheus in cui archiviare le regole di registrazione", @@ -2257,7 +2259,7 @@ }, "redirect-to-clone-rule": { "body-evaluation-group": "Sarà necessario impostare un nuovo gruppo di valutazione per la regola copiata perché quella originale è stata sottoposta a provisioning e non può essere utilizzata per le regole create nell'interfaccia utente.", - "body-not-provisioned": "La nuova regola <1>non sarà contrassegnata come regola con provisioning.", + "body-not-provisioned": "", "confirmText-copy": "Copia", "title-copy-provisioned-alert-rule": "Copia la regola di avviso fornita" }, @@ -2292,13 +2294,13 @@ "routing-settings": { "aria-label-group-by": "Raggruppa per", "description-group-by": "Combina più avvisi in un'unica notifica raggruppandoli in base agli stessi valori di etichetta. Se vuoto, viene ereditato dal criterio di notifica predefinito.", - "group-interval": "Intervallo di gruppo: <1>{{groupIntervalValue}}", - "group-wait": "Attesa gruppo: <1>{{groupWaitValue}}", - "grouping": "Raggruppamento: <1>{{fields}}", + "group-interval": "", + "group-wait": "", + "grouping": "", "label-group-by": "Raggruppa per", "label-override-grouping": "Sovrascrivi raggruppamento", "label-override-timings": "Sovrascrivi orari", - "repeat-interval": "Ripeti intervallo: <1>{{repeatIntervalValue}}" + "repeat-interval": "" }, "rule-actions-buttons": { "title-edit": "Modifica", @@ -2554,7 +2556,7 @@ "relative-with-to": "" }, "rule-type-picker": { - "grafana-managed": "Seleziona \"Gestito da Grafana\" a meno che tu non disponga di un'origine dei dati Mimir, Loki o Cortex con l'API Ruler abilitata." + "grafana-managed": "" }, "rule-view": { "query": { @@ -2887,7 +2889,7 @@ "test-contact-point-modal": { "custom-notification-message": "Invierai una notifica di prova che utilizza le annotazioni definite di seguito. È una buona opzione se utilizzi modelli e messaggi personalizzati.", "notification-message": "Messaggio di notifica", - "predefined-notification-message": "Invierai una notifica di prova che utilizza un avviso predefinito. Se hai definito un modello o un messaggio personalizzato, per ottenere risultati migliori passa al messaggio di notifica <1>personalizzato in alto.", + "predefined-notification-message": "", "send-test-notification": "Invia notifica di prova", "title-test-contact-point": "Prova punto di contatto" }, @@ -2896,7 +2898,7 @@ }, "threshold-expression-viewer": { "input": "Inserisci", - "stop-alerting-when": "Interrompi l'avviso (o lo stato in sospeso) quando " + "stop-alerting-when": "" }, "time-interval": { "add-time-interval": "Aggiungi intervallo di tempo", @@ -3084,7 +3086,7 @@ "title-notification-policies": "Politiche di notifica" }, "yaml-content-info": { - "body": "Il contenuto YAML nell'editor contiene solo la configurazione della regola di avviso <1>Per configurare Prometheus, è necessario fornire il resto del <4>contenuto del file di configurazione." + "body": "" } }, "alertlist": { @@ -3160,7 +3162,7 @@ "no-annotations-found": "Nessuna annotazione trovata" }, "annotation-list-item": { - "tooltip-created-by": "Creazione di:<1> {{email}}" + "tooltip-created-by": "" }, "category-annotation-query": "Query di annotazione", "category-display": "Visualizza", @@ -3198,7 +3200,7 @@ }, "empty-state": { "button-title": "Aggiungi query di annotazione", - "info-box-content": "<0>Le annotazioni forniscono un modo per integrare i dati degli eventi nei grafici. Sono visualizzate come linee verticali e icone su tutti i pannelli dei grafici. Quando si passa il mouse su un'icona di annotazione, è possibile ottenere il testo e i tag dell'evento. Puoi aggiungere eventi di annotazione direttamente da Grafana tenendo premuto CTRL o CMD e facendo clic sul grafico (in alternativa, trascina l'area). Questi verranno archiviati nel database delle annotazioni di Grafana.", + "info-box-content": "", "info-box-content-2": "Consulta la <2>Documentazione delle annotazioni per ulteriori informazioni.", "title": "Non sono ancora state aggiunte query di annotazioni personalizzate" }, @@ -3236,7 +3238,7 @@ "auth-settings": "Impostazioni di autenticazione" }, "auth-drawer-unconneced": { - "subtitle": "Configura le impostazioni di autenticazione. Scopri di più nella nostra <2>documentazione." + "subtitle": "" }, "auth-drawer-unconnected": { "advanced-auth": "Autenticazione avanzata", @@ -3270,7 +3272,7 @@ "allowed-organizations-description": "Elenco di organizzazioni separate da virgole o spazi. L'utente deve essere membro\ndi almeno un'organizzazione per accedere.", "allowed-organizations-label": "Organizzazioni consentite", "allowed-organizations-placeholder": "Inserisci le organizzazioni (my-team, myteam...) e premi Invio per aggiungerle", - "api-url-description": "L'endpoint delle informazioni utente del tuo provider OAuth2. Le informazioni restituite da questo endpoint devono essere compatibili con <2>OpenID UserInfo.", + "api-url-description": "", "api-url-required": "Questo campo deve essere un URL valido se impostato.", "auth-style-description": "Determina come \"{{ clientIDLabel }}\" e \"{{ clientSecretLabel }}\" vengono inviati al provider Oauth2. L'impostazione predefinita è Rilevamento automatico.", "auth-style-label": "Stile di autenticazione", @@ -3415,7 +3417,7 @@ } }, "auth-config-auth-config-page-unconnected": { - "subtitle": "Gestisci le impostazioni di autenticazione e configura il Single Sign-On. Scopri di più nella nostra <2>documentazione." + "subtitle": "" }, "bar-chart": { "warn": { @@ -4133,7 +4135,7 @@ }, "scopes": { "apply-selected-scopes": "Applica", - "selected-scopes-label": "Ambiti di applicazione: " + "selected-scopes-label": "" }, "search-box": { "placeholder": "Cerca o vai a..." @@ -4275,7 +4277,7 @@ "okay": "Ok" }, "not-found-datasource": { - "body": "Potresti aver digitato male l'URL oppure il componente aggiuntivo con l'ID <1> non è disponibile.<3>Per visualizzare un elenco delle origini dei dati disponibili, <5>clicca qui." + "body": "" }, "oss": { "connections-home-page": { @@ -4318,8 +4320,8 @@ "versionHistory": { "comparison": { "header": { - "hide-json-diff": "Nascondi differenza JSON ", - "show-json-diff": "Mostra differenza JSON ", + "hide-json-diff": "", + "show-json-diff": "", "text": "Versione {{version}} aggiornata da {{createdBy}} ({{ageString}}) {{message}}" }, "select": "Seleziona due versioni per avviare il confronto" @@ -4346,7 +4348,7 @@ "label-label": "Etichetta", "label-placeholder": "ad es. Tracce Tempo", "label-required": "Questo campo è obbligatorio.", - "sub-text": "<0>Definisci il testo che descriverà la correlazione.", + "sub-text": "", "title": "Definisci l'etichetta di correlazione (passaggio 1 di 3)" }, "configure-correlation-target-form": { @@ -4390,7 +4392,7 @@ }, "source-form": { "control-required": "Questo campo è obbligatorio.", - "description": "Un punto dati deve fornire valori a tutte le variabili come campi o come output di trasformazioni per far comparire il pulsante di correlazione nella visualizzazione.<1>Nota: non tutte le variabili devono essere definite esplicitamente di seguito. Una trasformazione come <4>logfmt creerà variabili per ogni coppia chiave/valore.", + "description": "", "description-external-pre": "Hai utilizzato le seguenti variabili nell'URL di destinazione:", "description-query-pre": "Hai utilizzato le seguenti variabili nella query di destinazione:", "external-title": "Configura l'origine dati che utilizzerà l'URL (passaggio 3 di 3)", @@ -4402,12 +4404,12 @@ "results-required": "Questo campo è obbligatorio.", "source-description": "I risultati dell'origine dati selezionata hanno collegamenti visualizzati nel pannello", "source-label": "Origine", - "sub-text": "<0>Definisci quale origine dati visualizzerà la correlazione e quali dati sostituiranno le variabili precedentemente definite." + "sub-text": "" }, "sub-title": "Definisci il modo in cui i dati che risiedono in diverse origini dati sono correlati tra loro. Scopri di più nella <2>documentazione", "target-form": { "control-rules": "Questo campo è obbligatorio.", - "sub-text": "<0>Definisci a cosa si collegherà la correlazione. Con il tipo di query, quando si fa clic sulla correlazione verrà eseguita una query. Con il tipo esterno, facendo clic sulla correlazione si aprirà un URL.", + "sub-text": "", "target-description-external": "Specifica l'URL che si aprirà quando si fa clic sul link", "target-description-query": "Specifica quale origine dati viene interrogata quando si fa clic sul link", "target-label": "Destinazione", @@ -4614,7 +4616,7 @@ } }, "confirm-plugin-dashboard-save-modal": { - "body-plugin-dashboard": "Le modifiche andranno perse quando aggiornerai il componente aggiuntivo.<1><2>Utilizza <1>Salva con nome per creare una versione personalizzata.", + "body-plugin-dashboard": "", "cancel": "Annulla", "overwrite": "Sovrascrivi", "title-plugin-dashboard": "Dashboard del componente aggiuntivo" @@ -4831,7 +4833,7 @@ "add-visualization-body": "Seleziona un'origine dati, quindi esegui query e visualizza i dati con grafici, statistiche e tabelle o crea elenchi, markdown e altri widget.", "add-visualization-button": "Aggiungi visualizzazione", "add-visualization-header": "Avvia il tuo nuovo dashboard aggiungendo una visualizzazione", - "import-a-dashboard-body": "Importa dashboard da file o <2>grafana.com.", + "import-a-dashboard-body": "", "import-a-dashboard-header": "Importa un dashboard", "import-dashboard-button": "Importa dashboard", "show-less-dashboards": "", @@ -5289,8 +5291,8 @@ "title-provisioned": "Dashboard configurata" }, "save-dashboard-error-proxy": { - "body-name-exists": "Esiste già una dashboard con lo stesso nome nella cartella selezionata.<1><2>Desideri comunque salvare questa dashboard?", - "body-version-mismatch": "Qualcun altro ha aggiornato questa dashboard<1><2>Desideri comunque salvare questa dashboard?", + "body-name-exists": "", + "body-version-mismatch": "", "confirmText-save-and-overwrite": "Salva e sovrascrivi", "title-name-exists": "Conflitto", "title-version-mismatch": "Conflitto" @@ -5308,7 +5310,7 @@ "cancel": "Annulla", "cannot-be-saved": "Questa dashboard non può essere salvata dall'interfaccia utente di Grafana perché è stata fornita da un'altra fonte. Copia il JSON o salvalo in un file qui sotto, dopodiché potrai aggiornare la dashboard nella fonte di provisioning.", "copy-json-to-clipboard": "Copia JSON negli appunti", - "file-path": "<0>Percorso file: {{filePath}}", + "file-path": "", "save-json-to-file": "Salva JSON nel file", "see-docs": "Consulta la <2>documentazione per ulteriori informazioni sul provisioning." }, @@ -5507,7 +5509,7 @@ "transformation-picker": { "info": "Le trasformazioni ti consentono di unire, calcolare, riordinare, nascondere e rinominare i risultati della query prima che vengano visualizzati.", "info-graph-not-suitable": "Molte trasformazioni non sono adatte se si utilizza la visualizzazione Grafico, poiché attualmente questa supporta solo i dati delle serie temporali.", - "info-switch-to-table": "Può essere utile passare alla visualizzazione Tabella per saperne di più su una trasformazione. ", + "info-switch-to-table": "", "placeholder-search-for-transformation": "Cerca trasformazione", "read-more": "Scopri di più", "title-transformations": "Trasformazioni" @@ -5573,8 +5575,8 @@ "version-history-comparison": { "button-restore": "Ripristina alla versione {{version}} ", "label-view-json-diff": "Visualizza differenza JSON", - "new-updated-by": "<0>Versione {{version}} aggiornata da {{editor}} {{timeAgo}}", - "old-updated-by": "<0>Versione {{version}} aggiornata da {{editor}} {{timeAgo}}" + "new-updated-by": "", + "old-updated-by": "" }, "version-history-table": { "aria-label-toggle-selection": "Toggle di selezione della versione {{version}}", @@ -5974,7 +5976,7 @@ "cancel": "Annulla" }, "render-save-button-and-error": { - "body-plugin-dashboard": "Le modifiche andranno perse quando aggiornerai il componente aggiuntivo. Utilizza <1>Salva con nome per creare una versione personalizzata.", + "body-plugin-dashboard": "", "title-failed-to-save-dashboard": "Impossibile salvare la dashboard", "title-plugin-dashboard": "Dashboard del componente aggiuntivo", "title-someone-else-has-updated-this-dashboard": "Qualcun altro ha aggiornato questa dashboard", @@ -5983,7 +5985,7 @@ "save-and-overwrite": "\"Salva e sovrascrivi\"" }, "library-viz-panel-info": { - "last-edited": "{{timeAgo}} da ", + "last-edited": "", "usage-count_one": "Utilizzato su {{count}} dashboard", "usage-count_other": "Utilizzato su {{count}} dashboard" }, @@ -6044,7 +6046,7 @@ }, "panel-data-queries-tab-rendered": { "add-query": "Aggiungi query", - "expression": "Espressione " + "expression": "" }, "panel-data-transformations-tab": { "tab-label": "Trasformazioni" @@ -6102,7 +6104,7 @@ "query": "Query" }, "query-variable-editor-form": { - "description-examples": "I gruppi di acquisizione con nome possono essere utilizzati per separare il testo e il valore di visualizzazione (<1>vedi esempi).", + "description-examples": "", "description-optional": "Facoltativo, se desideri estrarre parte di un nome di serie o di un segmento di nodo della metrica.", "label-data-source": "Sorgente dati", "label-static-options-sort": "Ordinamento opzioni statiche", @@ -6163,7 +6165,7 @@ "label-message": "Messaggio", "placeholder-describe-changes-optional": "Aggiungi una nota per descrivere le modifiche (opzionale).", "render-footer": { - "body-plugin-dashboard": "Le modifiche andranno perse quando aggiornerai il componente aggiuntivo. Utilizza <1>Salva con nome per creare una versione personalizzata.", + "body-plugin-dashboard": "", "no-changes-to-save": "Nessuna modifica da salvare", "title-failed-to-save-dashboard": "Impossibile salvare la dashboard", "title-plugin-dashboard": "Dashboard del componente aggiuntivo", @@ -6199,7 +6201,7 @@ "cancel": "Annulla", "cannot-be-saved": "Questa dashboard non può essere salvata dall'interfaccia utente di Grafana perché è stata fornita da un'altra fonte. Copia il JSON o salvalo in un file qui sotto, dopodiché potrai aggiornare la dashboard nella fonte di provisioning.", "copy-json-to-clipboard": "Copia JSON negli appunti", - "file-path": "<0>Percorso file: {{filePath}}", + "file-path": "", "label-description": "Descrizione", "label-target-folder": "Cartella di destinazione", "label-title": "Titolo", @@ -6368,8 +6370,8 @@ }, "version-history-comparison": { "label-view-json-diff": "Visualizza differenza JSON", - "new-version-updated": "<0>Versione {{version}} aggiornata da {{editor}} {{timeAgo}}", - "old-version-updated": "<0>Versione {{version}} aggiornata da {{editor}} {{timeAgo}}" + "new-version-updated": "", + "old-version-updated": "" }, "version-history-header": { "compare-versions": "Confronto in corso {{baseVersion}} <3> {{newVersion}}", @@ -6447,7 +6449,7 @@ "provisioned-delete-modal": { "confirm-button": "OK", "text-1": "Questo dashboard è gestito dal provisioning di Grafana e non può essere eliminato. Rimuovi il dashboard dal file di configurazione per eliminarlo.", - "text-2": "Consulta la documentazione di Grafana per ulteriori informazioni sul provisioning. ", + "text-2": "", "text-3": "Percorso file: {{provisionedId}}", "text-link": "Vai alla pagina dei documenti", "title": "Impossibile eliminare il dashboard con provisioning" @@ -6525,7 +6527,7 @@ }, "data-source-testing-status-page": { "error-more-details-link": "Fai clic <2>qui per saperne di più su questo errore.", - "success-more-details-links": "Successivamente, puoi iniziare a visualizzare i dati <2>creando un dashboard o eseguendo query sui dati nella <5>vista Esplora." + "success-more-details-links": "" }, "data-sources": { "datasource-add-button": { @@ -6621,7 +6623,7 @@ "test": "Prova" }, "cloud-info-box": { - "body-alert": "Oppure puoi ignorare tutto e utilizzare {{mainDS}} (e {{extraDS}}) come origini dei dati completamente gestite, scalabili e ospitate da Grafana Labs con il <6>piano Grafana Cloud gratuito per sempre.", + "body-alert": "", "title-alert": "Configura la tua origine dei dati {{mainDS}} qui sotto" }, "dashboards-table": { @@ -6749,18 +6751,18 @@ "no-events-yet": "Ancora nessun evento" }, "render-info-viewer": { - "data-counter": "Dati: {{numDataChanges}} ", + "data-counter": "", "elapsed-time": "Tempo: {{elapsed}} ms", "field": "Campo", "last": "Ultimo", - "render-counter": "Rendering: {{numRenders}} ", - "schema-counter": "Schema: {{numSchemaChanges}} ", + "render-counter": "", + "schema-counter": "", "title-reset-counters": "Reimposta contatori", "tooltip-step-back": "Indietro", "type": "Tipo" }, "state-view": { - "current-value": "Valore corrente: {{currentValue}} ", + "current-value": "", "label-state-name": "Nome stato" } }, @@ -7207,7 +7209,7 @@ }, "footer": { "learn-more": "Scopri di più", - "pro-tip-define-sources-through-configuration-files": " Suggerimento: è inoltre possibile definire le origini dei dati tramite i file di configurazione. " + "pro-tip-define-sources-through-configuration-files": "" } }, "pane": { @@ -7269,8 +7271,6 @@ "query-deleted": "Query eliminata" }, "rich-history-queries-tab": { - "displaying-partial-queries": "{{ count }} query visualizzate", - "displaying-queries": "{{ count }} query", "filter-aria-label": "Filtra le query per origine/i dati", "filter-history": "Cronologia filtro", "filter-placeholder": "Filtra le query per origine/i dati", @@ -7280,7 +7280,11 @@ "search-placeholder": "Cerca query", "showing-queries": "{{ shown }} di {{ total }} visualizzati<0>Carica altro", "sort-aria-label": "Ordina query", - "sort-placeholder": "Ordina query per" + "sort-placeholder": "Ordina query per", + "displaying-partial-queries_one": "", + "displaying-partial-queries_other": "", + "displaying-queries_one": "", + "displaying-queries_other": "" }, "rich-history-settings-tab": { "alert-info": "Grafana manterrà le voci fino a {{optionLabel}}.Le voci preferite non verranno eliminate.", @@ -7472,7 +7476,7 @@ "copy-shortened-link-menu": "Apri le opzioni per copiare il link", "refresh-picker-cancel": "Annulla", "refresh-picker-run": "Esegui query", - "split-close": "Chiudi ", + "split-close": "", "split-close-tooltip": "Chiudi il riquadro diviso", "split-narrow": "Riduci riquadro", "split-title": "Dividi", @@ -7602,8 +7606,8 @@ }, "math": { "available-math-functions": "Funzioni matematiche disponibili", - "run-math-operations": "Esegui operazioni matematiche su una o più query. Si fa riferimento alla query tramite {{refExample}} ad es. {{ref1}}, {{ref2}}, {{ref3}} ecc.<10>Esempio: <12>{{example}}", - "tooltip-footer": "Consulta la nostra documentazione aggiuntiva su <2>Espressioni matematiche.", + "run-math-operations": "", + "tooltip-footer": "", "tooltip-title": "Operatore matematico", "tooltip-trigger": "Espressione" }, @@ -8642,7 +8646,7 @@ }, "data-source-http-settings": { "access-help": "Aiuto <1>", - "access-help-details": "La modalità di accesso controlla il modo in cui verranno gestite le richieste all'origine dati.<1> <1>Server dovrebbe essere la modalità preferita se non diversamente specificato.", + "access-help-details": "", "access-help-title": "Accedi alla Guida", "access-label": "Accedi", "allowed-cookies": "Cookie consentiti ", @@ -8910,7 +8914,7 @@ "cell-inspect": "Ispeziona valore", "cell-inspect-tooltip": "Ispeziona valore", "copy": "Copia negli appunti", - "csv-counts": "Righe: {{rows}}, Colonne: {{columns}} <5>", + "csv-counts": "", "csv-placeholder": "Inserisci qui il CSV...", "filter-placeholder": "Valori filtro", "filter-popup-apply": "Ok", @@ -9195,7 +9199,6 @@ "name-line-width": "Larghezza linea", "name-stacking": "Impilabile" }, - "inline-token-warning-badge-tooltip": "", "inspector": { "inspect-data-tab": { "loading": "Caricamento", @@ -9359,7 +9362,7 @@ "error-fetching": "Errore durante il recupero delle impostazioni LDAP", "error-saving": "Errore durante il salvataggio delle impostazioni LDAP", "error-validate-form": "Errore durante la convalida delle impostazioni LDAP", - "feature-flag-disabled": "Questa pagina è accessibile solo abilitando il flag di funzionalità <1>ssoSettingsLDAP.", + "feature-flag-disabled": "", "saved": "Impostazioni LDAP salvate" }, "bind-dn": { @@ -9400,7 +9403,7 @@ "label": "DNS di base per la ricerca", "placeholder": "esempio: dc=grafana,dc=org" }, - "subtitle": "L'integrazione LDAP in Grafana consente agli utenti di Grafana di accedere con le proprie credenziali LDAP. Scopri di più nella nostra <2><0>documentazione.", + "subtitle": "", "title": "Impostazioni di base" }, "library-panel": { @@ -9444,7 +9447,7 @@ "dashboard-name": "Nome dashboard" }, "library-panel-info": { - "last-edited": "Ultima modifica il {{timeAgo}} da ", + "last-edited": "", "usage-count_one": "Utilizzato su {{count}} dashboard", "usage-count_other": "Utilizzato su {{count}} dashboard" }, @@ -9749,7 +9752,7 @@ "tooltip-unpin-line": "Sblocca riga" }, "log-row-message": { - "ellipsis": "… ", + "ellipsis": "", "more": "altro", "see-details": "Consulta i dettagli del registro", "tooltip-error": "Errore: {{errorMessage}}" @@ -10145,7 +10148,7 @@ }, "resource-table": { "dashboard-load-error": "Impossibile caricare il dashboard", - "error-library-element-sub": "Elemento della libreria {uid}", + "error-library-element-sub": "", "error-library-element-title": "Impossibile caricare l'elemento della libreria", "unknown-datasource-title": "Origine dei dati {{datasourceUID}}", "unknown-datasource-type": "Origine dati sconosciuta" @@ -10793,10 +10796,10 @@ "placeholder-optional": "(opzionale)", "role": "Ruolo", "submit": "Invia", - "tooltip": "Ora puoi selezionare l'opzione \"Nessun ruolo di base\" e aggiungere autorizzazioni in base alle tue esigenze personalizzate. Puoi trovare maggiori informazioni nella <1>nostra documentazione." + "tooltip": "" }, "user-invite-page": { - "sub-title": "Invia un invito o aggiungi un utente Grafana esistente all'organizzazione.<1> {{orgName}}", + "sub-title": "", "text": { "invite-user": "Invita un utente" } @@ -10885,7 +10888,7 @@ "switch-to-table": "Passa alla tabella" }, "panel-plugin-error": { - "text-load-error": "Controlla i registri di avvio del server per ulteriori informazioni. <1>Se questo componente aggiuntivo è stato caricato da Git, assicurati che sia stato compilato.", + "text-load-error": "", "title-load-error": "Errore durante il caricamento: {{panelId}}", "title-not-found": "Componente aggiuntivo del pannello non trovato: {{id}}" }, @@ -11079,7 +11082,7 @@ }, "details": { "connections-tab": { - "description": "Al momento hai le seguenti origini dati configurate per {{pluginName}}, fai clic su un riquadro per visualizzare i dettagli di configurazione. Puoi trovare tutte le connessioni delle origini dati in <4><0>Connessioni - <3>Origini dati." + "description": "" }, "disabled-error": { "angular-deprecation-link": "Scopri di più sulla deprecazione di Angular", @@ -11096,7 +11099,7 @@ }, "labels": { "contactGrafanaLabs": "Contatta Grafana Labs", - "customLinks": "Collegamenti personalizzati ", + "customLinks": "", "customLinksTooltip": "Questi link sono forniti dallo sviluppatore del plug-in per offrire risorse e informazioni aggiuntive specifiche per lo sviluppatore", "dependencies": "Dipendenze", "documentation": "Documentazione", @@ -11107,7 +11110,7 @@ "latestVersion": "Versione più recente", "license": "Licenza", "raiseAnIssue": "Segnala un problema", - "reportAbuse": "Segnala un problema ", + "reportAbuse": "", "reportAbuseTooltip": "Segnala i problemi relativi a plug-in dannosi o pericolosi direttamente a Grafana Labs.", "repository": "Repository", "signature": "Firma", @@ -11117,8 +11120,8 @@ "modal": { "cancel": "Annulla", "copyEmail": "Copia indirizzo email", - "description": "Questa funzione serve per segnalare comportamenti dannosi o pericolosi all'interno dei plug-in. Per problemi relativi ai plug-in, inviaci un'email a: ", - "node": "Nota: per problemi generali relativi ai plug-in, come bug o richieste di funzionalità, contatta l'autore del plug-in utilizzando i link forniti. ", + "description": "", + "node": "", "title": "Segnala un problema relativo a un plug-in" } }, @@ -11186,7 +11189,7 @@ "message": "Tutti i plug-in sono aggiornati" }, "not-found-plugin": { - "body-plugin-not-found": "Impossibile trovare il componente aggiuntivo. Verifica che l'URL sia corretto o <1>vai al <3>catalogo dei componenti aggiuntivi.", + "body-plugin-not-found": "", "title-plugin-not-found": "Componente aggiuntivo non trovato" }, "plugin-actions": { @@ -11650,7 +11653,6 @@ "unsupported-repository-type": "" }, "inline-secure-values-warning": "", - "inline-token-warning-badge-text": "", "job-status": { "label-view-details": "Visualizza dettagli", "loading-finished-job": "Caricamento attività terminata in corso...", @@ -11827,6 +11829,17 @@ "label-current-step": "Passaggio corrente", "label-pending-step": "Passaggio in sospeso" }, + "status-badge": { + "automatic-pulling-disabled": "", + "deleting": "", + "error": "", + "pending": "", + "pulling": "", + "unknown": "", + "up-to-date": "", + "waiting-for-health-check": "", + "warning": "" + }, "success-title-default": "Operazione riuscita", "sync-job": { "error-no-job-id": "Impossibile avviare l'attività", @@ -12004,7 +12017,7 @@ "annotations-show-text": "Annotazioni = mostra", "time-range-picker-disabled-text": "Selettore intervallo di tempo = disabilitato", "time-range-picker-enabled-text": "Selettore intervallo di tempo = abilitato", - "time-range-text": "Intervallo di tempo = " + "time-range-text": "" }, "share": { "success-delete": "Il tuo dashboard non è più condivisibile" @@ -12043,7 +12056,7 @@ "revoke-user-access-modal-desc-line1": "Vuoi davvero revocare l'accesso a {{email}}?" }, "delete-user-shared-dashboards-modal": { - "revoke-user-access-modal-desc-line2": "Questa azione revoca immediatamente l'accesso a {{email}} a tutti i dashboard condivisi." + "revoke-user-access-modal-desc-line2": "" }, "modal": { "shared-dashboard-modal-title": "Dashboard condivisi" @@ -12212,7 +12225,7 @@ }, "menu": { "clear-button": "Cancella tutto", - "tooltip": "Ora puoi selezionare l'opzione \"Nessun ruolo di base\" e aggiungere autorizzazioni in base alle tue esigenze personalizzate. Puoi trovare maggiori informazioni nella <1>nostra documentazione." + "tooltip": "" }, "menu-aria-label": "Menu selettore ruoli", "menu-group-option-aria-label": "Opzione selettore ruoli", @@ -12222,7 +12235,7 @@ }, "sub-menu-aria-label": "Sottomenu selettore ruoli", "title": { - "description": "Assegna ruoli agli utenti per garantire un controllo granulare sull'accesso alle funzionalità e alle risorse di Grafana. Scopri di più nella nostra <2>documentazione." + "description": "" } }, "role-picker-drawer": { @@ -12345,7 +12358,7 @@ }, "select": { "select-menu": { - "selected-count": "Selezionato " + "selected-count": "" } }, "service-account-create-page": { @@ -12444,6 +12457,7 @@ "aria-label-role": "Ruolo" }, "service-account-tokens-table": { + "aria-label-delete-button": "", "created": "Creato", "expires": "Scade ", "last-used-at": "Ultimo utilizzo alle", @@ -12531,7 +12545,7 @@ "info-text": "Crea un link diretto a questo dashboard o pannello, personalizzato con le opzioni seguenti.", "link-url": "Collega URL", "render-alert": "Plug-in del renderer di immagini non installato", - "render-instructions": "Per eseguire il rendering di un'immagine, è necessario installare il <2>plug-in del renderer di immagini Grafana. Contatta l'amministratore di Grafana per installare il plug-in.", + "render-instructions": "", "rendered-image": "Immagine con rendering del collegamento diretto", "save-alert": "Il dashboard non è stato salvato", "save-dashboard": "Per eseguire il rendering di un'immagine del pannello, è necessario prima salvare il dashboard.", @@ -12555,7 +12569,7 @@ "info-text-1": "Un'istantanea è un modo immediato per condividere pubblicamente un dashboard interattivo. Al momento della creazione, rimuoviamo i dati sensibili come le query (metrica, modello e annotazione) e i link del pannello, lasciando solo i dati delle metriche visibili e i nomi delle serie incorporati nel dashboard.", "info-text-2": "Nota: l'istantanea <1>può essere visualizzata da chiunque sia in possesso del link e sia in grado di accedere all'URL. Fai attenzione quando la condividi.", "local-button": "Pubblica istantanea", - "mistake-message": "Hai commesso un errore? ", + "mistake-message": "", "name": "Nome istantanea", "timeout": "Timeout (secondi)", "timeout-description": "Potrebbe essere necessario configurare il valore Timeout se la raccolta delle metriche del dashboard richiede molto tempo.", @@ -13167,7 +13181,7 @@ "forwards-time-aria-label": "Usa un intervallo di tempo successivo", "to": "a", "zoom-out-button": "Riduci l'intervallo di tempo", - "zoom-out-tooltip": "Riduci l'intervallo di tempo <1> CTRL+Z" + "zoom-out-tooltip": "" }, "time-range": { "apply": "Applica intervallo di tempo", @@ -13292,7 +13306,7 @@ }, "transformations": { "empty": { - "add-transformation-body": "Le trasformazioni consentono di modificare i dati in vari modi prima che vengano mostrati nella visualizzazione.<1>Questo include l'unione dei dati, la ridenominazione dei campi, l'esecuzione di calcoli, la formattazione dei dati per la visualizzazione e altro ancora.", + "add-transformation-body": "", "add-transformation-header": "Inizia a trasformare i dati" } }, @@ -13559,7 +13573,7 @@ "label-format": "Formato", "label-set-timezone": "Imposta fuso orario", "label-time-field": "Campo dell'ora", - "tooltip-format": "Il formato di output per il campo specificato come <2>stringa di formato Moment.js.", + "tooltip-format": "", "tooltip-timezone-manually": "Imposta manualmente il fuso orario della data" }, "format-time-transformer-editor": { @@ -14154,8 +14168,8 @@ "message": "Nessun utente trovato" }, "token-revoked-modal": { - "auto-revoked": "Il token della sessione è stato revocato automaticamente perché hai raggiunto <2>il numero massimo di {{numSessions}} sessioni simultanee per il tuo account.", - "resume-message": "<0>Per riprendere la sessione, accedi di nuovo.Contatta l'amministratore o visita la pagina della licenza per verificare la tua quota se vieni disconnesso ripetutamente in modo automatico.", + "auto-revoked": "", + "resume-message": "", "sign-in": "Accedi", "title-you-have-been-automatically-signed-out": "Sei stato disconnesso automaticamente" }, diff --git a/public/locales/ja-JP/grafana.json b/public/locales/ja-JP/grafana.json index 242dde381fc..6ffbd6ef018 100644 --- a/public/locales/ja-JP/grafana.json +++ b/public/locales/ja-JP/grafana.json @@ -108,7 +108,7 @@ "dismiss": "閉じる", "heading": "エンタープライズ認証", "learn-more-link": "詳細を見る", - "text": "<1>SAML、<3>SCIM、<6>LDAP、<8>RBACを使用して、ユーザー、チーム、権限を自動的に管理できます。Grafana CloudとEnterpriseで利用可能です。" + "text": "" }, "feature-listing": { "title-auditing": "監査", @@ -209,7 +209,7 @@ "title-delete": "削除" }, "orgs": { - "delete-body": "本当に「{{deleteOrgName}}」を削除しますか?<3> <5>この組織のすべてのダッシュボードが削除されます!", + "delete-body": "", "id-header": "ID", "name-header": "名前", "new-org-button": "新しい組織" @@ -716,6 +716,7 @@ "title-annotations": "注釈" }, "link-dashboard-and-panel": "ダッシュボードとパネルをリンク", + "placeholder-value-input": "", "placeholder-value-input-default": "カスタム注釈内容を入力..." }, "bulk-actions": { @@ -1139,7 +1140,7 @@ "title-something-wrong-trying-fetch-group-details": "グループの詳細取得中に問題が発生しました" }, "evaluation-interval-limit-exceeded": { - "body-minimum-interval": "Grafanaで、最小評価間隔<1>{{minInterval}}を設定済みです。<3>より短い間隔を設定するには管理者に連絡してください。", + "body-minimum-interval": "", "title-global-evaluation-interval-limit-exceeded": "グローバル評価間隔の制限を超えました" }, "existing-rule-editor": { @@ -1287,7 +1288,7 @@ "resolved": "解決済み" } }, - "review-alert-payload": " ペイロードに追加するアラートデータを確認:", + "review-alert-payload": "", "title-add-custom-alerts": "カスタムアラートを追加" }, "get-alert-suggestions": { @@ -1411,7 +1412,7 @@ "title-add-folder-and-labels": "フォルダとラベルを追加" }, "grafana-managed-rule-type": { - "description": "あらゆる種類の複数のデータソースに対応しています。<1>式を使ってデータを変換できます。" + "description": "" }, "grafana-modify-export": { "body-invalid-rule-id": "ページURLのルールUIDが無効です。URLを確認して再試行してください。", @@ -1847,7 +1848,7 @@ "aria-label-new": "新規" }, "mimir-flavored-type": { - "description": "Mimir、Loki、またはCortexデータソースを使用してください。<1>式はサポートされていません。" + "description": "" }, "min-interval-option": { "label-interval": "間隔", @@ -2076,7 +2077,7 @@ "warning-1": "この通知ポリシーを削除すると、完全に削除されます。", "warning-2": "本当にこれを削除してもよろしいですか?" }, - "filter-description": "通知ポリシーを、カンマで区切られたマッチャーのリストを使用してフィルタリングします。例:<1>severity=critical, region=EMEA", + "filter-description": "", "generated-policies": "自動生成されたポリシー", "matchers": "マッチャー", "metadata": { @@ -2119,7 +2120,8 @@ "conflict": "通知ポリシーツリーは別のユーザーによって更新されました。", "error-code": "エラーメッセージ:「{{error}}」", "routes": { - "conflictingMatchers": "ルートを追加または更新できません:マッチャー、{{-matchers}}をマージすると、外部ルーティングツリーと競合し、このルートには到達できなくなります。" + "conflictingMatchers": "ルートを追加または更新できません:マッチャー、{{-matchers}}をマージすると、外部ルーティングツリーと競合し、このルートには到達できなくなります。", + "unknownMatchers": "" }, "suffix": "ページを更新して、やり直してください。", "title": "通知ポリシーの追加または更新に失敗しました" @@ -2236,7 +2238,7 @@ "error-no-query-editor": "次の理由によりクエリエディタを読み込めませんでした:{{errorMessage}}" }, "recording-rule-type": { - "description": "式を事前計算します。<1>アラートルールと組み合わせて使用してください。" + "description": "" }, "recording-rules": { "description-target-data-source": "記録ルールの保存先のPrometheusデータソース", @@ -2249,7 +2251,7 @@ }, "redirect-to-clone-rule": { "body-evaluation-group": "元のルールはプロビジョニングされたもので、UI上で作成したルールには使用できないため、コピーしたルールには新しい評価グループを設定する必要があります。", - "body-not-provisioned": "新しいルールはプロビジョニングされたルールとしてマーク<1>されません。", + "body-not-provisioned": "", "confirmText-copy": "コピー", "title-copy-provisioned-alert-rule": "プロビジョニングされたアラートルールをコピー" }, @@ -2284,13 +2286,13 @@ "routing-settings": { "aria-label-group-by": "グループ化", "description-group-by": "同じラベル値でグループ化することで、複数のアラートを1つの通知にまとめます。空の場合はデフォルトの通知ポリシーから継承されます。", - "group-interval": "グループ間隔:<1 >{{groupIntervalValue}}", - "group-wait": "グループ待機:<1 >{{groupWaitValue}}", - "grouping": "グループ化:<1 >{{fields}}", + "group-interval": "", + "group-wait": "", + "grouping": "", "label-group-by": "グループ化", "label-override-grouping": "グループ化を上書き", "label-override-timings": "タイミングを上書き", - "repeat-interval": "繰り返し間隔:<1 >{{repeatIntervalValue}}" + "repeat-interval": "" }, "rule-actions-buttons": { "title-edit": "編集", @@ -2542,7 +2544,7 @@ "relative-with-to": "" }, "rule-type-picker": { - "grafana-managed": "Ruler APIが有効なMimir、Loki、またはCortexデータソースがない限り、「Grafana管理」を選択してください。" + "grafana-managed": "" }, "rule-view": { "query": { @@ -2875,7 +2877,7 @@ "test-contact-point-modal": { "custom-notification-message": "以下で定義された注釈を使用してテスト通知を送信します。カスタムテンプレートやメッセージを使用する場合に適したオプションです。", "notification-message": "通知メッセージ", - "predefined-notification-message": "事前定義されたアラートを使用してテスト通知を送信します。カスタムテンプレートやメッセージを定義している場合は、上の<1>カスタム通知メッセージに切り替えるとより良い結果が得られます。", + "predefined-notification-message": "", "send-test-notification": "テスト通知を送信", "title-test-contact-point": "連絡先をテスト" }, @@ -2884,7 +2886,7 @@ }, "threshold-expression-viewer": { "input": "入力", - "stop-alerting-when": "次の場合、アラート(または保留状態)を停止する" + "stop-alerting-when": "" }, "time-interval": { "add-time-interval": "時間間隔を追加", @@ -3072,7 +3074,7 @@ "title-notification-policies": "通知ポリシー" }, "yaml-content-info": { - "body": "エディターのYAMLコンテンツにはアラートルール設定のみが含まれています。<1>Prometheusを設定するには、<4>設定ファイルの残りの部分を提供する必要があります。。" + "body": "" } }, "alertlist": { @@ -3148,7 +3150,7 @@ "no-annotations-found": "注釈が見つかりません" }, "annotation-list-item": { - "tooltip-created-by": "作成者:<1> {{email}} " + "tooltip-created-by": "" }, "category-annotation-query": "注釈クエリ", "category-display": "表示", @@ -3186,7 +3188,7 @@ }, "empty-state": { "button-title": "注釈クエリを追加", - "info-box-content": "<0>注釈は、イベントデータをグラフに統合する方法を提供します。すべてのグラフパネルで、垂直線とアイコンとして視覚化されます。注釈アイコンにカーソルを合わせると、イベントのイベントテキストとタグを取得できます。CTRLまたはCMDを押しながらグラフをクリック(または領域をドラッグ)することで、Grafanaから直接注釈イベントを追加できます。これらはGrafanaの注釈データベースに保存されます。", + "info-box-content": "", "info-box-content-2": "詳細については、<2>注釈のドキュメントをご覧ください。", "title": "カスタム注釈クエリがまだ追加されていません" }, @@ -3224,7 +3226,7 @@ "auth-settings": "認証設定" }, "auth-drawer-unconneced": { - "subtitle": "認証設定を行ってください。詳細については、<2>ドキュメントをご覧ください。" + "subtitle": "" }, "auth-drawer-unconnected": { "advanced-auth": "高度な認証", @@ -3258,7 +3260,7 @@ "allowed-organizations-description": "カンマまたはスペースで区切られた組織のリスト。ユーザーがログインするには、少なくとも\n1つの組織のメンバーである必要があります。", "allowed-organizations-label": "許可された組織", "allowed-organizations-placeholder": "組織(my-team、myteam...)を入力し、Enterキーを押して追加します", - "api-url-description": "OAuth2プロバイダーのユーザー情報エンドポイント。このエンドポイントから返される情報は<2>OpenID UserInfoと互換性がある必要があります。", + "api-url-description": "", "api-url-required": "このフィールドを設定する場合、有効なURLを入力する必要があります。", "auth-style-description": "「{{ clientIDLabel }}」と「{{ clientSecretLabel }}」がOAuth2プロバイダーに送信される方法を決定します。デフォルトは自動検出です。", "auth-style-label": "認証形式", @@ -3403,7 +3405,7 @@ } }, "auth-config-auth-config-page-unconnected": { - "subtitle": "認証設定を管理し、シングルサインオンを設定します。詳細については、<2>ドキュメントをご覧ください。" + "subtitle": "" }, "bar-chart": { "warn": { @@ -4113,7 +4115,7 @@ }, "scopes": { "apply-selected-scopes": "適用", - "selected-scopes-label": "スコープ:" + "selected-scopes-label": "" }, "search-box": { "placeholder": "検索またはジャンプ先を指定..." @@ -4255,7 +4257,7 @@ "okay": "OK" }, "not-found-datasource": { - "body": "URLの入力ミスか、ID <1> のプラグインが利用できない可能性があります。<3>利用可能なデータソース一覧を表示するには、<5>ここをクリックしてください。" + "body": "" }, "oss": { "connections-home-page": { @@ -4298,8 +4300,8 @@ "versionHistory": { "comparison": { "header": { - "hide-json-diff": "JSON diffを非表示にする ", - "show-json-diff": "JSON diffを表示する ", + "hide-json-diff": "", + "show-json-diff": "", "text": "バージョン:{{version}}、更新者:{{createdBy}}({{ageString}}){{message}}" }, "select": "比較を開始する2つのバージョンを選択してください" @@ -4326,7 +4328,7 @@ "label-label": "ラベル", "label-placeholder": "例:テンポトレース", "label-required": "このフィールドは必須です。", - "sub-text": "<0>相関関係を説明するテキストを定義してください。", + "sub-text": "", "title": "相関ラベルを定義する(ステップ1/3)" }, "configure-correlation-target-form": { @@ -4370,7 +4372,7 @@ }, "source-form": { "control-required": "このフィールドは必須です。", - "description": "データポイントは、すべての変数に値をフィールドとして、または相関ボタンを視覚化に表示するための変換出力として提供する必要があります。<1>注:すべての変数を以下に明示的に定義する必要はありません。<4>logfmtなどの変換は、すべてのキー/値ペアに対して変数を作成します。", + "description": "", "description-external-pre": "ターゲットURLで次の変数を使用しました。", "description-query-pre": "ターゲットクエリで次の変数を使用しました。", "external-title": "URLを使用するデータソースを構成する(ステップ3/3)", @@ -4382,12 +4384,12 @@ "results-required": "このフィールドは必須です。", "source-description": "選択したソースデータソースからの結果には、パネルにリンクが表示されます", "source-label": "送信元", - "sub-text": "<0>どのデータソースが相関を表示するか、どのデータが以前に定義された変数を置き換えるかを定義します。" + "sub-text": "" }, "sub-title": "異なるデータソースに存在するデータがどのように相互に関連しているかを定義します。詳細については、<2>ドキュメントをご参照ください。", "target-form": { "control-rules": "このフィールドは必須です。", - "sub-text": "<0>相関がリンクするものを定義します。クエリタイプを使用すると、相関がクリックされたときにクエリが実行されます。外部タイプでは、相関をクリックするとURLが開きます。", + "sub-text": "", "target-description-external": "リンクがクリックされたときに開くURLを指定します", "target-description-query": "リンクがクリックされたときにクエリを実行するデータソースを指定します", "target-label": "ターゲット", @@ -4594,7 +4596,7 @@ } }, "confirm-plugin-dashboard-save-modal": { - "body-plugin-dashboard": "プラグインを更新すると、変更は失われます。<1><2>カスタムバージョンを作成するには、<1>名前を付けて保存を使用してください。", + "body-plugin-dashboard": "", "cancel": "キャンセル", "overwrite": "上書き", "title-plugin-dashboard": "プラグインダッシュボード" @@ -4811,7 +4813,7 @@ "add-visualization-body": "データソースを選択し、グラフ、統計、テーブルを使用してデータをクエリおよび視覚化するか、リスト、マークダウン、その他のウィジェットを作成します。", "add-visualization-button": "視覚化を追加", "add-visualization-header": "視覚化を追加して新しいダッシュボードを開始します", - "import-a-dashboard-body": "ファイルまたは<1>grafana.comからダッシュボードをインポートします。", + "import-a-dashboard-body": "", "import-a-dashboard-header": "ダッシュボードをインポートする", "import-dashboard-button": "ダッシュボードをインポート", "show-less-dashboards": "", @@ -5268,8 +5270,8 @@ "title-provisioned": "プロビジョニング済みダッシュボード" }, "save-dashboard-error-proxy": { - "body-name-exists": "選択したフォルダには同じ名前のダッシュボードがすでに存在します。<1><2>このダッシュボードの保存を続行しますか?", - "body-version-mismatch": "他のユーザーがこのダッシュボードを更新しました<1><2>このダッシュボードを保存しますか?", + "body-name-exists": "", + "body-version-mismatch": "", "confirmText-save-and-overwrite": "保存して上書き", "title-name-exists": "競合", "title-version-mismatch": "競合" @@ -5287,7 +5289,7 @@ "cancel": "キャンセル", "cannot-be-saved": "このダッシュボードは別のソースからプロビジョニングされているため、Grafana UIからは保存できません。JSONをコピーするか下記のファイルに保存した上で、プロビジョニング元でダッシュボードを更新できます。", "copy-json-to-clipboard": "JSONをクリップボードにコピー", - "file-path": "<0>ファイルパス: {{filePath}}", + "file-path": "", "save-json-to-file": "JSONをファイルに保存", "see-docs": "プロビジョニングについての詳細は<2>ドキュメントをご覧ください。" }, @@ -5486,7 +5488,7 @@ "transformation-picker": { "info": "変換機能を使用すると、視覚化する前にクエリ結果の結合、計算、並べ替え、非表示、名前変更ができます。", "info-graph-not-suitable": "現在、グラフ表示は時系列データのみに対応しているため、多くの変換機能は適していません。", - "info-switch-to-table": "変換によって何が起こっているかを理解するには、テーブル表示に切り替えることをお勧めします。", + "info-switch-to-table": "", "placeholder-search-for-transformation": "変換を検索", "read-more": "続きを読む", "title-transformations": "変換" @@ -5552,8 +5554,8 @@ "version-history-comparison": { "button-restore": "バージョン、{{version}}に復元", "label-view-json-diff": "JSON差分を表示", - "new-updated-by": "<0>バージョン{{version}}、{{editor}}が{{timeAgo}}に更新", - "old-updated-by": "<0>バージョン{{version}}、{{editor}}が{{timeAgo}}に更新" + "new-updated-by": "", + "old-updated-by": "" }, "version-history-table": { "aria-label-toggle-selection": "バージョン{{version}}の選択を切り替え", @@ -5953,7 +5955,7 @@ "cancel": "キャンセル" }, "render-save-button-and-error": { - "body-plugin-dashboard": "プラグイン更新時に変更は失われます。カスタムバージョンを作成するには、<1>名前を付けて保存を使用してください。", + "body-plugin-dashboard": "", "title-failed-to-save-dashboard": "ダッシュボードを保存できませんでした", "title-plugin-dashboard": "プラグインダッシュボード", "title-someone-else-has-updated-this-dashboard": "他のユーザーがこのダッシュボードを更新しました", @@ -5962,7 +5964,7 @@ "save-and-overwrite": "「保存して上書き」" }, "library-viz-panel-info": { - "last-edited": "が{{timeAgo}}に実施", + "last-edited": "", "usage-count_other": "{{count}}件のダッシュボードで使用中" }, "managed-badge": { @@ -6022,7 +6024,7 @@ }, "panel-data-queries-tab-rendered": { "add-query": "クエリを追加", - "expression": "式" + "expression": "" }, "panel-data-transformations-tab": { "tab-label": "変換" @@ -6080,7 +6082,7 @@ "query": "クエリ" }, "query-variable-editor-form": { - "description-examples": "名前付きキャプチャグループを使用すると、表示テキストと値を分けることができます(<1>例を参照)。", + "description-examples": "", "description-optional": "シリーズ名やメトリックノードセグメントの一部を抽出したい場合の任意設定です。", "label-data-source": "データソース", "label-static-options-sort": "スタティックオプションの並び替え", @@ -6141,7 +6143,7 @@ "label-message": "メッセージ", "placeholder-describe-changes-optional": "変更内容を説明するメモを追加してください(任意)。", "render-footer": { - "body-plugin-dashboard": "プラグイン更新時に変更は失われます。カスタムバージョンを作成するには、<1>名前を付けて保存を使用してください。", + "body-plugin-dashboard": "", "no-changes-to-save": "保存する変更はありません", "title-failed-to-save-dashboard": "ダッシュボードを保存できませんでした", "title-plugin-dashboard": "プラグインダッシュボード", @@ -6176,7 +6178,7 @@ "cancel": "キャンセル", "cannot-be-saved": "このダッシュボードは別のソースからプロビジョニングされているため、Grafana UIからは保存できません。JSONをコピーするか下記のファイルに保存した上で、プロビジョニング元でダッシュボードを更新できます。", "copy-json-to-clipboard": "JSONをクリップボードにコピー", - "file-path": "<0>ファイルパス: {{filePath}}", + "file-path": "", "label-description": "説明", "label-target-folder": "ターゲットフォルダ", "label-title": "タイトル", @@ -6345,8 +6347,8 @@ }, "version-history-comparison": { "label-view-json-diff": "JSON差分を表示", - "new-version-updated": "<0>バージョン{{version}}、{{editor}}が{{timeAgo}}に更新", - "old-version-updated": "<0>バージョン{{version}}、{{editor}}が{{timeAgo}}に更新" + "new-version-updated": "", + "old-version-updated": "" }, "version-history-header": { "compare-versions": "{{baseVersion}}<3>と{{newVersion}}を比較", @@ -6424,7 +6426,7 @@ "provisioned-delete-modal": { "confirm-button": "OK", "text-1": "このダッシュボードはGrafanaプロビジョニングによって管理されており、削除できません。構成ファイルからダッシュボードを削除して削除します。", - "text-2": "プロビジョニングの詳細については、grafanaのドキュメントを参照してください。", + "text-2": "", "text-3": "ファイルパス:{{provisionedId}}", "text-link": "ドキュメントページへ移動", "title": "プロビジョニングされたダッシュボードを削除できません" @@ -6502,7 +6504,7 @@ }, "data-source-testing-status-page": { "error-more-details-link": "このエラーの詳細については、<2>こちらをクリックしてください。", - "success-more-details-links": "次に、<2>ダッシュボードを構築するか、<5>Exploreビューでデータをクエリすることで、データの視覚化を開始できます。" + "success-more-details-links": "" }, "data-sources": { "datasource-add-button": { @@ -6598,7 +6600,7 @@ "test": "テスト" }, "cloud-info-box": { - "body-alert": "または、<6>永久無料のGrafana Cloudプランで、Grafana Labsからフルマネージドでスケーラブルなホスト済みデータソースの{{mainDS}}(および{{extraDS}})を入手して、手間を省くことも可能です。", + "body-alert": "", "title-alert": "以下で{{mainDS}}データソースを設定します" }, "dashboards-table": { @@ -6726,18 +6728,18 @@ "no-events-yet": "まだイベントはありません" }, "render-info-viewer": { - "data-counter": "データ: {{numDataChanges}} ", + "data-counter": "", "elapsed-time": "時間: {{elapsed}}ミリ秒", "field": "フィールド", "last": "最新", - "render-counter": "レンダリング: {{numRenders}} ", - "schema-counter": "スキーマ: {{numSchemaChanges}} ", + "render-counter": "", + "schema-counter": "", "title-reset-counters": "カウンターをリセット", "tooltip-step-back": "戻る", "type": "種類" }, "state-view": { - "current-value": "現在の値: {{currentValue}} ", + "current-value": "", "label-state-name": "状態名" } }, @@ -7184,7 +7186,7 @@ }, "footer": { "learn-more": "詳細を見る", - "pro-tip-define-sources-through-configuration-files": "豆知識:設定ファイルでもデータソースを定義できます。" + "pro-tip-define-sources-through-configuration-files": "" } }, "pane": { @@ -7246,8 +7248,6 @@ "query-deleted": "クエリが削除されました" }, "rich-history-queries-tab": { - "displaying-partial-queries": "{{ count }}件のクエリを表示しています", - "displaying-queries": "{{ count }}件のクエリ", "filter-aria-label": "データソースのクエリをフィルタリングします", "filter-history": "履歴をフィルタリング", "filter-placeholder": "データソースのクエリをフィルタリングします", @@ -7257,7 +7257,9 @@ "search-placeholder": "クエリを検索", "showing-queries": "{{ total }}件中{{ shown }}件を表示中 <0>さらに表示", "sort-aria-label": "クエリを並べ替え", - "sort-placeholder": "次でクエリを並べ替え" + "sort-placeholder": "次でクエリを並べ替え", + "displaying-partial-queries_other": "", + "displaying-queries_other": "" }, "rich-history-settings-tab": { "alert-info": "Grafanaはエントリを最大{{optionLabel}}件まで保持します。スター付きのエントリは削除されません。", @@ -7449,7 +7451,7 @@ "copy-shortened-link-menu": "コピーリンクのオプションを開く", "refresh-picker-cancel": "キャンセル", "refresh-picker-run": "クエリの実行", - "split-close": "閉める", + "split-close": "", "split-close-tooltip": "分割ペインを閉じる", "split-narrow": "狭いペイン", "split-title": "分割", @@ -7579,8 +7581,8 @@ }, "math": { "available-math-functions": "利用可能な数学関数", - "run-math-operations": "1つ以上のクエリで数学演算を実行します。クエリは{{refExample}}(つまり{{ref1}}、{{ref2}}、{{ref3}}など)で参照できます。<10>例:<12>{{example}}", - "tooltip-footer": "<2>数式に関する追加ドキュメントをご覧ください。", + "run-math-operations": "", + "tooltip-footer": "", "tooltip-title": "数学演算子", "tooltip-trigger": "式" }, @@ -8609,7 +8611,7 @@ }, "data-source-http-settings": { "access-help": "<1>をヘルプ", - "access-help-details": "アクセスモードは、データソースへの要求の処理方法を制御します。特に明記されていない場合は、<1><1>サーバーが望ましい方法です。", + "access-help-details": "", "access-help-title": "ヘルプにアクセス", "access-label": "アクセス", "allowed-cookies": "許可されたクッキー", @@ -8877,7 +8879,7 @@ "cell-inspect": "値を検査", "cell-inspect-tooltip": "値を検査", "copy": "クリップボードにコピー", - "csv-counts": "行:{{rows}}、列:{{columns}} <5>", + "csv-counts": "", "csv-placeholder": "ここにCSVを入力...", "filter-placeholder": "値をフィルタリング", "filter-popup-apply": "OK", @@ -9162,7 +9164,6 @@ "name-line-width": "線の太さ", "name-stacking": "積み上げ" }, - "inline-token-warning-badge-tooltip": "", "inspector": { "inspect-data-tab": { "loading": "読込中", @@ -9324,7 +9325,7 @@ "error-fetching": "LDAP設定の取得中にエラーが発生しました", "error-saving": "LDAP設定の保存中にエラーが発生", "error-validate-form": "LDAP設定の検証中にエラーが発生しました", - "feature-flag-disabled": "このページにアクセスできるのは、<1>ssoSettingsLDAP機能フラグを有効にする場合のみです。", + "feature-flag-disabled": "", "saved": "LDAP設定を保存しました" }, "bind-dn": { @@ -9365,7 +9366,7 @@ "label": "検索ベースDNS", "placeholder": "例:dc=grafana,dc=org" }, - "subtitle": "GrafanaのLDAP統合により、GrafanaユーザーはLDAP認証情報を使用してログインできます。詳細については、<2><0>ドキュメントをご覧ください。", + "subtitle": "", "title": "基本設定" }, "library-panel": { @@ -9409,7 +9410,7 @@ "dashboard-name": "ダッシュボード名" }, "library-panel-info": { - "last-edited": "が{{timeAgo}}に最終編集", + "last-edited": "", "usage-count_other": "{{count}}件のダッシュボードで使用中" }, "library-panels-search": { @@ -9708,7 +9709,7 @@ "tooltip-unpin-line": "行のピン留めを解除" }, "log-row-message": { - "ellipsis": "… ", + "ellipsis": "", "more": "さらに", "see-details": "ログの詳細を見る", "tooltip-error": "エラー:{{errorMessage}}" @@ -10104,7 +10105,7 @@ }, "resource-table": { "dashboard-load-error": "ダッシュボードを読み込めません", - "error-library-element-sub": "ライブラリ要素{uid}", + "error-library-element-sub": "", "error-library-element-title": "ライブラリ要素を読み込めません", "unknown-datasource-title": "データソース{{datasourceUID}}", "unknown-datasource-type": "不明なデータソース" @@ -10749,10 +10750,10 @@ "placeholder-optional": "(任意)", "role": "ロール", "submit": "送信", - "tooltip": "「基本的な役割なし」オプションを選択し、カスタムニーズに権限を追加できるようになりました。詳細については、<1>ドキュメントをご覧ください。" + "tooltip": "" }, "user-invite-page": { - "sub-title": "招待状を送信するか、既存のGrafanaユーザーを組織<1>{{orgName}}に追加します。", + "sub-title": "", "text": { "invite-user": "ユーザーを招待" } @@ -10841,7 +10842,7 @@ "switch-to-table": "テーブルに切り替え" }, "panel-plugin-error": { - "text-load-error": "詳細はサーバーの起動ログを確認してください。<1>このプラグインがGitから読み込まれた場合は、コンパイルされていることを確認してください。", + "text-load-error": "", "title-load-error": "読み込みエラー:{{panelId}}", "title-not-found": "パネルプラグインが見つかりません:{{id}}" }, @@ -11035,7 +11036,7 @@ }, "details": { "connections-tab": { - "description": "現在、次のデータソースが{{pluginName}}に設定されています。タイルをクリックして、設定の詳細を表示します。すべてのデータソース接続は、<4><0>接続 - <3>データソースにあります。" + "description": "" }, "disabled-error": { "angular-deprecation-link": "Angularの非推奨事項の詳細を読む", @@ -11052,7 +11053,7 @@ }, "labels": { "contactGrafanaLabs": "Grafana Labsに問い合わせる", - "customLinks": "カスタムリンク", + "customLinks": "", "customLinksTooltip": "これらのリンクは、プラグイン開発者が提供する、開発者向けの追加リソースと情報です。", "dependencies": "依存関係", "documentation": "ドキュメント", @@ -11063,7 +11064,7 @@ "latestVersion": "最新のバージョン", "license": "ライセンス", "raiseAnIssue": "問題を提起する", - "reportAbuse": "懸念事項を報告する ", + "reportAbuse": "", "reportAbuseTooltip": "悪意のあるプラグインや有害なプラグインに関連する問題は、Grafana Labsに直接報告してください。", "repository": "レポジトリ", "signature": "署名", @@ -11073,8 +11074,8 @@ "modal": { "cancel": "キャンセル", "copyEmail": "メールアドレスをコピー", - "description": "この機能は、プラグイン内の悪意のある動作や有害な動作を報告するためのもの機能です。プラグインに関するご質問は、次までメールでお問い合わせください。", - "node": "注:バグや機能リクエストなどの一般的なプラグインの問題については、提供されているリンクを使用してプラグインの作成者にお問い合わせください。", + "description": "", + "node": "", "title": "プラグインの懸念事項を報告する" } }, @@ -11142,7 +11143,7 @@ "message": "すべてのプラグインが最新です" }, "not-found-plugin": { - "body-plugin-not-found": "プラグインが見つかりません。URLが正しいことを確認するか、<3>プラグインカタログにアクセスしてください。", + "body-plugin-not-found": "", "title-plugin-not-found": "プラグインが見つかりません" }, "plugin-actions": { @@ -11600,7 +11601,6 @@ "unsupported-repository-type": "" }, "inline-secure-values-warning": "", - "inline-token-warning-badge-text": "", "job-status": { "label-view-details": "詳細を表示", "loading-finished-job": "完了したジョブを読み込み中...", @@ -11777,6 +11777,17 @@ "label-current-step": "現在のステップ", "label-pending-step": "保留中のステップ" }, + "status-badge": { + "automatic-pulling-disabled": "", + "deleting": "", + "error": "", + "pending": "", + "pulling": "", + "unknown": "", + "up-to-date": "", + "waiting-for-health-check": "", + "warning": "" + }, "success-title-default": "成功", "sync-job": { "error-no-job-id": "ジョブを開始できませんでした", @@ -11954,7 +11965,7 @@ "annotations-show-text": "注釈 = 表示", "time-range-picker-disabled-text": "時間範囲ピッカー = 無効", "time-range-picker-enabled-text": "時間範囲ピッカー = 有効", - "time-range-text": "時間範囲 = " + "time-range-text": "" }, "share": { "success-delete": "ダッシュボードは共有できなくなりました" @@ -11993,7 +12004,7 @@ "revoke-user-access-modal-desc-line1": "{{email}}のアクセス権を取り消してもよろしいです か?" }, "delete-user-shared-dashboards-modal": { - "revoke-user-access-modal-desc-line2": "このアクションにより、{{email}}は、すべての共有ダッシュボードへのアクセスが即座に取り消されます。" + "revoke-user-access-modal-desc-line2": "" }, "modal": { "shared-dashboard-modal-title": "共有したダッシュボード" @@ -12159,7 +12170,7 @@ }, "menu": { "clear-button": "すべてをクリア", - "tooltip": "「基本的な役割なし」オプションを選択し、カスタムニーズに権限を追加できるようになりました。詳細については、<1>ドキュメントをご覧ください。" + "tooltip": "" }, "menu-aria-label": "ロール選択ツールメニュー", "menu-group-option-aria-label": "ロール選択オプション", @@ -12169,7 +12180,7 @@ }, "sub-menu-aria-label": "ロール選択ツールのサブメニュー", "title": { - "description": "Grafanaの機能とリソースへのアクセスを細かく制御するために、ユーザーに役割を割り当てます。詳細については、<2>ドキュメントをご覧ください。" + "description": "" } }, "role-picker-drawer": { @@ -12292,7 +12303,7 @@ }, "select": { "select-menu": { - "selected-count": "選択中" + "selected-count": "" } }, "service-account-create-page": { @@ -12391,6 +12402,7 @@ "aria-label-role": "ロール" }, "service-account-tokens-table": { + "aria-label-delete-button": "", "created": "作成済み", "expires": "有効期限", "last-used-at": "最終使用日時", @@ -12477,7 +12489,7 @@ "info-text": "以下のオプションでカスタマイズした、このダッシュボードまたはパネルへの直接リンクを作成します。", "link-url": "URLをリンク", "render-alert": "画像レンダラープラグインがインストールされていません", - "render-instructions": "画像をレンダリングするには、<2>Grafana画像レンダラープラグインをインストールする必要があります。プラグインをインストールするには、Grafana管理者にお問い合わせください。", + "render-instructions": "", "rendered-image": "レンダリングされた画像への直接リンク", "save-alert": "ダッシュボードは保存されていません", "save-dashboard": "パネル画像をレンダリングするには、最初にダッシュボードを保存する必要があります。", @@ -12501,7 +12513,7 @@ "info-text-1": "スナップショットは、インタラクティブなダッシュボードを瞬時に公開できる方法です。作成時に、クエリ(メトリック、テンプレート、および注釈)やパネルリンクなどの機密データを削除し、可視化されたメトリックデータと系列名のみをダッシュボードに埋め込みます。", "info-text-2": "スナップショットは、リンクがあり、URLにアクセスできる<1>誰でも閲覧できることにご注意ください。賢明に共有してください。", "local-button": "スナップショットを公開", - "mistake-message": "間違えましたか?", + "mistake-message": "", "name": "スナップショット名", "timeout": "タイムアウト(秒)", "timeout-description": "ダッシュボードメトリックの収集に時間がかかる場合は、タイムアウト値を設定する必要があります。", @@ -13112,7 +13124,7 @@ "forwards-time-aria-label": "時間範囲を前に移動", "to": "へ", "zoom-out-button": "時間範囲をズームアウト", - "zoom-out-tooltip": "時間範囲ズームアウト <1> CTRL+Z" + "zoom-out-tooltip": "" }, "time-range": { "apply": "時間範囲を適用", @@ -13237,7 +13249,7 @@ }, "transformations": { "empty": { - "add-transformation-body": "変換を使用すると、視覚化が表示される前にさまざまな方法でデータを変更できます。<1>これには、データの結合、フィールド名の変更、計算、表示用のデータのフォーマットなどが含まれます。", + "add-transformation-body": "", "add-transformation-header": "データの変換を開始" } }, @@ -13504,7 +13516,7 @@ "label-format": "形式", "label-set-timezone": "タイムゾーンを設定", "label-time-field": "時間フィールド", - "tooltip-format": "<2>Moment.js形式文字列として指定されたフィールドの出力形式。", + "tooltip-format": "", "tooltip-timezone-manually": "日付のタイムゾーンを手動で設定" }, "format-time-transformer-editor": { @@ -14099,8 +14111,8 @@ "message": "ユーザーが見つかりません" }, "token-revoked-modal": { - "auto-revoked": "アカウントの<2>同時セッション数の上限({{numSessions}}件)に達したため、セッショントークンは自動的に失効しました。", - "resume-message": "<0>セッションを再開するには、もう一度サインインしてください。自動的にサインアウトが繰り返される場合は、管理者に連絡するか、ライセンスページでクォータを確認してください。", + "auto-revoked": "", + "resume-message": "", "sign-in": "サインイン", "title-you-have-been-automatically-signed-out": "自動的にサインアウトされました" }, diff --git a/public/locales/ko-KR/grafana.json b/public/locales/ko-KR/grafana.json index 1818ac731f6..80dee79c3a2 100644 --- a/public/locales/ko-KR/grafana.json +++ b/public/locales/ko-KR/grafana.json @@ -108,7 +108,7 @@ "dismiss": "닫기", "heading": "엔터프라이즈 인증", "learn-more-link": "자세히 알아보기", - "text": "Grafana Cloud 및 Enterprise에서 사용할 수 있는 <1>SAML, <3>SCIM, <6>LDAP, <8>RBAC를 사용하여 사용자, 팀, 권한을 자동으로 관리합니다." + "text": "" }, "feature-listing": { "title-auditing": "감사", @@ -209,7 +209,7 @@ "title-delete": "삭제" }, "orgs": { - "delete-body": "정말 '{{deleteOrgName}}'을(를) 삭제하시겠어요?<3> <5>이 조직의 모든 대시보드가 제거됩니다!", + "delete-body": "", "id-header": "ID", "name-header": "이름", "new-org-button": "새 조직" @@ -716,6 +716,7 @@ "title-annotations": "주석" }, "link-dashboard-and-panel": "대시보드 및 패널 연결", + "placeholder-value-input": "", "placeholder-value-input-default": "사용자 지정 주석 내용을 입력하세요..." }, "bulk-actions": { @@ -1139,7 +1140,7 @@ "title-something-wrong-trying-fetch-group-details": "그룹 세부 정보를 가져오는 중에 문제가 발생했습니다" }, "evaluation-interval-limit-exceeded": { - "body-minimum-interval": "Grafana에서 <1>{{minInterval}}의 최소 평가 간격이 구성되었습니다.<3>간격을 더 짧게 구성하려면 관리자에게 문의하세요.", + "body-minimum-interval": "", "title-global-evaluation-interval-limit-exceeded": "전역 평가 간격 한도 초과됨" }, "existing-rule-editor": { @@ -1287,7 +1288,7 @@ "resolved": "해결됨" } }, - "review-alert-payload": " 페이로드에 추가할 경고 데이터 검토:", + "review-alert-payload": "", "title-add-custom-alerts": "사용자 지정 경고 추가" }, "get-alert-suggestions": { @@ -1411,7 +1412,7 @@ "title-add-folder-and-labels": "폴더 및 라벨 추가" }, "grafana-managed-rule-type": { - "description": "모든 종류의 여러 데이터 소스를 지원합니다.<1>표현식으로 데이터를 변환합니다." + "description": "" }, "grafana-modify-export": { "body-invalid-rule-id": "페이지 URL의 규칙 UID가 유효하지 않습니다. URL을 확인한 후 다시 시도하세요.", @@ -1847,7 +1848,7 @@ "aria-label-new": "신규" }, "mimir-flavored-type": { - "description": "Mimir, Loki 또는 Cortex 데이터 소스를 사용합니다.<1>표현식은 지원되지 않습니다." + "description": "" }, "min-interval-option": { "label-interval": "간격", @@ -2076,7 +2077,7 @@ "warning-1": "이 알림 정책을 삭제하면 영구적으로 제거됩니다.", "warning-2": "정말로 이 정책을 삭제하시겠어요?" }, - "filter-description": "다음과 같이 쉼표로 구분된 일치 조건의 목록을 사용하여 알림 정책을 필터링합니다. <1>심각도=심각, 지역=EMEA", + "filter-description": "", "generated-policies": "자동 생성된 정책", "matchers": "일치 조건", "metadata": { @@ -2119,7 +2120,8 @@ "conflict": "알림 정책 트리가 다른 사용자에 의해 업데이트되었습니다.", "error-code": "오류 메시지: '{{error}}'", "routes": { - "conflictingMatchers": "라우트를 추가하거나 업데이트할 수 없습니다. {{-matchers}} 일치 조건을 병합하면 일치 조건이 외부 라우팅 트리와 충돌하여 해당 라우트에 접근할 수 없게 됩니다." + "conflictingMatchers": "라우트를 추가하거나 업데이트할 수 없습니다. {{-matchers}} 일치 조건을 병합하면 일치 조건이 외부 라우팅 트리와 충돌하여 해당 라우트에 접근할 수 없게 됩니다.", + "unknownMatchers": "" }, "suffix": "페이지를 새로고침한 후 다시 시도해 주세요.", "title": "알림 정책을 추가하거나 업데이트하지 못했습니다" @@ -2236,7 +2238,7 @@ "error-no-query-editor": "{{errorMessage}}(으)로 인해 쿼리 편집기를 로딩할 수 없습니다" }, "recording-rule-type": { - "description": "표현식을 미리 계산합니다.<1>경고 규칙과 결합해야 합니다." + "description": "" }, "recording-rules": { "description-target-data-source": "기록 규칙을 저장할 Prometheus 데이터 소스", @@ -2249,7 +2251,7 @@ }, "redirect-to-clone-rule": { "body-evaluation-group": "원본 규칙이 프로비저닝되어 UI에서 생성된 규칙에 사용할 수 없으므로 복사한 규칙에 대한 새 평가 그룹을 설정해야 합니다.", - "body-not-provisioned": "새 규칙은 프로비저닝된 규칙으로 표시되지 <1>않습니다.", + "body-not-provisioned": "", "confirmText-copy": "복사", "title-copy-provisioned-alert-rule": "프로비저닝된 경고 규칙 복사" }, @@ -2284,13 +2286,13 @@ "routing-settings": { "aria-label-group-by": "그룹화 기준", "description-group-by": "동일한 라벨 값을 기준으로 그룹화하여 여러 개의 경고를 하나의 알림으로 결합합니다. 비어 있는 경우 기본 알림 정책에서 상속됩니다.", - "group-interval": "그룹 간격: <1>{{groupIntervalValue}}", - "group-wait": "그룹 대기: <1>{{groupWaitValue}}", - "grouping": "그룹화: <1>{{fields}}", + "group-interval": "", + "group-wait": "", + "grouping": "", "label-group-by": "그룹화 기준", "label-override-grouping": "그룹화 재정의", "label-override-timings": "타이밍 재정의", - "repeat-interval": "반복 간격: <1>{{repeatIntervalValue}}" + "repeat-interval": "" }, "rule-actions-buttons": { "title-edit": "편집", @@ -2542,7 +2544,7 @@ "relative-with-to": "" }, "rule-type-picker": { - "grafana-managed": "Ruler API가 활성화된 Mimir, Loki 또는 Cortex 데이터 소스가 없는 경우 “Grafana 관리형”을 선택합니다." + "grafana-managed": "" }, "rule-view": { "query": { @@ -2875,7 +2877,7 @@ "test-contact-point-modal": { "custom-notification-message": "아래에 정의된 주석을 사용하는 테스트 알림을 전송합니다. 사용자 정의 템플릿 및 메시지를 사용하는 경우 이 옵션이 좋습니다.", "notification-message": "알림 메시지", - "predefined-notification-message": "미리 정의된 경고를 사용하는 테스트 알림을 전송합니다. 정의해 둔 사용자 지정 템플릿 또는 메시지가 있다면, 위에서 <1>사용자 지정 알림 메시지로 전환하여 더 나은 결과를 얻을 수 있습니다.", + "predefined-notification-message": "", "send-test-notification": "테스트 알림 전송", "title-test-contact-point": "연락처 테스트" }, @@ -2884,7 +2886,7 @@ }, "threshold-expression-viewer": { "input": "입력", - "stop-alerting-when": "다음 경우 경고(또는 보류 상태) 중지 " + "stop-alerting-when": "" }, "time-interval": { "add-time-interval": "시간 간격 추가", @@ -3072,7 +3074,7 @@ "title-notification-policies": "알림 정책" }, "yaml-content-info": { - "body": "편집기의 YAML 콘텐츠에는 경고 규칙 구성만 포함되어 있습니다. <1>Prometheus를 구성하려면 <4>구성 파일 콘텐츠의 나머지 부분을 제공해야 합니다." + "body": "" } }, "alertlist": { @@ -3148,7 +3150,7 @@ "no-annotations-found": "주석을 찾을 수 없습니다." }, "annotation-list-item": { - "tooltip-created-by": "작성자:<1> {{email}} " + "tooltip-created-by": "" }, "category-annotation-query": "주석 쿼리", "category-display": "디스플레이", @@ -3186,7 +3188,7 @@ }, "empty-state": { "button-title": "주석 쿼리 추가", - "info-box-content": "<0>주석은 이벤트 데이터를 그래프에 통합하는 방법을 제공합니다. 이는 모든 그래프 패널에서 세로 선과 아이콘으로 시각화됩니다. 주석 아이콘 위에 마우스를 갖다대면 이벤트에 대한 이벤트 텍스트와 태그를 확인할 수 있습니다. CTRL 또는 CMD를 누른 상태에서 그래프를 클릭(또는 영역을 드래그)하면 Grafana에서 바로 주석 이벤트를 추가할 수 있습니다. 이 정보는 Grafana의 주석 데이터베이스에 저장됩니다.", + "info-box-content": "", "info-box-content-2": "자세한 내용은 <2>주석 문서를 확인하세요.", "title": "아직 추가된 사용자 정의 주석 쿼리 없음" }, @@ -3224,7 +3226,7 @@ "auth-settings": "인증 설정" }, "auth-drawer-unconneced": { - "subtitle": "인증 설정을 구성합니다. 자세한 내용은 Grafana의 <2>문서를 확인하세요." + "subtitle": "" }, "auth-drawer-unconnected": { "advanced-auth": "고급 인증", @@ -3258,7 +3260,7 @@ "allowed-organizations-description": "쉼표 또는 공백으로 구분된 조직 목록입니다. 사용자가 로그인하려면 하나 이상의\n조직의 멤버여야 합니다.", "allowed-organizations-label": "허용된 조직", "allowed-organizations-placeholder": "조직(my-team, myteam...)을 입력하고 엔터 키를 눌러 추가", - "api-url-description": "OAuth2 제공자의 사용자 정보 엔드포인트입니다. 이 엔드포인트에서 반환되는 정보는 <2>OpenID UserInfo와 호환되어야 합니다.", + "api-url-description": "", "api-url-required": "설정된 경우 이 필드는 유효한 URL이어야 합니다.", "auth-style-description": "\"{{ clientIDLabel }}\" 및 \"{{ clientSecretLabel }}\"이(가) Oauth2 제공자에 전송되는 방식을 결정합니다. 기본값은 AutoDetect입니다.", "auth-style-label": "인증 스타일", @@ -3403,7 +3405,7 @@ } }, "auth-config-auth-config-page-unconnected": { - "subtitle": "인증 설정을 관리하고 싱글 사인온을 구성하세요. 자세한 내용은 Grafana의 <2>문서를 확인하세요." + "subtitle": "" }, "bar-chart": { "warn": { @@ -4113,7 +4115,7 @@ }, "scopes": { "apply-selected-scopes": "적용", - "selected-scopes-label": "범위: " + "selected-scopes-label": "" }, "search-box": { "placeholder": "검색 또는 다음으로 건너뛰기..." @@ -4255,7 +4257,7 @@ "okay": "확인" }, "not-found-datasource": { - "body": "URL을 잘못 입력했거나 ID가 <1>인 플러그인이 사용 불가능한 것일 수 있습니다.<3>사용 가능한 데이터 소스 목록을 보려면 <5>여기를 클릭하세요." + "body": "" }, "oss": { "connections-home-page": { @@ -4298,8 +4300,8 @@ "versionHistory": { "comparison": { "header": { - "hide-json-diff": "JSON 차이 숨기기 ", - "show-json-diff": "JSON 차이 표시 ", + "hide-json-diff": "", + "show-json-diff": "", "text": "{{version}} 버전이 {{createdBy}}에 의해 업데이트됨({{ageString}}) {{message}}" }, "select": "비교를 시작할 두 버전을 선택하세요." @@ -4326,7 +4328,7 @@ "label-label": "라벨", "label-placeholder": "예: Tempo 추적", "label-required": "이 필드는 필수 입력 항목입니다.", - "sub-text": "<0>상관 관계를 설명하는 텍스트를 정의합니다.", + "sub-text": "", "title": "상관 관계 라벨 정의(1/3단계)" }, "configure-correlation-target-form": { @@ -4370,7 +4372,7 @@ }, "source-form": { "control-required": "이 필드는 필수 입력 항목입니다.", - "description": "데이터 포인트가 모든 변수에 값을 필드 또는 변환 출력으로 제공해야 상관 관계 버튼이 시각화에 표시됩니다.<1>참고: 모든 변수를 아래에 명시적으로 정의할 필요는 없습니다. <4>logfmt와 같은 변환은 모든 키/값 쌍에 대해 변수를 생성합니다.", + "description": "", "description-external-pre": "대상 URL에서 다음 변수를 사용했습니다.", "description-query-pre": "대상 쿼리에서 다음 변수를 사용했습니다.", "external-title": "URL을 사용할 데이터 소스 구성(3/3단계)", @@ -4382,12 +4384,12 @@ "results-required": "이 필드는 필수 입력 항목입니다.", "source-description": "선택한 소스 데이터 소스의 결과에 패널 내 표시된 링크가 있습니다.", "source-label": "소스", - "sub-text": "<0>상관 관계를 표시할 데이터 소스와 이전에 정의된 변수를 대체할 데이터를 정의합니다." + "sub-text": "" }, "sub-title": "서로 다른 데이터 소스에 저장된 데이터가 서로 어떻게 관련되는지 정의합니다. 자세한 내용은 <2>문서를 참조하세요.", "target-form": { "control-rules": "이 필드는 필수 입력 항목입니다.", - "sub-text": "<0>상관 관계가 연결될 대상을 정의합니다. 쿼리 유형을 사용하면 상관 관계가 클릭될 때 쿼리가 실행됩니다. 외부 유형의 경우 상관 관계를 클릭하면 URL이 열립니다.", + "sub-text": "", "target-description-external": "링크를 클릭할 때 열릴 URL을 지정하세요.", "target-description-query": "링크를 클릭할 때 쿼리할 데이터 소스를 지정하세요.", "target-label": "대상", @@ -4594,7 +4596,7 @@ } }, "confirm-plugin-dashboard-save-modal": { - "body-plugin-dashboard": "플러그인을 업데이트하면 변경 사항이 손실됩니다.<1><2>사용자 정의 버전을 만들려면 <1>다른 이름으로 저장을 사용하세요.", + "body-plugin-dashboard": "", "cancel": "취소", "overwrite": "덮어쓰기", "title-plugin-dashboard": "플러그인 대시보드" @@ -4811,7 +4813,7 @@ "add-visualization-body": "데이터 소스를 선택한 다음 차트, 통계, 표를 사용하여 데이터를 쿼리하고 시각화하거나 목록, 마크다운 및 기타 위젯을 생성합니다.", "add-visualization-button": "시각화 추가", "add-visualization-header": "시각화 추가하여 새 대시보드 시작하기", - "import-a-dashboard-body": "파일 또는 <1>grafana.com에서 대시보드 가져오기", + "import-a-dashboard-body": "", "import-a-dashboard-header": "대시보드 가져오기", "import-dashboard-button": "대시보드 가져오기", "show-less-dashboards": "", @@ -5268,8 +5270,8 @@ "title-provisioned": "프로비저닝된 대시보드" }, "save-dashboard-error-proxy": { - "body-name-exists": "선택한 폴더에 동일한 이름의 대시보드가 이미 존재합니다.<1><2>그래도 이 대시보드를 저장하시겠어요?", - "body-version-mismatch": "다른 사람이 이 대시보드를 업데이트했습니다<1><2>그래도 이 대시보드를 저장하시겠어요?", + "body-name-exists": "", + "body-version-mismatch": "", "confirmText-save-and-overwrite": "저장 및 덮어쓰기", "title-name-exists": "충돌", "title-version-mismatch": "충돌" @@ -5287,7 +5289,7 @@ "cancel": "취소", "cannot-be-saved": "이 대시보드는 다른 소스에서 프로비저닝되었으므로 Grafana UI에서 저장할 수 없습니다. JSON을 복사하거나 아래 파일에 저장하면 프로비저닝 소스에서 대시보드를 업데이트할 수 있습니다.", "copy-json-to-clipboard": "JSON을 클립보드로 복사", - "file-path": "<0>파일 경로: {{filePath}}", + "file-path": "", "save-json-to-file": "JSON을 파일에 저장", "see-docs": "프로비저닝에 대한 자세한 내용은 <2>문서를 참고하세요." }, @@ -5486,7 +5488,7 @@ "transformation-picker": { "info": "변환을 사용하면 쿼리 결과를 시각화하기 전에 조인, 계산, 재정렬, 숨기기 및 이름 변경을 할 수 있습니다.", "info-graph-not-suitable": "그래프 시각화를 사용하는 경우 현재 시계열 데이터만 지원되므로 많은 변환이 적합하지 않습니다.", - "info-switch-to-table": "표 시각화로 전환하면 변환을 통해 어떤 작업이 이뤄지는지 이해하는 데 도움이 될 수 있습니다. ", + "info-switch-to-table": "", "placeholder-search-for-transformation": "변환 검색", "read-more": "더 읽어보기", "title-transformations": "변환" @@ -5552,8 +5554,8 @@ "version-history-comparison": { "button-restore": "{{version}} 버전으로 복구", "label-view-json-diff": "JSON 차이 보기", - "new-updated-by": "<0>{{version}} 버전이 {{editor}}에 의해 {{timeAgo}}에 업데이트됨", - "old-updated-by": "<0>{{version}} 버전이 {{editor}}에 의해 {{timeAgo}}에 업데이트됨" + "new-updated-by": "", + "old-updated-by": "" }, "version-history-table": { "aria-label-toggle-selection": "{{version}} 버전 선택 토글", @@ -5953,7 +5955,7 @@ "cancel": "취소" }, "render-save-button-and-error": { - "body-plugin-dashboard": "플러그인을 업데이트하면 변경 사항이 손실됩니다. 사용자 정의 버전을 만들려면 <1>다른 이름으로 저장을 사용하세요.", + "body-plugin-dashboard": "", "title-failed-to-save-dashboard": "대시보드 저장 실패", "title-plugin-dashboard": "플러그인 대시보드", "title-someone-else-has-updated-this-dashboard": "다른 사람이 이 대시보드를 업데이트했습니다", @@ -5962,7 +5964,7 @@ "save-and-overwrite": "'저장 및 덮어쓰기'" }, "library-viz-panel-info": { - "last-edited": " 님({{timeAgo}}에)", + "last-edited": "", "usage-count_other": "{{count}}개의 대시보드에서 사용됨" }, "managed-badge": { @@ -6022,7 +6024,7 @@ }, "panel-data-queries-tab-rendered": { "add-query": "쿼리 추가", - "expression": "표현식 " + "expression": "" }, "panel-data-transformations-tab": { "tab-label": "변환" @@ -6080,7 +6082,7 @@ "query": "쿼리" }, "query-variable-editor-form": { - "description-examples": "이름을 지정한 캡처 그룹을 사용하여 표시 텍스트와 값을 분리할 수 있습니다(<1>예시 참고).", + "description-examples": "", "description-optional": "선택 사항, 시리즈 이름 또는 메트릭 노드 세그먼트의 일부를 추출하려는 경우.", "label-data-source": "데이터 소스", "label-static-options-sort": "정적 옵션 정렬", @@ -6141,7 +6143,7 @@ "label-message": "메시지", "placeholder-describe-changes-optional": "변경 사항을 설명하는 메모를 추가하세요(선택 사항).", "render-footer": { - "body-plugin-dashboard": "플러그인을 업데이트하면 변경 사항이 손실됩니다. 사용자 정의 버전을 만들려면 <1>다른 이름으로 저장을 사용하세요.", + "body-plugin-dashboard": "", "no-changes-to-save": "저장할 변경 사항이 없습니다", "title-failed-to-save-dashboard": "대시보드 저장 실패", "title-plugin-dashboard": "플러그인 대시보드", @@ -6176,7 +6178,7 @@ "cancel": "취소", "cannot-be-saved": "이 대시보드는 다른 소스에서 프로비저닝되었으므로 Grafana UI에서 저장할 수 없습니다. JSON을 복사하거나 아래 파일에 저장하면 프로비저닝 소스에서 대시보드를 업데이트할 수 있습니다.", "copy-json-to-clipboard": "JSON을 클립보드로 복사", - "file-path": "<0>파일 경로: {{filePath}}", + "file-path": "", "label-description": "설명", "label-target-folder": "대상 폴더", "label-title": "제목", @@ -6345,8 +6347,8 @@ }, "version-history-comparison": { "label-view-json-diff": "JSON 차이 보기", - "new-version-updated": "<0>{{version}} 버전이 {{editor}}에 의해 {{timeAgo}}에 업데이트됨", - "old-version-updated": "<0>{{version}} 버전이 {{editor}}에 의해 {{timeAgo}}에 업데이트됨" + "new-version-updated": "", + "old-version-updated": "" }, "version-history-header": { "compare-versions": "{{baseVersion}} <3> {{newVersion}} 비교 중", @@ -6424,7 +6426,7 @@ "provisioned-delete-modal": { "confirm-button": "확인", "text-1": "이 대시보드는 Grafana 프로비저닝에서 관리하며 삭제할 수 없습니다. 대시보드를 삭제하려면 구성 파일에서 대시보드를 제거하세요.", - "text-2": "프로비저닝에 대한 자세한 내용은 Grafana 문서를 참조하세요. ", + "text-2": "", "text-3": "파일 경로: {{provisionedId}}", "text-link": "문서 페이지로 이동", "title": "프로비저닝된 대시보드는 삭제할 수 없습니다." @@ -6502,7 +6504,7 @@ }, "data-source-testing-status-page": { "error-more-details-link": "이 오류에 대해 자세히 알아보려면 <2>여기를 클릭하세요.", - "success-more-details-links": "그런 다음 <2>대시보드를 구축하거나 <5>탐색 보기에서 데이터를 쿼리하여 데이터 시각화를 시작할 수 있습니다." + "success-more-details-links": "" }, "data-sources": { "datasource-add-button": { @@ -6598,7 +6600,7 @@ "test": "테스트" }, "cloud-info-box": { - "body-alert": "또는 이 작업을 건너뛰고 <6>Grafana Cloud 평생 무료 플랜을 통해 Grafana Labs에서 완전 관리되고 확장 가능하며 호스팅되는 데이터 소스인 {{mainDS}}(및 {{extraDS}})을(를) 받으세요.", + "body-alert": "", "title-alert": "아래에서 {{mainDS}} 데이터 소스를 구성하세요" }, "dashboards-table": { @@ -6726,18 +6728,18 @@ "no-events-yet": "아직 이벤트 없음" }, "render-info-viewer": { - "data-counter": "데이터: {{numDataChanges}} ", + "data-counter": "", "elapsed-time": "시간: {{elapsed}}ms", "field": "필드", "last": "마지막", - "render-counter": "렌더링: {{numRenders}} ", - "schema-counter": "스키마: {{numSchemaChanges}} ", + "render-counter": "", + "schema-counter": "", "title-reset-counters": "카운터 재설정", "tooltip-step-back": "뒤로 가기", "type": "유형" }, "state-view": { - "current-value": "현재 값: {{currentValue}} ", + "current-value": "", "label-state-name": "주 이름" } }, @@ -7184,7 +7186,7 @@ }, "footer": { "learn-more": "자세히 알아보기", - "pro-tip-define-sources-through-configuration-files": " 전문가 팁: 구성 파일을 통해 데이터 소스를 정의할 수도 있습니다. " + "pro-tip-define-sources-through-configuration-files": "" } }, "pane": { @@ -7246,8 +7248,6 @@ "query-deleted": "쿼리 삭제됨" }, "rich-history-queries-tab": { - "displaying-partial-queries": "쿼리 {{ count }}개 표시 중", - "displaying-queries": "쿼리 {{ count }}개", "filter-aria-label": "데이터 소스에 대한 쿼리 필터링", "filter-history": "이력 필터링", "filter-placeholder": "데이터 소스에 대한 쿼리 필터링", @@ -7257,7 +7257,9 @@ "search-placeholder": "쿼리 검색", "showing-queries": "{{ shown }}/{{ total }}개 표시 중<0>더 불러오기", "sort-aria-label": "쿼리 정렬", - "sort-placeholder": "쿼리 정렬 기준" + "sort-placeholder": "쿼리 정렬 기준", + "displaying-partial-queries_other": "", + "displaying-queries_other": "" }, "rich-history-settings-tab": { "alert-info": "Grafana는 입력 항목을 최대 {{optionLabel}}개까지 보관합니다.별표 표시된 입력 항목은 삭제되지 않습니다.", @@ -7449,7 +7451,7 @@ "copy-shortened-link-menu": "링크 복사 옵션 열기", "refresh-picker-cancel": "취소", "refresh-picker-run": "쿼리 실행", - "split-close": "닫기 ", + "split-close": "", "split-close-tooltip": "분할 창 닫기", "split-narrow": "좁은 창", "split-title": "분할", @@ -7579,8 +7581,8 @@ }, "math": { "available-math-functions": "사용 가능한 수학 함수", - "run-math-operations": "하나 이상의 쿼리에 대해 수학 연산을 실행합니다. {{refExample}}({{ref1}}, {{ref2}}, {{ref3}} 등)(으)로 쿼리를 참조합니다.<10>예: <12>{{example}}", - "tooltip-footer": "<2>수식에 대한 추가 문서를 참조하세요.", + "run-math-operations": "", + "tooltip-footer": "", "tooltip-title": "수학 연산자", "tooltip-trigger": "표현식" }, @@ -8609,7 +8611,7 @@ }, "data-source-http-settings": { "access-help": "도움말 <1>", - "access-help-details": "액세스 모드는 데이터 소스에 대한 요청을 처리하는 방법을 제어합니다.달리 명시되어 있지 않으면 <1><1>서버를 선택하는 것이 좋습니다.", + "access-help-details": "", "access-help-title": "액세스 권한 도움말", "access-label": "액세스 권한", "allowed-cookies": "허용된 쿠키", @@ -8877,7 +8879,7 @@ "cell-inspect": "값 검사", "cell-inspect-tooltip": "값 검사", "copy": "클립보드로 복사", - "csv-counts": "행:{{rows}}, 열:{{columns}} <5>", + "csv-counts": "", "csv-placeholder": "여기에 CSV를 입력하세요...", "filter-placeholder": "값 필터링", "filter-popup-apply": "확인", @@ -9162,7 +9164,6 @@ "name-line-width": "선 너비", "name-stacking": "스태킹" }, - "inline-token-warning-badge-tooltip": "", "inspector": { "inspect-data-tab": { "loading": "로딩 중", @@ -9324,7 +9325,7 @@ "error-fetching": "LDAP 설정을 가져오던 중 오류 발생", "error-saving": "LDAP 설정을 저장하던 중 오류 발생", "error-validate-form": "LDAP 설정 유효성 검증 중 오류 발생", - "feature-flag-disabled": "이 페이지는 <1>ssoSettingsLDAP 기능 플래그를 활성화해야만 액세스할 수 있습니다.", + "feature-flag-disabled": "", "saved": "LDAP 설정 저장됨" }, "bind-dn": { @@ -9365,7 +9366,7 @@ "label": "검색 기본 DNS", "placeholder": "예: dc=grafana,dc=org" }, - "subtitle": "Grafana에서 LDAP 통합을 사용하면 Grafana 사용자가 자신의 LDAP 자격 증명으로 로그인할 수 있습니다. 자세한 내용은 Grafana의 <2><0>문서를 참조하세요.", + "subtitle": "", "title": "기본 설정" }, "library-panel": { @@ -9409,7 +9410,7 @@ "dashboard-name": "대시보드 이름" }, "library-panel-info": { - "last-edited": "마지막 편집: 님({{timeAgo}}에)", + "last-edited": "", "usage-count_other": "{{count}}개의 대시보드에서 사용됨" }, "library-panels-search": { @@ -9708,7 +9709,7 @@ "tooltip-unpin-line": "줄 고정 해제" }, "log-row-message": { - "ellipsis": "… ", + "ellipsis": "", "more": "더 보기", "see-details": "로그 세부 정보 보기", "tooltip-error": "오류: {{errorMessage}}" @@ -10104,7 +10105,7 @@ }, "resource-table": { "dashboard-load-error": "대시보드 로딩 불가", - "error-library-element-sub": "라이브러리 요소 {uid}", + "error-library-element-sub": "", "error-library-element-title": "라이브러리 요소 로딩 불가", "unknown-datasource-title": "{{datasourceUID}} 데이터 소스", "unknown-datasource-type": "알 수 없는 데이터 소스" @@ -10749,10 +10750,10 @@ "placeholder-optional": "(선택 사항)", "role": "역할", "submit": "제출", - "tooltip": "이제 '기본 역할 없음' 옵션을 선택하고 사용자의 필요에 맞게 권한을 추가할 수 있습니다. 자세한 내용은 <1>문서를 참조하세요." + "tooltip": "" }, "user-invite-page": { - "sub-title": "초대장을 보내거나 기존 Grafana 사용자를<1> {{orgName}} 조직에 추가하세요.", + "sub-title": "", "text": { "invite-user": "사용자 초대" } @@ -10841,7 +10842,7 @@ "switch-to-table": "표로 전환" }, "panel-plugin-error": { - "text-load-error": "자세한 내용은 서버 시작 로그를 확인하세요. <1>이 플러그인을 Git에서 로딩한 경우 컴파일되었는지 확인하세요.", + "text-load-error": "", "title-load-error": "로딩 중 오류 발생: {{panelId}}", "title-not-found": "패널 플러그인을 찾을 수 없음: {{id}}" }, @@ -11035,7 +11036,7 @@ }, "details": { "connections-tab": { - "description": "현재 {{pluginName}}에 대해 다음 데이터 소스가 구성되어 있습니다. 구성 세부 정보를 보려면 타일을 클릭하세요. 모든 데이터 소스 연결은 <4><0>연결 - <3>데이터 소스에서 찾으실 수 있습니다." + "description": "" }, "disabled-error": { "angular-deprecation-link": "Angular 지원 중단에 대해 자세히 알아보기", @@ -11052,7 +11053,7 @@ }, "labels": { "contactGrafanaLabs": "Grafana Labs에 문의", - "customLinks": "사용자 지정 링크 ", + "customLinks": "", "customLinksTooltip": "이러한 링크는 플러그인 개발자가 개발자 고유의 추가 리소스와 정보를 지원하기 위해 제공합니다.", "dependencies": "종속 관계", "documentation": "문서", @@ -11063,7 +11064,7 @@ "latestVersion": "최신 버전", "license": "라이선스", "raiseAnIssue": "문제 제기", - "reportAbuse": "우려 사항 신고 ", + "reportAbuse": "", "reportAbuseTooltip": "악성 또는 유해한 플러그인과 관련된 문제는 바로 Grafana Labs에 신고해 주세요.", "repository": "리포지토리", "signature": "서명", @@ -11073,8 +11074,8 @@ "modal": { "cancel": "취소", "copyEmail": "이메일 주소 복사", - "description": "이 기능은 플러그인 내의 악의적이거나 유해한 속성을 신고하기 위한 것입니다. 플러그인 관련 문제는 다음 이메일 주소로 문의해 주세요. ", - "node": "참고: 버그 또는 기능 요청과 같은 일반적인 플러그인 문제는 제공된 링크를 사용하여 플러그인 작성자에게 문의하세요. ", + "description": "", + "node": "", "title": "플러그인 우려 사항 신고" } }, @@ -11142,7 +11143,7 @@ "message": "모든 플러그인이 최신 상태입니다." }, "not-found-plugin": { - "body-plugin-not-found": "해당 플러그인을 찾을 수 없습니다. URL이 올바른지 확인하거나 <1><3>플러그인 카탈로그로 이동하세요.", + "body-plugin-not-found": "", "title-plugin-not-found": "플러그인을 찾을 수 없습니다" }, "plugin-actions": { @@ -11600,7 +11601,6 @@ "unsupported-repository-type": "" }, "inline-secure-values-warning": "", - "inline-token-warning-badge-text": "", "job-status": { "label-view-details": "세부 정보 보기", "loading-finished-job": "완료된 작업 로딩 중...", @@ -11777,6 +11777,17 @@ "label-current-step": "현재 단계", "label-pending-step": "보류 중인 단계" }, + "status-badge": { + "automatic-pulling-disabled": "", + "deleting": "", + "error": "", + "pending": "", + "pulling": "", + "unknown": "", + "up-to-date": "", + "waiting-for-health-check": "", + "warning": "" + }, "success-title-default": "성공", "sync-job": { "error-no-job-id": "작업을 시작하지 못했습니다", @@ -11954,7 +11965,7 @@ "annotations-show-text": "주석 = 표시", "time-range-picker-disabled-text": "시간 범위 선택기 = 비활성화됨", "time-range-picker-enabled-text": "시간 범위 선택기 = 활성화됨", - "time-range-text": "시간 범위 = " + "time-range-text": "" }, "share": { "success-delete": "대시보드를 더 이상 공유할 수 없습니다." @@ -11993,7 +12004,7 @@ "revoke-user-access-modal-desc-line1": "정말 {{email}}에 대한 액세스 권한을 철회하시겠어요?" }, "delete-user-shared-dashboards-modal": { - "revoke-user-access-modal-desc-line2": "이 작업을 수행하면 모든 공유 대시보드에 대한 {{email}}의 액세스 권한이 즉시 철회됩니다." + "revoke-user-access-modal-desc-line2": "" }, "modal": { "shared-dashboard-modal-title": "공유된 대시보드" @@ -12159,7 +12170,7 @@ }, "menu": { "clear-button": "전체 초기화", - "tooltip": "이제 '기본 역할 없음' 옵션을 선택하고 사용자의 필요에 맞게 권한을 추가할 수 있습니다. 자세한 내용은 <1>문서를 참조하세요." + "tooltip": "" }, "menu-aria-label": "역할 선택기 메뉴", "menu-group-option-aria-label": "역할 선택기 옵션", @@ -12169,7 +12180,7 @@ }, "sub-menu-aria-label": "역할 선택기 하위 메뉴", "title": { - "description": "사용자에게 역할을 할당하여 Grafana의 기능과 리소스에 대한 액세스 권한을 세분화하여 제어하세요. 자세한 내용은 Grafana의 <2>문서를 참조하세요." + "description": "" } }, "role-picker-drawer": { @@ -12292,7 +12303,7 @@ }, "select": { "select-menu": { - "selected-count": "선택됨 " + "selected-count": "" } }, "service-account-create-page": { @@ -12391,6 +12402,7 @@ "aria-label-role": "역할" }, "service-account-tokens-table": { + "aria-label-delete-button": "", "created": "생성됨", "expires": "만료", "last-used-at": "마지막 사용 시간", @@ -12477,7 +12489,7 @@ "info-text": "아래 옵션으로 사용자 정의된 이 대시보드 또는 패널에 대한 직접 링크를 생성합니다.", "link-url": "링크 URL", "render-alert": "이미지 렌더러 플러그인 미설치", - "render-instructions": "이미지를 렌더링하려면 <2>Grafana 이미지 렌더러 플러그인을 설치해야 합니다. 플러그인을 설치하려면 Grafana 관리자에게 문의하세요.", + "render-instructions": "", "rendered-image": "렌더링된 이미지에 직접 연결", "save-alert": "대시보드 저장되지 않음", "save-dashboard": "패널 이미지를 렌더링하려면 먼저 대시보드를 저장해야 합니다.", @@ -12501,7 +12513,7 @@ "info-text-1": "스냅샷은 인터랙티브 대시보드를 즉시 공개적으로 공유할 수 있는 방법입니다. 스냅샷이 생성되면, 쿼리(메트릭, 템플릿, 주석), 패널 링크와 같은 민감한 데이터는 제거되고 대시보드에 임베드된 표시 메트릭 데이터와 시리즈 이름만 남습니다.", "info-text-2": "스냅샷은 링크가 있고 URL에 액세스할 수 있는 <1>모든 사용자가 볼 수 있다는 점을 기억하세요. 신중하게 공유하세요.", "local-button": "스냅샷 게시", - "mistake-message": "혹시 실수로 게시하셨나요? ", + "mistake-message": "", "name": "스냅샷 이름", "timeout": "타임아웃(초)", "timeout-description": "대시보드 메트릭을 수집하는 데 시간이 오래 걸리는 경우 타임아웃 값을 구성해야 할 수 있습니다.", @@ -13112,7 +13124,7 @@ "forwards-time-aria-label": "시간 범위를 이후로 변경", "to": "종료", "zoom-out-button": "시간 범위 확대", - "zoom-out-tooltip": "시간 범위 확대 <1> CTRL+Z" + "zoom-out-tooltip": "" }, "time-range": { "apply": "시간 범위 적용", @@ -13237,7 +13249,7 @@ }, "transformations": { "empty": { - "add-transformation-body": "변환을 사용하면 시각화가 표시되기 전에 다양한 방법으로 데이터를 변경할 수 있습니다.<1>여기에는 데이터 병합, 필드 이름 변경, 계산, 표시용 데이터 형식 지정 등이 포함됩니다.", + "add-transformation-body": "", "add-transformation-header": "데이터 변환 시작" } }, @@ -13504,7 +13516,7 @@ "label-format": "형식", "label-set-timezone": "시간대 설정", "label-time-field": "시간 필드", - "tooltip-format": "<2>Moment.js 형식 문자열로 지정된 필드의 출력 형식입니다.", + "tooltip-format": "", "tooltip-timezone-manually": "날짜의 시간대를 수동으로 설정합니다" }, "format-time-transformer-editor": { @@ -14099,8 +14111,8 @@ "message": "찾은 사용자 없음" }, "token-revoked-modal": { - "auto-revoked": "계정의 <2>최대 동시 세션 수인 {{numSessions}}개에 도달했기 때문에 세션 토큰이 자동으로 취소되었습니다.", - "resume-message": "<0>세션을 재개하려면 다시 로그인하세요.자동 로그아웃이 반복되는 경우, 관리자에게 문의하거나 라이선스 페이지에서 할당량을 확인하세요.", + "auto-revoked": "", + "resume-message": "", "sign-in": "로그인", "title-you-have-been-automatically-signed-out": "자동으로 로그아웃되었습니다" }, diff --git a/public/locales/nl-NL/grafana.json b/public/locales/nl-NL/grafana.json index b1072873e9e..f23f595bff2 100644 --- a/public/locales/nl-NL/grafana.json +++ b/public/locales/nl-NL/grafana.json @@ -108,7 +108,7 @@ "dismiss": "Sluiten", "heading": "Enterprise-authenticatie", "learn-more-link": "Meer informatie", - "text": "Beheer gebruikers, teams en machtigingen automatisch met <1>SAML, <3>SCIM, <6>LDAP en <8>RBAC — beschikbaar in Grafana Cloud en Enterprise." + "text": "" }, "feature-listing": { "title-auditing": "Auditing", @@ -209,7 +209,7 @@ "title-delete": "Verwijderen" }, "orgs": { - "delete-body": "Weet je zeker dat je '{{deleteOrgName}}' wilt verwijderen?<3> <5>Alle dashboards voor deze organisatie worden verwijderd!", + "delete-body": "", "id-header": "ID", "name-header": "Naam", "new-org-button": "Nieuwe organisatie" @@ -719,6 +719,7 @@ "title-annotations": "Annotaties" }, "link-dashboard-and-panel": "Dashboard en paneel koppelen", + "placeholder-value-input": "", "placeholder-value-input-default": "Aangepaste annotatie-inhoud invoeren..." }, "bulk-actions": { @@ -1144,7 +1145,7 @@ "title-something-wrong-trying-fetch-group-details": "Er is iets misgegaan bij het ophalen van de groepsgegevens" }, "evaluation-interval-limit-exceeded": { - "body-minimum-interval": "Er is een minimaal evaluatie-interval van <1>{{minInterval}} geconfigureerd in Grafana.<3>Neem contact op met de beheerder om een lager interval te configureren.", + "body-minimum-interval": "", "title-global-evaluation-interval-limit-exceeded": "Globale evaluatie-intervallimiet is overschreden" }, "existing-rule-editor": { @@ -1292,7 +1293,7 @@ "resolved": "Opgelost" } }, - "review-alert-payload": "Waarschuwingsgegevens beoordelen om toe te voegen aan de payload:", + "review-alert-payload": "", "title-add-custom-alerts": "Aangepaste waarschuwingen toevoegen" }, "get-alert-suggestions": { @@ -1416,7 +1417,7 @@ "title-add-folder-and-labels": "Map en labels toevoegen" }, "grafana-managed-rule-type": { - "description": "Ondersteunt meerdere gegevensbronnen van welke aard dan ook.<1>Gegevens transformeren met expressies." + "description": "" }, "grafana-modify-export": { "body-invalid-rule-id": "De regel-UID in de pagina-URL is ongeldig. Controleer de URL en probeer het opnieuw.", @@ -1853,7 +1854,7 @@ "aria-label-new": "nieuw" }, "mimir-flavored-type": { - "description": "Gebruik een Mimir-, Loki- of Cortex-gegevensbron.<1>Expressies worden niet ondersteund" + "description": "" }, "min-interval-option": { "label-interval": "Interval", @@ -2082,7 +2083,7 @@ "warning-1": "Als je dit meldingsbeleid verwijdert, wordt dit permanent verwijderd.", "warning-2": "Weet je zeker dat je dit beleid wil verwijderen?" }, - "filter-description": "Filter meldingsbeleid met behulp van een door komma's gescheiden lijst met matchers, bijv.:<1>severity=critical, region=EMEA", + "filter-description": "", "generated-policies": "Automatisch gegenereerd beleid", "matchers": "Matchers", "metadata": { @@ -2126,7 +2127,8 @@ "conflict": "Een andere gebruiker heeft wijzigingen aangebracht in de structuur van het notificatiebeleid.", "error-code": "Foutmelding: '{{error}}'", "routes": { - "conflictingMatchers": "Kan route niet toevoegen of bijwerken: matchers conflicteren met een externe routeringsstructuur als we matchers {{-matchers}} samenvoegen. Dit zou de route onbereikbaar maken." + "conflictingMatchers": "Kan route niet toevoegen of bijwerken: matchers conflicteren met een externe routeringsstructuur als we matchers {{-matchers}} samenvoegen. Dit zou de route onbereikbaar maken.", + "unknownMatchers": "" }, "suffix": "Vernieuw de pagina en probeer het opnieuw.", "title": "Kan meldingsbeleid niet toevoegen of bijwerken" @@ -2244,7 +2246,7 @@ "error-no-query-editor": "Kon querybewerker niet laden vanwege: {{errorMessage}}" }, "recording-rule-type": { - "description": "Expressies vooraf berekenen.<1>Moet worden gecombineerd met een waarschuwingsregel." + "description": "" }, "recording-rules": { "description-target-data-source": "De Prometheus-gegevensbron om opnameregels in op te slaan", @@ -2257,7 +2259,7 @@ }, "redirect-to-clone-rule": { "body-evaluation-group": "Je moet een nieuwe evaluatiegroep instellen voor de gekopieerde regel omdat de oorspronkelijke is geprovisioneerd en niet kan worden gebruikt voor regels die in de gebruikersinterface zijn gemaakt.", - "body-not-provisioned": "De nieuwe regel wordt <1>niet gemarkeerd als een ingestelde regel.", + "body-not-provisioned": "", "confirmText-copy": "Kopiëren", "title-copy-provisioned-alert-rule": "Provisioned waarschuwingsregel kopiëren" }, @@ -2292,13 +2294,13 @@ "routing-settings": { "aria-label-group-by": "Groeperen op", "description-group-by": "Combineer meerdere waarschuwingen tot één melding door ze te groeperen op dezelfde labelwaarden. Als dit leeg is, wordt het overgenomen van het standaardmeldingsbeleid.", - "group-interval": "Groepsinterval: <1>{{groupIntervalValue}}", - "group-wait": "Groepswacht: <1>{{groupWaitValue}}", - "grouping": "Groepering: <1>{{fields}}", + "group-interval": "", + "group-wait": "", + "grouping": "", "label-group-by": "Groeperen op", "label-override-grouping": "Groepering overschrijven", "label-override-timings": "Timings overschrijven", - "repeat-interval": "Herhaalinterval: <1>{{repeatIntervalValue}}" + "repeat-interval": "" }, "rule-actions-buttons": { "title-edit": "Bewerken", @@ -2554,7 +2556,7 @@ "relative-with-to": "" }, "rule-type-picker": { - "grafana-managed": "Selecteer 'Grafana beheerd', tenzij je een Mimir-, Loki- of Cortex-gegevensbron hebt met de Ruler-API ingeschakeld." + "grafana-managed": "" }, "rule-view": { "query": { @@ -2887,7 +2889,7 @@ "test-contact-point-modal": { "custom-notification-message": "Je verzendt een testmelding die de onderstaande annotaties gebruikt. Dit is een goede optie als je aangepaste sjablonen en berichten gebruikt.", "notification-message": "Melding", - "predefined-notification-message": "Je verzendt een testmelding die gebruikmaakt van een vooraf gedefinieerde waarschuwing. Als je een aangepast sjabloon of bericht hebt gedefinieerd, schakel je voor betere resultaten over naar <1>aangepast meldingsbericht, van bovenaf.", + "predefined-notification-message": "", "send-test-notification": "Testmelding verzenden", "title-test-contact-point": "Contactpunt testen" }, @@ -2896,7 +2898,7 @@ }, "threshold-expression-viewer": { "input": "Invoer", - "stop-alerting-when": "Waarschuwingen (of status 'in afwachting') stoppen wanneer " + "stop-alerting-when": "" }, "time-interval": { "add-time-interval": "Tijdsinterval toevoegen", @@ -3084,7 +3086,7 @@ "title-notification-policies": "Meldingsbeleid" }, "yaml-content-info": { - "body": "De YAML-inhoud in de bewerker bevat alleen configuratie van waarschuwingsregels <1>Om Prometheus te configureren, moet je de rest van de <4>inhoud van het configuratiebestand opgeven." + "body": "" } }, "alertlist": { @@ -3160,7 +3162,7 @@ "no-annotations-found": "Geen annotaties gevonden" }, "annotation-list-item": { - "tooltip-created-by": "Gemaakt door:<1> {{email}}" + "tooltip-created-by": "" }, "category-annotation-query": "Annotatiequery", "category-display": "Display", @@ -3198,7 +3200,7 @@ }, "empty-state": { "button-title": "Annotatiequery toevoegen", - "info-box-content": "<0>Annotaties bieden een manier om gebeurtenisgegevens in je grafieken te integreren. Ze worden gevisualiseerd als verticale lijnen en pictogrammen op alle grafiekpanelen. Wanneer je met de muis over een annotatiepictogram beweegt, kun je gebeurtenistekst en -tags voor de gebeurtenis krijgen. Je kunt annotatiegebeurtenissen rechtstreeks vanuit Grafana toevoegen door Ctrl of CMD ingedrukt te houden + op grafiek te klikken (of regio te slepen). Deze worden opgeslagen in de annotatiedatabase van Grafana.", + "info-box-content": "", "info-box-content-2": "Bekijk de <2>Annotatiedocumentatie voor meer informatie.", "title": "Er zijn nog geen aangepaste annotatiequery's toegevoegd" }, @@ -3236,7 +3238,7 @@ "auth-settings": "Auth-instellingen" }, "auth-drawer-unconneced": { - "subtitle": "Auth-instellingen configureren. Lees meer in onze <2>documentatie." + "subtitle": "" }, "auth-drawer-unconnected": { "advanced-auth": "Geavanceerde auth", @@ -3270,7 +3272,7 @@ "allowed-organizations-description": "Lijst van door komma's of spaties gescheiden organisaties. De gebruiker moet lid zijn van ten minste\néén organisatie om in te loggen.", "allowed-organizations-label": "Toegestane organisaties", "allowed-organizations-placeholder": "Voer organisaties in (my-team, myteam...) en druk op Enter om toe te voegen", - "api-url-description": "Het eindpunt voor gebruikersinformatie van je OAuth2-provider. Informatie die door dit eindpunt wordt geretourneerd, moet compatibel zijn met <2>OpenID-gebruikersinformatie.", + "api-url-description": "", "api-url-required": "Dit veld moet een geldige URL zijn, indien ingesteld.", "auth-style-description": "Het bepaalt hoe '{{ clientIDLabel }}' en '{{ clientSecretLabel }}' worden verzonden naar de Oauth2-provider. Standaard is AutoDetect.", "auth-style-label": "Auth-stijl", @@ -3415,7 +3417,7 @@ } }, "auth-config-auth-config-page-unconnected": { - "subtitle": "Je auth-instellingen beheren en single sign-on configureren. Lees meer in onze <2>documentatie." + "subtitle": "" }, "bar-chart": { "warn": { @@ -4133,7 +4135,7 @@ }, "scopes": { "apply-selected-scopes": "Toepassen", - "selected-scopes-label": "Bereik: " + "selected-scopes-label": "" }, "search-box": { "placeholder": "Zoek of ga naar ..." @@ -4275,7 +4277,7 @@ "okay": "OK" }, "not-found-datasource": { - "body": "Misschien heb je de URL verkeerd getypt of is de plug-in met de id <1> niet beschikbaar.<3>Om een lijst met beschikbare gegevensbronnen te zien, <5>klik je hier." + "body": "" }, "oss": { "connections-home-page": { @@ -4318,8 +4320,8 @@ "versionHistory": { "comparison": { "header": { - "hide-json-diff": "JSON diff verbergen ", - "show-json-diff": "JSON diff weergeven ", + "hide-json-diff": "", + "show-json-diff": "", "text": "Versie {{version}} is bijgewerkt door {{createdBy}} ({{ageString}}) {{message}}" }, "select": "Selecteer twee versies om te vergelijken" @@ -4346,7 +4348,7 @@ "label-label": "Label", "label-placeholder": "bijv. Tempo-sporen", "label-required": "Dit veld is verplicht.", - "sub-text": "<0>Definieer tekst die de correlatie beschrijft.", + "sub-text": "", "title": "Definieer correlatielabel (Stap 1 van 3)" }, "configure-correlation-target-form": { @@ -4390,7 +4392,7 @@ }, "source-form": { "control-required": "Dit veld is verplicht.", - "description": "Een datapunt moet waarden voor alle variabelen leveren, als velden of als uitvoer van transformaties, om de correlatieknop in de visualisatie te laten verschijnen.<1>Opmerking: niet elke variabele hoeft hieronder expliciet te worden gedefinieerd. Een transformatie zoals <4>logfmt maakt variabelen aan voor elk sleutel/waardepaar.", + "description": "", "description-external-pre": "Je hebt de volgende variabelen gebruikt in de doel-URL:", "description-query-pre": "Je hebt de volgende variabelen gebruikt in de doelquery:", "external-title": "Configureer de gegevensbron die de URL zal gebruiken (Stap 3 van 3)", @@ -4402,12 +4404,12 @@ "results-required": "Dit veld is verplicht.", "source-description": "Resultaten van geselecteerde gegevensbron hebben links die in het paneel worden weergegeven", "source-label": "Bron", - "sub-text": "<0>Definieer welke gegevensbron de correlatie weergeeft en welke gegevens eerder gedefinieerde variabelen vervangen." + "sub-text": "" }, "sub-title": "Definieer hoe gegevens die zich in verschillende gegevensbronnen bevinden zich tot elkaar verhouden. Lees meer in de <2>documentatie", "target-form": { "control-rules": "Dit veld is verplicht.", - "sub-text": "<0>Definieer waaraan de correlatie wordt gekoppeld. Bij het querytype wordt een query uitgevoerd wanneer op de correlatie wordt geklikt. Met het externe type open je een URL door op de correlatie te klikken.", + "sub-text": "", "target-description-external": "Geef de URL op die wordt geopend wanneer op de link wordt geklikt", "target-description-query": "Geef op welke gegevensbron wordt opgevraagd wanneer op de link wordt geklikt", "target-label": "Doel", @@ -4614,7 +4616,7 @@ } }, "confirm-plugin-dashboard-save-modal": { - "body-plugin-dashboard": "Je wijzigingen zullen verloren gaan wanneer je de plug-in bijwerkt.<1><2>Gebruik <1>Opslaan als om een aangepaste versie te maken.", + "body-plugin-dashboard": "", "cancel": "Annuleren", "overwrite": "Overschrijven", "title-plugin-dashboard": "Plug-indashboard" @@ -4831,7 +4833,7 @@ "add-visualization-body": "Selecteer een gegevensbron en zoek en visualiseer je gegevens met grafieken, statistieken en tabellen of maak lijsten, prijsverlagingen en andere widgets.", "add-visualization-button": "Visualisatie toevoegen", "add-visualization-header": "Begin je nieuwe dashboard door een visualisatie toe te voegen", - "import-a-dashboard-body": "Importeer dashboards uit bestanden of <1>grafana.com.", + "import-a-dashboard-body": "", "import-a-dashboard-header": "Dashboard importeren", "import-dashboard-button": "Dashboard importeren", "show-less-dashboards": "", @@ -5289,8 +5291,8 @@ "title-provisioned": "Geprovisioneerd dashboard" }, "save-dashboard-error-proxy": { - "body-name-exists": "Er bestaat al een dashboard met dezelfde naam in de geselecteerde map.<1><2>Wil je dit dashboard nog steeds opslaan?", - "body-version-mismatch": "Iemand anders heeft dit dashboard bijgewerkt<1><2>Wil je dit dashboard nog steeds opslaan?", + "body-name-exists": "", + "body-version-mismatch": "", "confirmText-save-and-overwrite": "Opslaan en overschrijven", "title-name-exists": "Conflict", "title-version-mismatch": "Conflict" @@ -5308,7 +5310,7 @@ "cancel": "Annuleren", "cannot-be-saved": "Dit dashboard kan niet worden opgeslagen vanuit de Grafana-gebruikersinterface omdat het is geprovisioneerd vanuit een andere bron. Kopieer de JSON of sla deze op in een onderstaand bestand. Vervolgens kun je je dashboard bijwerken in de provisioningbron.", "copy-json-to-clipboard": "JSON kopiëren naar klembord", - "file-path": "<0>Bestandspad: {{filePath}} ", + "file-path": "", "save-json-to-file": "JSON opslaan naar bestand", "see-docs": "Bekijk de <2>documentatie voor meer informatie over provisioning." }, @@ -5507,7 +5509,7 @@ "transformation-picker": { "info": "Met transformaties kun je je queryresultaten samenvoegen, berekenen, opnieuw ordenen, verbergen en hernoemen voordat ze worden gevisualiseerd.", "info-graph-not-suitable": "Veel transformaties zijn niet geschikt als je de grafiekvisualisatie gebruikt, omdat deze momenteel alleen tijdreeksgegevens ondersteunt.", - "info-switch-to-table": "Het kan helpen om over te schakelen naar de tabelvisualisatie om te begrijpen wat een transformatie doet. ", + "info-switch-to-table": "", "placeholder-search-for-transformation": "Transformatie zoeken", "read-more": "Lees verder", "title-transformations": "Transformaties" @@ -5573,8 +5575,8 @@ "version-history-comparison": { "button-restore": "Herstellen naar versie {{version}}", "label-view-json-diff": "JSON diff weergeven", - "new-updated-by": "<0>Versie {{version}} bijgewerkt door {{editor}} {{timeAgo}}", - "old-updated-by": "<0>Versie {{version}} bijgewerkt door {{editor}} {{timeAgo}}" + "new-updated-by": "", + "old-updated-by": "" }, "version-history-table": { "aria-label-toggle-selection": "Selectie van versie {{version}} in-/uitschakelen", @@ -5974,7 +5976,7 @@ "cancel": "Annuleren" }, "render-save-button-and-error": { - "body-plugin-dashboard": "Je wijzigingen zullen verloren gaan wanneer je de plug-in bijwerkt. Gebruik <1>Opslaan als om een aangepaste versie te maken.", + "body-plugin-dashboard": "", "title-failed-to-save-dashboard": "Kan dashboard niet opslaan", "title-plugin-dashboard": "Plug-indashboard", "title-someone-else-has-updated-this-dashboard": "Iemand anders heeft dit dashboard bijgewerkt", @@ -5983,7 +5985,7 @@ "save-and-overwrite": "'Opslaan en overschrijven'" }, "library-viz-panel-info": { - "last-edited": "{{timeAgo}} door ", + "last-edited": "", "usage-count_one": "Gebruikt op {{count}} dashboards", "usage-count_other": "Gebruikt op {{count}} dashboards" }, @@ -6044,7 +6046,7 @@ }, "panel-data-queries-tab-rendered": { "add-query": "Query toevoegen", - "expression": "Expressie " + "expression": "" }, "panel-data-transformations-tab": { "tab-label": "Transformaties" @@ -6102,7 +6104,7 @@ "query": "Query" }, "query-variable-editor-form": { - "description-examples": "Benoemde opnamegroepen kunnen worden gebruikt om de weergavetekst en -waarde te scheiden (<1>zie voorbeelden).", + "description-examples": "", "description-optional": "Optioneel, als je een deel van een serienaam of metrisch knooppuntsegment wilt extraheren.", "label-data-source": "Gegevensbron", "label-static-options-sort": "Statische opties sorteren", @@ -6163,7 +6165,7 @@ "label-message": "Bericht", "placeholder-describe-changes-optional": "Een opmerking toevoegen om je wijzigingen te beschrijven (optioneel).", "render-footer": { - "body-plugin-dashboard": "Je wijzigingen zullen verloren gaan wanneer je de plug-in bijwerkt. Gebruik <1>Opslaan als om een aangepaste versie te maken.", + "body-plugin-dashboard": "", "no-changes-to-save": "Geen wijzigingen om op te slaan", "title-failed-to-save-dashboard": "Kan dashboard niet opslaan", "title-plugin-dashboard": "Plug-indashboard", @@ -6199,7 +6201,7 @@ "cancel": "Annuleren", "cannot-be-saved": "Dit dashboard kan niet worden opgeslagen vanuit de Grafana-gebruikersinterface omdat het is geprovisioneerd vanuit een andere bron. Kopieer de JSON of sla deze op in een onderstaand bestand. Vervolgens kun je je dashboard bijwerken in de provisioningbron.", "copy-json-to-clipboard": "JSON kopiëren naar klembord", - "file-path": "<0>Bestandspad: {{filePath}} ", + "file-path": "", "label-description": "Beschrijving", "label-target-folder": "Doelmap", "label-title": "Titel", @@ -6368,8 +6370,8 @@ }, "version-history-comparison": { "label-view-json-diff": "JSON diff weergeven", - "new-version-updated": "<0>Versie {{version}} bijgewerkt door {{editor}} {{timeAgo}}", - "old-version-updated": "<0>Versie {{version}} bijgewerkt door {{editor}} {{timeAgo}}" + "new-version-updated": "", + "old-version-updated": "" }, "version-history-header": { "compare-versions": "{{baseVersion}} <3> {{newVersion}} worden vergelijken", @@ -6447,7 +6449,7 @@ "provisioned-delete-modal": { "confirm-button": "OK", "text-1": "Dit dashboard wordt beheerd door Grafana-provisioning en kan niet worden verwijderd. Verwijder het dashboard uit het configuratiebestand om het te verwijderen.", - "text-2": "Zie Grafana-documentatie voor meer informatie over provisioning. ", + "text-2": "", "text-3": "Bestandspad: {{provisionedId}}", "text-link": "Naar de documentenpagina", "title": "Kan provisioned dashboard niet verwijderen" @@ -6525,7 +6527,7 @@ }, "data-source-testing-status-page": { "error-more-details-link": "Klik <2>hier voor meer informatie over deze fout.", - "success-more-details-links": "Vervolgens kun je beginnen met het visualiseren van gegevens door <2> een dashboard te bouwen of door gegevens op te vragen in de <5> Verkennen-weergave." + "success-more-details-links": "" }, "data-sources": { "datasource-add-button": { @@ -6621,7 +6623,7 @@ "test": "Testen" }, "cloud-info-box": { - "body-alert": "Of bespaar je de moeite en krijg {{mainDS}} (en {{extraDS}}) als volledig beheerde, schaalbare en gehoste gegevensbronnen van Grafana Labs met het <6>altijd gratis Grafana Cloud-abonnement.", + "body-alert": "", "title-alert": "Configureer hieronder je gegevensbron voor {{mainDS}}" }, "dashboards-table": { @@ -6749,18 +6751,18 @@ "no-events-yet": "Nog geen gebeurtenissen" }, "render-info-viewer": { - "data-counter": "Gegevens: {{numDataChanges}} ", + "data-counter": "", "elapsed-time": "Tijd: {{elapsed}} ms", "field": "Veld", "last": "Laatste", - "render-counter": "Weergeven: {{numRenders}} ", - "schema-counter": "Schema: {{numSchemaChanges}} ", + "render-counter": "", + "schema-counter": "", "title-reset-counters": "Tellers resetten", "tooltip-step-back": "Stap achteruit", "type": "Type" }, "state-view": { - "current-value": "Huidige waarde: {{currentValue}} ", + "current-value": "", "label-state-name": "Statusnaam" } }, @@ -7207,7 +7209,7 @@ }, "footer": { "learn-more": "Meer informatie", - "pro-tip-define-sources-through-configuration-files": "ProTip: je kunt ook gegevensbronnen definiëren via configuratiebestanden. " + "pro-tip-define-sources-through-configuration-files": "" } }, "pane": { @@ -7269,8 +7271,6 @@ "query-deleted": "Query verwijderd" }, "rich-history-queries-tab": { - "displaying-partial-queries": "{{ count }} query's weergeven", - "displaying-queries": "{{ count }} query's", "filter-aria-label": "Query's filteren voor gegevensbron(nen)", "filter-history": "Filtergeschiedenis", "filter-placeholder": "Query's filteren voor gegevensbron(nen)", @@ -7280,7 +7280,11 @@ "search-placeholder": "Query's doorzoeken", "showing-queries": "{{ shown }} van {{ total }} wordt weergegeven <0>Meer laden", "sort-aria-label": "Query's sorteren", - "sort-placeholder": "Query's sorteren op" + "sort-placeholder": "Query's sorteren op", + "displaying-partial-queries_one": "", + "displaying-partial-queries_other": "", + "displaying-queries_one": "", + "displaying-queries_other": "" }, "rich-history-settings-tab": { "alert-info": "Grafana houdt invoer bij tot {{optionLabel}}.Items met ster worden niet verwijderd.", @@ -7472,7 +7476,7 @@ "copy-shortened-link-menu": "Opties voor kopiëren van links openen", "refresh-picker-cancel": "Annuleren", "refresh-picker-run": "Query uitvoeren", - "split-close": " Sluiten ", + "split-close": "", "split-close-tooltip": "Gesplitst deelvenster sluiten", "split-narrow": "Smal deelvenster", "split-title": "Splitsen", @@ -7602,8 +7606,8 @@ }, "math": { "available-math-functions": "Beschikbare wiskundige functies", - "run-math-operations": "Voer wiskundige bewerkingen uit op een of meer query's. Je verwijst naar de query met {{refExample}} bijv. {{ref1}}, {{ref2}}, {{ref3}} enz.<10>Voorbeeld: <12>{{example}}", - "tooltip-footer": "Zie onze aanvullende documentatie over <2>wiskundige expressies.", + "run-math-operations": "", + "tooltip-footer": "", "tooltip-title": "Wiskundige operator", "tooltip-trigger": "Expressie" }, @@ -8642,7 +8646,7 @@ }, "data-source-http-settings": { "access-help": "Help <1>", - "access-help-details": "Toegangsmodus bepaalt hoe verzoeken aan de gegevensbron worden afgehandeld.<1> <1>Server moet de voorkeur hebben als er niets anders is vermeld.", + "access-help-details": "", "access-help-title": "Hulp inschakelen", "access-label": "Toegang", "allowed-cookies": "Toegestane cookies", @@ -8910,7 +8914,7 @@ "cell-inspect": "Waarde inspecteren", "cell-inspect-tooltip": "Waarde inspecteren", "copy": "Naar klembord kopiëren", - "csv-counts": "Rijen:{{rows}}, kolommen:{{columns}} <5>", + "csv-counts": "", "csv-placeholder": "Voer hier csv in ...", "filter-placeholder": "Filter waarden", "filter-popup-apply": "Ok", @@ -9195,7 +9199,6 @@ "name-line-width": "Lijndikte", "name-stacking": "Opslaan" }, - "inline-token-warning-badge-tooltip": "", "inspector": { "inspect-data-tab": { "loading": "Bezig met laden", @@ -9359,7 +9362,7 @@ "error-fetching": "Fout bij ophalen van LDAP-instellingen", "error-saving": "Fout bij opslaan van LDAP-instellingen", "error-validate-form": "Fout bij valideren van LDAP-instellingen", - "feature-flag-disabled": "Deze pagina is alleen toegankelijk door de <1> ssoSettingsLDAP functievlag in te schakelen.", + "feature-flag-disabled": "", "saved": "LDAP-instellingen zijn opgeslagen" }, "bind-dn": { @@ -9400,7 +9403,7 @@ "label": "Base dns doorzoeken", "placeholder": "voorbeeld: dc=grafana,dc=org" }, - "subtitle": "Met de LDAP-integratie in Grafana kunnen je Grafana-gebruikers inloggen met hun LDAP-inloggegevens. Lees meer in onze <2><0>documentatie.", + "subtitle": "", "title": "Basisinstellingen" }, "library-panel": { @@ -9444,7 +9447,7 @@ "dashboard-name": "Dashboardnaam" }, "library-panel-info": { - "last-edited": "Laatst gewijzigd op {{timeAgo}} door ", + "last-edited": "", "usage-count_one": "Gebruikt op {{count}} dashboards", "usage-count_other": "Gebruikt op {{count}} dashboards" }, @@ -9749,7 +9752,7 @@ "tooltip-unpin-line": "Vastzetten van lijn ongedaan maken" }, "log-row-message": { - "ellipsis": "… ", + "ellipsis": "", "more": "meer", "see-details": "Zie logboek voor details", "tooltip-error": "Fout: {{errorMessage}}" @@ -10145,7 +10148,7 @@ }, "resource-table": { "dashboard-load-error": "Kan dashboard niet laden", - "error-library-element-sub": "Bibliotheekelement {uid}", + "error-library-element-sub": "", "error-library-element-title": "Kan bibliotheekelement niet laden", "unknown-datasource-title": "Gegevensbron {{datasourceUID}}", "unknown-datasource-type": "Onbekende gegevensbron" @@ -10793,10 +10796,10 @@ "placeholder-optional": "(optioneel)", "role": "Rol", "submit": "Verzenden", - "tooltip": "Je kunt nu de optie 'Geen basisrol' selecteren en toestemmingen toevoegen aan je aangepaste behoeften. Meer informatie vind je in <1>onze documentatie." + "tooltip": "" }, "user-invite-page": { - "sub-title": "Stuur uitnodiging of voeg een bestaande Grafana-gebruiker toe aan de organisatie.<1> {{orgName}}", + "sub-title": "", "text": { "invite-user": "Gebruiker uitnodigen" } @@ -10885,7 +10888,7 @@ "switch-to-table": "Schakelen naar tabel" }, "panel-plugin-error": { - "text-load-error": "Controleer de opstartlogs van de server voor meer informatie. <1>Als deze plug-in is geladen vanuit Git, zorg er dan voor dat deze is gecompileerd.", + "text-load-error": "", "title-load-error": "Er is een fout opgetreden bij het laden van: {{panelId}}", "title-not-found": "Paneelplug-in niet gevonden: {{id}}" }, @@ -11079,7 +11082,7 @@ }, "details": { "connections-tab": { - "description": "Je hebt momenteel de volgende gegevensbronnen geconfigureerd voor {{pluginName}}. Klik op een tegel om de configuratiegegevens te bekijken. Je kunt al je gegevensbronverbindingen vinden in <4><0>Verbindingen - <3>Gegevensbronnen." + "description": "" }, "disabled-error": { "angular-deprecation-link": "Lees meer over het uitfaseren van Angular-functionaliteiten", @@ -11096,7 +11099,7 @@ }, "labels": { "contactGrafanaLabs": "Neem contact op met Grafana Labs", - "customLinks": "Aangepaste links ", + "customLinks": "", "customLinksTooltip": "Deze links worden verstrekt door de ontwikkelaar van de plug-in om aanvullende, ontwikkelaarsspecifieke bronnen en informatie te bieden", "dependencies": "Afhankelijkheden", "documentation": "Documentatie", @@ -11107,7 +11110,7 @@ "latestVersion": "Nieuwste versie", "license": "Licentie", "raiseAnIssue": "Een probleem melden", - "reportAbuse": "Een probleem melden ", + "reportAbuse": "", "reportAbuseTooltip": "Meld problemen met kwaadaardige of schadelijke plug-ins rechtstreeks aan Grafana Labs.", "repository": "Repository", "signature": "Handtekening", @@ -11117,8 +11120,8 @@ "modal": { "cancel": "Annuleren", "copyEmail": "E-mailadres kopiëren", - "description": "Deze functie is voor het melden van kwaadaardig of schadelijk gedrag binnen plug-ins. Voor problemen met plug-ins, stuur een e-mail naar: ", - "node": "Opmerking: neem voor algemene plug-inproblemen zoals bugs of functieverzoeken contact op met de auteur van de plug-in via de verstrekte links. ", + "description": "", + "node": "", "title": "Een probleem met een plug-in melden" } }, @@ -11186,7 +11189,7 @@ "message": "Alle plug-ins zijn up-to-date" }, "not-found-plugin": { - "body-plugin-not-found": "Deze plug-in is niet gevonden. Controleer of de URL correct is of <1>ga naar de <3>plug-incatalogus.", + "body-plugin-not-found": "", "title-plugin-not-found": "Plug-in niet gevonden" }, "plugin-actions": { @@ -11650,7 +11653,6 @@ "unsupported-repository-type": "" }, "inline-secure-values-warning": "", - "inline-token-warning-badge-text": "", "job-status": { "label-view-details": "Details bekijken", "loading-finished-job": "Voltooide taak laden...", @@ -11827,6 +11829,17 @@ "label-current-step": "Huidige stap", "label-pending-step": "Stap in afwachting" }, + "status-badge": { + "automatic-pulling-disabled": "", + "deleting": "", + "error": "", + "pending": "", + "pulling": "", + "unknown": "", + "up-to-date": "", + "waiting-for-health-check": "", + "warning": "" + }, "success-title-default": "Succes", "sync-job": { "error-no-job-id": "Kan taak niet starten", @@ -12004,7 +12017,7 @@ "annotations-show-text": "Annotaties = weergeven", "time-range-picker-disabled-text": "Tijdsbereikkiezer = uitgeschakeld", "time-range-picker-enabled-text": "Tijdsbereikkiezer = ingeschakeld", - "time-range-text": "Tijdsbereik = " + "time-range-text": "" }, "share": { "success-delete": "Je dashboard kan niet meer worden gedeeld" @@ -12043,7 +12056,7 @@ "revoke-user-access-modal-desc-line1": "Weet je zeker dat je de toegang van {{email}} wilt intrekken?" }, "delete-user-shared-dashboards-modal": { - "revoke-user-access-modal-desc-line2": "Met deze actie wordt de toegang van {{email}} tot alle openbare dashboards onmiddellijk ingetrokken." + "revoke-user-access-modal-desc-line2": "" }, "modal": { "shared-dashboard-modal-title": "Gedeelde dashboards" @@ -12212,7 +12225,7 @@ }, "menu": { "clear-button": "Alles wissen", - "tooltip": "Je kunt nu de optie 'Geen basisrol' selecteren en toestemmingen toevoegen aan je aangepaste behoeften. Meer informatie vind je in <1>onze documentatie." + "tooltip": "" }, "menu-aria-label": "Menu rolkiezer", "menu-group-option-aria-label": "Optie rolkiezer", @@ -12222,7 +12235,7 @@ }, "sub-menu-aria-label": "Submenu rolkiezer", "title": { - "description": "Wijs rollen toe aan gebruikers om gedetailleerde controle over de toegang tot Grafana's functies en bronnen te garanderen. Lees meer in onze <2>documentatie." + "description": "" } }, "role-picker-drawer": { @@ -12345,7 +12358,7 @@ }, "select": { "select-menu": { - "selected-count": "Geselecteerd " + "selected-count": "" } }, "service-account-create-page": { @@ -12444,6 +12457,7 @@ "aria-label-role": "Rol" }, "service-account-tokens-table": { + "aria-label-delete-button": "", "created": "Gemaakt", "expires": "Verloopt op", "last-used-at": "Laatst gebruikt op", @@ -12531,7 +12545,7 @@ "info-text": "Maak een directe link naar dit dashboard of paneel, aangepast met de onderstaande opties.", "link-url": "Link-URL", "render-alert": "Afbeeldingweergave-plug-in niet geïnstalleerd", - "render-instructions": "Om een afbeelding weer te geven, moet je de <2>Grafana- afbeeldingsweergave-plug-in installeren. Neem contact op met je Grafana-beheerder om de plug-in te installeren.", + "render-instructions": "", "rendered-image": "Directe link naar gerenderde afbeelding", "save-alert": "Dashboard is niet opgeslagen", "save-dashboard": "Om een paneelafbeelding weer te geven, moet je eerst het dashboard opslaan.", @@ -12555,7 +12569,7 @@ "info-text-1": "Met een snapshot kun je direct een interactief dashboard publiek delen. Bij het maken verwijderen we gevoelige gegevens zoals query's (metriek, sjabloon en annotatie) en paneelkoppelingen, waardoor alleen de zichtbare metrische gegevens en serienamen in je dashboard worden ingesloten.", "info-text-2": "Houd er rekening mee dat je snapshot <1>kan worden bekeken door iedereen die de link heeft en toegang heeft tot de URL. Let goed op wat je deelt.", "local-button": "Snapshot publiceren", - "mistake-message": "Heb je een fout gemaakt? ", + "mistake-message": "", "name": "Snapshotnaam", "timeout": "Time-out (seconden)", "timeout-description": "Mogelijk moet je de time-outwaarde configureren als het lang duurt om je dashboardstatistieken te verzamelen.", @@ -13167,7 +13181,7 @@ "forwards-time-aria-label": "Tijdsbereik vooruitzetten", "to": "tot", "zoom-out-button": "Tijdsbereik uitzoomen", - "zoom-out-tooltip": "Tijdsbereik uitzoomen <1> CTRL+Z" + "zoom-out-tooltip": "" }, "time-range": { "apply": "Tijdsbereik toepassen", @@ -13292,7 +13306,7 @@ }, "transformations": { "empty": { - "add-transformation-body": "Met transformaties kunnen gegevens op verschillende manieren worden gewijzigd voordat je visualisatie wordt weergegeven.<1>Dit omvat het samenvoegen van gegevens, het hernoemen van velden, het maken van berekeningen, het opmaken van gegevens voor weergave en meer.", + "add-transformation-body": "", "add-transformation-header": "Begin met het transformeren van gegevens" } }, @@ -13559,7 +13573,7 @@ "label-format": "Formaat", "label-set-timezone": "Tijdzone instellen", "label-time-field": "Tijdveld", - "tooltip-format": "De uitvoerindeling voor het veld dat is opgegeven als een <2>Moment.js-indelingsreeks.", + "tooltip-format": "", "tooltip-timezone-manually": "Stel de tijdzone van de datum handmatig in" }, "format-time-transformer-editor": { @@ -14154,8 +14168,8 @@ "message": "Geen gebruikers gevonden" }, "token-revoked-modal": { - "auto-revoked": "Je sessietoken is automatisch ingetrokken omdat je <2>het maximale aantal van {{numSessions}} gelijktijdige sessies voor je account hebt bereikt.", - "resume-message": "<0>Log opnieuw in om je sessie te hervatten.Neem contact op met je beheerder of bezoek de licentiepagina om je quotum te bekijken als je herhaaldelijk automatisch wordt afgemeld.", + "auto-revoked": "", + "resume-message": "", "sign-in": "Aanmelden", "title-you-have-been-automatically-signed-out": "Je bent automatisch afgemeld" }, diff --git a/public/locales/pl-PL/grafana.json b/public/locales/pl-PL/grafana.json index def81eec364..37540c44888 100644 --- a/public/locales/pl-PL/grafana.json +++ b/public/locales/pl-PL/grafana.json @@ -108,7 +108,7 @@ "dismiss": "Odrzuć", "heading": "Uwierzytelnianie – Enterprise", "learn-more-link": "Dowiedz się więcej", - "text": "Automatycznie zarządzaj użytkownikami, zespołami i uprawnieniami za pomocą <1>SAML, <3>SCIM, <6>LDAP i <8>RBAC – dostępnych w Grafana Cloud i Enterprise." + "text": "" }, "feature-listing": { "title-auditing": "Audyty", @@ -209,7 +209,7 @@ "title-delete": "Usuń" }, "orgs": { - "delete-body": "Czy na pewno chcesz usunąć „{{deleteOrgName}}”?<3> <5>Wszystkie pulpity tej organizacji zostaną usunięte.", + "delete-body": "", "id-header": "ID", "name-header": "Nazwa", "new-org-button": "Nowa organizacja" @@ -725,6 +725,7 @@ "title-annotations": "Komentarze" }, "link-dashboard-and-panel": "Połącz pulpit i panel", + "placeholder-value-input": "", "placeholder-value-input-default": "Wpisz treść niestandardowej adnotacji…" }, "bulk-actions": { @@ -1154,7 +1155,7 @@ "title-something-wrong-trying-fetch-group-details": "Podczas próby pobrania szczegółów grupy wystąpił problem" }, "evaluation-interval-limit-exceeded": { - "body-minimum-interval": "W usłudze Grafana skonfigurowano minimalny odstęp czasu oceny: <1>{{minInterval}}.<3>Skontaktuj się z administratorem, aby skonfigurować mniejszy odstęp czasu.", + "body-minimum-interval": "", "title-global-evaluation-interval-limit-exceeded": "Przekroczono globalny limit odstępu czasu oceny" }, "existing-rule-editor": { @@ -1302,7 +1303,7 @@ "resolved": "Zakończone" } }, - "review-alert-payload": " Przejrzyj dane alertu, które chcesz dodać do ładunku:", + "review-alert-payload": "", "title-add-custom-alerts": "Dodaj alerty niestandardowe" }, "get-alert-suggestions": { @@ -1426,7 +1427,7 @@ "title-add-folder-and-labels": "Dodaj folder i etykiety" }, "grafana-managed-rule-type": { - "description": "Obsługuje wiele źródeł danych dowolnego rodzaju.<1>Przekształcanie danych za pomocą wyrażeń." + "description": "" }, "grafana-modify-export": { "body-invalid-rule-id": "Identyfikator UID reguły w adresie URL strony jest nieprawidłowy. Sprawdź adres URL i spróbuj ponownie.", @@ -1865,7 +1866,7 @@ "aria-label-new": "nowość" }, "mimir-flavored-type": { - "description": "Użyj źródła danych Mimir, Loki lub Cortex.<1>Wyrażenia nie są obsługiwane." + "description": "" }, "min-interval-option": { "label-interval": "Interwał", @@ -2094,7 +2095,7 @@ "warning-1": "Usunięcie tego zbioru zasad dot. powiadomień jest nieodwracalne.", "warning-2": "Na pewno chcesz usunąć te zasady?" }, - "filter-description": "Filtruj zasady powiadomień, używając oddzielonej przecinkami listy dopasowań, np.:<1>severity=critical, region=EMEA", + "filter-description": "", "generated-policies": "Zasady generowane automatycznie", "matchers": "Dopasowania", "metadata": { @@ -2140,7 +2141,8 @@ "conflict": "Inny użytkownik zaktualizował drzewo zbiorów zasad dot. powiadamiania.", "error-code": "Komunikat o błędzie: „{{error}}”", "routes": { - "conflictingMatchers": "Nie można dodać ani zaktualizować trasy: dopasowywanie będzie w konflikcie z zewnętrznym drzewem routingu, jeśli kryteria {{-matchers}} zostaną scalone. Spowoduje to, że trasa będzie nieosiągalna." + "conflictingMatchers": "Nie można dodać ani zaktualizować trasy: dopasowywanie będzie w konflikcie z zewnętrznym drzewem routingu, jeśli kryteria {{-matchers}} zostaną scalone. Spowoduje to, że trasa będzie nieosiągalna.", + "unknownMatchers": "" }, "suffix": "Odśwież stronę i spróbuj ponownie.", "title": "Nie udało się dodać lub zaktualizować zasad dotyczących powiadomień" @@ -2260,7 +2262,7 @@ "error-no-query-editor": "Nie udało się załadować edytora zapytań. Powód: {{errorMessage}}" }, "recording-rule-type": { - "description": "Oblicz wstępnie wyrażenia.<1>Powinno to być połączone z regułą alertu." + "description": "" }, "recording-rules": { "description-target-data-source": "Źródło danych Prometheus, w którym mają być przechowywane reguły rejestrowania", @@ -2273,7 +2275,7 @@ }, "redirect-to-clone-rule": { "body-evaluation-group": "Konieczne będzie ustawienie nowej grupy oceny dla skopiowanej reguły, ponieważ oryginalna grupa została aprowizowana i nie można jej użyć w przypadku reguł utworzonych w interfejsie użytkownika.", - "body-not-provisioned": "Nowa reguła <1>nie zostanie oznaczona jako reguła po aprowizacji.", + "body-not-provisioned": "", "confirmText-copy": "Kopiuj", "title-copy-provisioned-alert-rule": "Kopiuj regułę aprowizowanego alertu" }, @@ -2308,13 +2310,13 @@ "routing-settings": { "aria-label-group-by": "Grupuj według", "description-group-by": "Połącz wiele alertów w jedno powiadomienie, grupując je według tych samych wartości etykiet. Jeśli pole jest puste, jego wartość jest dziedziczona na podstawie domyślnej zasady dotyczącej powiadomień.", - "group-interval": "Odstęp czasu grupy: <1>{{groupIntervalValue}}", - "group-wait": "Oczekiwanie grupy: <1>{{groupWaitValue}}", - "grouping": "Grupowanie: <1>{{fields}}", + "group-interval": "", + "group-wait": "", + "grouping": "", "label-group-by": "Grupuj według", "label-override-grouping": "Zastąp grupowanie", "label-override-timings": "Zastąp harmonogramy", - "repeat-interval": "Powtarzanie odstępu czasu: <1>{{repeatIntervalValue}}" + "repeat-interval": "" }, "rule-actions-buttons": { "title-edit": "Edytuj", @@ -2578,7 +2580,7 @@ "relative-with-to": "" }, "rule-type-picker": { - "grafana-managed": "Wybierz „Zarządzane przez Grafana”, chyba że masz źródło danych Mimir, Loki lub Cortex z włączonym interfejsem API Ruler." + "grafana-managed": "" }, "rule-view": { "query": { @@ -2911,7 +2913,7 @@ "test-contact-point-modal": { "custom-notification-message": "Wyślesz powiadomienie testowe, które będzie korzystać z adnotacji zdefiniowanych poniżej. Jest to dobra opcja, jeśli korzystasz z niestandardowych szablonów i wiadomości.", "notification-message": "Wiadomość z powiadomieniem", - "predefined-notification-message": "Wyślesz powiadomienie testowe, które będzie korzystać ze wstępnie zdefiniowanego alertu. Jeśli zdefiniowano niestandardowy szablon lub wiadomość, w celu uzyskania lepszych wyników u góry przełącz się na <1>niestandardową wiadomość z powiadomieniem.", + "predefined-notification-message": "", "send-test-notification": "Wyślij powiadomienie testowe", "title-test-contact-point": "Testuj punkt kontaktu" }, @@ -2920,7 +2922,7 @@ }, "threshold-expression-viewer": { "input": "Wejście", - "stop-alerting-when": "Zatrzymaj alerty (lub stan oczekiwania), gdy " + "stop-alerting-when": "" }, "time-interval": { "add-time-interval": "Dodaj odstęp czasu", @@ -3108,7 +3110,7 @@ "title-notification-policies": "Zasady powiadamiania" }, "yaml-content-info": { - "body": "Treść YAML w edytorze zawiera tylko konfigurację reguły alertu. <1>Aby skonfigurować usługę Prometheus, musisz podać resztę <4>zawartości pliku konfiguracyjnego." + "body": "" } }, "alertlist": { @@ -3184,7 +3186,7 @@ "no-annotations-found": "Nie znaleziono adnotacji" }, "annotation-list-item": { - "tooltip-created-by": "Utworzone przez:<1> {{email}}" + "tooltip-created-by": "" }, "category-annotation-query": "Zapytanie dotyczące adnotacji", "category-display": "Wyświetl", @@ -3222,7 +3224,7 @@ }, "empty-state": { "button-title": "Dodaj zapytanie do komentarza", - "info-box-content": "<0>Komentarze umożliwiają integrację danych zdarzeń z wykresami. Są one wizualizowane jako pionowe linie i ikony na wszystkich panelach wykresów. Po najechaniu kursorem na ikonę komentarza możesz odczytać tekst związany ze zdarzeniem i poznać jego znaczniki. Zdarzenia komentarzy można dodawać bezpośrednio w usłudze Grafana, przytrzymując klawisz CTRL lub CMD i klikając wykres (lub przeciągając region). Zostaną one zapisane w bazie komentarzy Grafana.", + "info-box-content": "", "info-box-content-2": "Więcej informacji można znaleźć w <2>dokumentacji komentarzy.", "title": "Brak dodanych niestandardowych zapytań do komentarzy" }, @@ -3260,7 +3262,7 @@ "auth-settings": "Ustawienia uwierzytelniania" }, "auth-drawer-unconneced": { - "subtitle": "Skonfiguruj ustawienia uwierzytelniania. Więcej informacji znajdziesz w <2>dokumentacji." + "subtitle": "" }, "auth-drawer-unconnected": { "advanced-auth": "Zaawansowane uwierzytelnianie", @@ -3294,7 +3296,7 @@ "allowed-organizations-description": "Lista organizacji rozdzielona przecinkami lub spacjami. Użytkownik musi należeć do co najmniej \njednej organizacji, aby się zalogować.", "allowed-organizations-label": "Dozwolone organizacje", "allowed-organizations-placeholder": "Wprowadź organizacje (mój-zespół, mój_zespół itp.) i naciśnij klawisz Enter, aby je dodać", - "api-url-description": "Punkt końcowy dostawcy OAuth2 udostępniający informacje o użytkownikach. Informacje zwracane przez ten punkt końcowy muszą być zgodne z formatem <2>OpenID UserInfo.", + "api-url-description": "", "api-url-required": "To pole musi zawierać prawidłowy adres URL, jeśli jest ustawiony.", "auth-style-description": "Określa, w jaki sposób „{{ clientIDLabel }}” i „{{ clientSecretLabel }}” są wysyłane do dostawcy OAuth2. Domyślnie jest to tryb automatycznego wykrywania.", "auth-style-label": "Styl uwierzytelniania", @@ -3439,7 +3441,7 @@ } }, "auth-config-auth-config-page-unconnected": { - "subtitle": "Zarządzaj ustawieniami uwierzytelniania i skonfiguruj logowanie jednokrotne. Więcej informacji znajdziesz w <2>dokumentacji." + "subtitle": "" }, "bar-chart": { "warn": { @@ -4173,7 +4175,7 @@ }, "scopes": { "apply-selected-scopes": "Zastosuj", - "selected-scopes-label": "Zakresy: " + "selected-scopes-label": "" }, "search-box": { "placeholder": "Wyszukaj lub przejdź do…" @@ -4315,7 +4317,7 @@ "okay": "OK" }, "not-found-datasource": { - "body": "Być może błędnie wpisano adres URL lub wtyczka o identyfikatorze <1> jest niedostępna.<3>Aby wyświetlić listę dostępnych źródeł danych, <5>kliknij tutaj." + "body": "" }, "oss": { "connections-home-page": { @@ -4358,8 +4360,8 @@ "versionHistory": { "comparison": { "header": { - "hide-json-diff": "Ukryj różnicę JSON ", - "show-json-diff": "Pokaż różnicę JSON ", + "hide-json-diff": "", + "show-json-diff": "", "text": "Wersja {{version}} zaktualizowana przez {{createdBy}} ({{ageString}}) {{message}} " }, "select": "Wybierz dwie wersje, aby rozpocząć porównywanie" @@ -4386,7 +4388,7 @@ "label-label": "Etykieta", "label-placeholder": "np. śledzenie Tempo", "label-required": "To pole jest wymagane.", - "sub-text": "<0>Zdefiniuj tekst, który opisze korelację.", + "sub-text": "", "title": "Zdefiniuj etykietę korelacji (krok 1 z 3)" }, "configure-correlation-target-form": { @@ -4430,7 +4432,7 @@ }, "source-form": { "control-required": "To pole jest wymagane.", - "description": "Aby przycisk korelacji pojawił się na wizualizacji, punkt danych musi dostarczać wartości do wszystkich zmiennych w postaci pól lub danych wyjściowych transformacji.<1>Uwaga: nie każda zmienna musi być wyraźnie zdefiniowana poniżej. Transformacja taka jak <4>logfmt utworzy zmienne dla każdej pary klucz/wartość.", + "description": "", "description-external-pre": "W docelowym adresie URL użyto następujących zmiennych:", "description-query-pre": "W zapytaniu docelowym użyto następujących zmiennych:", "external-title": "Skonfiguruj źródło danych, które będzie korzystać z adresu URL (krok 3 z 3)", @@ -4442,12 +4444,12 @@ "results-required": "To pole jest wymagane.", "source-description": "Przy wynikach z wybranego źródła danych w panelu widoczne są linki", "source-label": "Źródło", - "sub-text": "<0>Zdefiniuj, które źródło danych wyświetli korelację i które dane zastąpią wcześniej zdefiniowane zmienne." + "sub-text": "" }, "sub-title": "Zdefiniuj zależności między danymi z różnych źródeł. Więcej informacji znajdziesz w <2>dokumentacji", "target-form": { "control-rules": "To pole jest wymagane.", - "sub-text": "<0>Zdefiniuj, z czym będzie się łączyć korelacja. W przypadku typu zapytania zapytanie zostanie uruchomione po kliknięciu korelacji. W przypadku typu zewnętrznego kliknięcie korelacji otworzy adres URL.", + "sub-text": "", "target-description-external": "Podaj adres URL, który otworzy się po kliknięciu linku", "target-description-query": "Określ, którego źródła danych będzie dotyczyć zapytanie utworzone po kliknięciu linku", "target-label": "Cel", @@ -4654,7 +4656,7 @@ } }, "confirm-plugin-dashboard-save-modal": { - "body-plugin-dashboard": "Zmiany zostaną utracone po zaktualizowaniu wtyczki.<1><2>Użyj opcji <1>Zapisz jako, aby utworzyć wersję niestandardową.", + "body-plugin-dashboard": "", "cancel": "Anuluj", "overwrite": "Zastąp", "title-plugin-dashboard": "Pulpit wtyczek" @@ -4871,7 +4873,7 @@ "add-visualization-body": "Wybierz źródło danych, a następnie wyszukaj i zwizualizuj dane na wykresach, w statystykach i tabelach lub utwórz listy, korzystaj ze znaczników markdown i innych widżetów.", "add-visualization-button": "Dodaj wizualizację", "add-visualization-header": "Dodaj wizualizację, aby rozpocząć tworzenie nowego pulpitu", - "import-a-dashboard-body": "Zaimportuj pulpity z plików lub witryny <2>grafana.com.", + "import-a-dashboard-body": "", "import-a-dashboard-header": "Importuj pulpit", "import-dashboard-button": "Importuj pulpit", "show-less-dashboards": "", @@ -5331,8 +5333,8 @@ "title-provisioned": "Pulpit aprowizowany" }, "save-dashboard-error-proxy": { - "body-name-exists": "W wybranym folderze istnieje już pulpit o tej samej nazwie.<1><2>Czy nadal chcesz zapisać ten pulpit?", - "body-version-mismatch": "Ktoś inny zaktualizował ten pulpit<1><2>Czy nadal chcesz zapisać ten pulpit?", + "body-name-exists": "", + "body-version-mismatch": "", "confirmText-save-and-overwrite": "Zapisz i zastąp", "title-name-exists": "Konflikt", "title-version-mismatch": "Konflikt" @@ -5350,7 +5352,7 @@ "cancel": "Anuluj", "cannot-be-saved": "Nie można zapisać tego pulpitu z poziomu interfejsu Grafany, ponieważ został on skonfigurowany z innego źródła. Skopiuj treść JSON lub zapisz ją w poniższym pliku, a następnie zaktualizuj pulpit w źródle aprowizacji.", "copy-json-to-clipboard": "Kopiuj JSON do schowka", - "file-path": "<0>Ścieżka do pliku: {{filePath}}", + "file-path": "", "save-json-to-file": "Zapisz JSON w pliku", "see-docs": "Więcej informacji na temat konfiguracji można znaleźć w <2>dokumentacji." }, @@ -5549,7 +5551,7 @@ "transformation-picker": { "info": "Transformacje umożliwiają łączenie, obliczanie, zmianę kolejności, ukrywanie i zmienianie nazw wyników zapytania przed ich wizualizacją.", "info-graph-not-suitable": "Wiele transformacji nie jest odpowiednich, jeśli korzystasz z wizualizacji wykresów, ponieważ obecnie obsługuje ona tylko dane szeregów czasowych.", - "info-switch-to-table": "Aby zrozumieć, na czym polega transformacja, pomocne może być przejście na wizualizację tabeli. ", + "info-switch-to-table": "", "placeholder-search-for-transformation": "Szukaj transformacji", "read-more": "Czytaj więcej", "title-transformations": "Transformacje" @@ -5615,8 +5617,8 @@ "version-history-comparison": { "button-restore": "Przywróć do wersji {{version}}", "label-view-json-diff": "Wyświetl plik diff JSON", - "new-updated-by": "<0>Wersja {{version}} zaktualizowana przez: {{editor}}, {{timeAgo}}", - "old-updated-by": "<0>Wersja {{version}} zaktualizowana przez: {{editor}}, {{timeAgo}}" + "new-updated-by": "", + "old-updated-by": "" }, "version-history-table": { "aria-label-toggle-selection": "Przełącz wybór wersji {{version}}", @@ -6016,7 +6018,7 @@ "cancel": "Anuluj" }, "render-save-button-and-error": { - "body-plugin-dashboard": "Zmiany zostaną utracone po zaktualizowaniu wtyczki. Użyj opcji <1>Zapisz jako, aby utworzyć wersję niestandardową.", + "body-plugin-dashboard": "", "title-failed-to-save-dashboard": "Nie udało się zapisać pulpitu", "title-plugin-dashboard": "Pulpit wtyczek", "title-someone-else-has-updated-this-dashboard": "Ktoś inny zaktualizował ten pulpit", @@ -6025,7 +6027,7 @@ "save-and-overwrite": "„Zapisz i zastąp”" }, "library-viz-panel-info": { - "last-edited": "{{timeAgo}} przez: ", + "last-edited": "", "usage-count_one": "Używane na {{count}} pulpitach", "usage-count_few": "Używane na {{count}} pulpitach", "usage-count_many": "Używane na {{count}} pulpitach", @@ -6088,7 +6090,7 @@ }, "panel-data-queries-tab-rendered": { "add-query": "Dodaj zapytanie", - "expression": "Wyrażenie " + "expression": "" }, "panel-data-transformations-tab": { "tab-label": "Transformacje" @@ -6146,7 +6148,7 @@ "query": "Zapytanie" }, "query-variable-editor-form": { - "description-examples": "Nazwane grupy rejestracji mogą być używane do oddzielania wyświetlanego tekstu i wartości (<1>patrz przykłady).", + "description-examples": "", "description-optional": "Opcjonalnie pozwalają wyodrębnić część nazwy serii lub segmentu węzła metryki.", "label-data-source": "Źródło danych", "label-static-options-sort": "Sortowanie opcji statycznych", @@ -6207,7 +6209,7 @@ "label-message": "Wiadomość", "placeholder-describe-changes-optional": "Dodaj notatkę, aby opisać zmiany (opcjonalnie).", "render-footer": { - "body-plugin-dashboard": "Zmiany zostaną utracone po zaktualizowaniu wtyczki. Użyj opcji <1>Zapisz jako, aby utworzyć wersję niestandardową.", + "body-plugin-dashboard": "", "no-changes-to-save": "Brak zmian do zapisania", "title-failed-to-save-dashboard": "Nie udało się zapisać pulpitu", "title-plugin-dashboard": "Pulpit wtyczek", @@ -6245,7 +6247,7 @@ "cancel": "Anuluj", "cannot-be-saved": "Nie można zapisać tego pulpitu z poziomu interfejsu Grafany, ponieważ został on skonfigurowany z innego źródła. Skopiuj treść JSON lub zapisz ją w poniższym pliku, a następnie zaktualizuj pulpit w źródle aprowizacji.", "copy-json-to-clipboard": "Kopiuj JSON do schowka", - "file-path": "<0>Ścieżka do pliku: {{filePath}}", + "file-path": "", "label-description": "Opis", "label-target-folder": "Katalog docelowy", "label-title": "Tytuł", @@ -6414,8 +6416,8 @@ }, "version-history-comparison": { "label-view-json-diff": "Wyświetl plik diff JSON", - "new-version-updated": "<0>Wersja {{version}} zaktualizowana przez: {{editor}}, {{timeAgo}}", - "old-version-updated": "<0>Wersja {{version}} zaktualizowana przez: {{editor}}, {{timeAgo}}" + "new-version-updated": "", + "old-version-updated": "" }, "version-history-header": { "compare-versions": "Porównanie: {{baseVersion}} <3> {{newVersion}}", @@ -6493,7 +6495,7 @@ "provisioned-delete-modal": { "confirm-button": "OK", "text-1": "Ten pulpit nawigacyjny jest zarządzany z poziomu konfiguracji w usłudze Grafana i nie można go usunąć. Aby go usunąć, usuń pulpit z pliku konfiguracyjnego.", - "text-2": "Więcej informacji na temat konfiguracji można znaleźć w dokumentacji usługi Grafana. ", + "text-2": "", "text-3": "Ścieżka pliku: {{provisionedId}}", "text-link": "Przejdź do strony dokumentów", "title": "Nie można usunąć skonfigurowanego pulpitu" @@ -6571,7 +6573,7 @@ }, "data-source-testing-status-page": { "error-more-details-link": "Kliknij <2>tutaj, aby dowiedzieć się więcej o tym błędzie.", - "success-more-details-links": "Następnie możesz rozpocząć wizualizację danych, <2>tworząc pulpit lub tworząc zapytanie dotyczące danych w widoku <5>Eksploruj." + "success-more-details-links": "" }, "data-sources": { "datasource-add-button": { @@ -6667,7 +6669,7 @@ "test": "Test" }, "cloud-info-box": { - "body-alert": "Możesz ułatwić sobie życie i wybrać {{mainDS}} (oraz {{extraDS}}) jako w pełni zarządzane, skalowalne źródła danych hostowane przez Grafana Labs w ramach <6>planu Grafana Cloud, który będzie zawsze bezpłatny.", + "body-alert": "", "title-alert": "Skonfiguruj źródło danych {{mainDS}} poniżej" }, "dashboards-table": { @@ -6795,18 +6797,18 @@ "no-events-yet": "Jeszcze nie ma zdarzeń" }, "render-info-viewer": { - "data-counter": "Dane: {{numDataChanges}} ", + "data-counter": "", "elapsed-time": "Czas: {{elapsed}} ms", "field": "Pole", "last": "Ostatni", - "render-counter": "Renderowanie: {{numRenders}} ", - "schema-counter": "Schemat: {{numSchemaChanges}} ", + "render-counter": "", + "schema-counter": "", "title-reset-counters": "Resetuj liczniki", "tooltip-step-back": "Krok wstecz", "type": "Typ" }, "state-view": { - "current-value": "Bieżąca wartość: {{currentValue}} ", + "current-value": "", "label-state-name": "Nazwa stanu" } }, @@ -7253,7 +7255,7 @@ }, "footer": { "learn-more": "Dowiedz się więcej", - "pro-tip-define-sources-through-configuration-files": " Wskazówka: źródła danych można też definiować za pomocą plików konfiguracyjnych. " + "pro-tip-define-sources-through-configuration-files": "" } }, "pane": { @@ -7315,8 +7317,6 @@ "query-deleted": "Usunięto zapytanie" }, "rich-history-queries-tab": { - "displaying-partial-queries": "Wyświetlanie {{ count }} zapytań", - "displaying-queries": "Liczba zapytań: {{ count }}", "filter-aria-label": "Filtruj zapytania dla źródeł danych", "filter-history": "Filtruj historię", "filter-placeholder": "Filtruj zapytania dla źródeł danych", @@ -7326,7 +7326,15 @@ "search-placeholder": "Szukaj zapytań", "showing-queries": "Wyświetlono {{ shown }} z {{ total }} <0>Załaduj więcej", "sort-aria-label": "Sortuj zapytania", - "sort-placeholder": "Sortuj zapytania według" + "sort-placeholder": "Sortuj zapytania według", + "displaying-partial-queries_one": "", + "displaying-partial-queries_few": "", + "displaying-partial-queries_many": "", + "displaying-partial-queries_other": "", + "displaying-queries_one": "", + "displaying-queries_few": "", + "displaying-queries_many": "", + "displaying-queries_other": "" }, "rich-history-settings-tab": { "alert-info": "Grafana zachowa wpisy do {{optionLabel}}.Wpisy oznaczone gwiazdką nie zostaną usunięte.", @@ -7518,7 +7526,7 @@ "copy-shortened-link-menu": "Otwórz opcje kopiowania linku", "refresh-picker-cancel": "Anuluj", "refresh-picker-run": "Uruchom zapytanie", - "split-close": " Zamknij ", + "split-close": "", "split-close-tooltip": "Zamknij podzielone okienko", "split-narrow": "Wąskie okno", "split-title": "Podział", @@ -7648,8 +7656,8 @@ }, "math": { "available-math-functions": "Dostępne funkcje matematyczne", - "run-math-operations": "Uruchom operacje matematyczne na co najmniej jednym zapytaniu. Odwołujesz się do zapytania za pomocą {{refExample}}, czyli {{ref1}}, {{ref2}}, {{ref3}} itp.<10>Przykład: <12>{{example}}", - "tooltip-footer": "Zapoznaj się z naszą dodatkową dokumentacją na temat <2>wyrażeń matematycznych.", + "run-math-operations": "", + "tooltip-footer": "", "tooltip-title": "Operator matematyczny", "tooltip-trigger": "Wyrażenie" }, @@ -8708,7 +8716,7 @@ }, "data-source-http-settings": { "access-help": "Pomoc <1>", - "access-help-details": "Tryb dostępu kontroluje sposób obsługi żądań do źródła danych.Jeśli nie określono inaczej, preferowanym trybem powinien być <1> <1>Serwer.", + "access-help-details": "", "access-help-title": "Uzyskaj dostęp do pomocy", "access-label": "Dostęp", "allowed-cookies": "Dozwolone pliki cookie", @@ -8976,7 +8984,7 @@ "cell-inspect": "Sprawdź wartość", "cell-inspect-tooltip": "Sprawdź wartość", "copy": "Kopiuj do schowka", - "csv-counts": "Wiersze:{{rows}}, Kolumny:{{columns}} <5>", + "csv-counts": "", "csv-placeholder": "Wprowadź plik CSV tutaj…", "filter-placeholder": "Wartości filtra", "filter-popup-apply": "OK", @@ -9261,7 +9269,6 @@ "name-line-width": "Szerokość linii", "name-stacking": "Układanie" }, - "inline-token-warning-badge-tooltip": "", "inspector": { "inspect-data-tab": { "loading": "Ładowanie", @@ -9429,7 +9436,7 @@ "error-fetching": "Błąd podczas pobierania ustawień LDAP", "error-saving": "Błąd zapisywania ustawień LDAP", "error-validate-form": "Błąd walidacji ustawień LDAP", - "feature-flag-disabled": "Ta strona jest dostępna tylko po włączeniu flagi funkcji <1>ssoSettingsLDAP.", + "feature-flag-disabled": "", "saved": "Ustawienia LDAP zapisane" }, "bind-dn": { @@ -9470,7 +9477,7 @@ "label": "Baza wyszukiwania adresów DNS", "placeholder": "przykład: dc=grafana,dc=org" }, - "subtitle": "Integracja LDAP w usłudze Grafana umożliwia jej użytkownikom logowanie się przy użyciu poświadczeń LDAP. Więcej informacji znajdziesz w naszej <2><0>dokumentacji.", + "subtitle": "", "title": "Podstawowe ustawienia" }, "library-panel": { @@ -9514,7 +9521,7 @@ "dashboard-name": "Nazwa pulpitu" }, "library-panel-info": { - "last-edited": "Ostatnio edytowane {{timeAgo}} przez: ", + "last-edited": "", "usage-count_one": "Używane na {{count}} pulpitu", "usage-count_few": "Używane na {{count}} pulpitach", "usage-count_many": "Używane na {{count}} pulpitu", @@ -9831,7 +9838,7 @@ "tooltip-unpin-line": "Odepnij wiersz" }, "log-row-message": { - "ellipsis": "… ", + "ellipsis": "", "more": "więcej", "see-details": "Zobacz szczegóły logu", "tooltip-error": "Błąd: {{errorMessage}}" @@ -10227,7 +10234,7 @@ }, "resource-table": { "dashboard-load-error": "Nie można załadować pulpitu", - "error-library-element-sub": "Element biblioteki {uid}", + "error-library-element-sub": "", "error-library-element-title": "Nie można załadować elementu biblioteki", "unknown-datasource-title": "Źródło danych {{datasourceUID}}", "unknown-datasource-type": "Nieznane źródło danych" @@ -10881,10 +10888,10 @@ "placeholder-optional": "(opcjonalnie)", "role": "Rola", "submit": "Prześlij", - "tooltip": "Możesz teraz wybrać opcję „Brak podstawowej roli” i dodać uprawnienia zgodnie z własnymi potrzebami. Więcej informacji znajdziesz w <1>dokumentacji." + "tooltip": "" }, "user-invite-page": { - "sub-title": "Wyślij zaproszenie lub dodaj istniejącego użytkownika Grafany do organizacji.<1> {{orgName}}", + "sub-title": "", "text": { "invite-user": "Zaproś użytkownika" } @@ -10973,7 +10980,7 @@ "switch-to-table": "Przełącz na tabelę" }, "panel-plugin-error": { - "text-load-error": "Więcej informacji znajdziesz w logach uruchamiania serwera. <1>Jeśli ta wtyczka została załadowana z serwisu Git, upewnij się, że została skompilowana.", + "text-load-error": "", "title-load-error": "Błąd podczas wczytywania panelu: {{panelId}}", "title-not-found": "Nie znaleziono wtyczki panelu: {{id}}" }, @@ -11167,7 +11174,7 @@ }, "details": { "connections-tab": { - "description": "{{pluginName}} ma skonfigurowane następujące źródła danych. Kliknij kafelek, aby wyświetlić szczegóły konfiguracji. Wszystkie połączenia źródeł danych znajdziesz w sekcji <4><0>Połączenia – <3>Źródła danych." + "description": "" }, "disabled-error": { "angular-deprecation-link": "Dowiedz się więcej o deprecjacji Angular", @@ -11184,7 +11191,7 @@ }, "labels": { "contactGrafanaLabs": "Skontaktuj się z Grafana Labs", - "customLinks": "Linki niestandardowe ", + "customLinks": "", "customLinksTooltip": "Linki te udostępnia programista wtyczki w celu zaoferowania dodatkowych, właściwych dla programisty zasobów i informacji", "dependencies": "Zależności", "documentation": "Dokumentacja", @@ -11195,7 +11202,7 @@ "latestVersion": "Najnowsza wersja", "license": "Licencja", "raiseAnIssue": "Zgłoś sprawę", - "reportAbuse": "Zgłoś problem ", + "reportAbuse": "", "reportAbuseTooltip": "Zgłaszaj sprawy związane ze złośliwymi lub szkodliwymi wtyczkami bezpośrednio do Grafana Labs.", "repository": "Repozytorium", "signature": "Podpis", @@ -11205,8 +11212,8 @@ "modal": { "cancel": "Anuluj", "copyEmail": "Kopiuj adres e-mail", - "description": "Ta funkcja służy do zgłaszania złośliwych lub szkodliwych zachowań w ramach wtyczek. W przypadku problemów z wtyczką napisz do nas na adres: ", - "node": "Uwaga: w przypadku ogólnych problemów z wtyczką, takich jak błędy lub prośby o dodanie nowych funkcji, skontaktuj się z autorem wtyczki, korzystając z podanych linków. ", + "description": "", + "node": "", "title": "Zgłoś problem z wtyczką" } }, @@ -11274,7 +11281,7 @@ "message": "Wszystkie wtyczki są aktualne" }, "not-found-plugin": { - "body-plugin-not-found": "Nie można znaleźć wtyczki. Sprawdź, czy adres URL jest poprawny, lub <1>przejdź do <3>katalogu wtyczek.", + "body-plugin-not-found": "", "title-plugin-not-found": "Nie znaleziono wtyczki" }, "plugin-actions": { @@ -11750,7 +11757,6 @@ "unsupported-repository-type": "" }, "inline-secure-values-warning": "", - "inline-token-warning-badge-text": "", "job-status": { "label-view-details": "Zobacz szczegóły", "loading-finished-job": "Wczytywanie zakończonego zadania…", @@ -11927,6 +11933,17 @@ "label-current-step": "Aktualny krok", "label-pending-step": "Oczekujący krok" }, + "status-badge": { + "automatic-pulling-disabled": "", + "deleting": "", + "error": "", + "pending": "", + "pulling": "", + "unknown": "", + "up-to-date": "", + "waiting-for-health-check": "", + "warning": "" + }, "success-title-default": "Powodzenie", "sync-job": { "error-no-job-id": "Nie udało się uruchomić zadania", @@ -12104,7 +12121,7 @@ "annotations-show-text": "Komentarze = pokaż", "time-range-picker-disabled-text": "Selektor zakresu czasu = wyłączony", "time-range-picker-enabled-text": "Selektor zakresu czasu = włączony", - "time-range-text": "Zakres czasu = " + "time-range-text": "" }, "share": { "success-delete": "Nie można już udostępnić pulpitu" @@ -12143,7 +12160,7 @@ "revoke-user-access-modal-desc-line1": "Czy na pewno chcesz cofnąć dostęp dla konta {{email}}?" }, "delete-user-shared-dashboards-modal": { - "revoke-user-access-modal-desc-line2": "To działanie spowoduje natychmiastowe odebranie dostępu konta {{email}} do wszystkich pulpitów udostępnionych." + "revoke-user-access-modal-desc-line2": "" }, "modal": { "shared-dashboard-modal-title": "Udostępnione pulpity" @@ -12318,7 +12335,7 @@ }, "menu": { "clear-button": "Wyczyść wszystko", - "tooltip": "Możesz teraz wybrać opcję „Brak podstawowej roli” i dodać uprawnienia zgodnie z własnymi potrzebami. Więcej informacji znajdziesz w <1>dokumentacji." + "tooltip": "" }, "menu-aria-label": "Menu selektora ról", "menu-group-option-aria-label": "Opcja selektora ról", @@ -12328,7 +12345,7 @@ }, "sub-menu-aria-label": "Podmenu selektora ról", "title": { - "description": "Przypisz użytkownikom role, aby zapewnić szczegółową kontrolę nad dostępem do funkcji i zasobów usługi Grafana. Więcej informacji znajdziesz w <2><0>dokumentacji." + "description": "" } }, "role-picker-drawer": { @@ -12451,7 +12468,7 @@ }, "select": { "select-menu": { - "selected-count": "Wybrano " + "selected-count": "" } }, "service-account-create-page": { @@ -12550,6 +12567,7 @@ "aria-label-role": "Rola" }, "service-account-tokens-table": { + "aria-label-delete-button": "", "created": "Utworzono", "expires": "Wygasa", "last-used-at": "Ostatnio używane", @@ -12639,7 +12657,7 @@ "info-text": "Utwórz bezpośredni link do tego pulpitu lub panelu, dostosowany za pomocą poniższych opcji.", "link-url": "Link URL", "render-alert": "Nie zainstalowano wtyczki renderowania obrazów", - "render-instructions": "Aby wyrenderować obraz, musisz zainstalować <2>wtyczkę do renderowania obrazów w Grafanie. Skontaktuj się z administratorem usługi Grafana, aby zainstalować wtyczkę.", + "render-instructions": "", "rendered-image": "Obraz renderowany z bezpośredniego linku", "save-alert": "Nie zapisano pulpitu", "save-dashboard": "Aby wyrenderować obraz panelu, musisz najpierw zapisać pulpit.", @@ -12663,7 +12681,7 @@ "info-text-1": "Migawka to błyskawiczny sposób na publiczne udostępnienie interaktywnego pulpitu. Po utworzeniu usuwamy wrażliwe dane, takie jak zapytania (dane, szablony i komentarze) oraz linki do paneli, pozostawiając tylko widoczne dane metryczne i nazwy serii osadzone na pulpicie.", "info-text-2": "Pamiętaj, że Twoją migawkę <1>może wyświetlić każdy, kto ma link i dostęp do adresu URL. Dziel się mądrze.", "local-button": "Opublikuj migawkę", - "mistake-message": "Czy to błąd? ", + "mistake-message": "", "name": "Nazwa migawki", "timeout": "Limit czasu (w sekundach)", "timeout-description": "Jeśli zbieranie danych z pulpitu zajmuje dużo czasu, może być konieczne skonfigurowanie wartości limitu czasu.", @@ -13277,7 +13295,7 @@ "forwards-time-aria-label": "Przesuń zakres czasu do przodu", "to": "do", "zoom-out-button": "Oddal zakres czasu", - "zoom-out-tooltip": "Oddal zakres czasu <1> CTRL+Z" + "zoom-out-tooltip": "" }, "time-range": { "apply": "Zastosuj zakres czasu", @@ -13402,7 +13420,7 @@ }, "transformations": { "empty": { - "add-transformation-body": "Transformacje umożliwiają zmianę danych na różne sposoby przed wyświetleniem wizualizacji.<1>Obejmuje to łączenie danych, zmianę nazw pól, wykonywanie obliczeń, formatowanie danych do wyświetlania i inne czynności.", + "add-transformation-body": "", "add-transformation-header": "Rozpocznij transformację danych" } }, @@ -13669,7 +13687,7 @@ "label-format": "Format", "label-set-timezone": "Ustaw strefę czasową", "label-time-field": "Pole czasu", - "tooltip-format": "Format wyjściowy pola określonego jako <2>Ciąg formatowania Moment.js.", + "tooltip-format": "", "tooltip-timezone-manually": "Ręcznie ustaw strefę czasową daty" }, "format-time-transformer-editor": { @@ -14264,8 +14282,8 @@ "message": "Nie znaleziono użytkowników" }, "token-revoked-modal": { - "auto-revoked": "Token sesji został automatycznie unieważniony, ponieważ osiągnięto <2>maksymalną liczbę {{numSessions}} jednoczesnych sesji na koncie.", - "resume-message": "<0>Aby wznowić sesję, zaloguj się ponownie.W przypadku wielokrotnego automatycznego wylogowania skontaktuj się z administratorem lub odwiedź stronę licencji, aby sprawdzić swój limit.", + "auto-revoked": "", + "resume-message": "", "sign-in": "Zaloguj się", "title-you-have-been-automatically-signed-out": "Nastąpiło automatyczne wylogowanie" }, diff --git a/public/locales/pt-BR/grafana.json b/public/locales/pt-BR/grafana.json index 2d8973c2893..f53b11abe29 100644 --- a/public/locales/pt-BR/grafana.json +++ b/public/locales/pt-BR/grafana.json @@ -108,7 +108,7 @@ "dismiss": "Ignorar", "heading": "Autenticação empresarial", "learn-more-link": "Saiba mais", - "text": "Gerencie usuários, equipes e permissões automaticamente com <1>SAML, <3>SCIM, <6>LDAP e <8>RBAC, disponíveis na Grafana Cloud e na Grafana Enterprise." + "text": "" }, "feature-listing": { "title-auditing": "Auditoria", @@ -209,7 +209,7 @@ "title-delete": "Excluir" }, "orgs": { - "delete-body": "Tem certeza de que deseja excluir \"{{deleteOrgName}}\"?<3> <5>Todos os painéis de controle desta organização serão removidos!", + "delete-body": "", "id-header": "ID", "name-header": "Nome", "new-org-button": "Nova organização" @@ -719,6 +719,7 @@ "title-annotations": "Anotações" }, "link-dashboard-and-panel": "Vincular painel de controle e painel", + "placeholder-value-input": "", "placeholder-value-input-default": "Insira o conteúdo da anotação personalizada…" }, "bulk-actions": { @@ -1144,7 +1145,7 @@ "title-something-wrong-trying-fetch-group-details": "Ocorreu um erro ao tentar obter detalhes do grupo" }, "evaluation-interval-limit-exceeded": { - "body-minimum-interval": "Um intervalo mínimo de avaliação de <1>{{minInterval}} foi configurado na Grafana.<3>Entre em contato com o administrador para configurar um intervalo menor.", + "body-minimum-interval": "", "title-global-evaluation-interval-limit-exceeded": "Limite de intervalo de avaliação global excedido" }, "existing-rule-editor": { @@ -1292,7 +1293,7 @@ "resolved": "Resolvido" } }, - "review-alert-payload": " Revise os dados de alerta para adicionar à carga útil:", + "review-alert-payload": "", "title-add-custom-alerts": "Adicionar alertas personalizados" }, "get-alert-suggestions": { @@ -1416,7 +1417,7 @@ "title-add-folder-and-labels": "Adicionar pasta e rótulos" }, "grafana-managed-rule-type": { - "description": "Compatível com várias fontes de dados de qualquer tipo.<1>Transforme dados com expressões." + "description": "" }, "grafana-modify-export": { "body-invalid-rule-id": "O UID da regra na URL da página é inválido. Verifique a URL e tente novamente.", @@ -1853,7 +1854,7 @@ "aria-label-new": "novo" }, "mimir-flavored-type": { - "description": "Use uma fonte de dados Mimir, Loki ou Cortex.<1>As expressões não são compatíveis." + "description": "" }, "min-interval-option": { "label-interval": "Intervalo", @@ -2082,7 +2083,7 @@ "warning-1": "A exclusão desta política de notificação irá removê-la permanentemente.", "warning-2": "Tem certeza de que deseja excluir esta política?" }, - "filter-description": "Filtre as políticas de notificação usando uma lista de correspondências separadas por vírgulas, por exemplo:<1>severity=critical, region=EMEA", + "filter-description": "", "generated-policies": "Políticas geradas automaticamente", "matchers": "Correspondências", "metadata": { @@ -2126,7 +2127,8 @@ "conflict": "A árvore de políticas de notificação foi atualizada por outro usuário.", "error-code": "Mensagem de erro: \"{{error}}\"", "routes": { - "conflictingMatchers": "Não é possível adicionar ou atualizar a rota: os operadores de correspondência entram em conflito com uma árvore de roteamento externa se mesclamos os operadores de correspondência {{-matchers}}. Isso tornaria a rota inacessível." + "conflictingMatchers": "Não é possível adicionar ou atualizar a rota: os operadores de correspondência entram em conflito com uma árvore de roteamento externa se mesclamos os operadores de correspondência {{-matchers}}. Isso tornaria a rota inacessível.", + "unknownMatchers": "" }, "suffix": "Atualize a página e tente novamente.", "title": "Falha ao adicionar ou atualizar a política de notificação" @@ -2244,7 +2246,7 @@ "error-no-query-editor": "Não foi possível carregar o editor de consultas devido a: {{errorMessage}}" }, "recording-rule-type": { - "description": "Pré-calcular expressões.<1>Deve ser combinado com uma regra de alerta." + "description": "" }, "recording-rules": { "description-target-data-source": "A fonte de dados do Prometheus em que as regras de gravação serão registradas", @@ -2257,7 +2259,7 @@ }, "redirect-to-clone-rule": { "body-evaluation-group": "Você precisará definir um novo grupo de avaliação para a regra copiada, pois o original foi provisionado e não pode ser usado para regras criadas na interface do usuário.", - "body-not-provisioned": "A nova regra <1>não será marcada como uma regra provisionada.", + "body-not-provisioned": "", "confirmText-copy": "Copiar", "title-copy-provisioned-alert-rule": "Copiar regra de alerta provisionada" }, @@ -2292,13 +2294,13 @@ "routing-settings": { "aria-label-group-by": "Agrupar por", "description-group-by": "Combine vários alertas em uma única notificação agrupando-os pelos mesmos valores de rótulo. Se estiver vazio, ele é herdado da política de notificação padrão.", - "group-interval": "Intervalo do grupo: <1>{{groupIntervalValue}}", - "group-wait": "Espera do grupo: <1>{{groupWaitValue}}", - "grouping": "Agrupamento: <1>{{fields}}", + "group-interval": "", + "group-wait": "", + "grouping": "", "label-group-by": "Agrupar por", "label-override-grouping": "Substituir agrupamento", "label-override-timings": "Substituir cronogramas", - "repeat-interval": "Intervalo de repetição: <1>{{repeatIntervalValue}}" + "repeat-interval": "" }, "rule-actions-buttons": { "title-edit": "Editar", @@ -2554,7 +2556,7 @@ "relative-with-to": "" }, "rule-type-picker": { - "grafana-managed": "Selecione \"Gerenciado pela Grafana\", a menos que você tenha uma fonte de dados Mimir, Loki ou Cortex com a API do Ruler ativada." + "grafana-managed": "" }, "rule-view": { "query": { @@ -2887,7 +2889,7 @@ "test-contact-point-modal": { "custom-notification-message": "Você enviará uma notificação de teste que usa as anotações definidas abaixo. Esta opção é indicada se você usar modelos e mensagens personalizados.", "notification-message": "Mensagem de notificação", - "predefined-notification-message": "Você enviará uma notificação de teste que usa um alerta predefinido. Se você definiu um modelo ou mensagem personalizada, mude para a mensagem de notificação <1>personalizada acima para ter resultados melhores.", + "predefined-notification-message": "", "send-test-notification": "Enviar notificação de teste", "title-test-contact-point": "Testar ponto de contato" }, @@ -2896,7 +2898,7 @@ }, "threshold-expression-viewer": { "input": "Entrada", - "stop-alerting-when": "Parar de alertar (ou estado pendente) quando for inferior a " + "stop-alerting-when": "" }, "time-interval": { "add-time-interval": "Adicionar intervalo de tempo", @@ -3084,7 +3086,7 @@ "title-notification-policies": "Política de notificações" }, "yaml-content-info": { - "body": "O conteúdo YAML no editor contém apenas a configuração da regra de alerta <1>Para configurar o Prometheus, você precisa fornecer o restante do <4>conteúdo do arquivo de configuração." + "body": "" } }, "alertlist": { @@ -3160,7 +3162,7 @@ "no-annotations-found": "Nenhuma anotação encontrada" }, "annotation-list-item": { - "tooltip-created-by": "Criado por:<1> {{email}}" + "tooltip-created-by": "" }, "category-annotation-query": "Consulta de anotação", "category-display": "Exibição", @@ -3198,7 +3200,7 @@ }, "empty-state": { "button-title": "Adicionar consulta de anotação", - "info-box-content": "<0>As anotações apresentam uma forma de integrar dados de eventos em seus gráficos. Elas são visualizadas como linhas verticais e ícones em todos os painéis de gráficos. Ao passar o mouse sobre um ícone de anotação, você pode conferir o texto e as etiquetas do evento. Você pode adicionar eventos de anotação diretamente na Grafana pressionando CTRL ou CMD e clicando no gráfico (ou arrastando a região). Eles serão armazenados no banco de dados de anotações da Grafana.", + "info-box-content": "", "info-box-content-2": "Consulte a <2>Documentação de anotações para saber mais.", "title": "Nenhuma consulta de anotações personalizadas foi adicionada ainda" }, @@ -3236,7 +3238,7 @@ "auth-settings": "Configurações de autenticação" }, "auth-drawer-unconneced": { - "subtitle": "Defina as configurações de autenticação. Saiba mais na nossa <2>documentação." + "subtitle": "" }, "auth-drawer-unconnected": { "advanced-auth": "Autenticação avançada", @@ -3270,7 +3272,7 @@ "allowed-organizations-description": "Lista de organizações separadas por vírgulas ou espaços. O usuário deve ser membro \nde pelo menos uma organização para fazer login.", "allowed-organizations-label": "Organizações permitidas", "allowed-organizations-placeholder": "Insira as organizações (minha-equipe, minhaequipe...) e pressione Enter para adicioná-las", - "api-url-description": "O endpoint de informações do usuário do seu provedor OAuth2. As informações que retornaram com este endpoint devem ser compatíveis com <2>OpenID UserInfo.", + "api-url-description": "", "api-url-required": "Este campo deve ser uma URL válida, se definido.", "auth-style-description": "Ele determina como \"{{ clientIDLabel }}\" e \"{{ clientSecretLabel }}\" são enviados para o provedor Oauth2. O padrão é AutoDetect.", "auth-style-label": "Estilo de autenticação", @@ -3415,7 +3417,7 @@ } }, "auth-config-auth-config-page-unconnected": { - "subtitle": "Gerencie suas configurações de autenticação e configure a autenticação única. Saiba mais na nossa <2>documentação." + "subtitle": "" }, "bar-chart": { "warn": { @@ -4133,7 +4135,7 @@ }, "scopes": { "apply-selected-scopes": "Aplicar", - "selected-scopes-label": "Escopos: " + "selected-scopes-label": "" }, "search-box": { "placeholder": "Buscar ou pular para..." @@ -4275,7 +4277,7 @@ "okay": "Ok" }, "not-found-datasource": { - "body": "Talvez você tenha digitado incorretamente a URL ou o plug-in com o ID <1> não esteja disponível.<3>Para ver uma lista de fontes de dados disponíveis, <5>clique aqui." + "body": "" }, "oss": { "connections-home-page": { @@ -4318,8 +4320,8 @@ "versionHistory": { "comparison": { "header": { - "hide-json-diff": "Ocultar JSON diff ", - "show-json-diff": "Exibir JSON diff ", + "hide-json-diff": "", + "show-json-diff": "", "text": "Versão {{version}} atualizada por {{createdBy}} ({{ageString}}) {{message}}" }, "select": "Selecione duas versões para começar a comparar" @@ -4346,7 +4348,7 @@ "label-label": "Etiqueta", "label-placeholder": "ex: Rastreamentos de tempo", "label-required": "Este campo é obrigatório.", - "sub-text": "<0>Defina o texto que descreverá a correlação.", + "sub-text": "", "title": "Definir rótulo de correlação (Passo 1 de 3)" }, "configure-correlation-target-form": { @@ -4390,7 +4392,7 @@ }, "source-form": { "control-required": "Este campo é obrigatório.", - "description": "Um ponto de dados precisa fornecer valores para todas as variáveis como campos ou resultados de transformações para que o botão de correlação seja exibido na visualização.<1>Observação: nem todas as variáveis precisam ser definidas de forma explícita abaixo. Uma transformação como <4>logfmt criará variáveis para cada par de chave/valor.", + "description": "", "description-external-pre": "Você usou as seguintes variáveis na URL de destino:", "description-query-pre": "Você usou as seguintes variáveis na consulta de destino:", "external-title": "Configure a fonte de dados que usará a URL (Passo 3 de 3)", @@ -4402,12 +4404,12 @@ "results-required": "Este campo é obrigatório.", "source-description": "Os resultados da fonte de dados selecionada têm links exibidos no painel", "source-label": "Fonte", - "sub-text": "<0>Defina qual fonte de dados exibirá a correlação e quais dados substituirão variáveis predefinidas. " + "sub-text": "" }, "sub-title": "Defina como os dados presentes em diferentes fontes de dados se relacionam entre si. Consulte a <2>documentação para saber mais.", "target-form": { "control-rules": "Este campo é obrigatório.", - "sub-text": "<0>Defina a que a correlação estará vinculada. Com o tipo de consulta, uma consulta será executada ao clicar na correlação. Com o tipo externo, uma URL será aberta ao clicar na correlação.", + "sub-text": "", "target-description-external": "Especifique a URL que será aberta ao clicar no link", "target-description-query": "Especifique qual fonte de dados é consultada quando o link é clicado", "target-label": "Alvo", @@ -4614,7 +4616,7 @@ } }, "confirm-plugin-dashboard-save-modal": { - "body-plugin-dashboard": "Suas alterações serão perdidas quando você atualizar o plug-in.<1><2>Use <1>Salvar como para criar uma versão personalizada.", + "body-plugin-dashboard": "", "cancel": "Cancelar", "overwrite": "Sobrescrever", "title-plugin-dashboard": "Painel de plug-ins" @@ -4831,7 +4833,7 @@ "add-visualization-body": "Selecione uma fonte de dados e consulte e visualize seus dados com gráficos, estatísticas e tabelas ou crie listas, markdowns e outros widgets.", "add-visualization-button": "Adicionar visualização", "add-visualization-header": "Comece seu novo painel de controle adicionando uma visualização", - "import-a-dashboard-body": "Importe painéis por meio de arquivos ou do <2>grafana.com.", + "import-a-dashboard-body": "", "import-a-dashboard-header": "Importar um painel de controle", "import-dashboard-button": "Importar painel de controle", "show-less-dashboards": "", @@ -5289,8 +5291,8 @@ "title-provisioned": "Painel provisionado" }, "save-dashboard-error-proxy": { - "body-name-exists": "Já existe um painel com o mesmo nome na pasta selecionada.<1><2>Deseja salvar este painel mesmo assim?", - "body-version-mismatch": "Outra pessoa atualizou este painel<1><2>Deseja salvar este painel mesmo assim?", + "body-name-exists": "", + "body-version-mismatch": "", "confirmText-save-and-overwrite": "Salvar e substituir", "title-name-exists": "Conflito", "title-version-mismatch": "Conflito" @@ -5308,7 +5310,7 @@ "cancel": "Cancelar", "cannot-be-saved": "Este painel não pode ser salvo a partir da interface do usuário da Grafana porque foi provisionado a partir de outra fonte. Copie o JSON ou salve-o em um arquivo abaixo e você poderá atualizar seu painel na fonte de provisionamento.", "copy-json-to-clipboard": "Copiar JSON para a área de transferência", - "file-path": "<0>Caminho do arquivo: {{filePath}}", + "file-path": "", "save-json-to-file": "Salvar JSON no arquivo", "see-docs": "Consulte a <2>documentação para obter mais informações sobre provisionamento." }, @@ -5507,7 +5509,7 @@ "transformation-picker": { "info": "As transformações permitem que você una, calcule, reordene, oculte e renomeie seus resultados de consulta antes que eles sejam visualizados.", "info-graph-not-suitable": "Muitas transformações não são compatíveis se você estiver usando a visualização de gráfico, pois no momento ela só é compatível com dados de séries temporais.", - "info-switch-to-table": "Pode ser útil mudar para a visualização de tabela para entender o que está acontecendo com uma transformação. ", + "info-switch-to-table": "", "placeholder-search-for-transformation": "Pesquisar por transformação", "read-more": "Leia mais", "title-transformations": "Transformações" @@ -5573,8 +5575,8 @@ "version-history-comparison": { "button-restore": "Restaurar para a versão {{version}}", "label-view-json-diff": "Visualizar diferença de JSON", - "new-updated-by": "<0>Versão {{version}} atualizada por {{editor}} há {{timeAgo}}", - "old-updated-by": "<0>Versão {{version}} atualizada por {{editor}} há {{timeAgo}}" + "new-updated-by": "", + "old-updated-by": "" }, "version-history-table": { "aria-label-toggle-selection": "Alternar seleção da versão {{version}}", @@ -5974,7 +5976,7 @@ "cancel": "Cancelar" }, "render-save-button-and-error": { - "body-plugin-dashboard": "Suas alterações serão perdidas quando você atualizar o plug-in. Use <1>Salvar como para criar uma versão personalizada.", + "body-plugin-dashboard": "", "title-failed-to-save-dashboard": "Falha ao salvar o painel", "title-plugin-dashboard": "Painel de plug-ins", "title-someone-else-has-updated-this-dashboard": "Outra pessoa atualizou este painel", @@ -5983,7 +5985,7 @@ "save-and-overwrite": "\"Salvar e substituir\"" }, "library-viz-panel-info": { - "last-edited": "{{timeAgo}} por", + "last-edited": "", "usage-count_one": "Usado em {{count}} painéis", "usage-count_other": "Usado em {{count}} painéis" }, @@ -6044,7 +6046,7 @@ }, "panel-data-queries-tab-rendered": { "add-query": "Adicionar consulta", - "expression": "Expressão " + "expression": "" }, "panel-data-transformations-tab": { "tab-label": "Transformações" @@ -6102,7 +6104,7 @@ "query": "Consulta" }, "query-variable-editor-form": { - "description-examples": "Os grupos de captura nomeados podem ser usados para separar o texto e o valor de exibição (<1>ver exemplos).", + "description-examples": "", "description-optional": "Opcional, se você quiser extrair parte de um nome de série ou segmento de node de métrica.", "label-data-source": "Fonte de dados", "label-static-options-sort": "Classificação de opções estáticas", @@ -6163,7 +6165,7 @@ "label-message": "Mensagem", "placeholder-describe-changes-optional": "Adicione uma observação para descrever suas alterações (opcional).", "render-footer": { - "body-plugin-dashboard": "Suas alterações serão perdidas quando você atualizar o plug-in. Use <1>Salvar como para criar uma versão personalizada.", + "body-plugin-dashboard": "", "no-changes-to-save": "Nenhuma alteração a ser salva", "title-failed-to-save-dashboard": "Falha ao salvar o painel", "title-plugin-dashboard": "Painel de plug-ins", @@ -6199,7 +6201,7 @@ "cancel": "Cancelar", "cannot-be-saved": "Este painel não pode ser salvo a partir da interface do usuário da Grafana porque foi provisionado a partir de outra fonte. Copie o JSON ou salve-o em um arquivo abaixo e você poderá atualizar seu painel na fonte de provisionamento.", "copy-json-to-clipboard": "Copiar JSON para a área de transferência", - "file-path": "<0>Caminho do arquivo: {{filePath}}", + "file-path": "", "label-description": "Descrição", "label-target-folder": "Pasta de destino", "label-title": "Título", @@ -6368,8 +6370,8 @@ }, "version-history-comparison": { "label-view-json-diff": "Visualizar diferença de JSON", - "new-version-updated": "<0>Versão {{version}} atualizada por {{editor}} há {{timeAgo}}", - "old-version-updated": "<0>Versão {{version}} atualizada por {{editor}} há {{timeAgo}}" + "new-version-updated": "", + "old-version-updated": "" }, "version-history-header": { "compare-versions": "Comparando {{baseVersion}} <3> {{newVersion}}", @@ -6447,7 +6449,7 @@ "provisioned-delete-modal": { "confirm-button": "OK", "text-1": "Este painel de controle é gerenciado pelo provisionamento da Grafana e não pode ser excluído. Remova o painel de controle do arquivo de configuração para excluí-lo.", - "text-2": "Consulte a documentação da Grafana para obter mais informações sobre provisionamento. ", + "text-2": "", "text-3": "Caminho do arquivo: {{provisionedId}}", "text-link": "Ir para a página de documentos", "title": "Não é possível excluir o painel de controle provisionado" @@ -6525,7 +6527,7 @@ }, "data-source-testing-status-page": { "error-more-details-link": "Clique <2>aqui para saber mais sobre esse erro.", - "success-more-details-links": "Em seguida, você pode começar a visualizar os dados <2>criando um painel de controle ou consultando os dados na <5>Visualização de exploração." + "success-more-details-links": "" }, "data-sources": { "datasource-add-button": { @@ -6621,7 +6623,7 @@ "test": "Teste" }, "cloud-info-box": { - "body-alert": "Ou evite essa tarefa e obtenha {{mainDS}} (e {{extraDS}}) como fontes de dados totalmente gerenciadas, escaláveis e hospedadas da Grafana Labs com o <6>plano gratuito vitalício da Grafana Cloud.", + "body-alert": "", "title-alert": "Configure sua fonte de {{mainDS}} dados abaixo" }, "dashboards-table": { @@ -6749,18 +6751,18 @@ "no-events-yet": "Sem eventos ainda" }, "render-info-viewer": { - "data-counter": "Dados: {{numDataChanges}} ", + "data-counter": "", "elapsed-time": "Tempo: {{elapsed}} ms", "field": "Campo", "last": "Último", - "render-counter": "Renderizações: {{numRenders}} ", - "schema-counter": "Esquema: {{numSchemaChanges}} ", + "render-counter": "", + "schema-counter": "", "title-reset-counters": "Redefinir contadores", "tooltip-step-back": "Recuar", "type": "Tipo" }, "state-view": { - "current-value": "Valor atual: {{currentValue}} ", + "current-value": "", "label-state-name": "Nome do estado" } }, @@ -7207,7 +7209,7 @@ }, "footer": { "learn-more": "Saiba mais", - "pro-tip-define-sources-through-configuration-files": " Dica: você também pode definir fontes de dados por meio de arquivos de configuração. " + "pro-tip-define-sources-through-configuration-files": "" } }, "pane": { @@ -7269,8 +7271,6 @@ "query-deleted": "Consulta excluída" }, "rich-history-queries-tab": { - "displaying-partial-queries": "Exibindo {{ count }} consultas", - "displaying-queries": "{{ count }} consultas", "filter-aria-label": "Filtrar consultas de fonte(s) de dados", "filter-history": "Histórico de filtros", "filter-placeholder": "Filtrar consultas de fonte(s) de dados", @@ -7280,7 +7280,11 @@ "search-placeholder": "Buscar consultas", "showing-queries": "Mostrando {{ shown }} de {{ total }} <0>Carregar mais", "sort-aria-label": "Ordenar consultas", - "sort-placeholder": "Ordenar consultas por" + "sort-placeholder": "Ordenar consultas por", + "displaying-partial-queries_one": "", + "displaying-partial-queries_other": "", + "displaying-queries_one": "", + "displaying-queries_other": "" }, "rich-history-settings-tab": { "alert-info": "O Grafana manterá lançamentos para {{optionLabel}}. As entradas nos favoritos não serão excluídas.", @@ -7472,7 +7476,7 @@ "copy-shortened-link-menu": "Abrir opções de cópia de link", "refresh-picker-cancel": "Cancelar", "refresh-picker-run": "Executar consulta", - "split-close": " Fechar ", + "split-close": "Fechar", "split-close-tooltip": "Fechar painel dividido", "split-narrow": "Painel estreito", "split-title": "Dividir", @@ -7602,8 +7606,8 @@ }, "math": { "available-math-functions": "Funções matemáticas disponíveis", - "run-math-operations": "Execute operações matemáticas em uma ou mais consultas. Você faz referência à consulta através de {{refExample}} — ou seja, {{ref1}}, {{ref2}}, {{ref3}}, etc.<10>Exemplo: <12>{{example}}", - "tooltip-footer": "Consulte nossa documentação adicional sobre <2>expressões matemáticas.", + "run-math-operations": "", + "tooltip-footer": "", "tooltip-title": "Operador matemático", "tooltip-trigger": "Expressão" }, @@ -8642,7 +8646,7 @@ }, "data-source-http-settings": { "access-help": "Ajuda <1>", - "access-help-details": "O modo de acesso controla como as solicitações à fonte de dados serão processadas.<1>O <1>Servidor deve ser priorizado se não houver outra opção indicada.", + "access-help-details": "", "access-help-title": "Ajuda com acesso", "access-label": "Acesso", "allowed-cookies": "Cookies permitidos", @@ -8910,7 +8914,7 @@ "cell-inspect": "Inspecionar valor", "cell-inspect-tooltip": "Inspecionar valor", "copy": "Copiar para a área de transferência", - "csv-counts": "Linhas:{{rows}}, Colunas:{{columns}} <5>", + "csv-counts": "", "csv-placeholder": "Insira o CSV aqui...", "filter-placeholder": "Filtrar valores", "filter-popup-apply": "Ok", @@ -9195,7 +9199,6 @@ "name-line-width": "Largura da linha", "name-stacking": "Empilhamento" }, - "inline-token-warning-badge-tooltip": "", "inspector": { "inspect-data-tab": { "loading": "Carregando", @@ -9359,7 +9362,7 @@ "error-fetching": "Erro ao buscar configurações de LDAP", "error-saving": "Erro ao salvar as configurações de LDAP", "error-validate-form": "Erro ao validar as configurações de LDAP", - "feature-flag-disabled": "Para acessar esta página, é necessário ativar o sinalizador de recurso <1>ssoSettingsLDAP.", + "feature-flag-disabled": "", "saved": "Configurações de LDAP salvas" }, "bind-dn": { @@ -9400,7 +9403,7 @@ "label": "Base DNS de pesquisa", "placeholder": "exemplo: dc=grafana,dc=org" }, - "subtitle": "A integração LDAP na Grafana permite que os usuários façam login com as credenciais LDAP. Saiba mais na nossa <2><0>documentação.", + "subtitle": "", "title": "Configurações básicas" }, "library-panel": { @@ -9444,7 +9447,7 @@ "dashboard-name": "Nome do painel" }, "library-panel-info": { - "last-edited": "Última edição em {{timeAgo}} por", + "last-edited": "", "usage-count_one": "Usado em {{count}} painéis", "usage-count_other": "Usado em {{count}} painéis" }, @@ -9749,7 +9752,7 @@ "tooltip-unpin-line": "Desafixar linha" }, "log-row-message": { - "ellipsis": "… ", + "ellipsis": "", "more": "mais", "see-details": "Veja os detalhes do log", "tooltip-error": "Erro: {{errorMessage}}" @@ -10145,7 +10148,7 @@ }, "resource-table": { "dashboard-load-error": "Não foi possível carregar o painel de controle", - "error-library-element-sub": "Elemento da biblioteca {uid}", + "error-library-element-sub": "", "error-library-element-title": "Não foi possível carregar o elemento da biblioteca", "unknown-datasource-title": "Fonte de dados {{datasourceUID}}", "unknown-datasource-type": "Fonte de dados desconhecida" @@ -10793,10 +10796,10 @@ "placeholder-optional": "(opcional)", "role": "Função", "submit": "Enviar", - "tooltip": "Agora você pode selecionar a opção \"Sem função básica\" e adicionar permissões personalizadas com base nas suas necessidades. Você pode encontrar mais informações em <1>nossa documentação." + "tooltip": "" }, "user-invite-page": { - "sub-title": "Envie um convite ou adicione um usuário que já possui conta na Grafana à organização.<1> {{orgName}}", + "sub-title": "", "text": { "invite-user": "Convidar usuário" } @@ -10885,7 +10888,7 @@ "switch-to-table": "Alternar para tabela" }, "panel-plugin-error": { - "text-load-error": "Verifique os logs de inicialização do servidor para mais informações. <1>Se este plug-in foi carregado a partir do Git, garanta que ele tenha sido compilado.", + "text-load-error": "", "title-load-error": "Erro ao carregar: {{panelId}}", "title-not-found": "Plug-in do painel não encontrado: {{id}}" }, @@ -11079,7 +11082,7 @@ }, "details": { "connections-tab": { - "description": "No momento, você tem as seguintes fontes de dados configuradas para {{pluginName}}. Clique em um bloco para ver os detalhes da configuração. Todas as suas conexões de fonte de dados estão disponíveis em <4><0>Conexões - <3>Fontes de dados." + "description": "" }, "disabled-error": { "angular-deprecation-link": "Leia mais sobre a descontinuação do Angular", @@ -11096,7 +11099,7 @@ }, "labels": { "contactGrafanaLabs": "Entre em contato com a Grafana Labs", - "customLinks": "Links personalizados ", + "customLinks": "", "customLinksTooltip": "Esses links são fornecidos pelo desenvolvedor do plug-in para disponibilizar mais recursos e informações específicos do desenvolvedor", "dependencies": "Dependências", "documentation": "Documentação", @@ -11107,7 +11110,7 @@ "latestVersion": "Última versão", "license": "Licença", "raiseAnIssue": "Comunicar um problema", - "reportAbuse": "Enviar uma dúvida ", + "reportAbuse": "", "reportAbuseTooltip": "Comunique problemas relacionados a plug-ins mal-intencionados ou prejudiciais diretamente à Grafana Labs.", "repository": "Repositório", "signature": "Assinatura", @@ -11117,8 +11120,8 @@ "modal": { "cancel": "Cancelar", "copyEmail": "Copiar endereço de e-mail", - "description": "Este recurso é utilizado para comunicar comportamentos mal-intencionados ou prejudiciais nos plug-ins. Para questões relacionadas a plug-ins, envie um e-mail para: ", - "node": "Observação: para problemas comuns envolvendo plug-ins, como bugs ou solicitações de recursos, entre em contato com o autor do plug-in por meio dos links fornecidos. ", + "description": "", + "node": "", "title": "Comunicar uma preocupação relacionada a um plug-in" } }, @@ -11186,7 +11189,7 @@ "message": "Todos os plugins estão atualizados" }, "not-found-plugin": { - "body-plugin-not-found": "Não foi possível encontrar esse plug-in. Verifique se a URL está correta ou <1>acesse o <3>catálogo de plug-ins.", + "body-plugin-not-found": "", "title-plugin-not-found": "Plug-in não encontrado" }, "plugin-actions": { @@ -11650,7 +11653,6 @@ "unsupported-repository-type": "" }, "inline-secure-values-warning": "", - "inline-token-warning-badge-text": "", "job-status": { "label-view-details": "Veja os detalhes", "loading-finished-job": "Carregando tarefa concluída…", @@ -11827,6 +11829,17 @@ "label-current-step": "Etapa atual", "label-pending-step": "Etapa pendente" }, + "status-badge": { + "automatic-pulling-disabled": "", + "deleting": "", + "error": "", + "pending": "", + "pulling": "", + "unknown": "", + "up-to-date": "", + "waiting-for-health-check": "", + "warning": "" + }, "success-title-default": "Sucesso", "sync-job": { "error-no-job-id": "Falha ao iniciar a tarefa", @@ -12004,7 +12017,7 @@ "annotations-show-text": "Anotações = mostrar", "time-range-picker-disabled-text": "Seletor de intervalo de tempo = desativado", "time-range-picker-enabled-text": "Seletor de intervalo de tempo = ativado", - "time-range-text": "Intervalo de tempo = " + "time-range-text": "" }, "share": { "success-delete": "Não é mais possível compartilhar seu painel de controle" @@ -12043,7 +12056,7 @@ "revoke-user-access-modal-desc-line1": "Tem certeza de que deseja revogar o acesso por {{email}}?" }, "delete-user-shared-dashboards-modal": { - "revoke-user-access-modal-desc-line2": "Esta ação revogará imediatamente o acesso de {{email}} a todos os painéis de controle compartilhados." + "revoke-user-access-modal-desc-line2": "" }, "modal": { "shared-dashboard-modal-title": "Painéis de controle compartilhados" @@ -12212,7 +12225,7 @@ }, "menu": { "clear-button": "Limpar tudo", - "tooltip": "Agora você pode selecionar a opção \"Sem função básica\" e adicionar permissões personalizadas com base nas suas necessidades. Você pode encontrar mais informações em <1>nossa documentação." + "tooltip": "" }, "menu-aria-label": "Menu do seletor de função", "menu-group-option-aria-label": "Opção do seletor de função", @@ -12222,7 +12235,7 @@ }, "sub-menu-aria-label": "Submenu do seletor de função", "title": { - "description": "Atribua funções aos usuários para garantir um controle minucioso sobre o acesso aos recursos e funções da Grafana. Saiba mais na nossa <2>documentação." + "description": "" } }, "role-picker-drawer": { @@ -12345,7 +12358,7 @@ }, "select": { "select-menu": { - "selected-count": "Selecionado " + "selected-count": "" } }, "service-account-create-page": { @@ -12444,6 +12457,7 @@ "aria-label-role": "Função" }, "service-account-tokens-table": { + "aria-label-delete-button": "", "created": "Criado", "expires": "Validade:", "last-used-at": "Última utilização:", @@ -12531,7 +12545,7 @@ "info-text": "Crie um link direto para este painel de controle ou painel, personalizado com as opções abaixo.", "link-url": "URL do link", "render-alert": "Plug-in renderizador de imagem não instalado", - "render-instructions": "Para renderizar uma imagem, você precisa instalar o <2>plug-in renderizador de imagens do Grafana. Entre em contato com o administrador do Grafana para instalar o plug-in.", + "render-instructions": "", "rendered-image": "Link direto de imagem renderizada", "save-alert": "O painel de controle não está salvo", "save-dashboard": "Para renderizar uma imagem do painel, você deve salvar o painel de controle primeiro.", @@ -12555,7 +12569,7 @@ "info-text-1": "Uma captura é uma maneira instantânea de compartilhar um painel de controle interativo publicamente. Quando criadas, nós tiramos dados confidenciais como consultas (métrica, modelo e anotação) e links do painel, deixando apenas os dados métricos e nomes de séries visíveis incorporados no seu painel de controle.", "info-text-2": "Tenha em mente que sua captura <1>pode ser visualizada por qualquer pessoa que possui o link e pode acessar o URL. Compartilhe com sabedoria.", "local-button": "Publicar captura", - "mistake-message": "Você cometeu um erro? ", + "mistake-message": "", "name": "Nome da captura", "timeout": "Tempo limite (segundos)", "timeout-description": "Talvez você precise configurar o valor de tempo limite se demorar muito para coletar as métricas do painel de controle.", @@ -13167,7 +13181,7 @@ "forwards-time-aria-label": "Avançar intervalo de tempo", "to": "para", "zoom-out-button": "Diminuir o intervalo de tempo", - "zoom-out-tooltip": "Redução de intervalo de tempo <1> CTRL+Z" + "zoom-out-tooltip": "" }, "time-range": { "apply": "Aplicar intervalo de tempo", @@ -13292,7 +13306,7 @@ }, "transformations": { "empty": { - "add-transformation-body": "As transformações permitem que os dados sejam alterados de várias maneiras antes de sua visualização ser mostrada. <1>Isso inclui juntar dados, renomear campos, fazer cálculos, formatar dados para exibição e muito mais.", + "add-transformation-body": "", "add-transformation-header": "Começar a transformar dados" } }, @@ -13559,7 +13573,7 @@ "label-format": "Formato", "label-set-timezone": "Definir fuso horário", "label-time-field": "Campo de hora", - "tooltip-format": "O formato de saída para o campo especificado como uma <2>sequência de caracteres de formato Moment.js.", + "tooltip-format": "", "tooltip-timezone-manually": "Defina o fuso horário da data manualmente" }, "format-time-transformer-editor": { @@ -14154,8 +14168,8 @@ "message": "Nenhum usuário encontrado" }, "token-revoked-modal": { - "auto-revoked": "Seu token de sessão foi revogado automaticamente porque você atingiu <2>o número máximo de {{numSessions}} sessões simultâneas para sua conta.", - "resume-message": "<0>Para retomar sua sessão, entre novamente.Caso sua sessão esteja sendo encerrada constante e automaticamente, entre em contato com o administrador ou visite a página de licença para conferir seu limite.", + "auto-revoked": "", + "resume-message": "", "sign-in": "Iniciar sessão", "title-you-have-been-automatically-signed-out": "A sessão foi encerrada automaticamente" }, diff --git a/public/locales/pt-PT/grafana.json b/public/locales/pt-PT/grafana.json index e3a8efaaa5f..0f74596b448 100644 --- a/public/locales/pt-PT/grafana.json +++ b/public/locales/pt-PT/grafana.json @@ -108,7 +108,7 @@ "dismiss": "Ignorar", "heading": "Autenticação empresarial", "learn-more-link": "Saiba mais", - "text": "Faça a gestão dos utilizadores, das equipas e das permissões automaticamente com <1>SAML, <3>SCIM, <6>LDAP e <8>RBAC — disponível no Grafana Cloud e Enterprise." + "text": "" }, "feature-listing": { "title-auditing": "Auditoria", @@ -209,7 +209,7 @@ "title-delete": "Eliminar" }, "orgs": { - "delete-body": "Tem a certeza de que pretende eliminar '{{deleteOrgName}}'?<3> <5>Todos os painéis desta organização serão removidos!", + "delete-body": "", "id-header": "ID", "name-header": "Nome", "new-org-button": "Nova organização" @@ -719,6 +719,7 @@ "title-annotations": "Anotações" }, "link-dashboard-and-panel": "Associar painel de controlo e painel", + "placeholder-value-input": "", "placeholder-value-input-default": "Introduzir o conteúdo da anotação personalizada..." }, "bulk-actions": { @@ -1144,7 +1145,7 @@ "title-something-wrong-trying-fetch-group-details": "Ocorreu um erro ao tentar obter os detalhes do grupo" }, "evaluation-interval-limit-exceeded": { - "body-minimum-interval": "Um intervalo de avaliação mínimo de <1>{{minInterval}} foi configurado na Grafana.<3>Contacte o administrador para configurar um intervalo mais baixo.", + "body-minimum-interval": "", "title-global-evaluation-interval-limit-exceeded": "Limite de intervalo de avaliação global excedido" }, "existing-rule-editor": { @@ -1292,7 +1293,7 @@ "resolved": "Resolvido" } }, - "review-alert-payload": "Reveja os dados de alerta para adicionar à carga útil:", + "review-alert-payload": "", "title-add-custom-alerts": "Adicionar alertas personalizados" }, "get-alert-suggestions": { @@ -1416,7 +1417,7 @@ "title-add-folder-and-labels": "Adicionar pasta e etiquetas" }, "grafana-managed-rule-type": { - "description": "Suporta várias origens de dados de qualquer tipo.<1>Transforme dados com expressões." + "description": "" }, "grafana-modify-export": { "body-invalid-rule-id": "O UID da regra no URL da página é inválido. Verifique o URL e tente novamente.", @@ -1853,7 +1854,7 @@ "aria-label-new": "novo" }, "mimir-flavored-type": { - "description": "Utilizar uma origem de dados Mimir, Loki ou Cortex.<1>As expressões não são suportadas." + "description": "" }, "min-interval-option": { "label-interval": "Intervalo", @@ -2082,7 +2083,7 @@ "warning-1": "A eliminação desta política de notificação irá removê-la permanentemente.", "warning-2": "Tem a certeza de que pretende eliminar esta política?" }, - "filter-description": "Filtre as políticas de notificação utilizando uma lista de correspondências separadas por vírgulas, por ex.:<1>gravidade=crítica, região=EMEA", + "filter-description": "", "generated-policies": "Políticas geradas automaticamente", "matchers": "Correspondências", "metadata": { @@ -2126,7 +2127,8 @@ "conflict": "A árvore de políticas de notificação foi atualizada por outro utilizador.", "error-code": "Mensagem de erro: \"{{error}}\"", "routes": { - "conflictingMatchers": "Não é possível adicionar ou atualizar a rota: os correspondentes entram em conflito com uma árvore de encaminhamento externa se combinarmos os correspondentes {{-matchers}}. Isso tornaria a rota inacessível." + "conflictingMatchers": "Não é possível adicionar ou atualizar a rota: os correspondentes entram em conflito com uma árvore de encaminhamento externa se combinarmos os correspondentes {{-matchers}}. Isso tornaria a rota inacessível.", + "unknownMatchers": "" }, "suffix": "Por favor, atualize a página e tente novamente.", "title": "Falha ao adicionar ou atualizar a política de notificação" @@ -2244,7 +2246,7 @@ "error-no-query-editor": "Não foi possível carregar o editor de consultas devido a: {{errorMessage}}" }, "recording-rule-type": { - "description": "Pré-calcular expressões.<1>Deve ser combinado com uma regra de alerta." + "description": "" }, "recording-rules": { "description-target-data-source": "A origem de dados do Prometheus para armazenar regras de gravação em", @@ -2257,7 +2259,7 @@ }, "redirect-to-clone-rule": { "body-evaluation-group": "Terá de definir um novo grupo de avaliação para a regra copiada, porque o original foi aprovisionado e não pode ser utilizado para regras criadas na interface do utilizador.", - "body-not-provisioned": "A nova regra <1>não será marcada como uma regra aprovisionada.", + "body-not-provisioned": "", "confirmText-copy": "Copiar", "title-copy-provisioned-alert-rule": "Copiar regra de alerta aprovisionada" }, @@ -2292,13 +2294,13 @@ "routing-settings": { "aria-label-group-by": "Agrupar por", "description-group-by": "Combinar vários alertas numa única notificação, agrupando-os pelos mesmos valores de etiqueta. Se estiver vazio, é herdado da política de notificação predefinida.", - "group-interval": "Intervalo do grupo: <1>{{groupIntervalValue}}", - "group-wait": "Espera do grupo: <1>{{groupWaitValue}}", - "grouping": "Agrupamento: <1>{{fields}}", + "group-interval": "", + "group-wait": "", + "grouping": "", "label-group-by": "Agrupar por", "label-override-grouping": "Substituir agrupamento", "label-override-timings": "Substituir tempos", - "repeat-interval": "Intervalo de repetição: <1>{{repeatIntervalValue}}" + "repeat-interval": "" }, "rule-actions-buttons": { "title-edit": "Editar", @@ -2554,7 +2556,7 @@ "relative-with-to": "" }, "rule-type-picker": { - "grafana-managed": "Selecione \"Gerido pela Grafana\", a menos que tenha uma origem de dados Mimir, Loki ou Cortex com a Ruler API ativada." + "grafana-managed": "" }, "rule-view": { "query": { @@ -2887,7 +2889,7 @@ "test-contact-point-modal": { "custom-notification-message": "Enviará uma notificação de teste que utiliza as anotações definidas abaixo. Esta é uma boa opção se utilizar modelos e mensagens personalizados.", "notification-message": "Mensagem de notificação", - "predefined-notification-message": "Enviará uma notificação de teste que utiliza um alerta predefinido. Se tiver definido um modelo personalizado ou uma mensagem personalizada, para obter melhores resultados, mude para a mensagem de notificação <1>personalizada acima.", + "predefined-notification-message": "", "send-test-notification": "Enviar notificação de teste", "title-test-contact-point": "Testar ponto de contacto" }, @@ -2896,7 +2898,7 @@ }, "threshold-expression-viewer": { "input": "Entrada", - "stop-alerting-when": "Deixar de alertar (ou estado pendente) quando " + "stop-alerting-when": "" }, "time-interval": { "add-time-interval": "Adicionar intervalo de tempo", @@ -3084,7 +3086,7 @@ "title-notification-policies": "Políticas de notificação" }, "yaml-content-info": { - "body": "O conteúdo de YAML no editor contém apenas a configuração da regra de alerta <1>Para configurar o Prometheus, tem de fornecer o restante do <4>conteúdo do ficheiro de configuração." + "body": "" } }, "alertlist": { @@ -3160,7 +3162,7 @@ "no-annotations-found": "Nenhuma anotação encontrada" }, "annotation-list-item": { - "tooltip-created-by": "Criado por:<1> {{email}}" + "tooltip-created-by": "" }, "category-annotation-query": "Consulta de anotação", "category-display": "Visualização", @@ -3198,7 +3200,7 @@ }, "empty-state": { "button-title": "Adicionar consulta de anotação", - "info-box-content": "<0>As anotações fornecem uma forma de integrar dados de eventos nos seus gráficos. São visualizadas como linhas verticais e ícones em todos os painéis de gráficos. Quando passa o rato sobre um ícone de anotação, pode obter o texto e as etiquetas do evento. Pode adicionar eventos de anotação diretamente da Grafana mantendo pressionada a tecla CTRL ou CMD + clique no gráfico (ou arrastando a região). Estes serão armazenados na base de dados de anotações da Grafana.", + "info-box-content": "", "info-box-content-2": "Consulte a <2>Documentação de anotações para obter mais informações.", "title": "Ainda não existem consultas de anotações personalizadas adicionadas" }, @@ -3236,7 +3238,7 @@ "auth-settings": "Definições de autenticação" }, "auth-drawer-unconneced": { - "subtitle": "Configurar as definições de autenticação. Saiba mais na nossa <2>documentação." + "subtitle": "" }, "auth-drawer-unconnected": { "advanced-auth": "Autenticação avançada", @@ -3270,7 +3272,7 @@ "allowed-organizations-description": "Lista de organizações separadas por vírgulas ou espaços. O utilizador deve ser membro \nde pelo menos uma organização para iniciar sessão.", "allowed-organizations-label": "Organizações permitidas", "allowed-organizations-placeholder": "Introduza organizações (my-team, myteam...) e prima Enter para adicionar", - "api-url-description": "O ponto final de informações do utilizador do seu fornecedor OAuth2. As informações obtidas por este ponto final devem ser compatíveis com <2>OpenID UserInfo.", + "api-url-description": "", "api-url-required": "Este campo deve ser um URL válido, se definido.", "auth-style-description": "Determina como \"{{ clientIDLabel }}\" e \"{{ clientSecretLabel }}\" são enviados para o fornecedor Oauth2. A predefinição é AutoDetect.", "auth-style-label": "Estilo de autenticação", @@ -3415,7 +3417,7 @@ } }, "auth-config-auth-config-page-unconnected": { - "subtitle": "Faça a gestão das suas definições de autenticação e configure o início de sessão único. Saiba mais na nossa <2>documentação." + "subtitle": "" }, "bar-chart": { "warn": { @@ -4133,7 +4135,7 @@ }, "scopes": { "apply-selected-scopes": "Aplicar", - "selected-scopes-label": "Campos de aplicação: " + "selected-scopes-label": "" }, "search-box": { "placeholder": "Pesquisar ou saltar para..." @@ -4275,7 +4277,7 @@ "okay": "OK" }, "not-found-datasource": { - "body": "Talvez tenha escrito mal o URL ou o plugin com a ID <1> não esteja disponível.<3>Para ver uma lista de origens de dados disponíveis, <5>clique aqui." + "body": "" }, "oss": { "connections-home-page": { @@ -4318,8 +4320,8 @@ "versionHistory": { "comparison": { "header": { - "hide-json-diff": "Ocultar diferenças JSON ", - "show-json-diff": "Mostrar diferenças JSON ", + "hide-json-diff": "", + "show-json-diff": "", "text": "Versão {{version}} atualizada por {{createdBy}} ({{ageString}}) {{message}}" }, "select": "Selecionar duas versões para começar a comparar" @@ -4346,7 +4348,7 @@ "label-label": "Etiqueta", "label-placeholder": "Por exemplo, Tempo Traces", "label-required": "Este campo é obrigatório.", - "sub-text": "<0>Defina o texto que descreverá a correlação.", + "sub-text": "", "title": "Defina a etiqueta de correlação (passo 1 de 3)" }, "configure-correlation-target-form": { @@ -4390,7 +4392,7 @@ }, "source-form": { "control-required": "Este campo é obrigatório.", - "description": "Um ponto de dados precisa de fornecer valores a todas as variáveis como campos ou como saída de transformações para fazer com que o botão de correlação apareça na visualização.<1>Nota: Nem todas as variáveis precisam de ser explicitamente definidas abaixo. Uma transformação como <4>logfmt criará variáveis para cada par de chave/valor.", + "description": "", "description-external-pre": "Utilizou as seguintes variáveis no URL de destino:", "description-query-pre": "Utilizou as seguintes variáveis na consulta de destino:", "external-title": "Configurar a origem de dados que utilizará o URL (passo 3 de 3)", @@ -4402,12 +4404,12 @@ "results-required": "Este campo é obrigatório.", "source-description": "Os resultados da origem dos dados selecionada têm links exibidos no painel", "source-label": "Origem", - "sub-text": "<0>Defina qual a origem dos dados que exibirá a correlação e quais os dados que substituirão as variáveis definidas anteriormente." + "sub-text": "" }, "sub-title": "Defina como os dados existentes em diferentes origens de dados se relacionam entre si. Leia mais na <2>documentação", "target-form": { "control-rules": "Este campo é obrigatório.", - "sub-text": "<0>Defina aquilo a que a correlação será ligada. Com o tipo de consulta, será executada uma consulta quando se clicar na correlação. Com o tipo externo, clicar na correlação abrirá um URL.", + "sub-text": "", "target-description-external": "Especifique o URL que será aberto quando se clicar no link", "target-description-query": "Especifique qual a origem de dados que é consultada quando se clicar no link", "target-label": "Destino", @@ -4614,7 +4616,7 @@ } }, "confirm-plugin-dashboard-save-modal": { - "body-plugin-dashboard": "As suas alterações serão perdidas quando atualizar o plugin.<1><2>Utilize <1>Guardar como para criar uma versão personalizada.", + "body-plugin-dashboard": "", "cancel": "Cancelar", "overwrite": "Substituir", "title-plugin-dashboard": "Painel de controlo do plugin" @@ -4831,7 +4833,7 @@ "add-visualization-body": "Selecione uma origem de dados e, em seguida, consulte e visualize os seus dados com gráficos, estatísticas e tabelas ou crie listas, remarcações e outros widgets.", "add-visualization-button": "Adicionar visualização", "add-visualization-header": "Inicie o seu novo painel de controlo ao adicionar uma visualização", - "import-a-dashboard-body": "Importe painéis de controlo de ficheiros ou de <2>grafana.com.", + "import-a-dashboard-body": "", "import-a-dashboard-header": "Importar um painel de controlo", "import-dashboard-button": "Importar painel de controlo", "show-less-dashboards": "", @@ -5289,8 +5291,8 @@ "title-provisioned": "Painel de controlo fornecido" }, "save-dashboard-error-proxy": { - "body-name-exists": "Já existe um painel de controlo com o mesmo nome na pasta selecionada.<1><2>Ainda pretende guardar este painel de controlo?", - "body-version-mismatch": "Outra pessoa atualizou este painel de controlo<1><2>Ainda pretende guardar este painel de controlo?", + "body-name-exists": "", + "body-version-mismatch": "", "confirmText-save-and-overwrite": "Guardar e substituir", "title-name-exists": "Conflito", "title-version-mismatch": "Conflito" @@ -5308,7 +5310,7 @@ "cancel": "Cancelar", "cannot-be-saved": "Este painel de controlo não pode ser guardado a partir da interface do utilizador da Grafana porque foi aprovisionado a partir de outra fonte. Copie o JSON ou guarde-o num ficheiro abaixo. Posteriormente, poderá atualizar o seu painel de controlo na fonte de aprovisionamento.", "copy-json-to-clipboard": "Copiar JSON para a área de transferência", - "file-path": "<0>Caminho do ficheiro: {{filePath}}", + "file-path": "", "save-json-to-file": "Guardar JSON no ficheiro", "see-docs": "Consulte a <2>documentação para obter mais informações sobre aprovisionamento." }, @@ -5507,7 +5509,7 @@ "transformation-picker": { "info": "As transformações permitem-lhe unir, calcular, reordenar, ocultar e renomear os resultados da sua consulta antes de serem visualizados.", "info-graph-not-suitable": "Muitas transformações não são adequadas se estiver a utilizar a visualização de gráfico, uma vez que atualmente só suporta dados de séries temporais.", - "info-switch-to-table": "Pode ser útil mudar para a visualização de tabela para entender o que uma transformação faz. ", + "info-switch-to-table": "", "placeholder-search-for-transformation": "Pesquisar por transformação", "read-more": "Ler mais", "title-transformations": "Transformações" @@ -5573,8 +5575,8 @@ "version-history-comparison": { "button-restore": "Restaurar para a versão {{version}}", "label-view-json-diff": "Visualizar diferenças JSON", - "new-updated-by": "<0>Versão {{version}} atualizada por {{editor}} {{timeAgo}}", - "old-updated-by": "<0>Versão {{version}} atualizada por {{editor}} {{timeAgo}}" + "new-updated-by": "", + "old-updated-by": "" }, "version-history-table": { "aria-label-toggle-selection": "Alternar seleção da versão {{version}}", @@ -5974,7 +5976,7 @@ "cancel": "Cancelar" }, "render-save-button-and-error": { - "body-plugin-dashboard": "As suas alterações serão perdidas quando atualizar o plugin. Utilize <1>Guardar como para criar uma versão personalizada.", + "body-plugin-dashboard": "", "title-failed-to-save-dashboard": "Não foi possível guardar o painel de controlo", "title-plugin-dashboard": "Painel de controlo do plugin", "title-someone-else-has-updated-this-dashboard": "Outra pessoa atualizou este painel de controlo", @@ -5983,7 +5985,7 @@ "save-and-overwrite": "\"Guardar e substituir\"" }, "library-viz-panel-info": { - "last-edited": "{{timeAgo}} por ", + "last-edited": "", "usage-count_one": "Utilizado em {{count}} painéis de controlo", "usage-count_other": "Utilizado em {{count}} painéis de controlo" }, @@ -6044,7 +6046,7 @@ }, "panel-data-queries-tab-rendered": { "add-query": "Adicionar consulta", - "expression": "Expressão " + "expression": "" }, "panel-data-transformations-tab": { "tab-label": "Transformações" @@ -6102,7 +6104,7 @@ "query": "Consulta" }, "query-variable-editor-form": { - "description-examples": "Os grupos de captura nomeados podem ser utilizados para separar o texto e o valor de exibição (<1>ver exemplos).", + "description-examples": "", "description-optional": "Opcional, se pretender extrair parte de um nome de série ou segmento de nó métrico.", "label-data-source": "Origem dos dados", "label-static-options-sort": "Ordenação de opções estáticas", @@ -6163,7 +6165,7 @@ "label-message": "Mensagem", "placeholder-describe-changes-optional": "Adicione uma nota para descrever as suas alterações (opcional).", "render-footer": { - "body-plugin-dashboard": "As suas alterações serão perdidas quando atualizar o plugin. Utilize <1>Guardar como para criar uma versão personalizada.", + "body-plugin-dashboard": "", "no-changes-to-save": "Não existem alterações para guardar", "title-failed-to-save-dashboard": "Não foi possível guardar o painel de controlo", "title-plugin-dashboard": "Painel de controlo do plugin", @@ -6199,7 +6201,7 @@ "cancel": "Cancelar", "cannot-be-saved": "Este painel de controlo não pode ser guardado a partir da interface do utilizador da Grafana porque foi aprovisionado a partir de outra fonte. Copie o JSON ou guarde-o num ficheiro abaixo. Posteriormente, poderá atualizar o seu painel de controlo na fonte de aprovisionamento.", "copy-json-to-clipboard": "Copiar JSON para a área de transferência", - "file-path": "<0>Caminho do ficheiro: {{filePath}}", + "file-path": "", "label-description": "Descrição", "label-target-folder": "Pasta de destino", "label-title": "Título", @@ -6368,8 +6370,8 @@ }, "version-history-comparison": { "label-view-json-diff": "Visualizar diferenças JSON", - "new-version-updated": "<0>Versão {{version}} atualizada por {{editor}} {{timeAgo}}", - "old-version-updated": "<0>Versão {{version}} atualizada por {{editor}} {{timeAgo}}" + "new-version-updated": "", + "old-version-updated": "" }, "version-history-header": { "compare-versions": "A comparar {{baseVersion}} <3> {{newVersion}}", @@ -6447,7 +6449,7 @@ "provisioned-delete-modal": { "confirm-button": "OK", "text-1": "Este painel de controlo é gerido pelo provisionamento da Grafana e não pode ser eliminado. Remova o painel de controlo do ficheiro de configuração para o eliminar.", - "text-2": "Consulte a documentação da Grafana para obter mais informações sobre provisionamento. ", + "text-2": "", "text-3": "Caminho do ficheiro: {{provisionedId}}", "text-link": "Ir para a página de documentos", "title": "Não é possível eliminar o painel de controlo disponibilizado" @@ -6525,7 +6527,7 @@ }, "data-source-testing-status-page": { "error-more-details-link": "Clique <2>aqui para saber mais sobre este erro.", - "success-more-details-links": "Em seguida, pode começar a visualizar os dados <2>criando um painel de controlo ou consultando os dados na <5>vista Explorar." + "success-more-details-links": "" }, "data-sources": { "datasource-add-button": { @@ -6621,7 +6623,7 @@ "test": "Teste" }, "cloud-info-box": { - "body-alert": "Ou evite o esforço e obtenha {{mainDS}} (e {{extraDS}}) como origens de dados totalmente geridas, escaláveis e hospedadas da Grafana Labs com o <6>plano Grafana Cloud gratuito para sempre.", + "body-alert": "", "title-alert": "Configurar a sua origem de dados {{mainDS}} abaixo" }, "dashboards-table": { @@ -6749,18 +6751,18 @@ "no-events-yet": "Ainda sem eventos" }, "render-info-viewer": { - "data-counter": "Dados: {{numDataChanges}} ", + "data-counter": "", "elapsed-time": "Tempo: {{elapsed}}ms", "field": "Campo", "last": "Último", - "render-counter": "Renderizar: {{numRenders}} ", - "schema-counter": "Esquema: {{numSchemaChanges}} ", + "render-counter": "", + "schema-counter": "", "title-reset-counters": "Redefinir contadores", "tooltip-step-back": "Recuar", "type": "Tipo" }, "state-view": { - "current-value": "Valor atual: {{currentValue}} ", + "current-value": "", "label-state-name": "Nome do estado" } }, @@ -7207,7 +7209,7 @@ }, "footer": { "learn-more": "Saiba mais", - "pro-tip-define-sources-through-configuration-files": "Dica: também pode definir origens de dados através de ficheiros de configuração. " + "pro-tip-define-sources-through-configuration-files": "" } }, "pane": { @@ -7269,8 +7271,6 @@ "query-deleted": "Consulta eliminada" }, "rich-history-queries-tab": { - "displaying-partial-queries": "A exibir {{ count }} consultas", - "displaying-queries": "{{ count }} consultas", "filter-aria-label": "Filtrar consultas para origens de dados", "filter-history": "Filtrar histórico", "filter-placeholder": "Filtrar consultas para origens de dados", @@ -7280,7 +7280,11 @@ "search-placeholder": "Pesquisar consultas", "showing-queries": "A mostrar {{ shown }} de {{ total }} <0>Carregar mais", "sort-aria-label": "Ordenar consultas", - "sort-placeholder": "Ordenar consultas por" + "sort-placeholder": "Ordenar consultas por", + "displaying-partial-queries_one": "", + "displaying-partial-queries_other": "", + "displaying-queries_one": "", + "displaying-queries_other": "" }, "rich-history-settings-tab": { "alert-info": "A Grafana guardará entradas até {{optionLabel}}.As entradas favoritas não serão eliminadas.", @@ -7472,7 +7476,7 @@ "copy-shortened-link-menu": "Abrir opções de cópia de link", "refresh-picker-cancel": "Cancelar", "refresh-picker-run": "Executar consulta", - "split-close": "Fechar ", + "split-close": "", "split-close-tooltip": "Fechar painel dividido", "split-narrow": "Painel estreito", "split-title": "Dividir", @@ -7602,8 +7606,8 @@ }, "math": { "available-math-functions": "Funções matemáticas disponíveis", - "run-math-operations": "Execute operações matemáticas numa ou mais consultas. Referencia a consulta por {{refExample}} ou seja, {{ref1}}, {{ref2}}, {{ref3}}, etc.<10>Exemplo: <12>{{example}}", - "tooltip-footer": "Consulte a nossa documentação adicional sobre <2>expressões matemáticas.", + "run-math-operations": "", + "tooltip-footer": "", "tooltip-title": "Operador matemático", "tooltip-trigger": "Expressão" }, @@ -8642,7 +8646,7 @@ }, "data-source-http-settings": { "access-help": "Ajuda <1>", - "access-help-details": "O modo de acesso controla a forma como os pedidos à origem de dados serão tratados.<1> <1>Servidor deve ser a forma preferida se nada mais for indicado.", + "access-help-details": "", "access-help-title": "Ajuda de acesso", "access-label": "Acesso", "allowed-cookies": "Cookies permitidos", @@ -8910,7 +8914,7 @@ "cell-inspect": "Inspecionar valor", "cell-inspect-tooltip": "Inspecionar valor", "copy": "Copiar para a área de transferência", - "csv-counts": "Linhas:{{rows}}, Colunas:{{columns}} <5>", + "csv-counts": "", "csv-placeholder": "Introduza o CSV aqui...", "filter-placeholder": "Filtrar valores", "filter-popup-apply": "Ok", @@ -9195,7 +9199,6 @@ "name-line-width": "Largura da linha", "name-stacking": "Empilhamento" }, - "inline-token-warning-badge-tooltip": "", "inspector": { "inspect-data-tab": { "loading": "A carregar", @@ -9359,7 +9362,7 @@ "error-fetching": "Erro ao obter as definições LDAP", "error-saving": "Erro ao guardar as definições LDAP", "error-validate-form": "Erro ao validar as definições LDAP", - "feature-flag-disabled": "Esta página apenas é acessível ativando o sinalizador de funcionalidade <1>ssoSettingsLDAP.", + "feature-flag-disabled": "", "saved": "Definições LDAP guardadas" }, "bind-dn": { @@ -9400,7 +9403,7 @@ "label": "DNS de base de pesquisa", "placeholder": "exemplo: dc=grafana,dc=org" }, - "subtitle": "A integração LDAP na Grafana permite que os seus utilizadores da Grafana iniciem sessão com as suas credenciais LDAP. Saiba mais na nossa <2><0>documentação.", + "subtitle": "", "title": "Definições básicas" }, "library-panel": { @@ -9444,7 +9447,7 @@ "dashboard-name": "Nome do painel de controlo" }, "library-panel-info": { - "last-edited": "Última edição em {{timeAgo}} por ", + "last-edited": "", "usage-count_one": "Utilizado em {{count}} painéis de controlo", "usage-count_other": "Utilizado em {{count}} painéis de controlo" }, @@ -9749,7 +9752,7 @@ "tooltip-unpin-line": "Desafixar linha" }, "log-row-message": { - "ellipsis": "… ", + "ellipsis": "", "more": "mais", "see-details": "Ver detalhes do registo", "tooltip-error": "Erro: {{errorMessage}}" @@ -10145,7 +10148,7 @@ }, "resource-table": { "dashboard-load-error": "Não foi possível carregar o painel de controlo", - "error-library-element-sub": "Elemento de biblioteca {uid}", + "error-library-element-sub": "", "error-library-element-title": "Não foi possível carregar o elemento de biblioteca", "unknown-datasource-title": "Origem dos dados {{datasourceUID}} ", "unknown-datasource-type": "Origem dos dados desconhecida" @@ -10793,10 +10796,10 @@ "placeholder-optional": "(opcional)", "role": "Função", "submit": "Enviar", - "tooltip": "Agora pode selecionar a opção \"Sem função básica\" e adicionar permissões às suas necessidades personalizadas. Pode encontrar mais informações na <1>nossa documentação." + "tooltip": "" }, "user-invite-page": { - "sub-title": "Envie um convite ou adicione um utilizador Grafana existente à organização.<1> {{orgName}}", + "sub-title": "", "text": { "invite-user": "Convidar utilizador" } @@ -10885,7 +10888,7 @@ "switch-to-table": "Mudar para tabela" }, "panel-plugin-error": { - "text-load-error": "Verificar os registos de inicialização do servidor para obter mais informações. <1>Se este plugin foi carregado do Git, certifique-se de que foi compilado.", + "text-load-error": "", "title-load-error": "Erro ao carregar: {{panelId}}", "title-not-found": "Plugin do painel não encontrado: {{id}}" }, @@ -11079,7 +11082,7 @@ }, "details": { "connections-tab": { - "description": "De momento, tem as seguintes origens de dados configuradas para {{pluginName}}, clique num mosaico para ver os detalhes da configuração. Pode encontrar todas as suas ligações das origens dos dados em <4><0>Ligações - <3>Origens dos dados." + "description": "" }, "disabled-error": { "angular-deprecation-link": "Leia mais sobre a depreciação de Angular", @@ -11096,7 +11099,7 @@ }, "labels": { "contactGrafanaLabs": "Contactar a Grafana Labs", - "customLinks": "Links personalizados ", + "customLinks": "", "customLinksTooltip": "Estes links são fornecidos pelo desenvolvedor do plugin para oferecer recursos e informações adicionais específicos do desenvolvedor", "dependencies": "Dependências", "documentation": "Documentação", @@ -11107,7 +11110,7 @@ "latestVersion": "Versão mais recente", "license": "Licença", "raiseAnIssue": "Comunicar um problema", - "reportAbuse": "Comunicar uma preocupação ", + "reportAbuse": "", "reportAbuseTooltip": "Comunique problemas relacionados com plugins maliciosos ou prejudiciais diretamente à Grafana Labs.", "repository": "Repositório", "signature": "Assinatura", @@ -11117,8 +11120,8 @@ "modal": { "cancel": "Cancelar", "copyEmail": "Copiar endereço de e-mail", - "description": "Esta funcionalidade é para comunicar comportamentos maliciosos ou prejudiciais em plugins. Para questões relacionadas com plugins, envie-nos um e-mail para: ", - "node": "Nota: para questões gerais relacionadas com o plugin, como bugs ou pedidos de funcionalidades, entre em contacto com o autor do plugin utilizando os links fornecidos. ", + "description": "", + "node": "", "title": "Comunicar uma preocupação relativa ao plugin" } }, @@ -11186,7 +11189,7 @@ "message": "Todos os plugins estão atualizados" }, "not-found-plugin": { - "body-plugin-not-found": "Não é possível encontrar esse plugin. Verifique se o URL está correto ou <1>aceda ao <3>catálogo de plugins.", + "body-plugin-not-found": "", "title-plugin-not-found": "Plugin não encontrado" }, "plugin-actions": { @@ -11650,7 +11653,6 @@ "unsupported-repository-type": "" }, "inline-secure-values-warning": "", - "inline-token-warning-badge-text": "", "job-status": { "label-view-details": "Ver detalhes", "loading-finished-job": "A carregar o trabalho concluído...", @@ -11827,6 +11829,17 @@ "label-current-step": "Passo atual", "label-pending-step": "Passo pendente" }, + "status-badge": { + "automatic-pulling-disabled": "", + "deleting": "", + "error": "", + "pending": "", + "pulling": "", + "unknown": "", + "up-to-date": "", + "waiting-for-health-check": "", + "warning": "" + }, "success-title-default": "Sucesso", "sync-job": { "error-no-job-id": "Falha ao iniciar a tarefa", @@ -12004,7 +12017,7 @@ "annotations-show-text": "Anotações = mostrar", "time-range-picker-disabled-text": "Seletor de intervalo de tempo = desativado", "time-range-picker-enabled-text": "Seletor de intervalo de tempo = ativado", - "time-range-text": "Intervalo de tempo = " + "time-range-text": "" }, "share": { "success-delete": "O seu painel de controlo já não pode ser partilhado" @@ -12043,7 +12056,7 @@ "revoke-user-access-modal-desc-line1": "Tem a certeza de que pretende revogar o acesso a {{email}}?" }, "delete-user-shared-dashboards-modal": { - "revoke-user-access-modal-desc-line2": "Esta ação revogará imediatamente o acesso de {{email}}'s a todos os painéis de controlo partilhados." + "revoke-user-access-modal-desc-line2": "" }, "modal": { "shared-dashboard-modal-title": "Painéis de controlo partilhados" @@ -12212,7 +12225,7 @@ }, "menu": { "clear-button": "Limpar tudo", - "tooltip": "Agora pode selecionar a opção \"Sem função básica\" e adicionar permissões às suas necessidades personalizadas. Pode encontrar mais informações na <1>nossa documentação." + "tooltip": "" }, "menu-aria-label": "Menu do selecionador de funções", "menu-group-option-aria-label": "Opção do selecionador de funções", @@ -12222,7 +12235,7 @@ }, "sub-menu-aria-label": "Submenu do selecionador de funções", "title": { - "description": "Atribuir funções aos utilizadores para garantir um controlo granular sobre o acesso às funcionalidades e recursos Grafana‘s. Saiba mais na nossa <2><0>documentação." + "description": "" } }, "role-picker-drawer": { @@ -12345,7 +12358,7 @@ }, "select": { "select-menu": { - "selected-count": "Selecionado " + "selected-count": "" } }, "service-account-create-page": { @@ -12444,6 +12457,7 @@ "aria-label-role": "Função" }, "service-account-tokens-table": { + "aria-label-delete-button": "", "created": "Criado", "expires": "Expira", "last-used-at": "Data da última utilização", @@ -12531,7 +12545,7 @@ "info-text": "Crie um link direto para este painel de controlo ou painel, personalizado com as opções abaixo.", "link-url": "URL do link", "render-alert": "Plugin de renderização de imagem não instalado", - "render-instructions": "Para renderizar uma imagem, tem de instalar o <2>plugin de renderização de imagens Grafana. Entre em contacto com o seu administrador Grafana para instalar o plugin.", + "render-instructions": "", "rendered-image": "Link direto para imagem renderizada", "save-alert": "O painel de controlo não está guardado", "save-dashboard": "Para processar uma imagem de painel, tem de guardar o painel de controlo primeiro.", @@ -12555,7 +12569,7 @@ "info-text-1": "Um instantâneo é uma forma instantânea de partilhar publicamente um painel interativo. Quando criado, retiramos dados confidenciais como consultas (métrica, modelo e anotação) e links do painel, deixando apenas os dados de métrica visíveis e os nomes das séries incorporados no seu painel.", "info-text-2": "Tenha em mente que o seu instantâneo <1>pode ser visto por qualquer pessoa que tenha o link e possa aceder ao URL. Partilhe com sensatez.", "local-button": "Publicar instantâneo", - "mistake-message": "Cometeu um erro? ", + "mistake-message": "", "name": "Nome do instantâneo", "timeout": "Tempo de espera (segundos)", "timeout-description": "Pode ter de configurar o valor do tempo limite se demorar muito tempo a recolher as métricas do seu painel de controlo.", @@ -13167,7 +13181,7 @@ "forwards-time-aria-label": "Mover o intervalo de tempo para a frente", "to": "para", "zoom-out-button": "Diminuir o zoom do intervalo de tempo", - "zoom-out-tooltip": "Diminuir o zoom do intervalo de tempo <1> CTRL+Z" + "zoom-out-tooltip": "" }, "time-range": { "apply": "Aplicar intervalo de tempo", @@ -13292,7 +13306,7 @@ }, "transformations": { "empty": { - "add-transformation-body": "As transformações permitem que os dados sejam alterados de várias maneiras antes da sua visualização ser mostrada.<1>Isto inclui unir dados, renomear campos, fazer cálculos, formatar dados para exibição e muito mais.", + "add-transformation-body": "", "add-transformation-header": "Começar a transformar dados" } }, @@ -13559,7 +13573,7 @@ "label-format": "Formato", "label-set-timezone": "Definir o fuso horário", "label-time-field": "Campo de hora", - "tooltip-format": "O formato de saída para o campo especificado como uma <2>sequência de caracteres de formato Moment.js.", + "tooltip-format": "", "tooltip-timezone-manually": "Defina o fuso horário da data manualmente" }, "format-time-transformer-editor": { @@ -14154,8 +14168,8 @@ "message": "Nenhum utilizador encontrado" }, "token-revoked-modal": { - "auto-revoked": "O seu token de sessão foi revogado automaticamente, porque atingiu <2>o número máximo de {{numSessions}} sessões simultâneas para a sua conta.", - "resume-message": "<0>Para retomar a sua sessão, inicie sessão novamente.Contacte o seu administrador ou visite a página de licenças para rever a sua quota se a sua sessão for terminada repetidamente de forma automática.", + "auto-revoked": "", + "resume-message": "", "sign-in": "Iniciar sessão", "title-you-have-been-automatically-signed-out": "A sua sessão foi terminada automaticamente" }, diff --git a/public/locales/ru-RU/grafana.json b/public/locales/ru-RU/grafana.json index ded982bf9ca..ae8747b74fb 100644 --- a/public/locales/ru-RU/grafana.json +++ b/public/locales/ru-RU/grafana.json @@ -108,7 +108,7 @@ "dismiss": "Закрыть", "heading": "Аутентификация Enterprise", "learn-more-link": "Подробнее", - "text": "Управляйте пользователями, командами и разрешениями автоматически с помощью <1>SAML, <3>SCIM, <6>LDAP и <8>RBAC (доступно в Grafana Cloud и Enterprise)." + "text": "" }, "feature-listing": { "title-auditing": "Проверка", @@ -209,7 +209,7 @@ "title-delete": "Удаление" }, "orgs": { - "delete-body": "Действительно удалить «{{deleteOrgName}}»?<3> <5>Все дашборды для этой организации будут удалены.", + "delete-body": "", "id-header": "Идентификатор", "name-header": "Имя", "new-org-button": "Новая организация" @@ -725,6 +725,7 @@ "title-annotations": "Аннотации" }, "link-dashboard-and-panel": "Связать дашборд и панель", + "placeholder-value-input": "", "placeholder-value-input-default": "Ввести содержимое пользовательской аннотации..." }, "bulk-actions": { @@ -1154,7 +1155,7 @@ "title-something-wrong-trying-fetch-group-details": "Ошибка при попытке получить данные группы" }, "evaluation-interval-limit-exceeded": { - "body-minimum-interval": "В Grafana установлен минимальный интервал оценки <1>{{minInterval}}.<3>Обратитесь к администратору, чтобы установить меньший интервал.", + "body-minimum-interval": "", "title-global-evaluation-interval-limit-exceeded": "Превышен предельный интервал глобальной оценки" }, "existing-rule-editor": { @@ -1302,7 +1303,7 @@ "resolved": "Устранено" } }, - "review-alert-payload": " Просмотр данных оповещения для добавления в полезные данные:", + "review-alert-payload": "", "title-add-custom-alerts": "Добавление пользовательских оповещений" }, "get-alert-suggestions": { @@ -1426,7 +1427,7 @@ "title-add-folder-and-labels": "Добавление папки и меток" }, "grafana-managed-rule-type": { - "description": "Поддерживает несколько источников данных любого типа.<1>Преобразуйте данные с помощью выражений." + "description": "" }, "grafana-modify-export": { "body-invalid-rule-id": "Недопустимый уникальный идентификатор правила в URL-адресе страницы. Проверьте URL-адрес и повторите попытку.", @@ -1865,7 +1866,7 @@ "aria-label-new": "новая" }, "mimir-flavored-type": { - "description": "Используйте источники данных Mimir, Loki или Cortex.<1>Выражения не поддерживаются." + "description": "" }, "min-interval-option": { "label-interval": "Интервал", @@ -2094,7 +2095,7 @@ "warning-1": "Политика уведомления будет безвозвратно удалена.", "warning-2": "Действительно удалить политику?" }, - "filter-description": "Фильтруйте политики уведомления, используя список сопоставлений, разделенных запятыми, например, <1>серьезность=критическая, регион=EMEA", + "filter-description": "", "generated-policies": "Автоматически генерируемые политики", "matchers": "Средства сопоставления", "metadata": { @@ -2140,7 +2141,8 @@ "conflict": "Другой пользователь обновил дерево политик уведомления.", "error-code": "Сообщение об ошибке: «{{error}}»", "routes": { - "conflictingMatchers": "Невозможно добавить или обновить маршрут: если объединить средства сопоставления {{-matchers}}, они будут конфликтовать с внешним деревом маршрутизации. Маршрут станет недоступным." + "conflictingMatchers": "Невозможно добавить или обновить маршрут: если объединить средства сопоставления {{-matchers}}, они будут конфликтовать с внешним деревом маршрутизации. Маршрут станет недоступным.", + "unknownMatchers": "" }, "suffix": "Обновите страницу и повторите попытку.", "title": "Не удалось добавить или обновить политику уведомления" @@ -2260,7 +2262,7 @@ "error-no-query-editor": "Не удалось загрузить редактор запросов. Причина: {{errorMessage}}" }, "recording-rule-type": { - "description": "Предварительно вычислите выражения.<1>Следует объединить с правилом оповещения." + "description": "" }, "recording-rules": { "description-target-data-source": "Источник данных Prometheus для хранения правил записи.", @@ -2273,7 +2275,7 @@ }, "redirect-to-clone-rule": { "body-evaluation-group": "Нужно будет установить новую группу оценки для скопированного правила, поскольку исходная группа была подготовлена и не может использоваться для правил, созданных в пользовательском интерфейсе.", - "body-not-provisioned": "Новое правило <1>не будет помечено как подготовленное.", + "body-not-provisioned": "", "confirmText-copy": "Копировать", "title-copy-provisioned-alert-rule": "Копирование подготовленного правила оповещения" }, @@ -2308,13 +2310,13 @@ "routing-settings": { "aria-label-group-by": "Группировать по", "description-group-by": "Объедините несколько оповещений в одно уведомление путем их группировки по одинаковым значениям меток. Если политика пуста, она наследуется от стандартной политики уведомления.", - "group-interval": "Интервал для группы: <1>{{groupIntervalValue}}", - "group-wait": "Время ожидания для группы: <1>{{groupWaitValue}}", - "grouping": "Группировка: <1>{{fields}}", + "group-interval": "", + "group-wait": "", + "grouping": "", "label-group-by": "Группировать по", "label-override-grouping": "Переопределить группировку", "label-override-timings": "Переопределить временные рамки", - "repeat-interval": "Интервал повторения: <1>{{repeatIntervalValue}}" + "repeat-interval": "" }, "rule-actions-buttons": { "title-edit": "Редактировать", @@ -2578,7 +2580,7 @@ "relative-with-to": "" }, "rule-type-picker": { - "grafana-managed": "Выберите «Управляемые Grafana», если у вас нет источника данных Mimir, Loki или Cortex с включенным Ruler API." + "grafana-managed": "" }, "rule-view": { "query": { @@ -2911,7 +2913,7 @@ "test-contact-point-modal": { "custom-notification-message": "Вы отправите тестовое уведомление, в котором используются аннотации, определенные ниже. Это подходящий вариант, если вы используете пользовательские шаблоны и сообщения.", "notification-message": "Сообщение уведомления", - "predefined-notification-message": "Вы отправите тестовое уведомление, в котором используется предопределенное оповещение. Если вы задали пользовательский шаблон или сообщение, для достижения лучших результатов переключитесь на <1>пользовательское сообщение уведомления, указанное выше.", + "predefined-notification-message": "", "send-test-notification": "Отправить тестовое уведомление", "title-test-contact-point": "Тестирование точки контакта" }, @@ -2920,7 +2922,7 @@ }, "threshold-expression-viewer": { "input": "Ввод", - "stop-alerting-when": "Прекратить оповещение (или состояние ожидания), если " + "stop-alerting-when": "" }, "time-interval": { "add-time-interval": "Добавить временной интервал", @@ -3108,7 +3110,7 @@ "title-notification-policies": "Политики уведомления" }, "yaml-content-info": { - "body": "Содержимое YAML в редакторе содержит только конфигурацию правил оповещения. <1>Чтобы настроить Prometheus, необходимо предоставить остальную часть <4>содержимого файла конфигурации." + "body": "" } }, "alertlist": { @@ -3184,7 +3186,7 @@ "no-annotations-found": "Аннотации не найдены" }, "annotation-list-item": { - "tooltip-created-by": "Автор:<1> {{email}}" + "tooltip-created-by": "" }, "category-annotation-query": "Запрос аннотаций", "category-display": "Отображение", @@ -3222,7 +3224,7 @@ }, "empty-state": { "button-title": "Добавить запрос аннотации", - "info-box-content": "<0>Аннотации позволяют интегрировать данные событий в графы. Они визуализируются в виде вертикальных линий и значков на всех панелях графов. При наведении курсора на значок аннотации отображаются текст и теги события. Можно добавлять события аннотаций непосредственно из Grafana, удерживая CTRL или CMD и нажав на граф (или перетащив область). Они будут храниться в базе данных аннотаций Grafana.", + "info-box-content": "", "info-box-content-2": "Для получения дополнительной информации ознакомьтесь с <2>документацией по аннотациям.", "title": "Пользовательские запросы аннотаций еще не добавлены" }, @@ -3260,7 +3262,7 @@ "auth-settings": "Параметры аутентификации" }, "auth-drawer-unconneced": { - "subtitle": "Настройка параметров аутентификации Подробнее см. в нашей <2>документации." + "subtitle": "" }, "auth-drawer-unconnected": { "advanced-auth": "Расширенная аутентификация", @@ -3294,7 +3296,7 @@ "allowed-organizations-description": "Список организаций, разделенных запятыми или пробелами. Чтобы войти в систему, пользователь должен \nбыть участником хотя бы одной организации.", "allowed-organizations-label": "Разрешенные организации", "allowed-organizations-placeholder": "Введите названия организаций (my-team, myteam...) и нажмите «Enter», чтобы их добавить", - "api-url-description": "Конечная точка информации о пользователе вашего поставщика OAuth2. Информация, возвращаемая этой конечной точкой, должна быть совместима с <2>OpenID UserInfo.", + "api-url-description": "", "api-url-required": "В поле должен быть указан действительный URL-адрес (если он настроен).", "auth-style-description": "Определяет, каким образом «{{ clientIDLabel }}» и «{{ clientSecretLabel }}» отправляются поставщику Oauth2. По умолчанию используется автоопределение.", "auth-style-label": "Метод авторизации", @@ -3439,7 +3441,7 @@ } }, "auth-config-auth-config-page-unconnected": { - "subtitle": "Управление параметрами аутентификации и настройка единого входа Подробнее см. в нашей <2>документации." + "subtitle": "" }, "bar-chart": { "warn": { @@ -4173,7 +4175,7 @@ }, "scopes": { "apply-selected-scopes": "Применить", - "selected-scopes-label": "Области: " + "selected-scopes-label": "" }, "search-box": { "placeholder": "Поиск или переход к..." @@ -4315,7 +4317,7 @@ "okay": "ОК" }, "not-found-datasource": { - "body": "Возможно, вы неправильно ввели URL-адрес или недоступен плагин с идентификатором <1>.<3>Чтобы просмотреть список доступных источников данных, <5>нажмите здесь." + "body": "" }, "oss": { "connections-home-page": { @@ -4358,8 +4360,8 @@ "versionHistory": { "comparison": { "header": { - "hide-json-diff": "Скрыть JSON Diff ", - "show-json-diff": "Показать JSON Diff ", + "hide-json-diff": "", + "show-json-diff": "", "text": "Версия {{version}} обновлена {{createdBy}} ({{ageString}}) {{message}}" }, "select": "Выберите две версии, чтобы начать сравнение" @@ -4386,7 +4388,7 @@ "label-label": "Метка", "label-placeholder": "например, трассировки Tempo", "label-required": "Поле является обязательным.", - "sub-text": "<0>Определите текст, который будет описывать корреляцию.", + "sub-text": "", "title": "Определение метки корреляции (шаг 1 из 3)" }, "configure-correlation-target-form": { @@ -4430,7 +4432,7 @@ }, "source-form": { "control-required": "Поле является обязательным.", - "description": "Чтобы кнопка корреляции появилась в визуализации, точка данных должна предоставить значения всем переменным в виде полей или выходных данных преобразований.<1>Примечание. Необязательно задавать каждую переменную ниже. Преобразование, например, <4>logfmt, создаст переменные для каждой пары «ключ/значение».", + "description": "", "description-external-pre": "Вы использовали следующие переменные в целевом URL-адресе:", "description-query-pre": "Вы использовали следующие переменные в целевом запросе:", "external-title": "Настройка источника данных, который будет использовать URL-адрес (шаг 3 из 3)", @@ -4442,12 +4444,12 @@ "results-required": "Поле является обязательным.", "source-description": "Результаты из выбранного источника данных содержат ссылки, отображаемые на панели.", "source-label": "Источник", - "sub-text": "<0>Определите, какой источник данных будет отображать корреляцию и какие данные заменят ранее заданные переменные." + "sub-text": "" }, "sub-title": "Определите соотношения данных, хранящихся в разных источниках. Подробнее — в <2>документации", "target-form": { "control-rules": "Поле является обязательным.", - "sub-text": "<0>Задайте, к чему будет привязана корреляция. Если выбран тип запроса, при нажатии на корреляцию будет выполняться запрос. Если выбрать внешний тип, при нажатии на корреляцию откроется URL-адрес.", + "sub-text": "", "target-description-external": "Укажите URL-адрес, который будет открываться при нажатии на ссылку.", "target-description-query": "Укажите запрашиваемый источник данных при нажатии на ссылку.", "target-label": "Цель", @@ -4654,7 +4656,7 @@ } }, "confirm-plugin-dashboard-save-modal": { - "body-plugin-dashboard": "При обновлении плагина ваши изменения будут потеряны.<1><2>Используйте <1>Сохранить как, чтобы создать собственную версию.", + "body-plugin-dashboard": "", "cancel": "Отмена", "overwrite": "Перезаписать", "title-plugin-dashboard": "Дашборд плагинов" @@ -4871,7 +4873,7 @@ "add-visualization-body": "Выберите источник данных, а затем запрашивайте и визуализируйте свои данные с помощью диаграмм, статистики и таблиц или создавайте списки, разметки и другие виджеты.", "add-visualization-button": "Добавить визуализацию", "add-visualization-header": "Создание нового дашборда с добавлением визуализации", - "import-a-dashboard-body": "Импортируйте дашборды из файлов или с <1>grafana.com.", + "import-a-dashboard-body": "", "import-a-dashboard-header": "Импорт дашборда", "import-dashboard-button": "Импорт дашборда", "show-less-dashboards": "", @@ -5331,8 +5333,8 @@ "title-provisioned": "Подготовленный дашборд" }, "save-dashboard-error-proxy": { - "body-name-exists": "Дашборд с таким именем уже существует в выбранной папке.<1><2>Все равно сохранить дашборд?", - "body-version-mismatch": "Дашборд обновлен другим пользователем<1><2>Все равно сохранить дашборд?", + "body-name-exists": "", + "body-version-mismatch": "", "confirmText-save-and-overwrite": "Сохранить и перезаписать", "title-name-exists": "Конфликт", "title-version-mismatch": "Конфликт" @@ -5350,7 +5352,7 @@ "cancel": "Отмена", "cannot-be-saved": "Дашборд невозможно сохранить из пользовательского интерфейса Grafana, поскольку он подготовлен в другом источнике. Скопируйте модель JSON или сохраните ее в файл ниже. Затем можно обновить свой дашборд в источнике подготовки.", "copy-json-to-clipboard": "Копировать JSON в буфер обмена", - "file-path": "<0>Путь к файлу: {{filePath}}", + "file-path": "", "save-json-to-file": "Сохранить модель JSON в файл", "see-docs": "Подробнее о подготовке см. в <2>документации." }, @@ -5549,7 +5551,7 @@ "transformation-picker": { "info": "Преобразования позволяют объединять, вычислять, изменять порядок, скрывать и переименовывать результаты запросов перед их визуализацией.", "info-graph-not-suitable": "Многие преобразования не подходят, если вы используете визуализацию в виде графа, поскольку в настоящее время она поддерживает только данные временных рядов.", - "info-switch-to-table": "Чтобы понять, что делает преобразование, можно переключиться на визуализацию в виде таблицы. ", + "info-switch-to-table": "", "placeholder-search-for-transformation": "Поиск преобразования", "read-more": "Узнать больше", "title-transformations": "Преобразования" @@ -5615,8 +5617,8 @@ "version-history-comparison": { "button-restore": "Восстановить до версии {{version}} ", "label-view-json-diff": "Просмотр JSON Diff", - "new-updated-by": "<0>Версию {{version}} обновил пользователь {{editor}} {{timeAgo}}", - "old-updated-by": "<0>Версию {{version}} обновил пользователь {{editor}} {{timeAgo}}" + "new-updated-by": "", + "old-updated-by": "" }, "version-history-table": { "aria-label-toggle-selection": "Переключить выбор версии {{version}}", @@ -6016,7 +6018,7 @@ "cancel": "Отмена" }, "render-save-button-and-error": { - "body-plugin-dashboard": "Изменения будут потеряны при обновлении плагина. Используйте <1>Сохранить как, чтобы создать пользовательскую версию.", + "body-plugin-dashboard": "", "title-failed-to-save-dashboard": "Не удалось сохранить дашборд", "title-plugin-dashboard": "Дашборд плагинов", "title-someone-else-has-updated-this-dashboard": "Дашборд обновлен другим пользователем", @@ -6025,7 +6027,7 @@ "save-and-overwrite": "'Сохранить и перезаписать'" }, "library-viz-panel-info": { - "last-edited": "{{timeAgo}} ", + "last-edited": "", "usage-count_one": "Используется на {{count}} дашбордах", "usage-count_few": "Используется на {{count}} дашбордах", "usage-count_many": "Используется на {{count}} дашбордах", @@ -6088,7 +6090,7 @@ }, "panel-data-queries-tab-rendered": { "add-query": "Добавить запрос", - "expression": "Выражение " + "expression": "" }, "panel-data-transformations-tab": { "tab-label": "Преобразования" @@ -6146,7 +6148,7 @@ "query": "Запрос" }, "query-variable-editor-form": { - "description-examples": "Именованные группы записи можно использовать для разделения отображаемого текста и значения (<1>см. примеры).", + "description-examples": "", "description-optional": "Дополнительно, если вы хотите извлечь часть имени ряда или сегмента узла метрики.", "label-data-source": "Источник данных", "label-static-options-sort": "Сортировка статических параметров", @@ -6207,7 +6209,7 @@ "label-message": "Сообщение", "placeholder-describe-changes-optional": "Добавьте примечание с описанием изменений (необязательно).", "render-footer": { - "body-plugin-dashboard": "Изменения будут потеряны при обновлении плагина. Используйте <1>Сохранить как, чтобы создать пользовательскую версию.", + "body-plugin-dashboard": "", "no-changes-to-save": "Нет изменений для сохранения", "title-failed-to-save-dashboard": "Не удалось сохранить дашборд", "title-plugin-dashboard": "Дашборд плагинов", @@ -6245,7 +6247,7 @@ "cancel": "Отмена", "cannot-be-saved": "Дашборд невозможно сохранить из пользовательского интерфейса Grafana, поскольку он подготовлен в другом источнике. Скопируйте модель JSON или сохраните ее в файл ниже. Затем можно обновить свой дашборд в источнике подготовки.", "copy-json-to-clipboard": "Копировать JSON в буфер обмена", - "file-path": "<0>Путь к файлу: {{filePath}}", + "file-path": "", "label-description": "Описание", "label-target-folder": "Целевая папка", "label-title": "Название", @@ -6414,8 +6416,8 @@ }, "version-history-comparison": { "label-view-json-diff": "Просмотр JSON Diff", - "new-version-updated": "<0>Версию {{version}} обновил пользователь {{editor}} {{timeAgo}}", - "old-version-updated": "<0>Версию {{version}} обновил пользователь {{editor}} {{timeAgo}}" + "new-version-updated": "", + "old-version-updated": "" }, "version-history-header": { "compare-versions": "Сравнение {{baseVersion}} <3> {{newVersion}}", @@ -6493,7 +6495,7 @@ "provisioned-delete-modal": { "confirm-button": "OK", "text-1": "Дашборд управляется функцией подготовки Grafana и не может быть удален. Чтобы удалить дашборд, его необходимо удалить из файла конфигурации.", - "text-2": "Для получения дополнительной информации о функции подготовки см. документацию Grafana. ", + "text-2": "", "text-3": "Путь к файлу: {{provisionedId}}", "text-link": "Перейти на страницу документации", "title": "Невозможно удалить подготовленный дашборд" @@ -6571,7 +6573,7 @@ }, "data-source-testing-status-page": { "error-more-details-link": "Чтобы узнать больше об этой ошибке, нажмите <2>здесь.", - "success-more-details-links": "Затем вы можете начать визуализировать данные, <2>создав панель или запросив данные в <5>представлении Explore." + "success-more-details-links": "" }, "data-sources": { "datasource-add-button": { @@ -6667,7 +6669,7 @@ "test": "Тестирование" }, "cloud-info-box": { - "body-alert": "Или не тратьте время и получите {{mainDS}} (и {{extraDS}}) в качестве полностью управляемых, масштабируемых и размещенных источников данных от Grafana Labs с <6>бессрочным бесплатным планом Grafana Cloud.", + "body-alert": "", "title-alert": "Настройте свой источник данных {{mainDS}} ниже" }, "dashboards-table": { @@ -6795,18 +6797,18 @@ "no-events-yet": "Пока нет событий" }, "render-info-viewer": { - "data-counter": "Данные: {{numDataChanges}} ", + "data-counter": "", "elapsed-time": "Время: {{elapsed}} мс", "field": "Поле", "last": "Последний", - "render-counter": "Рендеринг: {{numRenders}} ", - "schema-counter": "Схема: {{numSchemaChanges}} ", + "render-counter": "", + "schema-counter": "", "title-reset-counters": "Сброс счетчиков", "tooltip-step-back": "Шаг назад", "type": "Тип" }, "state-view": { - "current-value": "Текущее значение: {{currentValue}} ", + "current-value": "", "label-state-name": "Название состояния" } }, @@ -7253,7 +7255,7 @@ }, "footer": { "learn-more": "Подробнее", - "pro-tip-define-sources-through-configuration-files": "Совет. Источники данных можно также задавать в файлах конфигурации. " + "pro-tip-define-sources-through-configuration-files": "" } }, "pane": { @@ -7315,8 +7317,6 @@ "query-deleted": "Запрос удален" }, "rich-history-queries-tab": { - "displaying-partial-queries": "Отображается запросов: {{ count }}", - "displaying-queries": "Запросов: {{ count }}", "filter-aria-label": "Фильтровать запросы по источникам данных", "filter-history": "История фильтров", "filter-placeholder": "Фильтровать запросы по источникам данных", @@ -7326,7 +7326,15 @@ "search-placeholder": "Поисковые запросы", "showing-queries": "Показано {{ shown }} из {{ total }} <0>Загрузить еще", "sort-aria-label": "Сортировать запросы", - "sort-placeholder": "Сортировать запросы по" + "sort-placeholder": "Сортировать запросы по", + "displaying-partial-queries_one": "", + "displaying-partial-queries_few": "", + "displaying-partial-queries_many": "", + "displaying-partial-queries_other": "", + "displaying-queries_one": "", + "displaying-queries_few": "", + "displaying-queries_many": "", + "displaying-queries_other": "" }, "rich-history-settings-tab": { "alert-info": "Grafana будет хранить записи до {{optionLabel}}.Помеченные записи не удаляются.", @@ -7518,7 +7526,7 @@ "copy-shortened-link-menu": "Открыть параметры копирования ссылок", "refresh-picker-cancel": "Отмена", "refresh-picker-run": "Выполнить запрос", - "split-close": "Закрыть ", + "split-close": "", "split-close-tooltip": "Закрыть разделенную область", "split-narrow": "Сузить область", "split-title": "Разделение", @@ -7648,8 +7656,8 @@ }, "math": { "available-math-functions": "Доступные математические функции", - "run-math-operations": "Выполняйте математические операции для одного или нескольких запросов. Для ссылки на запрос используется {{refExample}}, например {{ref1}}, {{ref2}}, {{ref3}} и т. д.<10>Пример: <12>{{example}}", - "tooltip-footer": "Подробнее о <2>математических выражениях см. в нашей дополнительной документации.", + "run-math-operations": "", + "tooltip-footer": "", "tooltip-title": "Математический оператор", "tooltip-trigger": "Выражение" }, @@ -8708,7 +8716,7 @@ }, "data-source-http-settings": { "access-help": "Справка <1>", - "access-help-details": "Метод доступа определяет, как будут обрабатываться запросы к источнику данных.Если не указано иное, предпочтительным способом должен быть <1> <1>сервер.", + "access-help-details": "", "access-help-title": "Справка по доступу", "access-label": "Доступ", "allowed-cookies": "Разрешенные файлы cookie", @@ -8976,7 +8984,7 @@ "cell-inspect": "Проверить значение", "cell-inspect-tooltip": "Проверить значение", "copy": "Копировать в буфер обмена", - "csv-counts": "Строки:{{rows}}, столбцы:{{columns}} <5>", + "csv-counts": "", "csv-placeholder": "Ввести CSV...", "filter-placeholder": "Значения фильтра", "filter-popup-apply": "Ок", @@ -9261,7 +9269,6 @@ "name-line-width": "Ширина линии", "name-stacking": "Расположение в стеке" }, - "inline-token-warning-badge-tooltip": "", "inspector": { "inspect-data-tab": { "loading": "Загрузка", @@ -9429,7 +9436,7 @@ "error-fetching": "Ошибка при получении параметров LDAP", "error-saving": "Ошибка при сохранении параметров LDAP", "error-validate-form": "Ошибка проверки параметров LDAP", - "feature-flag-disabled": "Страница доступна только при включении флага функции <1>ssoSettingsLDAP.", + "feature-flag-disabled": "", "saved": "Параметры LDAP сохранены" }, "bind-dn": { @@ -9470,7 +9477,7 @@ "label": "Базовые DN для поиска", "placeholder": "пример: dc=grafana, dc=org" }, - "subtitle": "Интеграция LDAP в Grafana позволяет пользователям выполнять вход с помощью учетных данных LDAP. Подробнее в нашей <2><0>документации.", + "subtitle": "", "title": "Основные параметры" }, "library-panel": { @@ -9514,7 +9521,7 @@ "dashboard-name": "Название дашборда" }, "library-panel-info": { - "last-edited": "Последнее изменение: {{timeAgo}}, ", + "last-edited": "", "usage-count_one": "Используется на {{count}} дашборда", "usage-count_few": "Используется на {{count}} дашбордах", "usage-count_many": "Используется на {{count}} дашборда", @@ -9831,7 +9838,7 @@ "tooltip-unpin-line": "Открепить строку" }, "log-row-message": { - "ellipsis": "… ", + "ellipsis": "", "more": "больше", "see-details": "См. данные журнала", "tooltip-error": "Ошибка: {{errorMessage}}" @@ -10227,7 +10234,7 @@ }, "resource-table": { "dashboard-load-error": "Не удалось загрузить дашборд", - "error-library-element-sub": "Элемент библиотеки {uid}", + "error-library-element-sub": "", "error-library-element-title": "Не удалось загрузить элемент библиотеки", "unknown-datasource-title": "Источник данных {{datasourceUID}}", "unknown-datasource-type": "Неизвестный источник данных" @@ -10881,10 +10888,10 @@ "placeholder-optional": "(необязательно)", "role": "Роль", "submit": "Отправить", - "tooltip": "Теперь вы можете выбрать параметр «Нет основных ролей» и добавить разрешения в соответствии со своими потребностями. Дополнительную информацию можно найти в <1>нашей документации." + "tooltip": "" }, "user-invite-page": { - "sub-title": "Отправьте приглашение или добавьте существующего пользователя Grafana в организацию <1>{{orgName}}", + "sub-title": "", "text": { "invite-user": "Пригласить пользователя" } @@ -10973,7 +10980,7 @@ "switch-to-table": "Переключиться на таблицу" }, "panel-plugin-error": { - "text-load-error": "Дополнительную информацию см. в журналах запуска сервера. <1>Если плагин был загружен из Git, убедитесь, что он скомпилирован.", + "text-load-error": "", "title-load-error": "Ошибка при загрузке: {{panelId}}", "title-not-found": "Плагин панели {{id}} не найден" }, @@ -11167,7 +11174,7 @@ }, "details": { "connections-tab": { - "description": "В настоящее время у вас настроены следующие источники данных для {{pluginName}}. Нажмите плитку, чтобы просмотреть сведения о конфигурации. Все подключения к источникам данных можно найти в разделе <4><0>Подключения - <3>Источники данных." + "description": "" }, "disabled-error": { "angular-deprecation-link": "Подробнее об устаревании Angular", @@ -11184,7 +11191,7 @@ }, "labels": { "contactGrafanaLabs": "Связаться с Grafana Labs", - "customLinks": "Специальные ссылки ", + "customLinks": "", "customLinksTooltip": "Эти ссылки предоставлены разработчиком плагина и содержат дополнительные ресурсы и информацию, предназначенные для разработчиков.", "dependencies": "Зависимости", "documentation": "Документация", @@ -11195,7 +11202,7 @@ "latestVersion": "Новейшая версия", "license": "Лицензия", "raiseAnIssue": "Сообщить о проблеме", - "reportAbuse": "Сообщить о проблеме ", + "reportAbuse": "", "reportAbuseTooltip": "Сообщайте о проблемах, связанных с вредоносными или опасными плагинами, непосредственно в Grafana Labs.", "repository": "Репозиторий", "signature": "Подпись", @@ -11205,8 +11212,8 @@ "modal": { "cancel": "Отмена", "copyEmail": "Копировать адрес электронной почты", - "description": "Эта функция предназначена для уведомления о вредоносном или опасном поведении плагинов. Если у вас возникли проблемы с плагином, напишите нам по адресу: ", - "node": "Примечание. По общим вопросам, связанным с плагинами, например об ошибках или запросах функций, обращайтесь к автору плагина, используя предоставленные ссылки. ", + "description": "", + "node": "", "title": "Сообщить о проблеме с плагином" } }, @@ -11274,7 +11281,7 @@ "message": "Все плагины обновлены" }, "not-found-plugin": { - "body-plugin-not-found": "Не удалось найти плагин. Проверьте правильность URL-адреса или <1>перейдите в <3>каталог плагинов.", + "body-plugin-not-found": "", "title-plugin-not-found": "Плагин не найден" }, "plugin-actions": { @@ -11750,7 +11757,6 @@ "unsupported-repository-type": "" }, "inline-secure-values-warning": "", - "inline-token-warning-badge-text": "", "job-status": { "label-view-details": "Подробнее", "loading-finished-job": "Загрузка завершенного задания...", @@ -11927,6 +11933,17 @@ "label-current-step": "Текущий шаг", "label-pending-step": "Предстоящий шаг" }, + "status-badge": { + "automatic-pulling-disabled": "", + "deleting": "", + "error": "", + "pending": "", + "pulling": "", + "unknown": "", + "up-to-date": "", + "waiting-for-health-check": "", + "warning": "" + }, "success-title-default": "Выполнено", "sync-job": { "error-no-job-id": "Не удалось запустить задание", @@ -12104,7 +12121,7 @@ "annotations-show-text": "Аннотации = показать", "time-range-picker-disabled-text": "Указатель временного диапазона = отключен", "time-range-picker-enabled-text": "Указатель временного диапазона = включен", - "time-range-text": "Временной диапазон = " + "time-range-text": "" }, "share": { "success-delete": "Ваш дашборд больше не допускает совместного использования" @@ -12143,7 +12160,7 @@ "revoke-user-access-modal-desc-line1": "Действительно отозвать доступ для {{email}}?" }, "delete-user-shared-dashboards-modal": { - "revoke-user-access-modal-desc-line2": "Это действие приведет к немедленному отзыву доступа {{email}} ко всем совместно используемым дашбордам." + "revoke-user-access-modal-desc-line2": "" }, "modal": { "shared-dashboard-modal-title": "Совместно используемые дашборды" @@ -12318,7 +12335,7 @@ }, "menu": { "clear-button": "Очистить всё", - "tooltip": "Теперь вы можете выбрать параметр «Нет основных ролей» и добавить разрешения в соответствии со своими потребностями. Дополнительную информацию можно найти в <1>нашей документации." + "tooltip": "" }, "menu-aria-label": "Меню указателя роли", "menu-group-option-aria-label": "Параметр указателя роли", @@ -12328,7 +12345,7 @@ }, "sub-menu-aria-label": "Подменю указателя роли", "title": { - "description": "Назначайте роли пользователям, чтобы обеспечить детальное управление доступом к функциям и ресурсам Grafana. Подробнее в нашей <2>документации." + "description": "" } }, "role-picker-drawer": { @@ -12451,7 +12468,7 @@ }, "select": { "select-menu": { - "selected-count": "Выбрано " + "selected-count": "" } }, "service-account-create-page": { @@ -12550,6 +12567,7 @@ "aria-label-role": "Роль" }, "service-account-tokens-table": { + "aria-label-delete-button": "", "created": "Создан", "expires": "Срок действия", "last-used-at": "Время последнего использования", @@ -12639,7 +12657,7 @@ "info-text": "Создайте прямую ссылку на дашборд или панель, настроенные с помощью приведенных ниже параметров.", "link-url": "Привязать URL-адрес", "render-alert": "Плагин визуализации изображений не установлен", - "render-instructions": "Чтобы визуализировать изображение, необходимо установить <2>плагин визуализации изображений Grafana. Чтобы установить плагин, обратитесь к своему администратору Grafana.", + "render-instructions": "", "rendered-image": "Прямая ссылка на визуализированное изображение", "save-alert": "Дашборд не сохранен", "save-dashboard": "Чтобы визуализировать изображение панели, сначала необходимо сохранить дашборд.", @@ -12663,7 +12681,7 @@ "info-text-1": "Снимок — это мгновенный способ сделать интерактивный дашборд общедоступным. При создании удаляются конфиденциальные данные, такие как запросы (метрики, шаблон и аннотация) и ссылки на панели, и остаются только видимые метрические данные и имена рядов, встроенные в ваш дашборд.", "info-text-2": "Имейте в виду, что снимок <1>может просмотреть любой пользователь, у которого есть ссылка и доступ к URL-адресу. Публикуйте снимки с умом.", "local-button": "Опубликовать снимок", - "mistake-message": "Вы ошиблись? ", + "mistake-message": "", "name": "Имя снимка", "timeout": "Время ожидания (сек.)", "timeout-description": "Возможно, вам потребуется настроить значение времени ожидания на случай продолжительного сбора метрик дашборда.", @@ -13277,7 +13295,7 @@ "forwards-time-aria-label": "Переместить временной диапазон вперед", "to": "на", "zoom-out-button": "Уменьшение масштаба временного диапазона", - "zoom-out-tooltip": "Уменьшение масштаба временного диапазона <1> CTRL+Z" + "zoom-out-tooltip": "" }, "time-range": { "apply": "Применить временной диапазон", @@ -13402,7 +13420,7 @@ }, "transformations": { "empty": { - "add-transformation-body": "Преобразования позволяют изменять данные разными способами перед отображением визуализации.<1>Сюда входит объединение данных, переименование полей, выполнение расчетов, форматирование данных для отображения и многое другое.", + "add-transformation-body": "", "add-transformation-header": "Начать преобразование данных" } }, @@ -13669,7 +13687,7 @@ "label-format": "Формат", "label-set-timezone": "Установить часовой пояс", "label-time-field": "Поле времени", - "tooltip-format": "Формат вывода для поля, указанного в виде <2>строки в формате Moment.js.", + "tooltip-format": "", "tooltip-timezone-manually": "Установите часовой пояс вручную" }, "format-time-transformer-editor": { @@ -14264,8 +14282,8 @@ "message": "Пользователи не найдены" }, "token-revoked-modal": { - "auto-revoked": "Ваш токен сеанса автоматически отозван, поскольку вы достигли <2>максимального лимита в размере {{numSessions}} одновременных сеансов для своей учетной записи.", - "resume-message": "<0>Чтобы возобновить сеанс, выполните вход повторно.Если вы постоянно автоматически выходите из системы, обратитесь к администратору или перейдите на страницу лицензии, чтобы проверить свою квоту.", + "auto-revoked": "", + "resume-message": "", "sign-in": "Войти", "title-you-have-been-automatically-signed-out": "Вы автоматически вышли из системы" }, diff --git a/public/locales/sv-SE/grafana.json b/public/locales/sv-SE/grafana.json index db4a9953f36..b44428db3d0 100644 --- a/public/locales/sv-SE/grafana.json +++ b/public/locales/sv-SE/grafana.json @@ -108,7 +108,7 @@ "dismiss": "Avfärda", "heading": "Enterprise-autentisering", "learn-more-link": "Läs mer", - "text": "Hantera användare, team och behörigheter automatiskt med <1>SAML, <3>SCIM, <6>LDAP och <8>RBAC – tillgängligt i Grafana Cloud och Enterprise." + "text": "" }, "feature-listing": { "title-auditing": "Revision", @@ -209,7 +209,7 @@ "title-delete": "Radera" }, "orgs": { - "delete-body": "Är du säker på att du vill radera ”{{deleteOrgName}}”?<3> <5>Alla instrumentpaneler för den här organisationen kommer att tas bort!", + "delete-body": "", "id-header": "ID", "name-header": "Namn", "new-org-button": "Ny organisation" @@ -719,6 +719,7 @@ "title-annotations": "Kommentarer" }, "link-dashboard-and-panel": "Länka instrumentpanel och panel", + "placeholder-value-input": "", "placeholder-value-input-default": "Ange innehåll för anpassad kommentar …" }, "bulk-actions": { @@ -1144,7 +1145,7 @@ "title-something-wrong-trying-fetch-group-details": "Något gick fel när du försökte hämta gruppinformation" }, "evaluation-interval-limit-exceeded": { - "body-minimum-interval": "Ett minsta utvärderingsintervall på <1>{{minInterval}} har konfigurerats i Grafana.<3>Kontakta administratören för att konfigurera ett lägre intervall.", + "body-minimum-interval": "", "title-global-evaluation-interval-limit-exceeded": "Den globala utvärderingsintervallgränsen har överskridits" }, "existing-rule-editor": { @@ -1292,7 +1293,7 @@ "resolved": "Åtgärdad" } }, - "review-alert-payload": " Granska larmdata för att lägga till nyttolasten:", + "review-alert-payload": "", "title-add-custom-alerts": "Lägg till anpassade larm" }, "get-alert-suggestions": { @@ -1416,7 +1417,7 @@ "title-add-folder-and-labels": "Lägg till mapp och etiketter" }, "grafana-managed-rule-type": { - "description": "Stöder flera datakällor av något slag.<1>Omvandla data med uttryck." + "description": "" }, "grafana-modify-export": { "body-invalid-rule-id": "Regelns UID för sidans webbadress är ogiltig. Kontrollera webbadressen och försök igen.", @@ -1853,7 +1854,7 @@ "aria-label-new": "ny" }, "mimir-flavored-type": { - "description": "Använd en Mimir-, Loki- eller Cortex-datakälla.<1>Uttryck stöds inte." + "description": "" }, "min-interval-option": { "label-interval": "Intervall", @@ -2082,7 +2083,7 @@ "warning-1": "Om du tar bort denna aviseringspolicy tas den bort permanent.", "warning-2": "Är du säker på att du vill ta bort denna policy?" }, - "filter-description": "Filtrera aviseringspolicyer med hjälp av en kommaseparerad lista över matchare, till exempel:<1>severity=critical, region=EMEA", + "filter-description": "", "generated-policies": "Automatiskt genererade policyer", "matchers": "Matchare", "metadata": { @@ -2126,7 +2127,8 @@ "conflict": "Aviseringspolicyträdet har uppdaterats av en annan användare.", "error-code": "Felmeddelande: ”{{error}}”", "routes": { - "conflictingMatchers": "Kan inte lägga till eller uppdatera rutt: dess matchare {{-matchers}} orsakar en konflikt med ett externt routingträd om vi skulle slå samman dem. Det skulle göra rutten oåtkomlig." + "conflictingMatchers": "Kan inte lägga till eller uppdatera rutt: dess matchare {{-matchers}} orsakar en konflikt med ett externt routingträd om vi skulle slå samman dem. Det skulle göra rutten oåtkomlig.", + "unknownMatchers": "" }, "suffix": "Uppdatera sidan och försök igen.", "title": "Det gick inte att lägga till eller uppdatera aviseringspolicy" @@ -2244,7 +2246,7 @@ "error-no-query-editor": "Kunde inte ladda frågeredigerare på grund av: {{errorMessage}}" }, "recording-rule-type": { - "description": "Förberäkna uttryck.<1>Bör kombineras med en larmregel." + "description": "" }, "recording-rules": { "description-target-data-source": "Prometheus-datakällan där inspelningsregler ska sparas", @@ -2257,7 +2259,7 @@ }, "redirect-to-clone-rule": { "body-evaluation-group": "Du måste ställa in en ny utvärderingsgrupp för den kopierade regeln eftersom den ursprungliga har provisionerats och inte kan användas för regler som skapats i användargränssnittet.", - "body-not-provisioned": "Den nya regeln kommer <1>inte att markeras som en provisionerad regel.", + "body-not-provisioned": "", "confirmText-copy": "Kopiera", "title-copy-provisioned-alert-rule": "Kopiera provisionerad larmregel" }, @@ -2292,13 +2294,13 @@ "routing-settings": { "aria-label-group-by": "Gruppera efter", "description-group-by": "Kombinera flera larm till en enda avisering genom att gruppera dem efter samma etikettvärden. Om den är tom ärvs den från standardaviseringspolicyn.", - "group-interval": "Gruppintervall: <1>{{groupIntervalValue}}", - "group-wait": "Gruppväntan: <1>{{groupWaitValue}}", - "grouping": "Gruppering: <1>{{fields}}", + "group-interval": "", + "group-wait": "", + "grouping": "", "label-group-by": "Gruppera efter", "label-override-grouping": "Åsidosätt gruppering", "label-override-timings": "Åsidosätt tidsinställningar", - "repeat-interval": "Upprepa intervall: <1>{{repeatIntervalValue}}" + "repeat-interval": "" }, "rule-actions-buttons": { "title-edit": "Redigera", @@ -2554,7 +2556,7 @@ "relative-with-to": "" }, "rule-type-picker": { - "grafana-managed": "Välj ”Grafana-hanterad” om du inte har en Mimir-, Loki- eller Cortex-datakälla med Ruler API aktiverat." + "grafana-managed": "" }, "rule-view": { "query": { @@ -2887,7 +2889,7 @@ "test-contact-point-modal": { "custom-notification-message": "Du kommer att skicka en testavisering som använder de kommentarer som definieras nedan. Detta är ett bra alternativ om du använder anpassade mallar och meddelanden.", "notification-message": "Aviseringsmeddelande", - "predefined-notification-message": "Du kommer att skicka en testavisering som använder ett fördefinierat larm. Om du har definierat en anpassad mall eller ett anpassat meddelande kan du växla till <1>anpassat aviseringsmeddelande ovan för bättre resultat.", + "predefined-notification-message": "", "send-test-notification": "Skicka testavisering", "title-test-contact-point": "Testa kontaktpunkt" }, @@ -2896,7 +2898,7 @@ }, "threshold-expression-viewer": { "input": "Ingång", - "stop-alerting-when": "Stoppa larm (eller vänteläge) när " + "stop-alerting-when": "" }, "time-interval": { "add-time-interval": "Lägg till tidsintervall", @@ -3084,7 +3086,7 @@ "title-notification-policies": "Aviseringspolicyer" }, "yaml-content-info": { - "body": "YAML-innehållet i redigeraren innehåller endast larmregelkonfiguration <1>För att konfigurera Prometheus måste du ange resten av <4>konfigurationsfilens innehåll." + "body": "" } }, "alertlist": { @@ -3160,7 +3162,7 @@ "no-annotations-found": "Inga kommentarer hittades" }, "annotation-list-item": { - "tooltip-created-by": "Skapad av:<1> {{email}}" + "tooltip-created-by": "" }, "category-annotation-query": "Kommenteringsfråga", "category-display": "Display", @@ -3198,7 +3200,7 @@ }, "empty-state": { "button-title": "Lägg till kommenteringsfråga", - "info-box-content": "<0>Kommentarer är ett sätt att integrera händelsedata i dina diagram. De visualiseras som vertikala linjer och ikoner på alla diagrampaneler. När du håller muspekaren över en kommentarsikon kan du få se händelsetext och taggar för händelsen. Du kan lägga till kommentarshändelser direkt från Grafana genom att hålla ner CTRL eller CMD och klicka på diagrammet (eller dra regionen). Dessa kommer att sparas i Grafanas kommentarsdatabas.", + "info-box-content": "", "info-box-content-2": "Läs <2>Kommentarsdokumentationen för mer information.", "title": "Inga anpassade kommentarsfrågor har lagts till ännu" }, @@ -3236,7 +3238,7 @@ "auth-settings": "Autentiseringsinställningar" }, "auth-drawer-unconneced": { - "subtitle": "Konfigurera autentiseringsinställningar. Läs mer i vår <2>dokumentation." + "subtitle": "" }, "auth-drawer-unconnected": { "advanced-auth": "Avancerad autentisering", @@ -3270,7 +3272,7 @@ "allowed-organizations-description": "Lista över kommaseparerade eller mellanslagsavgränsade organisationer. Användaren bör vara medlem \n i minst en organisation för att logga in.", "allowed-organizations-label": "Tillåtna organisationer", "allowed-organizations-placeholder": "Ange organisationer (mitt-team, mittteam …) och tryck på returtangenten för att lägga till", - "api-url-description": "Slutpunkten för användarinformation för din OAuth2-leverantör. Information som returneras av denna slutpunkt måste vara kompatibel med <2>OpenID UserInfo.", + "api-url-description": "", "api-url-required": "Om detta fält är inställt måste det vara en giltig webbadress.", "auth-style-description": "Det avgör hur ”{{ clientIDLabel }}” och ”{{ clientSecretLabel }}” skickas till Oauth2-leverantören. Standard är AutoDetect.", "auth-style-label": "Autentiseringsstil", @@ -3415,7 +3417,7 @@ } }, "auth-config-auth-config-page-unconnected": { - "subtitle": "Hantera dina autentiseringsinställningar och konfigurera enkel inloggning. Läs mer i vår <2>dokumentation." + "subtitle": "" }, "bar-chart": { "warn": { @@ -4133,7 +4135,7 @@ }, "scopes": { "apply-selected-scopes": "Tillämpa", - "selected-scopes-label": "Omfattningar: " + "selected-scopes-label": "" }, "search-box": { "placeholder": "Sök eller hoppa till …" @@ -4275,7 +4277,7 @@ "okay": "Okej" }, "not-found-datasource": { - "body": "Kanske har du skrivit in webbadressen fel eller så är tillägget med ID <1> inte tillgängligt.<3>Om du vill se en lista över tillgängliga datakällor, <5>klicka här." + "body": "" }, "oss": { "connections-home-page": { @@ -4318,8 +4320,8 @@ "versionHistory": { "comparison": { "header": { - "hide-json-diff": "Dölj JSON-diff ", - "show-json-diff": "Visa JSON-diff ", + "hide-json-diff": "", + "show-json-diff": "", "text": "Version {{version}} uppdaterad av {{createdBy}} ({{ageString}}) {{message}}" }, "select": "Välj två versioner för att börja jämföra" @@ -4346,7 +4348,7 @@ "label-label": "Etikett", "label-placeholder": "t.ex. Tempokurvor", "label-required": "Detta fält är obligatoriskt.", - "sub-text": "<0>Definiera den text som beskriver korrelationen.", + "sub-text": "", "title": "Definiera korrelationsetiketten (steg 1 av 3)" }, "configure-correlation-target-form": { @@ -4390,7 +4392,7 @@ }, "source-form": { "control-required": "Detta fält är obligatoriskt.", - "description": "För att korrelationsknappen ska synas i visualiseringen måste en datapunkt ge värden för alla variabler, antingen som fält eller som resultat av transformationer.<1>Obs! Inte alla variabler behöver uttryckligen definieras nedan. En omvandling som till exempel <4>logfmt skapar variabler för varje nyckel-/värdepar.", + "description": "", "description-external-pre": "Du har använt följande variabler i måladressen:", "description-query-pre": "Du har använt följande variabler i målfrågan:", "external-title": "Konfigurera datakällan som ska använda webbadressen (steg 3 av 3)", @@ -4402,12 +4404,12 @@ "results-required": "Detta fält är obligatoriskt.", "source-description": "Resultat från den valda källdatakällan har länkar som visas i panelen", "source-label": "Källa", - "sub-text": "<0>Definiera vilken datakälla som visar korrelationen och vilka data som ersätter tidigare definierade variabler." + "sub-text": "" }, "sub-title": "Definiera hur data som finns i olika datakällor relaterar till varandra. Läs mer i <2>dokumentationen", "target-form": { "control-rules": "Detta fält är obligatoriskt.", - "sub-text": "<0>Definiera vad korrelationen länkar till. Med frågetypen körs en fråga när korrelationen klickas. Med den externa typen öppnas en URL genom att klicka på korrelationen.", + "sub-text": "", "target-description-external": "Ange webbadressen som öppnas när länken klickas", "target-description-query": "Ange vilken datakälla som frågas när länken klickas", "target-label": "Mål", @@ -4614,7 +4616,7 @@ } }, "confirm-plugin-dashboard-save-modal": { - "body-plugin-dashboard": "Dina ändringar kommer förloras när du uppdaterar tillägget. <1><2>Använd <1>Spara som för att skapa en anpassad version.", + "body-plugin-dashboard": "", "cancel": "Avbryt", "overwrite": "Skriv över", "title-plugin-dashboard": "Tilläggsinstrumentpanel" @@ -4831,7 +4833,7 @@ "add-visualization-body": "Välj en datakälla och sedan en fråga och visualisera dina data med diagram, statistik och tabeller eller skapa listor, markdown-dokument och andra widgetar.", "add-visualization-button": "Lägg till visualisering", "add-visualization-header": "Starta din nya instrumentpanel genom att lägga till en visualisering", - "import-a-dashboard-body": "Importera instrumentpaneler från filer eller från <2>grafana.com.", + "import-a-dashboard-body": "", "import-a-dashboard-header": "Importera en instrumentpanel", "import-dashboard-button": "Importera instrumentpanel", "show-less-dashboards": "", @@ -5289,8 +5291,8 @@ "title-provisioned": "Tilldelad instrumentpanel" }, "save-dashboard-error-proxy": { - "body-name-exists": "En instrumentpanel med samma namn finns redan i den valda mappen. <1><2>Vill du fortfarande spara denna instrumentpanel?", - "body-version-mismatch": "Någon annan har uppdaterat denna instrumentpanel<1><2>Vill du fortfarande spara denna instrumentpanel?", + "body-name-exists": "", + "body-version-mismatch": "", "confirmText-save-and-overwrite": "Spara och skriv över", "title-name-exists": "Konflikt", "title-version-mismatch": "Konflikt" @@ -5308,7 +5310,7 @@ "cancel": "Avbryt", "cannot-be-saved": "Denna instrumentpanel kan inte sparas från Grafanas användargränssnitt eftersom det har provisionerats från en annan källa. Kopiera JSON eller spara den till en fil nedan, så du kan uppdatera instrumentpanelen i provisioneringskällan.", "copy-json-to-clipboard": "Kopiera JSON till urklippet", - "file-path": "<0>Filsökväg: {{filePath}}", + "file-path": "", "save-json-to-file": "Spara JSON till fil", "see-docs": "Se <2>dokumentationen för mer information om provisionering." }, @@ -5507,7 +5509,7 @@ "transformation-picker": { "info": "Med transformering kan du ansluta, beräkna, ordna om, dölja och byta namn på frågeresultaten innan de visualiseras.", "info-graph-not-suitable": "Många transformeringar är inte lämpliga om du använder grafvisualiseringen, eftersom den för närvarande endast stöder tidsseriedata.", - "info-switch-to-table": "Det kan hjälpa att växla till tabellvisualiseringen för att förstå vad en transformering gör. ", + "info-switch-to-table": "", "placeholder-search-for-transformation": "Sök efter transformering", "read-more": "Läs mer", "title-transformations": "Omvandlingar" @@ -5573,8 +5575,8 @@ "version-history-comparison": { "button-restore": "Återställ till version {{version}}", "label-view-json-diff": "Visa JSON-skillnader", - "new-updated-by": "<0>Version {{version}} uppdaterad av {{editor}} {{timeAgo}}", - "old-updated-by": "<0>Version {{version}} uppdaterad av {{editor}} {{timeAgo}}" + "new-updated-by": "", + "old-updated-by": "" }, "version-history-table": { "aria-label-toggle-selection": "Växla val av version {{version}}", @@ -5974,7 +5976,7 @@ "cancel": "Avbryt" }, "render-save-button-and-error": { - "body-plugin-dashboard": "Dina ändringar kommer förloras när du uppdaterar tillägget. Använd <1>Spara som för att skapa en anpassad version.", + "body-plugin-dashboard": "", "title-failed-to-save-dashboard": "Det gick inte att spara instrumentpanel", "title-plugin-dashboard": "Tilläggsinstrumentpanel", "title-someone-else-has-updated-this-dashboard": "Någon annan har uppdaterat denna instrumentpanel", @@ -5983,7 +5985,7 @@ "save-and-overwrite": "”Spara och skriv över”" }, "library-viz-panel-info": { - "last-edited": "{{timeAgo}} av ", + "last-edited": "", "usage-count_one": "Används på {{count}} instrumentpaneler", "usage-count_other": "Används på {{count}} instrumentpaneler" }, @@ -6044,7 +6046,7 @@ }, "panel-data-queries-tab-rendered": { "add-query": "Lägg till fråga", - "expression": "Uttryck " + "expression": "" }, "panel-data-transformations-tab": { "tab-label": "Omvandlingar" @@ -6102,7 +6104,7 @@ "query": "Fråga" }, "query-variable-editor-form": { - "description-examples": "Namngivna fångstgrupper kan användas för att separera visningstexten och värdet (<1>se exempel).", + "description-examples": "", "description-optional": "Valfritt, om du vill extrahera en del av ett serienamn eller metriskt nodsegment.", "label-data-source": "Datakälla", "label-static-options-sort": "Sortering av statiska alternativ", @@ -6163,7 +6165,7 @@ "label-message": "Meddelande", "placeholder-describe-changes-optional": "Lägg till en anteckning för att beskriva dina ändringar (valfritt).", "render-footer": { - "body-plugin-dashboard": "Dina ändringar kommer förloras när du uppdaterar tillägget. Använd <1>Spara som för att skapa en anpassad version.", + "body-plugin-dashboard": "", "no-changes-to-save": "Inga ändringar att spara", "title-failed-to-save-dashboard": "Det gick inte att spara instrumentpanel", "title-plugin-dashboard": "Tilläggsinstrumentpanel", @@ -6199,7 +6201,7 @@ "cancel": "Avbryt", "cannot-be-saved": "Denna instrumentpanel kan inte sparas från Grafanas användargränssnitt eftersom det har provisionerats från en annan källa. Kopiera JSON eller spara den till en fil nedan, så du kan uppdatera instrumentpanelen i provisioneringskällan.", "copy-json-to-clipboard": "Kopiera JSON till urklippet", - "file-path": "<0>Filsökväg: {{filePath}}", + "file-path": "", "label-description": "Beskrivning", "label-target-folder": "Målmapp", "label-title": "Titel", @@ -6368,8 +6370,8 @@ }, "version-history-comparison": { "label-view-json-diff": "Visa JSON-skillnader", - "new-version-updated": "<0>Version {{version}} uppdaterad av {{editor}} {{timeAgo}}", - "old-version-updated": "<0>Version {{version}} uppdaterad av {{editor}} {{timeAgo}}" + "new-version-updated": "", + "old-version-updated": "" }, "version-history-header": { "compare-versions": "Jämför {{baseVersion}} <3> {{newVersion}}", @@ -6447,7 +6449,7 @@ "provisioned-delete-modal": { "confirm-button": "OK", "text-1": "Den här instrumentpanelen hanteras av Grafana och kan inte raderas. Ta bort instrumentpanelen från konfigurationsfilen om du vill radera den.", - "text-2": "Se Grafana-dokumentationen för mer information om provisionering. ", + "text-2": "", "text-3": "Filsökväg: {{provisionedId}}", "text-link": "Gå till dokumentsidan", "title": "Det går inte att ta bort den tillhandahållna instrumentpanelen" @@ -6525,7 +6527,7 @@ }, "data-source-testing-status-page": { "error-more-details-link": "Klicka <2>här för att läsa mer om detta fel.", - "success-more-details-links": "Därefter kan du börja visualisera data genom att <2>bygga en instrumentpanel eller genom att fråga efter data i <5>Utforska vy." + "success-more-details-links": "" }, "data-sources": { "datasource-add-button": { @@ -6621,7 +6623,7 @@ "test": "Test" }, "cloud-info-box": { - "body-alert": "Eller hoppa över ansträngningen och få {{mainDS}} (och {{extraDS}}) som fullt hanterade, skalbara och värdbaserade datakällor från Grafana Labs med <6>Grafana Cloud-prenumerationen gratis för alltid.", + "body-alert": "", "title-alert": "Konfigurera din {{mainDS}}-datakälla nedan" }, "dashboards-table": { @@ -6749,18 +6751,18 @@ "no-events-yet": "Inga händelser ännu" }, "render-info-viewer": { - "data-counter": "Data: {{numDataChanges}} ", + "data-counter": "", "elapsed-time": "Tid: {{elapsed}} ms", "field": "Fält", "last": "Efternamn", - "render-counter": "Rendering: {{numRenders}} ", - "schema-counter": "Schema: {{numSchemaChanges}} ", + "render-counter": "", + "schema-counter": "", "title-reset-counters": "Nollställ räkneverk", "tooltip-step-back": "Stega bakåt@ action", "type": "Typ" }, "state-view": { - "current-value": "Nuvarande värde: {{currentValue}} ", + "current-value": "", "label-state-name": "Regionens namn" } }, @@ -7207,7 +7209,7 @@ }, "footer": { "learn-more": "Läs mer", - "pro-tip-define-sources-through-configuration-files": " Tips: Du kan även definiera datakällor via konfigurationsfiler. " + "pro-tip-define-sources-through-configuration-files": "" } }, "pane": { @@ -7269,8 +7271,6 @@ "query-deleted": "Frågan raderad" }, "rich-history-queries-tab": { - "displaying-partial-queries": "Visar {{ count }} frågor", - "displaying-queries": "{{ count }} frågor", "filter-aria-label": "Filtrera frågor för datakällor", "filter-history": "Filterhistorik", "filter-placeholder": "Filtrera frågor för datakällor", @@ -7280,7 +7280,11 @@ "search-placeholder": "Sökfrågor", "showing-queries": "Visar {{ shown }} av {{ total }} <0>Ladda mer", "sort-aria-label": "Sortera frågor", - "sort-placeholder": "Sortera frågor efter" + "sort-placeholder": "Sortera frågor efter", + "displaying-partial-queries_one": "", + "displaying-partial-queries_other": "", + "displaying-queries_one": "", + "displaying-queries_other": "" }, "rich-history-settings-tab": { "alert-info": "Grafana kommer att spara posterna upp till {{optionLabel}}.Stjärnmärkta poster raderas inte.", @@ -7472,7 +7476,7 @@ "copy-shortened-link-menu": "Öppna alternativ för kopieringslänkar", "refresh-picker-cancel": "Avbryt", "refresh-picker-run": "Kör fråga", - "split-close": " Stäng ", + "split-close": "", "split-close-tooltip": "Stäng delad ruta", "split-narrow": "Smal ruta", "split-title": "Dela", @@ -7602,8 +7606,8 @@ }, "math": { "available-math-functions": "Tillgängliga matematikfunktioner", - "run-math-operations": "Kör matematiska operationer på en eller flera frågor. Du hänvisar till frågan med {{refExample}} t.ex. {{ref1}}, {{ref2}}, {{ref3}}etc.<10>Exempel: <12>{{example}}", - "tooltip-footer": "Se vår ytterligare dokumentation om <2>matematiska uttryck.", + "run-math-operations": "", + "tooltip-footer": "", "tooltip-title": "Matematisk operator", "tooltip-trigger": "Uttryck" }, @@ -8642,7 +8646,7 @@ }, "data-source-http-settings": { "access-help": "Hjälp <1>", - "access-help-details": "Åtkomstläge reglerar hur förfrågningar till datakällan ska hanteras.<1> <1>Server bör vara det föredragna sättet om inget annat anges.", + "access-help-details": "", "access-help-title": "Hjälp för Access", "access-label": "Access", "allowed-cookies": "Tillåtna cookies", @@ -8910,7 +8914,7 @@ "cell-inspect": "Inspektera värde", "cell-inspect-tooltip": "Inspektera värde", "copy": "Kopiera till klippbordet", - "csv-counts": "Rader:{{rows}}, Kolumner:{{columns}} <5>", + "csv-counts": "", "csv-placeholder": "Ange CSV här…", "filter-placeholder": "Filtrera värden", "filter-popup-apply": "Ok", @@ -9195,7 +9199,6 @@ "name-line-width": "Linjebredd", "name-stacking": "Stapling" }, - "inline-token-warning-badge-tooltip": "", "inspector": { "inspect-data-tab": { "loading": "Laddar", @@ -9359,7 +9362,7 @@ "error-fetching": "Fel vid hämtning av LDAP-inställningar", "error-saving": "Fel vid sparande av LDAP-inställningar", "error-validate-form": "Fel vid validering av LDAP-inställningar", - "feature-flag-disabled": "Den här sidan är endast tillgänglig genom att aktivera funktionsflaggan <1>ssoSettingsLDAP.", + "feature-flag-disabled": "", "saved": "LDAP-inställningar sparade" }, "bind-dn": { @@ -9400,7 +9403,7 @@ "label": "Sök bas-DNS", "placeholder": "exempel: dc=grafana,dc=org" }, - "subtitle": "LDAP-integrationen i Grafana gör det möjligt för dina Grafana-användare att logga in med sina LDAP-inloggningsuppgifter. Läs mer i vår <2><0>dokumentation.", + "subtitle": "", "title": "Grundinställningar" }, "library-panel": { @@ -9444,7 +9447,7 @@ "dashboard-name": "Namn för instrumentpanel" }, "library-panel-info": { - "last-edited": "Senast redigerad {{timeAgo}} av ", + "last-edited": "", "usage-count_one": "Används på {{count}} instrumentpaneler", "usage-count_other": "Används på {{count}} instrumentpaneler" }, @@ -9749,7 +9752,7 @@ "tooltip-unpin-line": "Lossa rad" }, "log-row-message": { - "ellipsis": "… ", + "ellipsis": "", "more": "mer", "see-details": "Se loggdetaljer", "tooltip-error": "Fel: {{errorMessage}}" @@ -10145,7 +10148,7 @@ }, "resource-table": { "dashboard-load-error": "Det gick inte att ladda instrumentpanelen", - "error-library-element-sub": "Bibliotekselement {uid}", + "error-library-element-sub": "", "error-library-element-title": "Det gick inte att ladda bibliotekselementet", "unknown-datasource-title": "Datakälla {{datasourceUID}}", "unknown-datasource-type": "Okänd datakälla" @@ -10793,10 +10796,10 @@ "placeholder-optional": "(valfritt)", "role": "Roll", "submit": "Skicka in", - "tooltip": "Du kan nu välja alternativet ”Ingen grundläggande roll” och lägga till behörigheter för dina anpassade behov. Du hittar mer information i <1>vår dokumentation." + "tooltip": "" }, "user-invite-page": { - "sub-title": "Skicka inbjudan eller lägg till en befintlig Grafana-användare i organisationen.<1> {{orgName}}", + "sub-title": "", "text": { "invite-user": "Bjud in användare" } @@ -10885,7 +10888,7 @@ "switch-to-table": "Byt till tabell" }, "panel-plugin-error": { - "text-load-error": "Kontrollera serverstartloggarna för mer information. <1>Om detta plugin laddades från Git, se till att det kompilerades.", + "text-load-error": "", "title-load-error": "Fel vid laddning: {{panelId}}", "title-not-found": "Paneltillägg hittades inte: {{id}}" }, @@ -11079,7 +11082,7 @@ }, "details": { "connections-tab": { - "description": "Du har för närvarande följande datakällor konfigurerade för {{pluginName}}. Klicka på en ruta för att visa konfigurationsdetaljerna. Du hittar alla dina anslutningar för datakällor under <4><0>Anslutningar – <3>Datakällor." + "description": "" }, "disabled-error": { "angular-deprecation-link": "Läs mer om Angular-utfasning", @@ -11096,7 +11099,7 @@ }, "labels": { "contactGrafanaLabs": "Kontakta Grafana Labs", - "customLinks": "Anpassade länkar ", + "customLinks": "", "customLinksTooltip": "Dessa länkar tillhandahålls av tilläggsutvecklaren för att erbjuda ytterligare utvecklarspecifika resurser och information", "dependencies": "Beroenden", "documentation": "Dokumentation", @@ -11107,7 +11110,7 @@ "latestVersion": "Senaste versionen", "license": "Licens", "raiseAnIssue": "Ta upp ett problem", - "reportAbuse": "Rapportera ett problem ", + "reportAbuse": "", "reportAbuseTooltip": "Rapportera problem relaterade till skadliga eller farliga tilläggsprogram direkt till Grafana Labs.", "repository": "Databas", "signature": "Underskrift", @@ -11117,8 +11120,8 @@ "modal": { "cancel": "Avbryt", "copyEmail": "Kopiera e-postadress", - "description": "Den här funktionen är avsedd för att rapportera skadligt eller farligt beteende inom tilläggsprogram. Vid problem med tilläggsprogram, mejla oss på: ", - "node": "Obs! Om det gäller allmänna problem med tilläggsprogram, som till exempel buggar eller funktionsförfrågningar, ska du kontakta tilläggsprogrammets skapare med de inkluderade länkarna. ", + "description": "", + "node": "", "title": "Rapportera ett problem med ett tilläggsprogram" } }, @@ -11186,7 +11189,7 @@ "message": "Alla tillägg är uppdaterade" }, "not-found-plugin": { - "body-plugin-not-found": "Detta plugin-program kan inte hittas. Kontrollera att webbadressen är korrekt eller <1>gå till <3>plugin-katalogen.", + "body-plugin-not-found": "", "title-plugin-not-found": "Plugin hittades inte" }, "plugin-actions": { @@ -11650,7 +11653,6 @@ "unsupported-repository-type": "" }, "inline-secure-values-warning": "", - "inline-token-warning-badge-text": "", "job-status": { "label-view-details": "Visa detaljer", "loading-finished-job": "Läser in färdigt jobb …", @@ -11827,6 +11829,17 @@ "label-current-step": "Nuvarande steg", "label-pending-step": "Väntande steg" }, + "status-badge": { + "automatic-pulling-disabled": "", + "deleting": "", + "error": "", + "pending": "", + "pulling": "", + "unknown": "", + "up-to-date": "", + "waiting-for-health-check": "", + "warning": "" + }, "success-title-default": "Lyckades", "sync-job": { "error-no-job-id": "Misslyckades att starta", @@ -12004,7 +12017,7 @@ "annotations-show-text": "Kommentarer = visa", "time-range-picker-disabled-text": "Tidsintervallväljare = inaktiverad", "time-range-picker-enabled-text": "Tidsintervallväljare = aktiverad", - "time-range-text": "Tidsintervall = " + "time-range-text": "" }, "share": { "success-delete": "Din instrumentpanel kan inte längre delas" @@ -12043,7 +12056,7 @@ "revoke-user-access-modal-desc-line1": "Är du säker på att du vill återkalla åtkomst för {{email}}?" }, "delete-user-shared-dashboards-modal": { - "revoke-user-access-modal-desc-line2": "Denna åtgärd återkallar omedelbart åtkomsten för {{email}} till alla delade kontrollpaneler." + "revoke-user-access-modal-desc-line2": "" }, "modal": { "shared-dashboard-modal-title": "Delade instrumentpaneler" @@ -12212,7 +12225,7 @@ }, "menu": { "clear-button": "Rensa alla", - "tooltip": "Du kan nu välja alternativet ”Ingen grundläggande roll” och lägga till behörigheter för dina anpassade behov. Du hittar mer information i <1>vår dokumentation." + "tooltip": "" }, "menu-aria-label": "Menyn Rollväljare", "menu-group-option-aria-label": "Alternativ för rollväljare", @@ -12222,7 +12235,7 @@ }, "sub-menu-aria-label": "Undermenyn rollväljare", "title": { - "description": "Tilldela roller till användare för att säkerställa detaljerad kontroll över åtkomst till Grafanas funktioner och resurser. Läs mer i vår <2>dokumentation." + "description": "" } }, "role-picker-drawer": { @@ -12345,7 +12358,7 @@ }, "select": { "select-menu": { - "selected-count": "Vald " + "selected-count": "" } }, "service-account-create-page": { @@ -12444,6 +12457,7 @@ "aria-label-role": "Roll" }, "service-account-tokens-table": { + "aria-label-delete-button": "", "created": "Skapad", "expires": "Löper ut", "last-used-at": "Användes senast", @@ -12531,7 +12545,7 @@ "info-text": "Skapa en direktlänk till denna instrumentpanel eller panel, anpassad med alternativen nedan.", "link-url": "Länkens webbadress", "render-alert": "Tilläggsprogram för bildrendering inte installerat", - "render-instructions": "För att rendera en bild måste du installera <2>Grafanas bildrenderingstillägg. Kontakta din Grafana-administratör för installation av tillägget.", + "render-instructions": "", "rendered-image": "Direktlänk till renderad bild", "save-alert": "Instrumentpanelen sparades inte", "save-dashboard": "För att rendera en panelbild måste du spara instrumentpanelen först.", @@ -12555,7 +12569,7 @@ "info-text-1": "En ögonblicksbild är ett omedelbart sätt att dela en interaktiv panel offentligt. När de skapas tar vi bort känsliga data som till exempel frågor (statistik, mallar och kommentarer) och panellänkar och lämnar endast synlig statistik och serienamn inbäddade i instrumentpanelen.", "info-text-2": "Tänk på att din ögonblicksbild <1>kan ses av alla som har länken och kan komma åt webbadressen. Dela klokt.", "local-button": "Publicera ögonblicksbild", - "mistake-message": "Gjorde du ett misstag? ", + "mistake-message": "", "name": "Namn för ögonblicksbild", "timeout": "Timeout (sekunder)", "timeout-description": "Du kan behöva konfigurera timeoutvärdet om det tar lång tid att samla in statistik från instrumentpanelen.", @@ -13167,7 +13181,7 @@ "forwards-time-aria-label": "Flytta tidsintervallet framåt", "to": "till", "zoom-out-button": "Zooma ut tidsintervall", - "zoom-out-tooltip": "Tidsintervall zooma ut <1> CTRL+Z" + "zoom-out-tooltip": "" }, "time-range": { "apply": "Tillämpa tidsintervall", @@ -13292,7 +13306,7 @@ }, "transformations": { "empty": { - "add-transformation-body": "Transformationer gör att data kan ändras på olika sätt innan din visualisering visas.<1>Det inkluderar att sammanfoga data, byta namn på fält, göra beräkningar, formatera data för visning med mera.", + "add-transformation-body": "", "add-transformation-header": "Börja omvandla data" } }, @@ -13559,7 +13573,7 @@ "label-format": "Format", "label-set-timezone": "Ange tidszon", "label-time-field": "Tidsfält", - "tooltip-format": "Utdataformatet för fältet anges som en <2>Moment.js-formatsträng.", + "tooltip-format": "", "tooltip-timezone-manually": "Ställ in tidszonen för datumet manuellt" }, "format-time-transformer-editor": { @@ -14154,8 +14168,8 @@ "message": "Inga användare hittades" }, "token-revoked-modal": { - "auto-revoked": "Din sessionstoken återkallades automatiskt eftersom du har nått <2>det maximala antalet {{numSessions}} samtidiga sessioner för ditt konto.", - "resume-message": "<0>Logga in igen för att återuppta sessionen.Kontakta din administratör eller gå till licenssidan för att granska din kvot om du upprepade gånger loggas ut automatiskt.", + "auto-revoked": "", + "resume-message": "", "sign-in": "Logga in", "title-you-have-been-automatically-signed-out": "Du har loggats ut automatiskt" }, diff --git a/public/locales/tr-TR/grafana.json b/public/locales/tr-TR/grafana.json index 3aa30fa95c6..8f6c3f2fad8 100644 --- a/public/locales/tr-TR/grafana.json +++ b/public/locales/tr-TR/grafana.json @@ -108,7 +108,7 @@ "dismiss": "Kapat", "heading": "Kurumsal kimlik doğrulama", "learn-more-link": "Daha fazla bilgi edinin", - "text": "Grafana Cloud ve Enterprise sürümlerinde kullanıcıları, ekipleri ve izinleri <1>SAML, <3>SCIM, <6>LDAP ve <8>RBAC ile otomatik olarak yönetin." + "text": "" }, "feature-listing": { "title-auditing": "Denetim", @@ -209,7 +209,7 @@ "title-delete": "Sil" }, "orgs": { - "delete-body": "\"{{deleteOrgName}}\" kuruluşunu silmek istediğinizden emin misiniz?<3> <5>Bu kuruluşa ait tüm panolar kaldırılacak!", + "delete-body": "", "id-header": "Kimlik", "name-header": "Ad", "new-org-button": "Yeni kuruluş" @@ -719,6 +719,7 @@ "title-annotations": "Ek açıklamalar" }, "link-dashboard-and-panel": "Panoyu ve paneli bağlayın", + "placeholder-value-input": "", "placeholder-value-input-default": "Özel ek açıklama içeriği girin..." }, "bulk-actions": { @@ -1144,7 +1145,7 @@ "title-something-wrong-trying-fetch-group-details": "Grup bilgileri getirilmeye çalışılırken bir hata oluştu" }, "evaluation-interval-limit-exceeded": { - "body-minimum-interval": "Grafana'da minimum değerlendirme aralığı <1>{{minInterval}} olarak ayarlandı.<3>Daha düşük bir aralık ayarlamak için lütfen yöneticinizle iletişime geçin.", + "body-minimum-interval": "", "title-global-evaluation-interval-limit-exceeded": "Genel değerlendirme aralığı sınırı aşıldı" }, "existing-rule-editor": { @@ -1292,7 +1293,7 @@ "resolved": "Çözüldü" } }, - "review-alert-payload": "Yüke eklenecek uyarı verilerini gözden geçirin:", + "review-alert-payload": "", "title-add-custom-alerts": "Özel uyarılar ekle" }, "get-alert-suggestions": { @@ -1416,7 +1417,7 @@ "title-add-folder-and-labels": "Klasör ve etiket ekle" }, "grafana-managed-rule-type": { - "description": "Her türden birden fazla veri kaynağını destekler.<1>Verileri ifadelerle dönüştürün." + "description": "" }, "grafana-modify-export": { "body-invalid-rule-id": "Sayfa URL'sindeki kural UID'si geçersiz. Lütfen URL'yi kontrol edin ve tekrar deneyin.", @@ -1853,7 +1854,7 @@ "aria-label-new": "yeni" }, "mimir-flavored-type": { - "description": "Mimir, Loki veya Cortex veri kaynağı kullanın.<1>İfadeler desteklenmiyor." + "description": "" }, "min-interval-option": { "label-interval": "Aralık", @@ -2082,7 +2083,7 @@ "warning-1": "Bu bildirim politikası silindiğinde kalıcı olarak kaldırılacaktır.", "warning-2": "Bu politikayı silmek istediğinizden emin misiniz?" }, - "filter-description": "Bildirim politikalarını, virgülle ayrılmış eşleşenler listesi kullanarak filtreleyin, örneğin: <1>severity=critical, region=EMEA", + "filter-description": "", "generated-policies": "Otomatik olarak oluşturulan politikalar", "matchers": "Eşleşenler", "metadata": { @@ -2126,7 +2127,8 @@ "conflict": "Bildirim politikası ağacı başka bir kullanıcı tarafından güncellendi.", "error-code": "Hata mesajı: \"{{error}}\"", "routes": { - "conflictingMatchers": "Yönlendirme eklenemiyor veya güncellenemiyor: {{-matchers}} eşleştiricilerini birleştirdiğimizde eşleştiriciler harici bir yönlendirme ağacıyla çakışır. Bu, yönlendirmenin erişilemez olmasına neden olur." + "conflictingMatchers": "Yönlendirme eklenemiyor veya güncellenemiyor: {{-matchers}} eşleştiricilerini birleştirdiğimizde eşleştiriciler harici bir yönlendirme ağacıyla çakışır. Bu, yönlendirmenin erişilemez olmasına neden olur.", + "unknownMatchers": "" }, "suffix": "Lütfen sayfayı yenileyin ve tekrar deneyin.", "title": "Bildirim politikası eklenemedi veya güncellenemedi" @@ -2244,7 +2246,7 @@ "error-no-query-editor": "Sorgu düzenleyici şu nedenle yüklenemedi: {{errorMessage}}" }, "recording-rule-type": { - "description": "İfadeleri önceden hesaplayın.<1>Bir uyarı kuralı ile birlikte kullanılmalıdır." + "description": "" }, "recording-rules": { "description-target-data-source": "Kayıt kurallarının saklanacağı Prometheus veri kaynağı", @@ -2257,7 +2259,7 @@ }, "redirect-to-clone-rule": { "body-evaluation-group": "Kopyalanan kural için yeni bir değerlendirme grubu ayarlamanız gerekir çünkü orijinal kural sağlanmış ve kullanıcı arayüzünde oluşturulan kurallar için kullanılamaz.", - "body-not-provisioned": "Yeni kural, sağlanmış bir kural olarak <1>işaretlenmeyecek.", + "body-not-provisioned": "", "confirmText-copy": "Kopyala", "title-copy-provisioned-alert-rule": "Sağlanan uyarı kuralını kopyala" }, @@ -2292,13 +2294,13 @@ "routing-settings": { "aria-label-group-by": "Gruplama ölçütü", "description-group-by": "Birden fazla uyarıyı aynı etiket değerlerine göre gruplayarak tek bir bildirime dönüştürün. Boş bırakılırsa varsayılan bildirim politikasından devralınır.", - "group-interval": "Grup aralığı: <1>{{groupIntervalValue}}", - "group-wait": "Grup bekleme: <1>{{groupWaitValue}}", - "grouping": "Gruplandırma: <1>{{fields}}", + "group-interval": "", + "group-wait": "", + "grouping": "", "label-group-by": "Gruplama ölçütü", "label-override-grouping": "Gruplandırmayı geçersiz kıl", "label-override-timings": "Zamanlamaları geçersiz kıl", - "repeat-interval": "Tekrarlama aralığı: <1>{{repeatIntervalValue}}" + "repeat-interval": "" }, "rule-actions-buttons": { "title-edit": "Düzenle", @@ -2554,7 +2556,7 @@ "relative-with-to": "" }, "rule-type-picker": { - "grafana-managed": "Ruler API etkin olan bir Mimir, Loki veya Cortex veri kaynağınız yoksa \"Grafana tarafından yönetilen\" seçeneğini belirleyin." + "grafana-managed": "" }, "rule-view": { "query": { @@ -2887,7 +2889,7 @@ "test-contact-point-modal": { "custom-notification-message": "Aşağıda tanımlanan açıklamaları kullanan bir test bildirimi göndereceksiniz. Özelleştirilmiş şablonlar ve mesajlar kullanıyorsanız bu iyi bir seçenektir.", "notification-message": "Bildirim mesajı", - "predefined-notification-message": "Önceden tanımlı bir uyarıyı kullanan bir test bildirimi göndereceksiniz. Özelleştirilmiş bir şablon veya mesaj tanımladıysanız daha iyi sonuçlar için yukarıdan <1>özel bildirim mesajına geçin.", + "predefined-notification-message": "", "send-test-notification": "Test bildirimi gönder", "title-test-contact-point": "İletişim noktasını test et" }, @@ -2896,7 +2898,7 @@ }, "threshold-expression-viewer": { "input": "Girdi", - "stop-alerting-when": "Şu durumda uyarıyı durdur (veya bekleme durumuna geç): " + "stop-alerting-when": "" }, "time-interval": { "add-time-interval": "Zaman aralığı ekle", @@ -3084,7 +3086,7 @@ "title-notification-policies": "Bildirim politikaları" }, "yaml-content-info": { - "body": "Düzenleyicideki YAML içeriği yalnızca uyarı kuralı yapılandırmasını içerir <1>Prometheus yapılandırması yapmak için <4>yapılandırma dosyasının kalan içeriğini sağlamanız gerekir." + "body": "" } }, "alertlist": { @@ -3160,7 +3162,7 @@ "no-annotations-found": "Ek açıklama bulunamadı" }, "annotation-list-item": { - "tooltip-created-by": "Oluşturan:<1> {{email}}" + "tooltip-created-by": "" }, "category-annotation-query": "Ek açıklama sorgusu", "category-display": "Ekran", @@ -3198,7 +3200,7 @@ }, "empty-state": { "button-title": "Ek açıklama sorgusu ekle", - "info-box-content": "<0>Ek açıklamalar, olay verilerini grafiklerinize entegre etmenizi sağlar. Tüm grafik panellerinde dikey çizgiler ve simgeler olarak görselleştirilirler. Bir ek açıklama simgesinin üzerine geldiğinizde, ilgili olayın metnini ve etiketlerini görebilirsiniz. CTRL veya CMD tuşları basılı halde grafik üzerine tıklayarak (veya bir bölgeyi sürükleyerek) doğrudan Grafana'dan ek açıklama olayları ekleyebilirsiniz. Bu EK açıklamalar, Grafana'nın açıklama veri tabanında saklanacaktır.", + "info-box-content": "", "info-box-content-2": "Daha fazla bilgi için <2>Ek açıklamalar belgelerine göz atın.", "title": "Henüz eklenmiş özel ek açıklama sorgusu yok" }, @@ -3236,7 +3238,7 @@ "auth-settings": "Kimlik doğrulaması ayarları" }, "auth-drawer-unconneced": { - "subtitle": "Kimlik doğrulama ayarlarını yapılandırın. Daha fazla bilgi için <2>belgelerimize bakın." + "subtitle": "" }, "auth-drawer-unconnected": { "advanced-auth": "Gelişmiş Kimlik Doğrulaması", @@ -3270,7 +3272,7 @@ "allowed-organizations-description": "Virgül veya boşlukla ayrılmış kuruluş listesi. Kullanıcının giriş yapabilmesi için en az bir\ngrubun üyesi olması gerekir.", "allowed-organizations-label": "İzin verilen kuruluşlar", "allowed-organizations-placeholder": "Kuruluşları girin (benim-ekibim, benimekibim...) ve eklemek için Enter tuşuna basın", - "api-url-description": "OAuth2 sağlayıcınızın kullanıcı bilgisi uç noktası. Bu uç noktadan dönen bilgiler <2>OpenID UserInfo ile uyumlu olmalıdır.", + "api-url-description": "", "api-url-required": "Bu alan ayarlanmışsa geçerli bir URL olmalıdır", "auth-style-description": "\"{{ clientIDLabel }}\" ve \"{{ clientSecretLabel }}\" bilgilerinin OAuth2 sağlayıcısına nasıl gönderileceğini belirler. Varsayılan Otomatik Algıla'dır.", "auth-style-label": "Kimlik doğrulama stili", @@ -3415,7 +3417,7 @@ } }, "auth-config-auth-config-page-unconnected": { - "subtitle": "Kimlik doğrulama ayarlarınızı yönetin ve çoklu oturum açmayı yapılandırın. Daha fazla bilgi için <2>belgelerimize bakın." + "subtitle": "" }, "bar-chart": { "warn": { @@ -4133,7 +4135,7 @@ }, "scopes": { "apply-selected-scopes": "Uygula", - "selected-scopes-label": "Kapsamlar: " + "selected-scopes-label": "" }, "search-box": { "placeholder": "Ara veya şuraya git:" @@ -4275,7 +4277,7 @@ "okay": "Tamam" }, "not-found-datasource": { - "body": "URL'yi yanlış yazmış olabilirsiniz veya <1> kimliğine sahip eklenti kullanılamıyor.<3>Mevcut veri kaynaklarını görmek için <5>buraya tıklayın." + "body": "" }, "oss": { "connections-home-page": { @@ -4318,8 +4320,8 @@ "versionHistory": { "comparison": { "header": { - "hide-json-diff": "JSON farklarını gizle ", - "show-json-diff": "JSON farklarını göster ", + "hide-json-diff": "", + "show-json-diff": "", "text": "{{version}} sürümü {{createdBy}} tarafından güncellendi ({{ageString}}) {{message}}" }, "select": "Karşılaştırmaya başlamak için iki sürüm seçin" @@ -4346,7 +4348,7 @@ "label-label": "Etiket", "label-placeholder": "Ör. Tempo izleri", "label-required": "Bu alan gereklidir.", - "sub-text": "<0>Korelasyonu tanımlayacak metni belirleyin.", + "sub-text": "", "title": "Korelasyon etiketini tanımlayın (Adım 1/3)" }, "configure-correlation-target-form": { @@ -4390,7 +4392,7 @@ }, "source-form": { "control-required": "Bu alan gereklidir.", - "description": "Bir görselleştirmede korelasyon düğmesinin görünmesi için bir veri noktasının tüm değişkenlere alanlar veya dönüşüm çıktısı olarak değer sağlamalıdır.<1>Not: Her değişkenin aşağıda açıkça tanımlanması gerekmez. <4>logfmt gibi bir dönüşüm, her anahtar/değer çifti için değişkenler oluşturacaktır.", + "description": "", "description-external-pre": "Hedef URL'de aşağıdaki değişkenleri kullandınız:", "description-query-pre": "Hedef sorguda aşağıdaki değişkenleri kullandınız:", "external-title": "URL'yi kullanacak veri kaynağını yapılandırın (Adım 3/3)", @@ -4402,12 +4404,12 @@ "results-required": "Bu alan gereklidir.", "source-description": "Seçilen kaynak veri kaynağından gelen sonuçlar panelde bağlantılarla görüntülenir.", "source-label": "Kaynak", - "sub-text": "<0>Korelasyonun hangi veri kaynağında görüntüleneceğini ve hangi verilerin önceden tanımlanmış değişkenlerin yerini alacağını tanımlayın." + "sub-text": "" }, "sub-title": "", "target-form": { "control-rules": "Bu alan gereklidir.", - "sub-text": "<0>Korelasyonun neyle bağlantı kuracağını tanımlayın. Sorgu türü ile korelasyona tıklandığında bir sorgu çalıştırılır. Haricî tür ile korelasyona tıklandığında bir URL açılır.", + "sub-text": "", "target-description-external": "Bağlantıya tıklandığında açılacak URL'yi belirtin", "target-description-query": "Bağlantıya tıklandığında hangi veri kaynağının sorgulanacağını belirtin", "target-label": "Hedef", @@ -4614,7 +4616,7 @@ } }, "confirm-plugin-dashboard-save-modal": { - "body-plugin-dashboard": "Eklentiyi güncellediğinizde değişiklikleriniz kaybolacaktır. <1><2>Özel sürüm oluşturmak için <1>Farklı Kaydet seçeneğini kullanın.", + "body-plugin-dashboard": "", "cancel": "İptal", "overwrite": "Üzerine yaz", "title-plugin-dashboard": "Eklenti panosu" @@ -5289,8 +5291,8 @@ "title-provisioned": "Sağlanan pano" }, "save-dashboard-error-proxy": { - "body-name-exists": "Seçilen klasörde aynı isimde bir pano zaten mevcut. <1><2>Yine de bu panoyu kaydetmek istiyor musunuz?", - "body-version-mismatch": "Başka bir kullanıcı bu panoyu güncelledi<1><2>Yine de bu panoyu kaydetmek ister misiniz?", + "body-name-exists": "", + "body-version-mismatch": "", "confirmText-save-and-overwrite": "Kaydet ve üzerine yaz", "title-name-exists": "Çakışma", "title-version-mismatch": "Çakışma" @@ -5308,7 +5310,7 @@ "cancel": "İptal", "cannot-be-saved": "Bu pano başka bir kaynaktan sağlandığı için Grafana kullanıcı arayüzünden kaydedilemez. JSON'u kopyalayın veya aşağıdan bir dosyaya kaydedin, ardından sağlama kaynağındaki panonuzu güncelleyebilirsiniz.", "copy-json-to-clipboard": "JSON'u panoya kopyala", - "file-path": "<0>Dosya yolu: {{filePath}} ", + "file-path": "", "save-json-to-file": "JSON'u dosyaya kaydet", "see-docs": "Sağlama hakkında daha fazla bilgi için <2>belgelere bakın. " }, @@ -5507,7 +5509,7 @@ "transformation-picker": { "info": "Dönüşümler, sorgu sonuçlarınızı görselleştirilmeden önce birleştirmenize, hesaplamanıza, yeniden sıralamanıza, gizlemenize ve yeniden adlandırmanıza olanak tanır.", "info-graph-not-suitable": "Grafik görselleştirme kullanıyorsanız birçok dönüşüm uygun olmayabilir çünkü şu anda yalnızca zaman serisi verilerini desteklemektedir.", - "info-switch-to-table": "Bir dönüşümün ne yaptığını anlamak için Tablo görselleştirmesine geçmek yardımcı olabilir. ", + "info-switch-to-table": "", "placeholder-search-for-transformation": "Dönüşüm ara", "read-more": "Daha fazlasını okuyun", "title-transformations": "Dönüşümler" @@ -5573,8 +5575,8 @@ "version-history-comparison": { "button-restore": "{{version}} sürümüne geri yükle", "label-view-json-diff": "JSON farkını görüntüle", - "new-updated-by": "<0>{{version}} sürümü {{editor}} tarafından {{timeAgo}} önce güncellendi", - "old-updated-by": "<0>{{version}} sürümü {{editor}} tarafından {{timeAgo}} önce güncellendi" + "new-updated-by": "", + "old-updated-by": "" }, "version-history-table": { "aria-label-toggle-selection": "{{version}} sürümünün seçimini değiştir", @@ -5974,7 +5976,7 @@ "cancel": "İptal" }, "render-save-button-and-error": { - "body-plugin-dashboard": "Eklentiyi güncellediğinizde değişiklikleriniz kaybolacaktır. Özel sürüm oluşturmak için <1>Farklı kaydet seçeneğini kullanın.", + "body-plugin-dashboard": "", "title-failed-to-save-dashboard": "Pano kaydedilemedi", "title-plugin-dashboard": "Eklenti panosu", "title-someone-else-has-updated-this-dashboard": "Başka biri bu panoyu güncelledi", @@ -5983,7 +5985,7 @@ "save-and-overwrite": "\"Kaydet ve üzerine yaz\"" }, "library-viz-panel-info": { - "last-edited": "{{timeAgo}} önce, tarafından", + "last-edited": "", "usage-count_one": "{{count}} panoda kullanılıyor", "usage-count_other": "{{count}} panoda kullanılıyor" }, @@ -6044,7 +6046,7 @@ }, "panel-data-queries-tab-rendered": { "add-query": "Sorgu ekle", - "expression": "İfade " + "expression": "" }, "panel-data-transformations-tab": { "tab-label": "Dönüşümler" @@ -6102,7 +6104,7 @@ "query": "Sorgu" }, "query-variable-editor-form": { - "description-examples": "Görüntü metnini ve değeri ayırmak için adlandırılmış yakalama grupları kullanılabilir (<1>örnekleri görün).", + "description-examples": "", "description-optional": "İsteğe bağlıdır, bir seri adının veya metrik düğüm parçasının bir kısmını çıkarmak istiyorsanız kullanılır.", "label-data-source": "Veri kaynağı", "label-static-options-sort": "Statik seçenekleri sırala", @@ -6163,7 +6165,7 @@ "label-message": "Mesaj", "placeholder-describe-changes-optional": "Değişikliklerinizi açıklamak için bir not ekleyin (isteğe bağlı).", "render-footer": { - "body-plugin-dashboard": "Eklentiyi güncellediğinizde değişiklikleriniz kaybolacaktır. Özel sürüm oluşturmak için <1>Farklı kaydet seçeneğini kullanın.", + "body-plugin-dashboard": "", "no-changes-to-save": "Kaydedilecek değişiklik yok", "title-failed-to-save-dashboard": "Pano kaydedilemedi", "title-plugin-dashboard": "Eklenti panosu", @@ -6199,7 +6201,7 @@ "cancel": "İptal", "cannot-be-saved": "Bu pano başka bir kaynaktan sağlandığı için Grafana kullanıcı arayüzünden kaydedilemez. JSON'u kopyalayın veya aşağıdan bir dosyaya kaydedin, ardından sağlama kaynağındaki panonuzu güncelleyebilirsiniz.", "copy-json-to-clipboard": "JSON'u panoya kopyala", - "file-path": "<0>Dosya yolu: {{filePath}} ", + "file-path": "", "label-description": "Açıklama", "label-target-folder": "Hedef klasör", "label-title": "Başlık", @@ -6368,8 +6370,8 @@ }, "version-history-comparison": { "label-view-json-diff": "JSON farkını görüntüle", - "new-version-updated": "<0>{{version}} sürümü {{editor}} tarafından {{timeAgo}} önce güncellendi", - "old-version-updated": "<0>{{version}} sürümü {{editor}} tarafından {{timeAgo}} önce güncellendi" + "new-version-updated": "", + "old-version-updated": "" }, "version-history-header": { "compare-versions": "{{baseVersion}} <3> {{newVersion}} karşılaştırması", @@ -6447,7 +6449,7 @@ "provisioned-delete-modal": { "confirm-button": "Tamam", "text-1": "Bu pano, Grafana sağlama sistemi tarafından yönetilmektedir ve silinemez. Panoyu silmek için yapılandırma dosyasından kaldırın.", - "text-2": "Sağlama sistemi hakkında daha fazla bilgi için Grafana belgelerine bakın. ", + "text-2": "", "text-3": "Dosya yolu: {{provisionedId}}", "text-link": "Belgeler sayfasına git", "title": "Sağlanan pano silinemiyor" @@ -6525,7 +6527,7 @@ }, "data-source-testing-status-page": { "error-more-details-link": "Bu hata hakkında daha fazla bilgi edinmek için <2>buraya tıklayın.", - "success-more-details-links": "Ardından, bir <2>pano oluşturarak veya <5>Keşfet görünümünde verileri sorgulayarak verileri görselleştirmeye başlayabilirsiniz." + "success-more-details-links": "" }, "data-sources": { "datasource-add-button": { @@ -6621,7 +6623,7 @@ "test": "Test" }, "cloud-info-box": { - "body-alert": "Veya uğraşmadan {{mainDS}} (ve {{extraDS}}) veri kaynaklarını Grafana Labs'tan tamamen yönetilen, ölçeklenebilir ve barındırılan <6>daima ücretsiz Grafana Cloud planıyla edinin.", + "body-alert": "", "title-alert": "Aşağıdan {{mainDS}} veri kaynağınızı yapılandırın" }, "dashboards-table": { @@ -6749,18 +6751,18 @@ "no-events-yet": "Henüz bir etkinlik yok" }, "render-info-viewer": { - "data-counter": "Veri: {{numDataChanges}} ", + "data-counter": "", "elapsed-time": "Süre: {{elapsed}} ms", "field": "Alan", "last": "Son", - "render-counter": "Oluşturma: {{numRenders}} ", - "schema-counter": "Şema: {{numSchemaChanges}} ", + "render-counter": "", + "schema-counter": "", "title-reset-counters": "Sayaçları sıfırla", "tooltip-step-back": "Bir adım geri git", "type": "Tür" }, "state-view": { - "current-value": "Geçerli değer: {{currentValue}} ", + "current-value": "", "label-state-name": "Durum adı" } }, @@ -7207,7 +7209,7 @@ }, "footer": { "learn-more": "Daha fazla bilgi edinin", - "pro-tip-define-sources-through-configuration-files": "İpucu: Veri kaynaklarını yapılandırma dosyaları aracılığıyla da tanımlayabilirsiniz. " + "pro-tip-define-sources-through-configuration-files": "" } }, "pane": { @@ -7269,8 +7271,6 @@ "query-deleted": "Sorgu silindi" }, "rich-history-queries-tab": { - "displaying-partial-queries": "{{ count }} sorgu gösteriliyor", - "displaying-queries": "{{ count }} sorgu", "filter-aria-label": "Veri kaynakları için sorguları filtreleyin", "filter-history": "Geçmişi filtrele", "filter-placeholder": "Veri kaynakları için sorguları filtreleyin", @@ -7280,7 +7280,11 @@ "search-placeholder": "Arama sorguları", "showing-queries": "{{ shown }}/{{ total }} gösteriliyor <0>Daha fazla yükle", "sort-aria-label": "Sorguları sıralayın", - "sort-placeholder": "Sorguları sıralama ölçütü:" + "sort-placeholder": "Sorguları sıralama ölçütü:", + "displaying-partial-queries_one": "", + "displaying-partial-queries_other": "", + "displaying-queries_one": "", + "displaying-queries_other": "" }, "rich-history-settings-tab": { "alert-info": "Grafana, kayıtları {{optionLabel}} süresince/kadar saklayacaktır.Yıldızlı kayıtlar silinmeyecektir.", @@ -7472,7 +7476,7 @@ "copy-shortened-link-menu": "Bağlantı kopyalama seçeneklerini aç", "refresh-picker-cancel": "İptal", "refresh-picker-run": "Sorgu çalıştır", - "split-close": "Kapat ", + "split-close": "", "split-close-tooltip": "Bölünmüş bölmeyi kapat", "split-narrow": "Dar bölme görünümü", "split-title": "Böl", @@ -7602,8 +7606,8 @@ }, "math": { "available-math-functions": "Kullanılabilir matematiksel işlevler", - "run-math-operations": "Bir veya daha fazla sorgu üzerinde matematiksel işlemler çalıştırın. Sorguya {{refExample}} ile referans verirsiniz. Örneğin {{ref1}}, {{ref2}}, {{ref3}} vb.<10>Örnek: <12>{{example}}", - "tooltip-footer": " <2>Matematiksel ifadeler hakkında ek belgelerimize bakın.", + "run-math-operations": "", + "tooltip-footer": "", "tooltip-title": "Matematik işleci", "tooltip-trigger": "İfade" }, @@ -8642,7 +8646,7 @@ }, "data-source-http-settings": { "access-help": "Yardım <1>", - "access-help-details": "Erişim modu, veri kaynağına yapılan isteklerin nasıl işleneceğini kontrol eder.<1> <1>Server aksi belirtilmedikçe tercih edilen yol olmalıdır.", + "access-help-details": "", "access-help-title": "Erişim yardımı", "access-label": "Erişim", "allowed-cookies": "İzin verilen çerezler", @@ -8910,7 +8914,7 @@ "cell-inspect": "Değeri incele", "cell-inspect-tooltip": "Değeri incele", "copy": "Panoya kopyala", - "csv-counts": "Satırlar:{{rows}}, Sütunlar:{{columns}} <5>", + "csv-counts": "", "csv-placeholder": "Buraya CSV girin...", "filter-placeholder": "Değerleri filtrele", "filter-popup-apply": "Tamam", @@ -9195,7 +9199,6 @@ "name-line-width": "Çizgi genişliği", "name-stacking": "İstifleme" }, - "inline-token-warning-badge-tooltip": "", "inspector": { "inspect-data-tab": { "loading": "Yükleniyor", @@ -9359,7 +9362,7 @@ "error-fetching": "LDAP ayarları alınırken hata oluştu", "error-saving": "LDAP ayarları kaydedilirken hata oluştu", "error-validate-form": "LDAP ayarları doğrulanırken hata oluştu", - "feature-flag-disabled": "Bu sayfaya yalnızca <1>ssoSettingsLDAP özellik bayrağı etkinleştirilerek erişilebilir.", + "feature-flag-disabled": "", "saved": "LDAP ayarları kaydedildi" }, "bind-dn": { @@ -9400,7 +9403,7 @@ "label": "Arama temel DN", "placeholder": "örnek: dc=grafana,dc=org" }, - "subtitle": "Grafana’daki LDAP entegrasyonu, Grafana kullanıcılarınızın LDAP kimlik bilgileriyle giriş yapmasına olanak tanır. Daha fazla bilgi için <2><0>belgelerimize bakın.", + "subtitle": "", "title": "Temel Ayarlar" }, "library-panel": { @@ -9444,7 +9447,7 @@ "dashboard-name": "Pano adı" }, "library-panel-info": { - "last-edited": "Son düzenleme {{timeAgo}} önce tarafından yapıldı", + "last-edited": "", "usage-count_one": "{{count}} panoda kullanılıyor", "usage-count_other": "{{count}} panoda kullanılıyor" }, @@ -9749,7 +9752,7 @@ "tooltip-unpin-line": "Satırın sabitlemesini kaldır" }, "log-row-message": { - "ellipsis": "… ", + "ellipsis": "", "more": "daha fazla", "see-details": "Günlük ayrıntılarını göster", "tooltip-error": "Hata: {{errorMessage}}" @@ -10145,7 +10148,7 @@ }, "resource-table": { "dashboard-load-error": "Pano yüklenemiyor", - "error-library-element-sub": "Kütüphane Bileşeni {uid}", + "error-library-element-sub": "", "error-library-element-title": "Kütüphane bileşeni yüklenemiyor", "unknown-datasource-title": "Veri kaynağı {{datasourceUID}}", "unknown-datasource-type": "Bilinmeyen veri kaynağı" @@ -10793,10 +10796,10 @@ "placeholder-optional": "(isteğe bağlı)", "role": "Rol", "submit": "Gönder", - "tooltip": "Artık \"Temel rol yok\" seçeneğini seçebilir ve izinleri özel ihtiyaçlarınıza göre ekleyebilirsiniz. Daha fazla bilgi için <1>belgelerimize göz atabilirsiniz." + "tooltip": "" }, "user-invite-page": { - "sub-title": "Davet gönderin veya mevcut bir Grafana kullanıcısını <1> {{orgName}} kuruluşuna ekleyin.", + "sub-title": "", "text": { "invite-user": "Kullanıcı davet et" } @@ -10885,7 +10888,7 @@ "switch-to-table": "Tabloya geç" }, "panel-plugin-error": { - "text-load-error": "Daha fazla bilgi için sunucu başlatma günlüklerini kontrol edin. <1>Bu eklenti Git üzerinden yüklendiyse derlendiğinden emin olun.", + "text-load-error": "", "title-load-error": "Yüklenirken hata oluştu: {{panelId}}", "title-not-found": "Panel eklentisi bulunamadı: {{id}}" }, @@ -11079,7 +11082,7 @@ }, "details": { "connections-tab": { - "description": "Şu anda {{pluginName}} için aşağıdaki veri kaynakları yapılandırılmış durumda, yapılandırma ayrıntılarını görmek için bir kutucuğa tıklayın. Tüm veri kaynağı bağlantılarınızı <4><0>Bağlantılar - <3>Veri kaynakları bölümünde bulabilirsiniz." + "description": "" }, "disabled-error": { "angular-deprecation-link": "Angular desteğinin sona ermesi hakkında daha fazla bilgi edinin", @@ -11096,7 +11099,7 @@ }, "labels": { "contactGrafanaLabs": "Grafana Labs ile iletişime geçin", - "customLinks": "Özel bağlantılar ", + "customLinks": "", "customLinksTooltip": "Bu bağlantılar, eklenti geliştiricisi tarafından ek kaynaklar ve geliştiriciye özel bilgiler sağlamak amacıyla eklenmiştir.", "dependencies": "Bağımlılıklar", "documentation": "Belgeler", @@ -11107,7 +11110,7 @@ "latestVersion": "En Son Sürüm", "license": "Lisans", "raiseAnIssue": "Sorun bildir", - "reportAbuse": "Sorun bildir ", + "reportAbuse": "", "reportAbuseTooltip": "Zararlı veya kötü amaçlı eklentilere ilişkin sorunları doğrudan Grafana Labs'a bildirin.", "repository": "Depo", "signature": "İmza", @@ -11117,8 +11120,8 @@ "modal": { "cancel": "İptal", "copyEmail": "E-posta adresini kopyala", - "description": "Bu özellik, eklentilerdeki kötü amaçlı veya zararlı davranışları bildirmek içindir. Eklentiyle ilgili endişeleriniz için bize şu adresten e-posta gönderin: ", - "node": "Not: Hata veya özellik isteği gibi genel eklenti sorunları için lütfen sağlanan bağlantıları kullanarak eklenti geliştiricisiyle iletişime geçin. ", + "description": "", + "node": "", "title": "Eklenti ile ilgili sorun bildir" } }, @@ -11186,7 +11189,7 @@ "message": "" }, "not-found-plugin": { - "body-plugin-not-found": "Bu eklenti bulunamıyor. Lütfen URL'nin doğru olduğundan emin olun veya <1><3>eklenti kataloğuna gidin.", + "body-plugin-not-found": "", "title-plugin-not-found": "Eklenti bulunamadı" }, "plugin-actions": { @@ -11650,7 +11653,6 @@ "unsupported-repository-type": "" }, "inline-secure-values-warning": "", - "inline-token-warning-badge-text": "", "job-status": { "label-view-details": "Ayrıntıları görüntüleyin", "loading-finished-job": "Tamamlanan iş yükleniyor...", @@ -11827,6 +11829,17 @@ "label-current-step": "Mevcut adım", "label-pending-step": "Bekleyen adım" }, + "status-badge": { + "automatic-pulling-disabled": "", + "deleting": "", + "error": "", + "pending": "", + "pulling": "", + "unknown": "", + "up-to-date": "", + "waiting-for-health-check": "", + "warning": "" + }, "success-title-default": "Başarılı", "sync-job": { "error-no-job-id": "İş başlatılamadı", @@ -12004,7 +12017,7 @@ "annotations-show-text": "Ek açıklamalar = göster", "time-range-picker-disabled-text": "Zaman aralığı seçici = devre dışı", "time-range-picker-enabled-text": "Zaman aralığı seçici = etkin", - "time-range-text": "Zaman aralığı = " + "time-range-text": "" }, "share": { "success-delete": "Panonuz artık paylaşılabilir değil" @@ -12043,7 +12056,7 @@ "revoke-user-access-modal-desc-line1": "{{email}} adresi ile ilişkilendirilmiş kullanıcının erişimini iptal etmek istediğinizden emin misiniz?" }, "delete-user-shared-dashboards-modal": { - "revoke-user-access-modal-desc-line2": "Bu işlem, {{email}} e-posta adresinin paylaşılan tüm panolara erişimini derhal iptal edecektir." + "revoke-user-access-modal-desc-line2": "" }, "modal": { "shared-dashboard-modal-title": "Paylaşılan panolar" @@ -12212,7 +12225,7 @@ }, "menu": { "clear-button": "Tümünü temizle", - "tooltip": "Artık \"Temel rol yok\" seçeneğini seçebilir ve izinleri özel ihtiyaçlarınıza göre ekleyebilirsiniz. Daha fazla bilgi için <1>belgelerimize göz atabilirsiniz." + "tooltip": "" }, "menu-aria-label": "Rol seçici menüsü", "menu-group-option-aria-label": "Rol seçme opsiyonu", @@ -12222,7 +12235,7 @@ }, "sub-menu-aria-label": "Rol seçici alt menüsü", "title": { - "description": "Kullanıcılara roller atayarak Grafana'nın özellikleri ve kaynakları üzerinde ayrıntılı erişim kontrolü sağlayabilirsiniz. Daha fazla bilgi için <2>belgelerimize bakın." + "description": "" } }, "role-picker-drawer": { @@ -12345,7 +12358,7 @@ }, "select": { "select-menu": { - "selected-count": "Seçildi " + "selected-count": "" } }, "service-account-create-page": { @@ -12444,6 +12457,7 @@ "aria-label-role": "Rol" }, "service-account-tokens-table": { + "aria-label-delete-button": "", "created": "Oluşturuldu", "expires": "Sona erme tarihi", "last-used-at": "Son kullanım zamanı", @@ -12531,7 +12545,7 @@ "info-text": "Aşağıdaki seçeneklerle özelleştirilen bu panoya veya panele doğrudan bir bağlantı oluşturun.", "link-url": "Bağlantı URL'si", "render-alert": "Görüntü işleme eklentisi yüklü değil", - "render-instructions": "Bir görsel oluşturmak için <2>Grafana görüntü işleme eklentisini yüklemeniz gerekir. Lütfen eklentiyi yüklemek için Grafana yöneticinizle iletişime geçin.", + "render-instructions": "", "rendered-image": "Doğrudan bağlantılı oluşturulmuş görüntü", "save-alert": "Pano kaydedilmedi", "save-dashboard": "Panel görüntüsü oluşturmak için önce panoyu kaydetmelisiniz.", @@ -12555,7 +12569,7 @@ "info-text-1": "Anlık görüntü, etkileşimli bir panoyu hızlı ve herkese açık şekilde paylaşmanın bir yoludur. Oluşturulduğunda sorgular (metrik, şablon, ek açıklama) ve panel bağlantıları gibi hassas veriler çıkarılır; yalnızca panonuzda ekli olan görünür metrik verileri ve seri adları kalır.", "info-text-2": "Oluşturduğunuz anlık görüntüye ilgili bağlantıya sahip olan ve URL'ye erişebilen <1>herkes ulaşabilir. Paylaşım yaparken bu durumu göz önünde bulundurun.", "local-button": "Anlık görüntüyü yayınla", - "mistake-message": "Bir hata mı yaptınız? ", + "mistake-message": "", "name": "Anlık görüntü adı", "timeout": "Zaman aşımı (saniye)", "timeout-description": "Pano metriklerinizin toplanması uzun sürüyorsa zaman aşımı değerini yapılandırmanız gerekebilir.", @@ -13167,7 +13181,7 @@ "forwards-time-aria-label": "Zaman aralığını ileri al", "to": "bitiş", "zoom-out-button": "Zaman aralığını büyüt", - "zoom-out-tooltip": "Zaman aralığını büyüt <1> CTRL+Z" + "zoom-out-tooltip": "" }, "time-range": { "apply": "Zaman aralığını uygula", @@ -13292,7 +13306,7 @@ }, "transformations": { "empty": { - "add-transformation-body": "Dönüşümler, görselleştirme gösterilmeden önce verilerin çeşitli şekillerde değiştirilmesine olanak tanır.<1> Bu işlemler arasında verileri birleştirme, alanları yeniden adlandırma, hesaplamalar yapma, verileri görüntüleme için biçimlendirme gibi seçenekler bulunur.", + "add-transformation-body": "", "add-transformation-header": "Verileri dönüştürmeye başlayın" } }, @@ -13559,7 +13573,7 @@ "label-format": "Biçim", "label-set-timezone": "Zaman dilimini ayarla", "label-time-field": "Zaman alanı", - "tooltip-format": "Alan için çıktı biçimi, <2>Moment.js biçimlendirme dizesi olarak belirtilir.", + "tooltip-format": "", "tooltip-timezone-manually": "Tarih için saat dilimini manuel olarak ayarlayın" }, "format-time-transformer-editor": { @@ -14154,8 +14168,8 @@ "message": "Kullanıcı bulunamadı" }, "token-revoked-modal": { - "auto-revoked": "Oturum belirteciniz, hesabınız için <2>izin verilen {{numSessions}} eş zamanlı oturum sınırına ulaşıldığı için otomatik olarak iptal edildi.", - "resume-message": "<0>Oturumunuza devam etmek için tekrar giriş yapın.Otomatik olarak sürekli oturumdan çıkarılıyorsanız yöneticinizle iletişime geçin veya lisans sayfasını ziyaret ederek kotanızı kontrol edin.", + "auto-revoked": "", + "resume-message": "", "sign-in": "Giriş yap", "title-you-have-been-automatically-signed-out": "Otomatik olarak çıkış yaptınız" }, diff --git a/public/locales/zh-Hans/grafana.json b/public/locales/zh-Hans/grafana.json index b5f5f4a2e26..92102c0443d 100644 --- a/public/locales/zh-Hans/grafana.json +++ b/public/locales/zh-Hans/grafana.json @@ -108,7 +108,7 @@ "dismiss": "忽略", "heading": "企业验证", "learn-more-link": "了解更多", - "text": "使用 <1>SAML、<3>SCIM、<6>LDAP 和 <8>RBAC 自动管理用户、团队和权限,这些功能在 Grafana Cloud 和 Enterprise 中均可用。" + "text": "" }, "feature-listing": { "title-auditing": "审计", @@ -209,7 +209,7 @@ "title-delete": "删除" }, "orgs": { - "delete-body": "您确定要删除“{{deleteOrgName}}”吗?<3> <5>此组织的所有数据面板都将被移除!", + "delete-body": "", "id-header": "ID", "name-header": "名称", "new-org-button": "新组织" @@ -716,6 +716,7 @@ "title-annotations": "注释" }, "link-dashboard-and-panel": "关联数据面板和面板", + "placeholder-value-input": "", "placeholder-value-input-default": "输入自定义注释内容..." }, "bulk-actions": { @@ -1139,7 +1140,7 @@ "title-something-wrong-trying-fetch-group-details": "尝试获取组详情时出错" }, "evaluation-interval-limit-exceeded": { - "body-minimum-interval": "在 Grafana 中配置了 <1>{{minInterval}} 的最小评估间隔。<3>请联系管理员以配置更低的间隔。", + "body-minimum-interval": "", "title-global-evaluation-interval-limit-exceeded": "超出了全局评估间隔限制" }, "existing-rule-editor": { @@ -1287,7 +1288,7 @@ "resolved": "已解决" } }, - "review-alert-payload": "查看要添加到负载的警报数据:", + "review-alert-payload": "", "title-add-custom-alerts": "添加自定义警报" }, "get-alert-suggestions": { @@ -1411,7 +1412,7 @@ "title-add-folder-and-labels": "添加文件夹和标签" }, "grafana-managed-rule-type": { - "description": "支持任何类型的多个数据源。<1>使用表达式转换数据。" + "description": "" }, "grafana-modify-export": { "body-invalid-rule-id": "页面 URL 中的规则 UID 无效。请检查 URL,然后重试。", @@ -1847,7 +1848,7 @@ "aria-label-new": "新建" }, "mimir-flavored-type": { - "description": "使用 Mimir、Loki 或 Cortex 数据源。<1>不支持表达式。" + "description": "" }, "min-interval-option": { "label-interval": "间隔", @@ -2076,7 +2077,7 @@ "warning-1": "删除此通知策略将永久移除它。", "warning-2": "您确定要删除此策略吗?" }, - "filter-description": "使用半角逗号分隔的匹配器列表来筛选通知策略,例如:<1>severity=critical, region=EMEA", + "filter-description": "", "generated-policies": "自动生成的策略", "matchers": "匹配器", "metadata": { @@ -2119,7 +2120,8 @@ "conflict": "通知策略树已由其他用户更新。", "error-code": "错误消息:“{{error}}”", "routes": { - "conflictingMatchers": "无法添加或更新路由:如果我们合并匹配器 {{-matchers}},匹配器将与外部路由树冲突。这将导致路由无法访问。" + "conflictingMatchers": "无法添加或更新路由:如果我们合并匹配器 {{-matchers}},匹配器将与外部路由树冲突。这将导致路由无法访问。", + "unknownMatchers": "" }, "suffix": "请刷新页面并重试。", "title": "添加或更新通知策略失败" @@ -2236,7 +2238,7 @@ "error-no-query-editor": "由于以下原因,无法加载查询编辑器:{{errorMessage}}" }, "recording-rule-type": { - "description": "预计算表达式。<1>应与警报规则结合使用。" + "description": "" }, "recording-rules": { "description-target-data-source": "用于存储录制规则的 Prometheus 数据源", @@ -2249,7 +2251,7 @@ }, "redirect-to-clone-rule": { "body-evaluation-group": "您需要为复制的规则设置一个新的评估组,因为原始规则已预配,无法用于在用户界面中创建的规则。", - "body-not-provisioned": "新规则将<1>不会被标记为预配规则。", + "body-not-provisioned": "", "confirmText-copy": "复制", "title-copy-provisioned-alert-rule": "复制已预置的警报规则" }, @@ -2284,13 +2286,13 @@ "routing-settings": { "aria-label-group-by": "分组依据", "description-group-by": "通过相同的标签值将多个警报分组,从而将它们合并成单个通知。如果为空,则继承自默认通知策略。", - "group-interval": "组间隔:<1>{{groupIntervalValue}}", - "group-wait": "组等待:<1>{{groupWaitValue}}", - "grouping": "分组:<1>{{fields}}", + "group-interval": "", + "group-wait": "", + "grouping": "", "label-group-by": "分组依据", "label-override-grouping": "覆盖分组", "label-override-timings": "覆盖时间设定", - "repeat-interval": "重复间隔:<1>{{repeatIntervalValue}}" + "repeat-interval": "" }, "rule-actions-buttons": { "title-edit": "编辑", @@ -2542,7 +2544,7 @@ "relative-with-to": "" }, "rule-type-picker": { - "grafana-managed": "选择“Grafana 托管”,除非您有启用了 Ruler API 的 Mimir、Loki 或 Cortex 数据源。" + "grafana-managed": "" }, "rule-view": { "query": { @@ -2875,7 +2877,7 @@ "test-contact-point-modal": { "custom-notification-message": "您将发送一条测试通知,该通知使用以下定义的注释。如果您使用自定义模板和消息,这是一个很好的选择。", "notification-message": "通知消息", - "predefined-notification-message": "您将发送一条测试通知,该通知使用预定义警报。如果您已定义自定义模板或消息,为了获得更好的结果,请从上方切换到<1>自定义通知消息。", + "predefined-notification-message": "", "send-test-notification": "发送测试通知", "title-test-contact-point": "测试联络点" }, @@ -2884,7 +2886,7 @@ }, "threshold-expression-viewer": { "input": "输入", - "stop-alerting-when": "当出现以下情况时停止提醒(或待处理状态):" + "stop-alerting-when": "" }, "time-interval": { "add-time-interval": "添加时间间隔", @@ -3072,7 +3074,7 @@ "title-notification-policies": "通知策略" }, "yaml-content-info": { - "body": "编辑器中的 YAML 内容仅包含警报规则配置<1>要配置 Prometheus,您需要提供 <4>配置文件内容的其余部分。" + "body": "" } }, "alertlist": { @@ -3148,7 +3150,7 @@ "no-annotations-found": "未找到注释" }, "annotation-list-item": { - "tooltip-created-by": "创建人:<1>{{email}}" + "tooltip-created-by": "" }, "category-annotation-query": "注释查询", "category-display": "显示", @@ -3186,7 +3188,7 @@ }, "empty-state": { "button-title": "添加注释查询", - "info-box-content": "<0>注释提供了一种将事件数据集成到图表中的方法。它们在所有图表面板上均以垂直线和图标的形式呈现。当您将光标悬停在注释图标上时,可以获取事件文本和事件的标记。您可以直接从 Grafana 添加注释事件,方法是按住 CTRL 或 CMD 键并点击图表(或拖动区域)。这些将存储在 Grafana 的注释数据库中。", + "info-box-content": "", "info-box-content-2": "查看<2>注释文档以获取更多信息。", "title": "尚未添加自定义注释查询" }, @@ -3224,7 +3226,7 @@ "auth-settings": "身份验证设置" }, "auth-drawer-unconneced": { - "subtitle": "配置身份验证设置。不妨在我们的<2>文档中了解更多信息。" + "subtitle": "" }, "auth-drawer-unconnected": { "advanced-auth": "高级身份验证", @@ -3258,7 +3260,7 @@ "allowed-organizations-description": "以逗号或空格分隔的组织列表。用户应至少是一个\n组织的成员才能登录。", "allowed-organizations-label": "允许的组织", "allowed-organizations-placeholder": "输入组织(my-team、myteam...)并按 Enter 键添加", - "api-url-description": "OAuth2 提供商的用户信息端点。此端点返回的信息必须与 <2>OpenID UserInfo 兼容。", + "api-url-description": "", "api-url-required": "如果设置,此字段必须是有效的网址。", "auth-style-description": "它决定了如何将“{{ clientIDLabel }}”和“{{ clientSecretLabel }}”发送到 Oauth2 提供程序。默认值为 AutoDetect。", "auth-style-label": "身份验证样式", @@ -3403,7 +3405,7 @@ } }, "auth-config-auth-config-page-unconnected": { - "subtitle": "管理身份验证设置并配置单点登录。不妨在我们的<2>文档中了解更多信息。" + "subtitle": "" }, "bar-chart": { "warn": { @@ -4113,7 +4115,7 @@ }, "scopes": { "apply-selected-scopes": "应用", - "selected-scopes-label": "范围:" + "selected-scopes-label": "" }, "search-box": { "placeholder": "搜索或跳转至..." @@ -4255,7 +4257,7 @@ "okay": "好的" }, "not-found-datasource": { - "body": "也许您输入了错误的 URL,或者 ID 为 <1> 的插件不可用。<3>要查看可用数据源的列表,请<5>点击此处。" + "body": "" }, "oss": { "connections-home-page": { @@ -4298,8 +4300,8 @@ "versionHistory": { "comparison": { "header": { - "hide-json-diff": "隐藏 JSON 差异", - "show-json-diff": "显示 JSON 差异", + "hide-json-diff": "", + "show-json-diff": "", "text": "版本 {{version}} 更新者 {{createdBy}} ({{ageString}}) {{message}}" }, "select": "选择两个版本以开始比较" @@ -4326,7 +4328,7 @@ "label-label": "标签", "label-placeholder": "例如:Tempo traces", "label-required": "此字段是必填字段。", - "sub-text": "<0>定义将会描述关联的文本。", + "sub-text": "", "title": "定义关联标签(第 1 步,共 3 步)" }, "configure-correlation-target-form": { @@ -4370,7 +4372,7 @@ }, "source-form": { "control-required": "此字段是必填字段。", - "description": "数据点需要将值作为字段或作为转换后的输出来提供给所有变量,以便在可视化中显示相关性按钮。<1>注:并非每个变量都需要在下方明确定义。<4>logfmt 等转换将为每个键/值对创建变量。", + "description": "", "description-external-pre": "您已在目标 URL 中使用以下变量:", "description-query-pre": "您已在目标查询中使用以下变量:", "external-title": "对将会使用 URL 的数据源进行配置(第 3 步,共 3 步)", @@ -4382,12 +4384,12 @@ "results-required": "此字段是必填字段。", "source-description": "所选源数据源得到的结果有在面板中显示的链接", "source-label": "源", - "sub-text": "<0>定义哪些数据源将显示关联,以及哪些数据将取代先前定义的变量。" + "sub-text": "" }, "sub-title": "定义不同数据源中的数据如何相互关联。请在<2>文档中阅读更多信息", "target-form": { "control-rules": "此字段是必填字段。", - "sub-text": "<0>定义相关性将链接到什么内容。使用查询类型时,点击相关性将运行查询。使用外部类型时,点击相关性将打开一个 URL。", + "sub-text": "", "target-description-external": "指定点击链接时将打开的 URL", "target-description-query": "指定点击链接时查询哪个数据源", "target-label": "目标", @@ -4594,7 +4596,7 @@ } }, "confirm-plugin-dashboard-save-modal": { - "body-plugin-dashboard": "更新插件时,您的更改将丢失。<1><1/>使用<1>另存为创建自定义版本。。", + "body-plugin-dashboard": "", "cancel": "取消", "overwrite": "覆盖", "title-plugin-dashboard": "插件数据面板" @@ -4811,7 +4813,7 @@ "add-visualization-body": "选择一个数据源,然后用图表、统计信息和表格查询您的数据以及将其可视化,或创建列表、Markdown 和其他小部件。", "add-visualization-button": "添加可视化", "add-visualization-header": "通过添加可视化开始您的新仪表板", - "import-a-dashboard-body": "从文件或 <2>grafana.com 导入数据面板。", + "import-a-dashboard-body": "", "import-a-dashboard-header": "导入仪表板", "import-dashboard-button": "导入仪表板", "show-less-dashboards": "", @@ -5268,8 +5270,8 @@ "title-provisioned": "已预置的数据面板" }, "save-dashboard-error-proxy": { - "body-name-exists": "所选文件夹中已存在具有相同名称的数据面板。<1><2>您仍然要保存此数据面板吗?。", - "body-version-mismatch": "其他人已更新此数据面板<1><2>您仍然要保存此数据面板吗?。", + "body-name-exists": "", + "body-version-mismatch": "", "confirmText-save-and-overwrite": "保存并覆盖", "title-name-exists": "冲突", "title-version-mismatch": "冲突" @@ -5287,7 +5289,7 @@ "cancel": "取消", "cannot-be-saved": "此数据面板无法从 Grafana 用户界面保存,因为它已从其他来源预配。复制 JSON 或将其保存到下面的文件中,然后您可以在预配源中更新您的数据面板。", "copy-json-to-clipboard": "将 JSON 复制到剪贴板", - "file-path": "<0>文件路径:{{filePath}}", + "file-path": "", "save-json-to-file": "将 JSON 保存到文件", "see-docs": "有关预配的更多信息,请参阅<2>文档<2/>。" }, @@ -5486,7 +5488,7 @@ "transformation-picker": { "info": "通过转换,您可以在查询结果可视化之前对其进行合并、计算、重新排序、隐藏和重命名。", "info-graph-not-suitable": "如果使用图形可视化,很多转换都不适合,因为它目前只支持时间序列数据。", - "info-switch-to-table": "它可以帮助切换到表格可视化,以了解转换的作用。", + "info-switch-to-table": "", "placeholder-search-for-transformation": "搜索转换", "read-more": "阅读更多", "title-transformations": "转换" @@ -5552,8 +5554,8 @@ "version-history-comparison": { "button-restore": "恢复到版本 {{version}}", "label-view-json-diff": "查看 JSON 差异", - "new-updated-by": "<0>版本 {{version}} 由{{editor}}更新于 {{timeAgo}}", - "old-updated-by": "<0>版本 {{version}} 由{{editor}}更新于 {{timeAgo}}" + "new-updated-by": "", + "old-updated-by": "" }, "version-history-table": { "aria-label-toggle-selection": "切换版本 {{version}} 的选择", @@ -5953,7 +5955,7 @@ "cancel": "取消" }, "render-save-button-and-error": { - "body-plugin-dashboard": "更新插件时,您的更改将丢失。使用<1>另存为创建自定义版本。", + "body-plugin-dashboard": "", "title-failed-to-save-dashboard": "保存数据面板失败", "title-plugin-dashboard": "插件数据面板", "title-someone-else-has-updated-this-dashboard": "其他人已更新此数据面板", @@ -5962,7 +5964,7 @@ "save-and-overwrite": "‘保存并覆盖’" }, "library-viz-panel-info": { - "last-edited": "{{timeAgo}}由 ", + "last-edited": "", "usage-count_other": "用于 {{count}} 个数据面板" }, "managed-badge": { @@ -6022,7 +6024,7 @@ }, "panel-data-queries-tab-rendered": { "add-query": "添加查询", - "expression": "表达式" + "expression": "" }, "panel-data-transformations-tab": { "tab-label": "转换" @@ -6080,7 +6082,7 @@ "query": "查询" }, "query-variable-editor-form": { - "description-examples": "命名捕获组可用于分隔显示文本和值(<1>参见示例)。", + "description-examples": "", "description-optional": "可选,如果您想要提取序列名称或指标节点段的一部分。", "label-data-source": "数据源", "label-static-options-sort": "静态选项排序", @@ -6141,7 +6143,7 @@ "label-message": "消息", "placeholder-describe-changes-optional": "添加备注以描述您的更改(可选)。", "render-footer": { - "body-plugin-dashboard": "更新插件时,您的更改将丢失。使用<1>另存为创建自定义版本。", + "body-plugin-dashboard": "", "no-changes-to-save": "没有要保存的更改", "title-failed-to-save-dashboard": "保存数据面板失败", "title-plugin-dashboard": "插件数据面板", @@ -6176,7 +6178,7 @@ "cancel": "取消", "cannot-be-saved": "此数据面板无法从 Grafana 用户界面保存,因为它已从其他来源预配。复制 JSON 或将其保存到下面的文件中,然后您可以在预配源中更新您的数据面板。", "copy-json-to-clipboard": "将 JSON 复制到剪贴板", - "file-path": "<0>文件路径:{{filePath}}", + "file-path": "", "label-description": "描述", "label-target-folder": "目标文件夹", "label-title": "标题", @@ -6345,8 +6347,8 @@ }, "version-history-comparison": { "label-view-json-diff": "查看 JSON 差异", - "new-version-updated": "<0>版本 {{version}} 由{{editor}}更新于 {{timeAgo}}", - "old-version-updated": "<0>版本 {{version}} 由{{editor}}更新于 {{timeAgo}}" + "new-version-updated": "", + "old-version-updated": "" }, "version-history-header": { "compare-versions": "比较 {{baseVersion}} <3> {{newVersion}}", @@ -6424,7 +6426,7 @@ "provisioned-delete-modal": { "confirm-button": "好", "text-1": "此数据面板由 Grafana 配置管理,无法删除。从配置文件中移除数据面板以将其删除。", - "text-2": "有关配置的更多信息,请参阅 Grafana 文档。", + "text-2": "", "text-3": "文件路径:{{provisionedId}}", "text-link": "前往文档页面", "title": "无法删除已配置的数据面板" @@ -6502,7 +6504,7 @@ }, "data-source-testing-status-page": { "error-more-details-link": "点击<2>此处了解有关此错误的更多信息。", - "success-more-details-links": "接下来,您可以通过<2>构建数据面板或在<5>Explore 视图中查询数据来开始可视化数据。" + "success-more-details-links": "" }, "data-sources": { "datasource-add-button": { @@ -6598,7 +6600,7 @@ "test": "测试" }, "cloud-info-box": { - "body-alert": "您也可以省去这些步骤,通过<6>永久免费的 Grafana Cloud 计划,从 Grafana Labs 获取完全托管、可扩展和托管式数据源 {{mainDS}}(和 {{extraDS}})。", + "body-alert": "", "title-alert": "在下方配置您的 {{mainDS}} 数据源" }, "dashboards-table": { @@ -6726,18 +6728,18 @@ "no-events-yet": "尚无事件" }, "render-info-viewer": { - "data-counter": "数据:{{numDataChanges}}", + "data-counter": "", "elapsed-time": "时间:{{elapsed}} 毫秒", "field": "字段", "last": "最后一个", - "render-counter": "渲染:{{numRenders}}", - "schema-counter": "架构:{{numSchemaChanges}}", + "render-counter": "", + "schema-counter": "", "title-reset-counters": "复位计数器", "tooltip-step-back": "后退", "type": "类型" }, "state-view": { - "current-value": "当前值:{{currentValue}}", + "current-value": "", "label-state-name": "状态名称" } }, @@ -7184,7 +7186,7 @@ }, "footer": { "learn-more": "了解更多", - "pro-tip-define-sources-through-configuration-files": "专业提示:您还可以通过配置文件定义数据源。" + "pro-tip-define-sources-through-configuration-files": "" } }, "pane": { @@ -7246,8 +7248,6 @@ "query-deleted": "查询已删除" }, "rich-history-queries-tab": { - "displaying-partial-queries": "显示 {{ count }} 条查询", - "displaying-queries": "{{ count }} 条查询", "filter-aria-label": "数据源筛选查询", "filter-history": "筛选历史记录", "filter-placeholder": "数据源筛选查询", @@ -7257,7 +7257,9 @@ "search-placeholder": "搜索查询", "showing-queries": "显示 {{ shown }}/{{ total }} <0>了解更多", "sort-aria-label": "排序查询", - "sort-placeholder": "查询排序方式:" + "sort-placeholder": "查询排序方式:", + "displaying-partial-queries_other": "", + "displaying-queries_other": "" }, "rich-history-settings-tab": { "alert-info": "Grafana 将最多保留 {{optionLabel}} 的条目。标有星标的条目不会被删除。", @@ -7579,8 +7581,8 @@ }, "math": { "available-math-functions": "可用的数学函数", - "run-math-operations": "对一个或多个查询运行数学运算。您可以通过 {{refExample}}(即 {{ref1}}、{{ref2}}、{{ref3}} 等)引用查询。<10>示例:<12>{{example}}", - "tooltip-footer": "请参阅我们关于<2>数学表达式的其他文档。", + "run-math-operations": "", + "tooltip-footer": "", "tooltip-title": "数学运算符", "tooltip-trigger": "表达式" }, @@ -8609,7 +8611,7 @@ }, "data-source-http-settings": { "access-help": "帮助<1>", - "access-help-details": "访问模式控制如何处理对数据源的请求。如果没有其他说明,<1><1>服务器应该是首选方式。", + "access-help-details": "", "access-help-title": "访问帮助", "access-label": "访问", "allowed-cookies": "允许的 Cookie", @@ -8877,7 +8879,7 @@ "cell-inspect": "检查值", "cell-inspect-tooltip": "检查值", "copy": "复制到剪贴板", - "csv-counts": "行:{{rows}},列:{{columns}} <5>", + "csv-counts": "", "csv-placeholder": "在此处输入 CSV...", "filter-placeholder": "筛选值", "filter-popup-apply": "好", @@ -9162,7 +9164,6 @@ "name-line-width": "线宽度", "name-stacking": "堆叠" }, - "inline-token-warning-badge-tooltip": "", "inspector": { "inspect-data-tab": { "loading": "正在加载", @@ -9324,7 +9325,7 @@ "error-fetching": "获取 LDAP 设置时出错", "error-saving": "保存 LDAP 设置时出错", "error-validate-form": "验证 LDAP 设置时出错", - "feature-flag-disabled": "此页面仅可通过启用 <1>ssoSettingsLDAP 功能标志来访问。", + "feature-flag-disabled": "", "saved": "LDAP 设置已保存" }, "bind-dn": { @@ -9365,7 +9366,7 @@ "label": "搜索基本专有名称", "placeholder": "示例:dc=grafana,dc=org" }, - "subtitle": "Grafana 中的 LDAP 集成允许您的 Grafana 用户使用其 LDAP 凭据登录。不妨在我们的<2><0>文档中了解更多信息。", + "subtitle": "", "title": "基本设置" }, "library-panel": { @@ -9409,7 +9410,7 @@ "dashboard-name": "数据面板名称" }, "library-panel-info": { - "last-edited": "上次编辑时间:{{timeAgo}},编辑者:", + "last-edited": "", "usage-count_other": "用于 {{count}} 个数据面板" }, "library-panels-search": { @@ -9708,7 +9709,7 @@ "tooltip-unpin-line": "取消固定行" }, "log-row-message": { - "ellipsis": "… ", + "ellipsis": "", "more": "更多", "see-details": "查看日志详细信息", "tooltip-error": "错误:{{errorMessage}}" @@ -10104,7 +10105,7 @@ }, "resource-table": { "dashboard-load-error": "无法加载数据面板", - "error-library-element-sub": "库元素 {uid}", + "error-library-element-sub": "", "error-library-element-title": "无法加载库元素", "unknown-datasource-title": "数据源 {{datasourceUID}}", "unknown-datasource-type": "未知数据源" @@ -10749,10 +10750,10 @@ "placeholder-optional": "(可选)", "role": "角色", "submit": "提交", - "tooltip": "您现在可以选择“无基本角色”选项,并根据自定义需求添加权限。您可以在<1>我们的文档中找到更多信息。" + "tooltip": "" }, "user-invite-page": { - "sub-title": "发送邀请或将现有 Grafana 用户添加到组织。<1>{{orgName}}", + "sub-title": "", "text": { "invite-user": "邀请用户" } @@ -10841,7 +10842,7 @@ "switch-to-table": "切换至表格" }, "panel-plugin-error": { - "text-load-error": "请检查服务器启动日志以获取更多信息。<1>如果此插件是从 Git 加载的,请确保它已编译。", + "text-load-error": "", "title-load-error": "加载时出错:{{panelId}}", "title-not-found": "找不到面板插件:{{id}}" }, @@ -11035,7 +11036,7 @@ }, "details": { "connections-tab": { - "description": "您当前为 {{pluginName}} 配置了以下数据源,点击磁贴可查看配置详细信息。您可以在 <4><0>连接 - <3>数据源中找到所有数据源连接。" + "description": "" }, "disabled-error": { "angular-deprecation-link": "了解更多关于 Angular 弃用的信息", @@ -11052,7 +11053,7 @@ }, "labels": { "contactGrafanaLabs": "联系 Grafana Labs", - "customLinks": "自定义链接", + "customLinks": "", "customLinksTooltip": "这些链接由插件开发者提供,为大家提供额外的开发者专属资源和信息", "dependencies": "依赖关系", "documentation": "文档", @@ -11063,7 +11064,7 @@ "latestVersion": "最新版本", "license": "许可", "raiseAnIssue": "报告问题", - "reportAbuse": "报告疑虑", + "reportAbuse": "", "reportAbuseTooltip": "直接向 Grafana Labs 报告与恶意或有害插件相关的问题。", "repository": "存储库", "signature": "签名", @@ -11073,8 +11074,8 @@ "modal": { "cancel": "取消", "copyEmail": "复制电子邮件地址", - "description": "此功能用于报告插件中的恶意或有害行为。有关插件问题,请联系我们,电子邮件地址为:", - "node": "注:对于一般的插件问题(如 bug 或功能请求),请使用提供的链接联系插件作者。", + "description": "", + "node": "", "title": "报告插件问题" } }, @@ -11142,7 +11143,7 @@ "message": "所有插件都是最新的" }, "not-found-plugin": { - "body-plugin-not-found": "找不到该插件。请检查 URL 是否正确,或<1>转到<3>插件目录。", + "body-plugin-not-found": "", "title-plugin-not-found": "未找到插件" }, "plugin-actions": { @@ -11600,7 +11601,6 @@ "unsupported-repository-type": "" }, "inline-secure-values-warning": "", - "inline-token-warning-badge-text": "", "job-status": { "label-view-details": "查看详情", "loading-finished-job": "正在加载已完成的作业...", @@ -11777,6 +11777,17 @@ "label-current-step": "当前步骤", "label-pending-step": "待处理步骤" }, + "status-badge": { + "automatic-pulling-disabled": "", + "deleting": "", + "error": "", + "pending": "", + "pulling": "", + "unknown": "", + "up-to-date": "", + "waiting-for-health-check": "", + "warning": "" + }, "success-title-default": "成功", "sync-job": { "error-no-job-id": "启动作业失败", @@ -11954,7 +11965,7 @@ "annotations-show-text": "注释 = 显示", "time-range-picker-disabled-text": "时间范围选择器 = 已禁用", "time-range-picker-enabled-text": "时间范围选择器 = 已启用", - "time-range-text": "时间范围 = " + "time-range-text": "" }, "share": { "success-delete": "您的数据面板不再可共享" @@ -11993,7 +12004,7 @@ "revoke-user-access-modal-desc-line1": "您确定要注销对 {{email}} 的访问权限吗?" }, "delete-user-shared-dashboards-modal": { - "revoke-user-access-modal-desc-line2": "此操作将立即撤销 {{email}} 对所有共享数据面板的访问权限。" + "revoke-user-access-modal-desc-line2": "" }, "modal": { "shared-dashboard-modal-title": "共享的数据面板" @@ -12159,7 +12170,7 @@ }, "menu": { "clear-button": "全部清除", - "tooltip": "您现在可以选择“无基本角色”选项,并根据自定义需求添加权限。您可以在<1>我们的文档中找到更多信息。" + "tooltip": "" }, "menu-aria-label": "角色选择器菜单", "menu-group-option-aria-label": "角色选择器选项", @@ -12169,7 +12180,7 @@ }, "sub-menu-aria-label": "角色选择器子菜单", "title": { - "description": "向用户分配角色,以确保对 Grafana 的功能和资源的访问进行细粒度控制。不妨在我们的<2>文档中了解更多信息。" + "description": "" } }, "role-picker-drawer": { @@ -12292,7 +12303,7 @@ }, "select": { "select-menu": { - "selected-count": "已选择" + "selected-count": "" } }, "service-account-create-page": { @@ -12391,6 +12402,7 @@ "aria-label-role": "角色" }, "service-account-tokens-table": { + "aria-label-delete-button": "", "created": "已创建", "expires": "过期", "last-used-at": "上次使用时间", @@ -12477,7 +12489,7 @@ "info-text": "创建指向此仪表板或面板的直接链接,通过以下选项自定义。", "link-url": "链接网址", "render-alert": "未安装图像渲染器插件", - "render-instructions": "要渲染图像,您必须安装 <2>Grafana 图像渲染器插件。请与您的 Grafana 管理员联系以安装插件。", + "render-instructions": "", "rendered-image": "直接链接至渲染后的图像", "save-alert": "仪表板未保存", "save-dashboard": "要渲染面板图像,需要先保存仪表板。", @@ -12501,7 +12513,7 @@ "info-text-1": "可通过快照即时、公开地分享交互式仪表板。创建后,我们会剥离敏感数据,如查询(指标、模板和注释)和面板链接,仅将可见指标数据和系列名称嵌入到仪表板中。", "info-text-2": "请注意,知晓该链接并能够访问该网址的<1>任何人都可以查看您的快照。分享需谨慎。", "local-button": "发布快照", - "mistake-message": "是不是弄错了什么?", + "mistake-message": "", "name": "快照名称", "timeout": "超时(秒)", "timeout-description": "如果需要很长时间才能收集仪表板指标,则可能需要配置超时值。", @@ -13112,7 +13124,7 @@ "forwards-time-aria-label": "向前移动时间范围", "to": "至", "zoom-out-button": "缩放时间范围", - "zoom-out-tooltip": "时间范围缩放 <1> CTRL+Z" + "zoom-out-tooltip": "" }, "time-range": { "apply": "应用时间范围", @@ -13237,7 +13249,7 @@ }, "transformations": { "empty": { - "add-transformation-body": "转换允许在显示可视化之前以各种方式更改数据。 <1>这包括合并数据、重命名字段、进行计算、格式化数据以便显示等等。", + "add-transformation-body": "", "add-transformation-header": "开始转换数据" } }, @@ -13504,7 +13516,7 @@ "label-format": "格式", "label-set-timezone": "设置时区", "label-time-field": "时间字段", - "tooltip-format": "指定为 <2>Moment.js 格式字符串的字段的输出格式。", + "tooltip-format": "", "tooltip-timezone-manually": "手动设置日期的时区" }, "format-time-transformer-editor": { @@ -14099,8 +14111,8 @@ "message": "找不到用户" }, "token-revoked-modal": { - "auto-revoked": "您的会话令牌已自动撤销,因为您已达到您的账户的<2>最大并发会话数 {{numSessions}}。", - "resume-message": "<0>要恢复会话,请重新登录。如果您多次自动退出登录,请与您的管理员联系或访问许可页面以查看您的配额。", + "auto-revoked": "", + "resume-message": "", "sign-in": "登录", "title-you-have-been-automatically-signed-out": "您已自动退出登录" }, diff --git a/public/locales/zh-Hant/grafana.json b/public/locales/zh-Hant/grafana.json index 37893071b08..c1d25184ba5 100644 --- a/public/locales/zh-Hant/grafana.json +++ b/public/locales/zh-Hant/grafana.json @@ -108,7 +108,7 @@ "dismiss": "關閉", "heading": "企業版驗證", "learn-more-link": "了解詳情", - "text": "使用 <1>SAML、<3>SCIM、<6>LDAP 和 <8>RBAC 自動管理使用者、團隊和權限 - 在 Grafana Cloud 和 Enterprise 中可以使用。" + "text": "" }, "feature-listing": { "title-auditing": "稽核", @@ -209,7 +209,7 @@ "title-delete": "刪除" }, "orgs": { - "delete-body": "您確定要刪除「{{deleteOrgName}}」嗎?<3> <5>將移除此組織的所有儀表板!", + "delete-body": "", "id-header": "ID", "name-header": "名稱", "new-org-button": "新組織" @@ -716,6 +716,7 @@ "title-annotations": "註釋" }, "link-dashboard-and-panel": "連結儀表板和面板", + "placeholder-value-input": "", "placeholder-value-input-default": "輸入自訂註解內容…" }, "bulk-actions": { @@ -1139,7 +1140,7 @@ "title-something-wrong-trying-fetch-group-details": "嘗試擷取群組詳細資料時發生錯誤" }, "evaluation-interval-limit-exceeded": { - "body-minimum-interval": "已在 Grafana 中設定 <1>{{minInterval}} 的最小評估間隔。<3>請聯絡管理員以設定較低的間隔。", + "body-minimum-interval": "", "title-global-evaluation-interval-limit-exceeded": "超出全域評估間隔限制" }, "existing-rule-editor": { @@ -1287,7 +1288,7 @@ "resolved": "已解決" } }, - "review-alert-payload": "檢閱要新增至負載的警報資料:", + "review-alert-payload": "", "title-add-custom-alerts": "新增自訂警報" }, "get-alert-suggestions": { @@ -1411,7 +1412,7 @@ "title-add-folder-and-labels": "新增資料夾和標籤" }, "grafana-managed-rule-type": { - "description": "支援多種資料來源。<1>使用表達式轉換資料。" + "description": "" }, "grafana-modify-export": { "body-invalid-rule-id": "頁面網址中的規則 UID 無效。請檢查網址,然後再試一次。", @@ -1847,7 +1848,7 @@ "aria-label-new": "新" }, "mimir-flavored-type": { - "description": "使用 Mimir、Loki 或 Cortex 資料來源。<1>不支援表達式。" + "description": "" }, "min-interval-option": { "label-interval": "間隔", @@ -2076,7 +2077,7 @@ "warning-1": "刪除此通知政策將永久移除該政策。", "warning-2": "您確定要刪除這個政策嗎?" }, - "filter-description": "使用以逗號分隔的比對條件清單來篩選通知政策,例如:<1>severity=critical, region=EMEA", + "filter-description": "", "generated-policies": "自動產生的政策", "matchers": "匹配條件", "metadata": { @@ -2119,7 +2120,8 @@ "conflict": "通知政策樹已由其他使用者更新。", "error-code": "錯誤訊息:「{{error}}」", "routes": { - "conflictingMatchers": "無法新增或更新路由:如果我們合併了比對器「{{-matchers}}」,比對器會與外部路由樹衝突。這將使路由無法到達。" + "conflictingMatchers": "無法新增或更新路由:如果我們合併了比對器「{{-matchers}}」,比對器會與外部路由樹衝突。這將使路由無法到達。", + "unknownMatchers": "" }, "suffix": "請重新整理此頁面並再試一次。", "title": "無法新增或更新通知政策" @@ -2236,7 +2238,7 @@ "error-no-query-editor": "由於以下原因,無法載入查詢編輯器:{{errorMessage}}" }, "recording-rule-type": { - "description": "預先計算表達式。<1>應與警報規則結合使用。" + "description": "" }, "recording-rules": { "description-target-data-source": "Prometheus 資料來源用於儲存紀錄規則", @@ -2249,7 +2251,7 @@ }, "redirect-to-clone-rule": { "body-evaluation-group": "您需要為複製的規則設定新的評估群組,因為原始群組已佈建,無法用於在使用者介面中建立的規則。", - "body-not-provisioned": "新規則將<1>不會標記為已佈建的規則。", + "body-not-provisioned": "", "confirmText-copy": "複製", "title-copy-provisioned-alert-rule": "複製已設定的警報規則" }, @@ -2284,13 +2286,13 @@ "routing-settings": { "aria-label-group-by": "分組依據", "description-group-by": "透過相同標籤值將多個警報合併為單個通知。如果為空,則會沿用預設通知政策。", - "group-interval": "群組間隔:<1>{{groupIntervalValue}}", - "group-wait": "群組等待:<1>{{groupWaitValue}}", - "grouping": "分組:<1>{{fields}}", + "group-interval": "", + "group-wait": "", + "grouping": "", "label-group-by": "分組依據", "label-override-grouping": "覆寫分組", "label-override-timings": "覆寫時間", - "repeat-interval": "重複間隔:<1>{{repeatIntervalValue}}" + "repeat-interval": "" }, "rule-actions-buttons": { "title-edit": "編輯", @@ -2542,7 +2544,7 @@ "relative-with-to": "" }, "rule-type-picker": { - "grafana-managed": "選擇「Grafana 管理」,除非有已啟用 Ruler API 的 Mimir、Loki 或 Cortex 資料來源。" + "grafana-managed": "" }, "rule-view": { "query": { @@ -2875,7 +2877,7 @@ "test-contact-point-modal": { "custom-notification-message": "您將傳送使用以下定義註解的測試通知。如果使用自訂範本和訊息,這是一個很好的選擇。", "notification-message": "通知訊息", - "predefined-notification-message": "您將傳送使用預定義警報的測試通知。若您已定義自訂範本或訊息,為了取得更好的結果,請從上方切換至<1>自訂通知訊息。", + "predefined-notification-message": "", "send-test-notification": "傳送測試通知", "title-test-contact-point": "測試聯絡點" }, @@ -2884,7 +2886,7 @@ }, "threshold-expression-viewer": { "input": "輸入", - "stop-alerting-when": "處於以下值時停止警報(或待處理狀態)" + "stop-alerting-when": "" }, "time-interval": { "add-time-interval": "新增時間間隔", @@ -3072,7 +3074,7 @@ "title-notification-policies": "通知政策" }, "yaml-content-info": { - "body": "編輯器中的 YAML 內容僅包含警報規則設定 <1>若要設定 Prometheus,則需要提供<4>設定檔內容的其餘部分。" + "body": "" } }, "alertlist": { @@ -3148,7 +3150,7 @@ "no-annotations-found": "找不到註解" }, "annotation-list-item": { - "tooltip-created-by": "建立者:<1>{{email}}" + "tooltip-created-by": "" }, "category-annotation-query": "註解查詢", "category-display": "顯示", @@ -3186,7 +3188,7 @@ }, "empty-state": { "button-title": "新增注釋查詢", - "info-box-content": "<0>注釋提供了一種將事件資料整合到圖表中的方法。它們在所有圖表面板上都可視化為垂直線和圖示。將滑鼠懸停在註解圖示上時,可查看事件的文字內容與標籤。您可以在 Grafana 中直接新增註解事件,只需按住 CTRL 或 CMD 並點擊圖表(或拖曳選取區域)。這些將會儲存在 Grafana 的註解資料庫中。", + "info-box-content": "", "info-box-content-2": "查看<2>註釋文件,了解更多資訊。", "title": "尚未新增自訂注釋查詢" }, @@ -3224,7 +3226,7 @@ "auth-settings": "驗證設定" }, "auth-drawer-unconneced": { - "subtitle": "設定驗證設定。請在我們的<2>文件中閱讀更多資訊。" + "subtitle": "" }, "auth-drawer-unconnected": { "advanced-auth": "進階驗證", @@ -3258,7 +3260,7 @@ "allowed-organizations-description": "以逗號或空格分隔的組織清單。使用者應至少是\n一個組織的成員才能登入。", "allowed-organizations-label": "允許的組織", "allowed-organizations-placeholder": "輸入組織 (my-team、myteam...),然後按 Enter 新增", - "api-url-description": "OAuth2 提供者的使用者資訊端點。此端點傳回的資訊必須與 <2>OpenID UserInfo 相容。", + "api-url-description": "", "api-url-required": "如果設定,則此欄位必須為有效的網址。", "auth-style-description": "此設定決定了如何將「{{ clientIDLabel }}」和「{{ clientSecretLabel }}」傳送給 Oauth2 提供者。預設為 AutoDetect。", "auth-style-label": "驗證樣式", @@ -3403,7 +3405,7 @@ } }, "auth-config-auth-config-page-unconnected": { - "subtitle": "管理您的驗證設定並設定單一登入。請在我們的<2>文件中閱讀更多資訊。" + "subtitle": "" }, "bar-chart": { "warn": { @@ -4113,7 +4115,7 @@ }, "scopes": { "apply-selected-scopes": "套用", - "selected-scopes-label": "範圍:" + "selected-scopes-label": "" }, "search-box": { "placeholder": "搜尋或跳至…" @@ -4255,7 +4257,7 @@ "okay": "確定" }, "not-found-datasource": { - "body": "也許您輸入了錯誤的網址,或者 ID 為 <1> 的外掛程式無法使用。<3>若要查看可用資料來源的清單,請<5>按此處。" + "body": "" }, "oss": { "connections-home-page": { @@ -4298,8 +4300,8 @@ "versionHistory": { "comparison": { "header": { - "hide-json-diff": "隱藏 JSON diff", - "show-json-diff": "顯示 JSON diff", + "hide-json-diff": "", + "show-json-diff": "", "text": "版本 {{version}} 的更新者是 {{createdBy}} ({{ageString}}) {{message}}" }, "select": "選擇兩個版本以開始比較" @@ -4326,7 +4328,7 @@ "label-label": "標籤", "label-placeholder": "例如:速度追蹤", "label-required": "此為必填欄位。", - "sub-text": "<0>定義將描述相關性的文字。", + "sub-text": "", "title": "定義相關性標籤(步驟 1/3)" }, "configure-correlation-target-form": { @@ -4370,7 +4372,7 @@ }, "source-form": { "control-required": "此為必填欄位。", - "description": "資料點需要以欄位或轉換輸出的方式提供所有變數的值,才能在可視化中顯示相關性按鈕。<1>注意:並非每個變數都需要在下方明確定義。<4>logfmt 等轉換將為每個鍵/值對建立變數。", + "description": "", "description-external-pre": "您已在目標網址中使用以下變數:", "description-query-pre": "您已在目標查詢中使用以下變數:", "external-title": "設定將使用網址的資料來源(步驟 3/3)", @@ -4382,12 +4384,12 @@ "results-required": "此為必填欄位。", "source-description": "來自所選資料來源的結果在面板中顯示連結", "source-label": "來源", - "sub-text": "<0>定義哪個資料來源將顯示相關性,以及哪些資料將取代先前定義的變數。" + "sub-text": "" }, "sub-title": "定義位於不同資料來源中的資料彼此之間的關係。請至<2>文件中閱讀更多資訊", "target-form": { "control-rules": "此為必填欄位。", - "sub-text": "<0>定義相關性將連結的目標。使用查詢類型,點選相關性時將執行查詢。使用外部類型時,點選相關性將開啟一個網址。", + "sub-text": "", "target-description-external": "指定點選連結時將開啟的網址", "target-description-query": "指定點選連結時要查詢的資料來源", "target-label": "目標", @@ -4594,7 +4596,7 @@ } }, "confirm-plugin-dashboard-save-modal": { - "body-plugin-dashboard": "更新外掛程式時,您的變更將會遺失。<1><2>使用<1>另存為建立自訂版本。", + "body-plugin-dashboard": "", "cancel": "取消", "overwrite": "覆寫", "title-plugin-dashboard": "外掛程式儀表板" @@ -4811,7 +4813,7 @@ "add-visualization-body": "選取資料來源,然後使用圖表、統計資料及表格查詢並將資料可視化,或建立清單、標記及其他小工具。", "add-visualization-button": "新增可視化", "add-visualization-header": "透過新增可視化來啟動您的新儀表板", - "import-a-dashboard-body": "從檔案或 <2>grafana.com 匯入儀表板。", + "import-a-dashboard-body": "", "import-a-dashboard-header": "匯入儀表板", "import-dashboard-button": "匯入儀表板", "show-less-dashboards": "", @@ -5268,8 +5270,8 @@ "title-provisioned": "已佈建儀表板" }, "save-dashboard-error-proxy": { - "body-name-exists": "所選資料夾中已存在名稱相同的儀表板。<1><2>仍要儲存此儀表板嗎?", - "body-version-mismatch": "其他人已更新此儀表板<1><2>仍要儲存此儀表板嗎?", + "body-name-exists": "", + "body-version-mismatch": "", "confirmText-save-and-overwrite": "儲存並覆寫", "title-name-exists": "衝突", "title-version-mismatch": "衝突" @@ -5287,7 +5289,7 @@ "cancel": "取消", "cannot-be-saved": "此儀表板無法從 Grafana UI 儲存,因為其已從其他來源設定。複製 JSON 或將其儲存到下方的檔案中,然後您可以在佈建來源中更新您的儀表板。", "copy-json-to-clipboard": "複製 JSON 到剪貼簿", - "file-path": "<0>檔案路徑:{{filePath}}", + "file-path": "", "save-json-to-file": "將 JSON 儲存至檔案", "see-docs": "有關佈建的更多資訊,請參閱<2>文件。" }, @@ -5486,7 +5488,7 @@ "transformation-picker": { "info": "在可視化之前,您可以使用轉換功能連接、計算、重新排序、隱藏和重新命名查詢結果。", "info-graph-not-suitable": "如果您使用的是「圖表」可視化,則許多轉換不適用,因為目前僅支援時間序列資料。", - "info-switch-to-table": "它可以協助切換到「表格」可視化,以了解轉換的作用。", + "info-switch-to-table": "", "placeholder-search-for-transformation": "搜尋轉換", "read-more": "了解更多", "title-transformations": "轉換" @@ -5552,8 +5554,8 @@ "version-history-comparison": { "button-restore": "還原至版本 {{version}}", "label-view-json-diff": "檢視 JSON diff", - "new-updated-by": "{{editor}}在 {{timeAgo}}前更新為<0>版本 {{version}}", - "old-updated-by": "{{editor}}在 {{timeAgo}}前更新為<0>版本 {{version}}" + "new-updated-by": "", + "old-updated-by": "" }, "version-history-table": { "aria-label-toggle-selection": "切換{{version}}版本選擇", @@ -5953,7 +5955,7 @@ "cancel": "取消" }, "render-save-button-and-error": { - "body-plugin-dashboard": "更新外掛程式時,您的變更將會遺失。使用<1>另存為建立自訂版本。", + "body-plugin-dashboard": "", "title-failed-to-save-dashboard": "無法儲存儀表板", "title-plugin-dashboard": "外掛程式儀表板", "title-someone-else-has-updated-this-dashboard": "其他人已更新此儀表板", @@ -5962,7 +5964,7 @@ "save-and-overwrite": "「儲存並覆寫」" }, "library-viz-panel-info": { - "last-edited": "在 {{timeAgo}}前", + "last-edited": "", "usage-count_other": "用於 {{count}} 個儀表板" }, "managed-badge": { @@ -6022,7 +6024,7 @@ }, "panel-data-queries-tab-rendered": { "add-query": "新增查詢", - "expression": "表達式" + "expression": "" }, "panel-data-transformations-tab": { "tab-label": "轉換" @@ -6080,7 +6082,7 @@ "query": "查詢" }, "query-variable-editor-form": { - "description-examples": "已命名的擷取群組可用於分隔顯示文字與數值(<1>請參閱範例)。", + "description-examples": "", "description-optional": "若想擷取系列名稱或指標節點區段的一部分,則為可選。", "label-data-source": "資料來源", "label-static-options-sort": "靜態選項排序", @@ -6141,7 +6143,7 @@ "label-message": "訊息", "placeholder-describe-changes-optional": "新增備註以描述您的變更(選填)。", "render-footer": { - "body-plugin-dashboard": "更新外掛程式時,您的變更將會遺失。使用<1>另存為建立自訂版本。", + "body-plugin-dashboard": "", "no-changes-to-save": "沒有要儲存的變更", "title-failed-to-save-dashboard": "無法儲存儀表板", "title-plugin-dashboard": "外掛程式儀表板", @@ -6176,7 +6178,7 @@ "cancel": "取消", "cannot-be-saved": "此儀表板無法從 Grafana UI 儲存,因為其已從其他來源設定。複製 JSON 或將其儲存到下方的檔案中,然後您可以在佈建來源中更新您的儀表板。", "copy-json-to-clipboard": "複製 JSON 到剪貼簿", - "file-path": "<0>檔案路徑:{{filePath}}", + "file-path": "", "label-description": "說明", "label-target-folder": "目標資料夾", "label-title": "標題", @@ -6345,8 +6347,8 @@ }, "version-history-comparison": { "label-view-json-diff": "檢視 JSON diff", - "new-version-updated": "{{editor}}在 {{timeAgo}}前更新為<0>版本 {{version}}", - "old-version-updated": "{{editor}}在 {{timeAgo}}前更新為<0>版本 {{version}}" + "new-version-updated": "", + "old-version-updated": "" }, "version-history-header": { "compare-versions": "比較 {{baseVersion}} <3> {{newVersion}}", @@ -6424,7 +6426,7 @@ "provisioned-delete-modal": { "confirm-button": "確定", "text-1": "此儀表板由 Grafana 佈建管理,無法刪除。從設定檔中移除儀表板以將其刪除。", - "text-2": "有關佈建的更多資訊,請參閱 Grafana 文件。", + "text-2": "", "text-3": "檔案路徑:{{provisionedId}}", "text-link": "前往文件頁面", "title": "無法刪除已設定的儀表板" @@ -6502,7 +6504,7 @@ }, "data-source-testing-status-page": { "error-more-details-link": "點選<2>此處,了解更多關於此錯誤的資訊。", - "success-more-details-links": "接下來,您可以透過<2>建立儀表板或在<5>瀏覽檢視中查詢資料,開始將資料視覺化。" + "success-more-details-links": "" }, "data-sources": { "datasource-add-button": { @@ -6598,7 +6600,7 @@ "test": "測試" }, "cloud-info-box": { - "body-alert": "或者,跳過這個步驟,並透過<6>永久免費的 Grafana Cloud 方案,從 Grafana Labs 取得完全受控、可擴展及託管的資料來源 {{mainDS}}(和 {{extraDS}})。", + "body-alert": "", "title-alert": "在下方設定您的 {{mainDS}} 資料來源" }, "dashboards-table": { @@ -6726,18 +6728,18 @@ "no-events-yet": "暫無事件" }, "render-info-viewer": { - "data-counter": "資料:{{numDataChanges}}", + "data-counter": "", "elapsed-time": "時間:{{elapsed}} 毫秒", "field": "欄位", "last": "最後", - "render-counter": "算繪:{{numRenders}}", - "schema-counter": "架構:{{numSchemaChanges}}", + "render-counter": "", + "schema-counter": "", "title-reset-counters": "重置計數器", "tooltip-step-back": "回到上一步", "type": "類型" }, "state-view": { - "current-value": "目前數值:{{currentValue}}", + "current-value": "", "label-state-name": "狀態名稱" } }, @@ -7184,7 +7186,7 @@ }, "footer": { "learn-more": "了解詳情", - "pro-tip-define-sources-through-configuration-files": "專家提示:您也可以透過設定檔案來定義資料來源。" + "pro-tip-define-sources-through-configuration-files": "" } }, "pane": { @@ -7246,8 +7248,6 @@ "query-deleted": "查詢已刪除" }, "rich-history-queries-tab": { - "displaying-partial-queries": "顯示 {{ count }} 個查詢", - "displaying-queries": "{{ count }} 個查詢", "filter-aria-label": "篩選資料來源的查詢", "filter-history": "篩選歷史記錄", "filter-placeholder": "篩選資料來源的查詢", @@ -7257,7 +7257,9 @@ "search-placeholder": "搜尋查詢", "showing-queries": "顯示 {{ shown }} 個,總計 {{ total }} 個 <0>載入更多", "sort-aria-label": "排序查詢", - "sort-placeholder": "查詢排序方式" + "sort-placeholder": "查詢排序方式", + "displaying-partial-queries_other": "", + "displaying-queries_other": "" }, "rich-history-settings-tab": { "alert-info": "Grafana 最多會保留 {{optionLabel}} 個條目。已加星號的條目不會被刪除。", @@ -7449,7 +7451,7 @@ "copy-shortened-link-menu": "開啟複製連結選項", "refresh-picker-cancel": "取消", "refresh-picker-run": "執行查詢", - "split-close": "關閉", + "split-close": "", "split-close-tooltip": "關閉分割窗格", "split-narrow": "縮小窗格", "split-title": "分割", @@ -7579,8 +7581,8 @@ }, "math": { "available-math-functions": "可用的數學函數", - "run-math-operations": "對一或多個查詢項目執行數學運算。您可以透過 {{refExample}}(即 {{ref1}}、{{ref2}}、{{ref3}}等)參照查詢項目。<10>範例:<12>{{example}}", - "tooltip-footer": "請參閱我們關於<2>數學表達式的其他文件。", + "run-math-operations": "", + "tooltip-footer": "", "tooltip-title": "數學運算子", "tooltip-trigger": "表達式" }, @@ -8609,7 +8611,7 @@ }, "data-source-http-settings": { "access-help": "說明 <1>", - "access-help-details": "存取模式控制如何處理對資料來源的要求。如果沒有其他說明,<1> <1>伺服器應為首選方式。", + "access-help-details": "", "access-help-title": "存取說明", "access-label": "存取", "allowed-cookies": "允許的 Cookie", @@ -8877,7 +8879,7 @@ "cell-inspect": "檢查值", "cell-inspect-tooltip": "檢查值", "copy": "複製到剪貼簿", - "csv-counts": "列:{{rows}},欄:{{columns}} <5>", + "csv-counts": "", "csv-placeholder": "在此處輸入 CSV …", "filter-placeholder": "篩選值", "filter-popup-apply": "好的", @@ -9162,7 +9164,6 @@ "name-line-width": "線寬", "name-stacking": "堆疊" }, - "inline-token-warning-badge-tooltip": "", "inspector": { "inspect-data-tab": { "loading": "正在載入", @@ -9324,7 +9325,7 @@ "error-fetching": "擷取 LDAP 設定時發生錯誤", "error-saving": "儲存 LDAP 設定時發生錯誤", "error-validate-form": "驗證 LDAP 設定時發生錯誤", - "feature-flag-disabled": "此頁面僅可透過啟用 <1>ssoSettingsLDAP 功能標記存取。", + "feature-flag-disabled": "", "saved": "LDAP 設定已儲存" }, "bind-dn": { @@ -9365,7 +9366,7 @@ "label": "搜尋基礎 DNS", "placeholder": "範例:dc=grafana,dc=org" }, - "subtitle": "Grafana 中的 LDAP 整合允許您的 Grafana 使用者使用其 LDAP 憑證登入。請至我們的<2><0>文件中閱讀更多資訊。", + "subtitle": "", "title": "基本設定" }, "library-panel": { @@ -9409,7 +9410,7 @@ "dashboard-name": "儀表板名稱" }, "library-panel-info": { - "last-edited": "上次編輯於 {{timeAgo}}前", + "last-edited": "", "usage-count_other": "用於 {{count}} 個儀表板" }, "library-panels-search": { @@ -9708,7 +9709,7 @@ "tooltip-unpin-line": "取消釘選行" }, "log-row-message": { - "ellipsis": "… ", + "ellipsis": "", "more": "更多", "see-details": "查看日誌詳細資訊", "tooltip-error": "錯誤:{{errorMessage}}" @@ -10104,7 +10105,7 @@ }, "resource-table": { "dashboard-load-error": "無法載入儀表板", - "error-library-element-sub": "資料庫元素 {uid}", + "error-library-element-sub": "", "error-library-element-title": "無法載入資料庫元素", "unknown-datasource-title": "資料來源 {{datasourceUID}}", "unknown-datasource-type": "未知資料來源" @@ -10749,10 +10750,10 @@ "placeholder-optional": "(選填)", "role": "角色", "submit": "提交", - "tooltip": "您現在可以選擇「無基本角色」選項,並根據您的自訂需求新增權限。您可以在<1>我們的文件中找到更多資訊。" + "tooltip": "" }, "user-invite-page": { - "sub-title": "傳送邀請或將現有 Grafana 使用者新增至組織。<1>{{orgName}}", + "sub-title": "", "text": { "invite-user": "邀請使用者" } @@ -10841,7 +10842,7 @@ "switch-to-table": "切換到表格" }, "panel-plugin-error": { - "text-load-error": "請檢查伺服器啟動紀錄,以了解更多資訊。<1>若此外掛程式是從 Git 載入,請確認是否已經過編譯。", + "text-load-error": "", "title-load-error": "載入時發生錯誤:{{panelId}}", "title-not-found": "找不到面板外掛程式:{{id}}" }, @@ -11035,7 +11036,7 @@ }, "details": { "connections-tab": { - "description": "您目前已設定「{{pluginName}}」的資料來源,點選圖塊以檢視設定詳細資料。您可以在<4><0>連線 - <3>資料來源中找到所有資料來源連線。" + "description": "" }, "disabled-error": { "angular-deprecation-link": "閱讀更多關於 Angular 遭取代的資訊", @@ -11052,7 +11053,7 @@ }, "labels": { "contactGrafanaLabs": "聯絡 Grafana Labs", - "customLinks": "自訂連結", + "customLinks": "", "customLinksTooltip": "這些連結由外掛程式開發人員提供,以提供額外的開發人員特定資源和資訊", "dependencies": "依存關係", "documentation": "文件", @@ -11063,7 +11064,7 @@ "latestVersion": "最新版本", "license": "授權", "raiseAnIssue": "提出問題", - "reportAbuse": "回報疑慮", + "reportAbuse": "", "reportAbuseTooltip": "將與惡意或有害外掛程式相關的問題直接報告給 Grafana Labs。", "repository": "存放庫", "signature": "簽名", @@ -11073,8 +11074,8 @@ "modal": { "cancel": "取消", "copyEmail": "複製電子郵件地址", - "description": "此功能用於報告外掛程式中的惡意或有害行為。如有外掛程式相關疑慮,請傳送電子郵件至:", - "node": "注意:對於一般的外掛程式問題,例如錯誤或功能要求,請使用提供的連結聯絡外掛程式作者。", + "description": "", + "node": "", "title": "回報外掛程式相關疑慮" } }, @@ -11142,7 +11143,7 @@ "message": "所有外掛程式均為最新版本" }, "not-found-plugin": { - "body-plugin-not-found": "找不到該外掛程式。請檢查網址是否正確或<1>前往<3>外掛程式目錄。", + "body-plugin-not-found": "", "title-plugin-not-found": "找不到外掛程式" }, "plugin-actions": { @@ -11600,7 +11601,6 @@ "unsupported-repository-type": "" }, "inline-secure-values-warning": "", - "inline-token-warning-badge-text": "", "job-status": { "label-view-details": "檢視詳細資料", "loading-finished-job": "正在載入已完成的作業…", @@ -11777,6 +11777,17 @@ "label-current-step": "目前步驟", "label-pending-step": "待處理步驟" }, + "status-badge": { + "automatic-pulling-disabled": "", + "deleting": "", + "error": "", + "pending": "", + "pulling": "", + "unknown": "", + "up-to-date": "", + "waiting-for-health-check": "", + "warning": "" + }, "success-title-default": "成功", "sync-job": { "error-no-job-id": "無法啟動作業", @@ -11954,7 +11965,7 @@ "annotations-show-text": "註釋 = 顯示", "time-range-picker-disabled-text": "時間範圍選擇器 = 已停用", "time-range-picker-enabled-text": "時間範圍選擇器 = 已啟用", - "time-range-text": "時間範圍 = " + "time-range-text": "" }, "share": { "success-delete": "您的儀表板不再可分享" @@ -11993,7 +12004,7 @@ "revoke-user-access-modal-desc-line1": "您確定要撤銷 {{email}} 的存取權限嗎?" }, "delete-user-shared-dashboards-modal": { - "revoke-user-access-modal-desc-line2": "此動作將立即撤銷 {{email}} 對所有共用儀表板的存取權限。" + "revoke-user-access-modal-desc-line2": "" }, "modal": { "shared-dashboard-modal-title": "共用儀表板" @@ -12159,7 +12170,7 @@ }, "menu": { "clear-button": "全部清除", - "tooltip": "您現在可以選擇「無基本角色」選項,並根據您的自訂需求新增權限。您可以在<1>我們的文件中找到更多資訊。" + "tooltip": "" }, "menu-aria-label": "角色選擇器選單", "menu-group-option-aria-label": "角色選擇器選項", @@ -12169,7 +12180,7 @@ }, "sub-menu-aria-label": "角色選擇器子選單", "title": { - "description": "為使用者指派角色,以確保對 Grafana 的功能和資源的存取進行精細控制。請至我們的<2>文件中閱讀更多資訊。" + "description": "" } }, "role-picker-drawer": { @@ -12292,7 +12303,7 @@ }, "select": { "select-menu": { - "selected-count": "已選取" + "selected-count": "" } }, "service-account-create-page": { @@ -12391,6 +12402,7 @@ "aria-label-role": "角色" }, "service-account-tokens-table": { + "aria-label-delete-button": "", "created": "已建立", "expires": "到期", "last-used-at": "上次使用時間", @@ -12477,7 +12489,7 @@ "info-text": "建立指向此儀表板或面板的直接連結,並使用以下選項自訂。", "link-url": "連結網址", "render-alert": "未安裝圖片轉譯器外掛程式", - "render-instructions": "若要轉譯圖片,您必須安裝 <2>Grafana 圖片轉譯器外掛程式。請聯絡您的 Grafana 管理員以安裝外掛程式。", + "render-instructions": "", "rendered-image": "直接連結轉譯的圖片", "save-alert": "儀表板未儲存", "save-dashboard": "若要呈現面板圖片,您必須先儲存儀表板。", @@ -12501,7 +12513,7 @@ "info-text-1": "快照是一種即時公開分享互動式儀表板的方式。建立後,我們會去除敏感資料,如查詢(指標、範本及註釋)及面板連結,只留下可見的度量值資料和嵌入在儀表板中的系列名稱。", "info-text-2": "請記住,擁有連結並可以存取網址的<1>任何人都可以查看您的快照。請謹慎分享。", "local-button": "發布快照", - "mistake-message": "您弄錯了嗎?", + "mistake-message": "", "name": "快照名稱", "timeout": "逾時(秒)", "timeout-description": "如果收集儀表板指標需要很長時間,則可能需要設定逾時值。", @@ -13112,7 +13124,7 @@ "forwards-time-aria-label": "將時間範圍向前移動", "to": "至", "zoom-out-button": "縮小時間範圍", - "zoom-out-tooltip": "時間範圍縮小<1> CTRL+Z" + "zoom-out-tooltip": "" }, "time-range": { "apply": "套用時間範圍", @@ -13237,7 +13249,7 @@ }, "transformations": { "empty": { - "add-transformation-body": "轉換功能可在顯示可視化之前,以各種方式變更資料。<1>這包括連接資料、重新命名欄位、進行計算、格式化資料以便顯示等。", + "add-transformation-body": "", "add-transformation-header": "開始轉換資料" } }, @@ -13504,7 +13516,7 @@ "label-format": "格式", "label-set-timezone": "設定時區", "label-time-field": "時間欄位", - "tooltip-format": "指定為 <2>Moment.js 格式字串的欄位輸出格式。", + "tooltip-format": "", "tooltip-timezone-manually": "手動設定日期的時區" }, "format-time-transformer-editor": { @@ -14099,8 +14111,8 @@ "message": "沒有找到使用者" }, "token-revoked-modal": { - "auto-revoked": "由於您已達到帳戶的<2>最大並行工作階段數量 {{numSessions}},因此您的工作階段權杖已自動撤銷。", - "resume-message": "<0>若要繼續工作階段,請重新登入。如果被重複自動登出,請聯絡您的管理員或前往授權頁面以查看您的配額。", + "auto-revoked": "", + "resume-message": "", "sign-in": "登入", "title-you-have-been-automatically-signed-out": "您已被自動登出" }, From fe9c21ebf861825fe8c753d94d26c23b32b9374c Mon Sep 17 00:00:00 2001 From: Georges Chaudy Date: Tue, 28 Oct 2025 10:56:08 +0100 Subject: [PATCH 042/378] unistore: replace CDK backend with KV store backend" (#112746) * deprecate the cdk backend in favor of the kv storage backend * lint * fix watchtests * cover limit=0 for ListHistory * fix rv too large --- pkg/storage/unified/apistore/restoptions.go | 33 +- pkg/storage/unified/apistore/watcher_test.go | 26 +- pkg/storage/unified/client.go | 17 +- pkg/storage/unified/resource/cdk_backend.go | 418 ------------------ pkg/storage/unified/resource/server.go | 2 +- pkg/storage/unified/resource/server_test.go | 28 +- .../unified/resource/storage_backend.go | 45 +- .../unified/resource/storage_backend_test.go | 30 ++ .../unified/testing/storage_backend.go | 48 ++ 9 files changed, 176 insertions(+), 471 deletions(-) delete mode 100644 pkg/storage/unified/resource/cdk_backend.go diff --git a/pkg/storage/unified/apistore/restoptions.go b/pkg/storage/unified/apistore/restoptions.go index 53ce1d2bb2a..58f702e78c1 100644 --- a/pkg/storage/unified/apistore/restoptions.go +++ b/pkg/storage/unified/apistore/restoptions.go @@ -3,13 +3,11 @@ package apistore import ( - "context" "os" "path/filepath" "time" - "gocloud.dev/blob/fileblob" - "gocloud.dev/blob/memblob" + badger "github.com/dgraph-io/badger/v4" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apiserver/pkg/registry/generic" @@ -53,18 +51,29 @@ func NewRESTOptionsGetterForClient( } func NewRESTOptionsGetterMemory(originalStorageConfig storagebackend.Config, secrets secret.InlineSecureValueSupport) (*RESTOptionsGetter, error) { - backend, err := resource.NewCDKBackend(context.Background(), resource.CDKBackendOptions{ - Bucket: memblob.OpenBucket(&memblob.Options{}), + // Create BadgerDB with in-memory mode + db, err := badger.Open(badger.DefaultOptions(""). + WithInMemory(true). + WithLogger(nil)) + if err != nil { + return nil, err + } + + kv := resource.NewBadgerKV(db) + backend, err := resource.NewKVStorageBackend(resource.KVBackendOptions{ + KvStore: kv, }) if err != nil { return nil, err } + server, err := resource.NewResourceServer(resource.ResourceServerOptions{ Backend: backend, }) if err != nil { return nil, err } + return NewRESTOptionsGetterForClient( resource.NewLocalResourceClient(server), secrets, @@ -83,25 +92,27 @@ func NewRESTOptionsGetterForFileXX(path string, path = filepath.Join(os.TempDir(), "grafana-apiserver") } - bucket, err := fileblob.OpenBucket(filepath.Join(path, "resource"), &fileblob.Options{ - CreateDir: true, - Metadata: fileblob.MetadataDontWrite, // skip - }) + db, err := badger.Open(badger.DefaultOptions(filepath.Join(path, "badger")). + WithLogger(nil)) if err != nil { return nil, err } - backend, err := resource.NewCDKBackend(context.Background(), resource.CDKBackendOptions{ - Bucket: bucket, + + kv := resource.NewBadgerKV(db) + backend, err := resource.NewKVStorageBackend(resource.KVBackendOptions{ + KvStore: kv, }) if err != nil { return nil, err } + server, err := resource.NewResourceServer(resource.ResourceServerOptions{ Backend: backend, }) if err != nil { return nil, err } + return NewRESTOptionsGetterForClient( resource.NewLocalResourceClient(server), nil, // secrets diff --git a/pkg/storage/unified/apistore/watcher_test.go b/pkg/storage/unified/apistore/watcher_test.go index afd2a77b08b..d23c8700c90 100644 --- a/pkg/storage/unified/apistore/watcher_test.go +++ b/pkg/storage/unified/apistore/watcher_test.go @@ -8,15 +8,13 @@ package apistore_test import ( "context" "fmt" - "os" "strings" "testing" "time" + badger "github.com/dgraph-io/badger/v4" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "gocloud.dev/blob/fileblob" - "gocloud.dev/blob/memblob" "k8s.io/apimachinery/pkg/api/apitesting" apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/meta" @@ -105,24 +103,20 @@ func testSetup(t testing.TB, opts ...setupOption) (context.Context, storage.Inte Resource: "pods", } - bucket := memblob.OpenBucket(nil) - if true { - tmp, err := os.MkdirTemp("", "xxx-*") - require.NoError(t, err) - - bucket, err = fileblob.OpenBucket(tmp, &fileblob.Options{ - CreateDir: true, - Metadata: fileblob.MetadataDontWrite, // skip - }) - require.NoError(t, err) - } ctx := storagetesting.NewContext() var server resource.ResourceServer switch setupOpts.storageType { case StorageTypeFile: - backend, err := resource.NewCDKBackend(ctx, resource.CDKBackendOptions{ - Bucket: bucket, + // Create in-memory BadgerDB for testing + db, err := badger.Open(badger.DefaultOptions(""). + WithInMemory(true). + WithLogger(nil)) + require.NoError(t, err) + + kv := resource.NewBadgerKV(db) + backend, err := resource.NewKVStorageBackend(resource.KVBackendOptions{ + KvStore: kv, }) require.NoError(t, err) diff --git a/pkg/storage/unified/client.go b/pkg/storage/unified/client.go index b0e7f6cf275..0a4d3e630ff 100644 --- a/pkg/storage/unified/client.go +++ b/pkg/storage/unified/client.go @@ -6,12 +6,12 @@ import ( "path/filepath" "time" + badger "github.com/dgraph-io/badger/v4" otgrpc "github.com/opentracing-contrib/go-grpc" "github.com/opentracing/opentracing-go" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc" - "gocloud.dev/blob/fileblob" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/keepalive" @@ -111,19 +111,22 @@ func newClient(opts options.StorageOptions, if opts.DataPath == "" { opts.DataPath = filepath.Join(cfg.DataPath, "grafana-apiserver") } - bucket, err := fileblob.OpenBucket(filepath.Join(opts.DataPath, "resource"), &fileblob.Options{ - CreateDir: true, - Metadata: fileblob.MetadataDontWrite, // skip - }) + + // Create BadgerDB instance + db, err := badger.Open(badger.DefaultOptions(filepath.Join(opts.DataPath, "badger")). + WithLogger(nil)) if err != nil { return nil, err } - backend, err := resource.NewCDKBackend(ctx, resource.CDKBackendOptions{ - Bucket: bucket, + + kv := resource.NewBadgerKV(db) + backend, err := resource.NewKVStorageBackend(resource.KVBackendOptions{ + KvStore: kv, }) if err != nil { return nil, err } + server, err := resource.NewResourceServer(resource.ResourceServerOptions{ Backend: backend, Blob: resource.BlobConfig{ diff --git a/pkg/storage/unified/resource/cdk_backend.go b/pkg/storage/unified/resource/cdk_backend.go deleted file mode 100644 index 0cb9628758a..00000000000 --- a/pkg/storage/unified/resource/cdk_backend.go +++ /dev/null @@ -1,418 +0,0 @@ -package resource - -import ( - "bytes" - "context" - "errors" - "fmt" - "io" - "iter" - "net/http" - "sort" - "strconv" - "strings" - "sync" - "sync/atomic" - "time" - - "go.opentelemetry.io/otel/trace" - "go.opentelemetry.io/otel/trace/noop" - "gocloud.dev/blob" - _ "gocloud.dev/blob/fileblob" - _ "gocloud.dev/blob/memblob" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - - "github.com/grafana/grafana/pkg/apimachinery/utils" - "github.com/grafana/grafana/pkg/storage/unified/resourcepb" -) - -type CDKBackendOptions struct { - Tracer trace.Tracer - Bucket CDKBucket - RootFolder string -} - -func NewCDKBackend(ctx context.Context, opts CDKBackendOptions) (StorageBackend, error) { - if opts.Tracer == nil { - opts.Tracer = noop.NewTracerProvider().Tracer("cdk-appending-store") - } - - if opts.Bucket == nil { - return nil, fmt.Errorf("missing bucket") - } - - found, _, err := opts.Bucket.ListPage(ctx, blob.FirstPageToken, 1, &blob.ListOptions{ - Prefix: opts.RootFolder, - Delimiter: "/", - }) - if err != nil { - return nil, err - } - if found == nil { - return nil, fmt.Errorf("the root folder does not exist") - } - - backend := &cdkBackend{ - tracer: opts.Tracer, - bucket: opts.Bucket, - root: opts.RootFolder, - } - backend.rv.Swap(time.Now().UnixMilli()) - return backend, nil -} - -type cdkBackend struct { - tracer trace.Tracer - bucket CDKBucket - root string - - mutex sync.Mutex - rv atomic.Int64 - - // Simple watch stream -- NOTE, this only works for single tenant! - broadcaster Broadcaster[*WrittenEvent] - stream chan<- *WrittenEvent -} - -func (s *cdkBackend) GetResourceLastImportTimes(ctx context.Context) iter.Seq2[ResourceLastImportTime, error] { - return func(yield func(ResourceLastImportTime, error) bool) { - yield(ResourceLastImportTime{}, errors.New("not implemented")) - } -} - -func (s *cdkBackend) ListModifiedSince(ctx context.Context, key NamespacedResource, sinceRv int64) (int64, iter.Seq2[*ModifiedResource, error]) { - return 0, func(yield func(*ModifiedResource, error) bool) { - yield(nil, errors.New("not implemented")) - } -} - -func (s *cdkBackend) getPath(key *resourcepb.ResourceKey, rv int64) string { - var buffer bytes.Buffer - buffer.WriteString(s.root) - - if key.Group == "" { - return buffer.String() - } - buffer.WriteString(key.Group) - - if key.Resource == "" { - return buffer.String() - } - buffer.WriteString("/") - buffer.WriteString(key.Resource) - - if key.Namespace == "" { - if key.Name == "" { - return buffer.String() - } - buffer.WriteString("/__cluster__") - } else { - buffer.WriteString("/") - buffer.WriteString(key.Namespace) - } - - if key.Name == "" { - return buffer.String() - } - buffer.WriteString("/") - buffer.WriteString(key.Name) - - if rv > 0 { - buffer.WriteString(fmt.Sprintf("/%d.json", rv)) - } - return buffer.String() -} - -// GetResourceStats implements Backend. -func (s *cdkBackend) GetResourceStats(ctx context.Context, namespace string, minCount int) ([]ResourceStats, error) { - return nil, fmt.Errorf("not implemented") -} - -func (s *cdkBackend) WriteEvent(ctx context.Context, event WriteEvent) (rv int64, err error) { - if event.Type == resourcepb.WatchEvent_ADDED { - // ReadResource deals with deleted values (i.e. a file exists but has generation -999). - resp := s.ReadResource(ctx, &resourcepb.ReadRequest{Key: event.Key}) - if resp.Error != nil && resp.Error.Code != http.StatusNotFound { - return 0, GetError(resp.Error) - } - if resp.Value != nil { - return 0, ErrResourceAlreadyExists - } - } - - // Scope the lock - { - s.mutex.Lock() - defer s.mutex.Unlock() - - rv = s.rv.Add(1) - err = s.bucket.WriteAll(ctx, s.getPath(event.Key, rv), event.Value, &blob.WriterOptions{ - ContentType: "application/json", - }) - } - - // notify all subscribers - if s.stream != nil { - write := &WrittenEvent{ - Type: event.Type, - Key: event.Key, - PreviousRV: event.PreviousRV, - Value: event.Value, - Timestamp: time.Now().UnixMilli(), - ResourceVersion: rv, - } - s.stream <- write - } - return rv, err -} - -func (s *cdkBackend) ReadResource(ctx context.Context, req *resourcepb.ReadRequest) *BackendReadResponse { - rv := req.ResourceVersion - - path := s.getPath(req.Key, rv) - if rv < 1 { - iter := s.bucket.List(&blob.ListOptions{Prefix: path + "/", Delimiter: "/"}) - for { - obj, err := iter.Next(ctx) - if errors.Is(err, io.EOF) { - break - } - if strings.HasSuffix(obj.Key, ".json") { - idx := strings.LastIndex(obj.Key, "/") + 1 - edx := strings.LastIndex(obj.Key, ".") - if idx > 0 { - v, err := strconv.ParseInt(obj.Key[idx:edx], 10, 64) - if err == nil && v > rv { - rv = v - path = obj.Key // find the path with biggest resource version - } - } - } - } - } - - raw, err := s.bucket.ReadAll(ctx, path) - if raw == nil && req.ResourceVersion > 0 { - if req.ResourceVersion > s.rv.Load() { - return &BackendReadResponse{ - Error: &resourcepb.ErrorResult{ - Code: http.StatusGatewayTimeout, - Reason: string(metav1.StatusReasonTimeout), // match etcd behavior - Message: "ResourceVersion is larger than max", - Details: &resourcepb.ErrorDetails{ - Causes: []*resourcepb.ErrorCause{ - { - Reason: string(metav1.CauseTypeResourceVersionTooLarge), - Message: fmt.Sprintf("requested: %d, current %d", req.ResourceVersion, s.rv.Load()), - }, - }, - }, - }, - } - } - - // If the there was an explicit request, get the latest - rsp := s.ReadResource(ctx, &resourcepb.ReadRequest{Key: req.Key}) - if rsp != nil && len(rsp.Value) > 0 { - raw = rsp.Value - rv = rsp.ResourceVersion - err = nil - } - } - if err == nil && isDeletedValue(raw) { - raw = nil - } - if raw == nil { - return &BackendReadResponse{Error: NewNotFoundError(req.Key)} - } - return &BackendReadResponse{ - Key: req.Key, - Folder: "", // TODO: implement this - ResourceVersion: rv, - Value: raw, - } -} - -func isDeletedValue(raw []byte) bool { - if bytes.Contains(raw, []byte(`"generation":-999`)) { - tmp := &unstructured.Unstructured{} - err := tmp.UnmarshalJSON(raw) - if err == nil && tmp.GetGeneration() == utils.DeletedGeneration { - return true - } - } - return false -} - -func (s *cdkBackend) ListIterator(ctx context.Context, req *resourcepb.ListRequest, cb func(ListIterator) error) (int64, error) { - resources, err := buildTree(ctx, s, req.Options.Key) - if err != nil { - return 0, err - } - err = cb(resources) - return resources.listRV, err -} - -func (s *cdkBackend) ListHistory(ctx context.Context, req *resourcepb.ListRequest, cb func(ListIterator) error) (int64, error) { - return 0, fmt.Errorf("listing from history not supported in CDK backend") -} - -func (s *cdkBackend) WatchWriteEvents(ctx context.Context) (<-chan *WrittenEvent, error) { - s.mutex.Lock() - defer s.mutex.Unlock() - - if s.broadcaster == nil { - var err error - s.broadcaster, err = NewBroadcaster(context.Background(), func(c chan<- *WrittenEvent) error { - s.stream = c - return nil - }) - if err != nil { - return nil, err - } - } - return s.broadcaster.Subscribe(ctx) -} - -// group > resource > namespace > name > versions -type cdkResource struct { - prefix string - versions []cdkVersion -} -type cdkVersion struct { - rv int64 - key string -} - -type cdkListIterator struct { - bucket CDKBucket - ctx context.Context - err error - - listRV int64 - resources []cdkResource - index int - - currentRV int64 - currentKey string - currentVal []byte -} - -// Next implements ListIterator. -func (c *cdkListIterator) Next() bool { - if c.err != nil { - return false - } - for { - c.currentVal = nil - c.index += 1 - if c.index >= len(c.resources) { - return false - } - - item := c.resources[c.index] - latest := item.versions[0] - raw, err := c.bucket.ReadAll(c.ctx, latest.key) - if err != nil { - c.err = err - return false - } - if !isDeletedValue(raw) { - c.currentRV = latest.rv - c.currentKey = latest.key - c.currentVal = raw - return true - } - } -} - -// Error implements ListIterator. -func (c *cdkListIterator) Error() error { - return c.err -} - -// ResourceVersion implements ListIterator. -func (c *cdkListIterator) ResourceVersion() int64 { - return c.currentRV -} - -// Value implements ListIterator. -func (c *cdkListIterator) Value() []byte { - return c.currentVal -} - -// ContinueToken implements ListIterator. -func (c *cdkListIterator) ContinueToken() string { - return fmt.Sprintf("index:%d/key:%s", c.index, c.currentKey) -} - -// Name implements ListIterator. -func (c *cdkListIterator) Name() string { - return c.currentKey // TODO (parse name from key) -} - -// Namespace implements ListIterator. -func (c *cdkListIterator) Namespace() string { - return c.currentKey // TODO (parse namespace from key) -} - -func (c *cdkListIterator) Folder() string { - return "" // TODO: implement this -} - -var _ ListIterator = (*cdkListIterator)(nil) - -func buildTree(ctx context.Context, s *cdkBackend, key *resourcepb.ResourceKey) (*cdkListIterator, error) { - byPrefix := make(map[string]*cdkResource) - path := s.getPath(key, 0) - iter := s.bucket.List(&blob.ListOptions{Prefix: path, Delimiter: ""}) // "" is recursive - for { - obj, err := iter.Next(ctx) - if errors.Is(err, io.EOF) { - break - } - if strings.HasSuffix(obj.Key, ".json") { - idx := strings.LastIndex(obj.Key, "/") + 1 - edx := strings.LastIndex(obj.Key, ".") - if idx > 0 { - rv, err := strconv.ParseInt(obj.Key[idx:edx], 10, 64) - if err == nil { - prefix := obj.Key[:idx] - res, ok := byPrefix[prefix] - if !ok { - res = &cdkResource{prefix: prefix} - byPrefix[prefix] = res - } - - res.versions = append(res.versions, cdkVersion{ - rv: rv, - key: obj.Key, - }) - } - } - } - } - - // Now sort all versions - resources := make([]cdkResource, 0, len(byPrefix)) - for _, res := range byPrefix { - sort.Slice(res.versions, func(i, j int) bool { - return res.versions[i].rv > res.versions[j].rv - }) - resources = append(resources, *res) - } - sort.Slice(resources, func(i, j int) bool { - a := resources[i].prefix - b := resources[j].prefix - return a < b - }) - - return &cdkListIterator{ - ctx: ctx, - bucket: s.bucket, - resources: resources, - listRV: s.rv.Load(), - index: -1, // must call next first - }, nil -} diff --git a/pkg/storage/unified/resource/server.go b/pkg/storage/unified/resource/server.go index 59ae4e1dc83..76c3e3c2a8c 100644 --- a/pkg/storage/unified/resource/server.go +++ b/pkg/storage/unified/resource/server.go @@ -1072,7 +1072,7 @@ func (s *server) List(ctx context.Context, req *resourcepb.ListRequest) (*resour pageBytes += len(item.Value) rsp.Items = append(rsp.Items, item) - if len(rsp.Items) >= int(req.Limit) || pageBytes >= maxPageBytes { + if (req.Limit > 0 && len(rsp.Items) >= int(req.Limit)) || pageBytes >= maxPageBytes { t := iter.ContinueToken() if iter.Next() { rsp.NextPageToken = t diff --git a/pkg/storage/unified/resource/server_test.go b/pkg/storage/unified/resource/server_test.go index 66536b4d5d8..391a931696d 100644 --- a/pkg/storage/unified/resource/server_test.go +++ b/pkg/storage/unified/resource/server_test.go @@ -4,20 +4,17 @@ import ( "context" "encoding/json" "errors" - "fmt" "log/slog" "net/http" - "os" "strings" "sync" "testing" "time" + badger "github.com/dgraph-io/badger/v4" "github.com/prometheus/client_golang/prometheus" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "gocloud.dev/blob/fileblob" - "gocloud.dev/blob/memblob" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" authlib "github.com/grafana/authlib/types" @@ -41,20 +38,19 @@ func TestSimpleServer(t *testing.T) { } ctx := authlib.WithAuthInfo(context.Background(), testUserA) - bucket := memblob.OpenBucket(nil) - if false { - tmp, err := os.MkdirTemp("", "xxx-*") + // Create in-memory BadgerDB for testing + db, err := badger.Open(badger.DefaultOptions(""). + WithInMemory(true). + WithLogger(nil)) + require.NoError(t, err) + defer func() { + err := db.Close() require.NoError(t, err) + }() - bucket, err = fileblob.OpenBucket(tmp, &fileblob.Options{ - CreateDir: true, - Metadata: fileblob.MetadataDontWrite, // skip - }) - require.NoError(t, err) - fmt.Printf("ROOT: %s\n\n", tmp) - } - store, err := NewCDKBackend(ctx, CDKBackendOptions{ - Bucket: bucket, + kv := NewBadgerKV(db) + store, err := NewKVStorageBackend(KVBackendOptions{ + KvStore: kv, }) require.NoError(t, err) diff --git a/pkg/storage/unified/resource/storage_backend.go b/pkg/storage/unified/resource/storage_backend.go index d6afaf43638..f7bca33766b 100644 --- a/pkg/storage/unified/resource/storage_backend.go +++ b/pkg/storage/unified/resource/storage_backend.go @@ -283,6 +283,40 @@ func (k *kvStorageBackend) ReadResource(ctx context.Context, req *resourcepb.Rea if req.Key == nil { return &BackendReadResponse{Error: &resourcepb.ErrorResult{Code: http.StatusBadRequest, Message: "missing key"}} } + + // If a specific resource version is requested, validate that it's not too high + if req.ResourceVersion > 0 { + // Fetch the latest RV + latestRV := k.snowflake.Generate().Int64() + if lastEventKey, err := k.eventStore.LastEventKey(ctx); err == nil { + latestRV = lastEventKey.ResourceVersion + } else if !errors.Is(err, ErrNotFound) { + return &BackendReadResponse{Error: &resourcepb.ErrorResult{ + Code: http.StatusInternalServerError, + Message: fmt.Sprintf("failed to fetch latest resource version: %v", err), + }} + } + + // Check if the requested RV is higher than the latest available RV + if req.ResourceVersion > latestRV { + return &BackendReadResponse{ + Error: &resourcepb.ErrorResult{ + Code: http.StatusGatewayTimeout, + Reason: string(metav1.StatusReasonTimeout), // match etcd behavior + Message: "ResourceVersion is larger than max", + Details: &resourcepb.ErrorDetails{ + Causes: []*resourcepb.ErrorCause{ + { + Reason: string(metav1.CauseTypeResourceVersionTooLarge), + Message: fmt.Sprintf("requested: %d, current %d", req.ResourceVersion, latestRV), + }, + }, + }, + }, + } + } + } + meta, err := k.dataStore.GetResourceKeyAtRevision(ctx, GetRequestKey{ Group: req.Key.Group, Resource: req.Key.Resource, @@ -335,8 +369,15 @@ func (k *kvStorageBackend) ListIterator(ctx context.Context, req *resourcepb.Lis resourceVersion = token.ResourceVersion } - // We set the listRV to the current time. + // We set the listRV to the last event resource version. + // If no events exist yet, we generate a new snowflake. listRV := k.snowflake.Generate().Int64() + if lastEventKey, err := k.eventStore.LastEventKey(ctx); err == nil { + listRV = lastEventKey.ResourceVersion + } else if !errors.Is(err, ErrNotFound) { + return 0, fmt.Errorf("failed to fetch last event: %w", err) + } + if resourceVersion > 0 { listRV = resourceVersion } @@ -360,7 +401,7 @@ func (k *kvStorageBackend) ListIterator(ctx context.Context, req *resourcepb.Lis } keys = append(keys, dataKey) // Only fetch the first limit items + 1 to get the next token. - if len(keys) >= int(req.Limit+1) { + if req.Limit > 0 && len(keys) >= int(req.Limit+1) { break } } diff --git a/pkg/storage/unified/resource/storage_backend_test.go b/pkg/storage/unified/resource/storage_backend_test.go index 8ec4bac7f71..4ef60d1a4c4 100644 --- a/pkg/storage/unified/resource/storage_backend_test.go +++ b/pkg/storage/unified/resource/storage_backend_test.go @@ -324,6 +324,36 @@ func TestKvStorageBackend_ReadResource_DeletedResource(t *testing.T) { require.Equal(t, objectToJSONBytes(t, testObj), response.Value) } +func TestKvStorageBackend_ReadResource_TooHighResourceVersion(t *testing.T) { + backend := setupTestStorageBackend(t) + ctx := context.Background() + + // First, create a resource + _, rv := createAndWriteTestObject(t, backend) + + // Try to read with a resource version that's way too high + readReq := &resourcepb.ReadRequest{ + Key: &resourcepb.ResourceKey{ + Namespace: "default", + Group: "apps", + Resource: "resources", + Name: "test-resource", + }, + ResourceVersion: rv + 1000000000000, // Way in the future + } + + response := backend.ReadResource(ctx, readReq) + require.NotNil(t, response.Error, "ReadResource should return error for too high resource version") + require.Equal(t, int32(504), response.Error.Code) // http.StatusGatewayTimeout + require.Equal(t, "Timeout", response.Error.Reason) + require.Equal(t, "ResourceVersion is larger than max", response.Error.Message) + require.NotNil(t, response.Error.Details) + require.Len(t, response.Error.Details.Causes, 1) + require.Equal(t, "ResourceVersionTooLarge", response.Error.Details.Causes[0].Reason) + require.Contains(t, response.Error.Details.Causes[0].Message, "requested:") + require.Contains(t, response.Error.Details.Causes[0].Message, "current") +} + func TestKvStorageBackend_ListIterator_Success(t *testing.T) { backend := setupTestStorageBackend(t) ctx := context.Background() diff --git a/pkg/storage/unified/testing/storage_backend.go b/pkg/storage/unified/testing/storage_backend.go index 8ce39d55e33..440f2af8a26 100644 --- a/pkg/storage/unified/testing/storage_backend.go +++ b/pkg/storage/unified/testing/storage_backend.go @@ -387,6 +387,30 @@ func runTestIntegrationBackendList(t *testing.T, backend resource.StorageBackend require.Empty(t, res.NextPageToken) }) + t.Run("fetch all with limit 0", func(t *testing.T) { + res, err := server.List(ctx, &resourcepb.ListRequest{ + Limit: 0, + Options: &resourcepb.ListOptions{ + Key: &resourcepb.ResourceKey{ + Namespace: ns, + Group: "group", + Resource: "resource", + }, + }, + }) + require.NoError(t, err) + require.Nil(t, res.Error) + require.Len(t, res.Items, 5) + // should be sorted by key ASC + require.Contains(t, string(res.Items[0].Value), "item1 ADDED") + require.Contains(t, string(res.Items[1].Value), "item2 MODIFIED") + require.Contains(t, string(res.Items[2].Value), "item4 ADDED") + require.Contains(t, string(res.Items[3].Value), "item5 ADDED") + require.Contains(t, string(res.Items[4].Value), "item6 ADDED") + + require.Empty(t, res.NextPageToken) + }) + t.Run("list latest first page ", func(t *testing.T) { res, err := server.List(ctx, &resourcepb.ListRequest{ Limit: 3, @@ -757,6 +781,30 @@ func runTestIntegrationBackendListHistory(t *testing.T, backend resource.Storage require.Contains(t, string(secondPageRes.Items[i].Value), "item1 MODIFIED") } }) + + // Test with limit=0 (should return all items) + t.Run("fetch all history with limit 0", func(t *testing.T) { + res, err := server.List(ctx, &resourcepb.ListRequest{ + Limit: 0, + Source: resourcepb.ListRequest_HISTORY, + Options: &resourcepb.ListOptions{ + Key: baseKey, + }, + }) + require.NoError(t, err) + require.Nil(t, res.Error) + require.Len(t, res.Items, 6) // Should return all 6 history items (1 ADDED + 5 MODIFIED) + + // Should be in descending order (default for history) + require.Equal(t, rvHistory5, res.Items[0].ResourceVersion) + require.Equal(t, rvHistory4, res.Items[1].ResourceVersion) + require.Equal(t, rvHistory3, res.Items[2].ResourceVersion) + require.Equal(t, rvHistory2, res.Items[3].ResourceVersion) + require.Equal(t, rvHistory1, res.Items[4].ResourceVersion) + require.Equal(t, rv1, res.Items[5].ResourceVersion) + + require.Empty(t, res.NextPageToken) + }) }) t.Run("fetch second page of history at revision", func(t *testing.T) { From 19d88de3cf0917f915610032dcd1cad9d02e0da7 Mon Sep 17 00:00:00 2001 From: "renovate-sh-app[bot]" <219655108+renovate-sh-app[bot]@users.noreply.github.com> Date: Tue, 28 Oct 2025 10:07:59 +0000 Subject: [PATCH 043/378] fix(deps): update dependency @grafana/azure-sdk to v0.0.8 (#113054) | datasource | package | from | to | | ---------- | ------------------ | ----- | ----- | | npm | @grafana/azure-sdk | 0.0.7 | 0.0.8 | Signed-off-by: renovate-sh-app[bot] <219655108+renovate-sh-app[bot]@users.noreply.github.com> Co-authored-by: renovate-sh-app[bot] <219655108+renovate-sh-app[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 74 +++++++++++++--------------------------------------- 2 files changed, 19 insertions(+), 57 deletions(-) diff --git a/package.json b/package.json index c57b1326372..37df4fb1c32 100644 --- a/package.json +++ b/package.json @@ -280,7 +280,7 @@ "@grafana/api-clients": "workspace:*", "@grafana/assistant": "0.1.0", "@grafana/aws-sdk": "0.7.1", - "@grafana/azure-sdk": "0.0.7", + "@grafana/azure-sdk": "0.0.8", "@grafana/data": "workspace:*", "@grafana/e2e-selectors": "workspace:*", "@grafana/faro-core": "^1.19.0", diff --git a/yarn.lock b/yarn.lock index 74808967fd1..b281216a8e8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3051,13 +3051,12 @@ __metadata: languageName: node linkType: hard -"@grafana/azure-sdk@npm:0.0.7": - version: 0.0.7 - resolution: "@grafana/azure-sdk@npm:0.0.7" +"@grafana/azure-sdk@npm:0.0.8": + version: 0.0.8 + resolution: "@grafana/azure-sdk@npm:0.0.8" dependencies: - react-dom: "npm:^18.3.1" - ts-jest: "npm:29.2.5" - checksum: 10/19985d0d3dbcb63a3c82bf6c17aeeb927d81f297c5589d64ef2ac6dabb3fd4e6b22f5c947f132575cc8bf37e2089394b4442f2c0db02fa4f62b617d297524d3a + react-dom: "npm:^19.2.0" + checksum: 10/9fc1571658f73b321f1e53761e15add98541c5e743b90ed6c13e55a176e6667a62883435165efe20da45bf8ed94f9d229cdcb4761bc00cba1304f0ef8ee28954 languageName: node linkType: hard @@ -18793,7 +18792,7 @@ __metadata: "@grafana/api-clients": "workspace:*" "@grafana/assistant": "npm:0.1.0" "@grafana/aws-sdk": "npm:0.7.1" - "@grafana/azure-sdk": "npm:0.0.7" + "@grafana/azure-sdk": "npm:0.0.8" "@grafana/data": "workspace:*" "@grafana/e2e-selectors": "workspace:*" "@grafana/eslint-config": "npm:8.2.0" @@ -21770,7 +21769,7 @@ __metadata: languageName: node linkType: hard -"jest-util@npm:^29.0.0, jest-util@npm:^29.7.0": +"jest-util@npm:^29.7.0": version: 29.7.0 resolution: "jest-util@npm:29.7.0" dependencies: @@ -27809,7 +27808,7 @@ __metadata: languageName: node linkType: hard -"react-dom@npm:18.3.1, react-dom@npm:^18.3.1": +"react-dom@npm:18.3.1": version: 18.3.1 resolution: "react-dom@npm:18.3.1" dependencies: @@ -27821,14 +27820,14 @@ __metadata: languageName: node linkType: hard -"react-dom@npm:^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0": - version: 19.0.0 - resolution: "react-dom@npm:19.0.0" +"react-dom@npm:^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0, react-dom@npm:^19.2.0": + version: 19.2.0 + resolution: "react-dom@npm:19.2.0" dependencies: - scheduler: "npm:^0.25.0" + scheduler: "npm:^0.27.0" peerDependencies: - react: ^19.0.0 - checksum: 10/aa64a2f1991042f516260e8b0eca0ae777b6c8f1aa2b5ae096e80bbb6ac9b005aef2bca697969841d34f7e1819556263476bdfea36c35092e8d9aefde3de2d9a + react: ^19.2.0 + checksum: 10/3dbba071b9b1e7a19eae55f05c100f6b44f88c0aee72397d719ae338248ca66ed5028e6964c1c14870cc3e1abcecc91b22baba6dc2072f819dea81a9fd72f2fd languageName: node linkType: hard @@ -29623,10 +29622,10 @@ __metadata: languageName: node linkType: hard -"scheduler@npm:^0.25.0": - version: 0.25.0 - resolution: "scheduler@npm:0.25.0" - checksum: 10/e661e38503ab29a153429a99203fefa764f28b35c079719eb5efdd2c1c1086522f6653d8ffce388209682c23891a6d1d32fa6badf53c35fb5b9cd0c55ace42de +"scheduler@npm:^0.27.0": + version: 0.27.0 + resolution: "scheduler@npm:0.27.0" + checksum: 10/eab3c3a8373195173e59c147224fc30dabe6dd453f248f5e610e8458512a5a2ee3a06465dc400ebfe6d35c9f5b7f3bb6b2e41c88c86fd177c25a73e7286a1e06 languageName: node linkType: hard @@ -32008,43 +32007,6 @@ __metadata: languageName: node linkType: hard -"ts-jest@npm:29.2.5": - version: 29.2.5 - resolution: "ts-jest@npm:29.2.5" - dependencies: - bs-logger: "npm:^0.2.6" - ejs: "npm:^3.1.10" - fast-json-stable-stringify: "npm:^2.1.0" - jest-util: "npm:^29.0.0" - json5: "npm:^2.2.3" - lodash.memoize: "npm:^4.1.2" - make-error: "npm:^1.3.6" - semver: "npm:^7.6.3" - yargs-parser: "npm:^21.1.1" - peerDependencies: - "@babel/core": ">=7.0.0-beta.0 <8" - "@jest/transform": ^29.0.0 - "@jest/types": ^29.0.0 - babel-jest: ^29.0.0 - jest: ^29.0.0 - typescript: ">=4.3 <6" - peerDependenciesMeta: - "@babel/core": - optional: true - "@jest/transform": - optional: true - "@jest/types": - optional: true - babel-jest: - optional: true - esbuild: - optional: true - bin: - ts-jest: cli.js - checksum: 10/f89e562816861ec4510840a6b439be6145f688b999679328de8080dc8e66481325fc5879519b662163e33b7578f35243071c38beb761af34e5fe58e3e326a958 - languageName: node - linkType: hard - "ts-jest@npm:29.4.0": version: 29.4.0 resolution: "ts-jest@npm:29.4.0" From 7a7fd45bdd32ccb5969bd0dc17e435b6547ac44e Mon Sep 17 00:00:00 2001 From: Alexander Zobnin Date: Tue, 28 Oct 2025 11:22:13 +0100 Subject: [PATCH 044/378] Zanzana: app platform style write APIs (#112812) * refactor zanzana client instantiation * refactor client imports * POC write API (Mutate) * fix linter * delete exisitng folder parents * refactor common functions * minor refactor * groupd operations by type * atomic folder operations * use deleteExisting for deletes * Add tests for folders * more tests * resource permissions tests * add more tests * fix mock zanzana client * fix linter * fix linter * re-use types from apps * add some comments to the protobuf --- apps/iam/pkg/reconcilers/folder_reconciler.go | 11 +- pkg/server/wire_gen.go | 4 +- .../dualwrite/collectors_test.go | 4 + pkg/services/authz/proto/v1/extention.pb.go | 1125 +++++++++++++---- pkg/services/authz/proto/v1/extention.proto | 64 + .../authz/proto/v1/extention_grpc.pb.go | 38 + pkg/services/authz/rbac.go | 5 +- pkg/services/authz/wireset.go | 2 +- pkg/services/authz/zanzana.go | 42 +- pkg/services/authz/zanzana/client.go | 16 +- pkg/services/authz/zanzana/client/client.go | 18 + pkg/services/authz/zanzana/client/noop.go | 8 +- .../authz/zanzana/client/shadow_client.go | 5 +- .../zanzana/{ => common}/translations.go | 61 +- pkg/services/authz/zanzana/common/tuple.go | 98 +- pkg/services/authz/zanzana/server.go | 30 - .../authz/zanzana/server/server_mutate.go | 90 ++ .../zanzana/server/server_mutate_folder.go | 142 +++ .../server/server_mutate_folder_test.go | 164 +++ .../server_mutate_resourcepermissions.go | 173 +++ .../server_mutate_resourcepermissions_test.go | 115 ++ .../zanzana/server/server_mutate_test.go | 135 ++ .../authz/zanzana/server/server_test.go | 97 +- pkg/services/authz/zanzana/store.go | 18 - pkg/services/authz/zanzana/zanzana.go | 145 +-- 25 files changed, 2108 insertions(+), 502 deletions(-) rename pkg/services/authz/zanzana/{ => common}/translations.go (67%) create mode 100644 pkg/services/authz/zanzana/server/server_mutate.go create mode 100644 pkg/services/authz/zanzana/server/server_mutate_folder.go create mode 100644 pkg/services/authz/zanzana/server/server_mutate_folder_test.go create mode 100644 pkg/services/authz/zanzana/server/server_mutate_resourcepermissions.go create mode 100644 pkg/services/authz/zanzana/server/server_mutate_resourcepermissions_test.go create mode 100644 pkg/services/authz/zanzana/server/server_mutate_test.go delete mode 100644 pkg/services/authz/zanzana/store.go diff --git a/apps/iam/pkg/reconcilers/folder_reconciler.go b/apps/iam/pkg/reconcilers/folder_reconciler.go index 59385b3b3a3..066637ee1e6 100644 --- a/apps/iam/pkg/reconcilers/folder_reconciler.go +++ b/apps/iam/pkg/reconcilers/folder_reconciler.go @@ -5,15 +5,16 @@ import ( "fmt" "time" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/codes" + "go.opentelemetry.io/otel/trace" + "github.com/grafana/grafana-app-sdk/logging" "github.com/grafana/grafana-app-sdk/operator" foldersKind "github.com/grafana/grafana/apps/folder/pkg/apis/folder/v1beta1" "github.com/grafana/grafana/pkg/apimachinery/utils" "github.com/grafana/grafana/pkg/services/authz" - "go.opentelemetry.io/otel" - "go.opentelemetry.io/otel/attribute" - "go.opentelemetry.io/otel/codes" - "go.opentelemetry.io/otel/trace" ) // PermissionStore interface for managing folder permissions @@ -36,7 +37,7 @@ type FolderReconciler struct { func NewFolderReconciler(cfg ReconcilerConfig) (operator.Reconciler, error) { // Create Zanzana client - zanzanaClient, err := authz.NewZanzanaClient("*", cfg.ZanzanaCfg) + zanzanaClient, err := authz.NewRemoteZanzanaClient("*", cfg.ZanzanaCfg) if err != nil { return nil, fmt.Errorf("unable to create zanzana client: %w", err) diff --git a/pkg/server/wire_gen.go b/pkg/server/wire_gen.go index feed7394400..ac23bdda879 100644 --- a/pkg/server/wire_gen.go +++ b/pkg/server/wire_gen.go @@ -442,7 +442,7 @@ func Initialize(ctx context.Context, cfg *setting.Cfg, opts Options, apiOpts api if err != nil { return nil, err } - zanzanaClient, err := authz.ProvideZanzana(cfg, sqlStore, tracingService, featureToggles, registerer) + zanzanaClient, err := authz.ProvideZanzanaClient(cfg, sqlStore, tracingService, featureToggles, registerer) if err != nil { return nil, err } @@ -1061,7 +1061,7 @@ func InitializeForTest(ctx context.Context, t sqlutil.ITestDB, testingT interfac if err != nil { return nil, err } - zanzanaClient, err := authz.ProvideZanzana(cfg, sqlStore, tracingService, featureToggles, registerer) + zanzanaClient, err := authz.ProvideZanzanaClient(cfg, sqlStore, tracingService, featureToggles, registerer) if err != nil { return nil, err } diff --git a/pkg/services/accesscontrol/dualwrite/collectors_test.go b/pkg/services/accesscontrol/dualwrite/collectors_test.go index 2c0ac88a689..32e021c4b1c 100644 --- a/pkg/services/accesscontrol/dualwrite/collectors_test.go +++ b/pkg/services/accesscontrol/dualwrite/collectors_test.go @@ -242,6 +242,10 @@ func (m *mockZanzanaClient) Compile(ctx context.Context, id authlib.AuthInfo, re return args.Get(0).(authlib.ItemChecker), args.Get(1).(authlib.Zookie), args.Error(2) } +func (m *mockZanzanaClient) Mutate(ctx context.Context, req *authzextv1.MutateRequest) error { + return nil +} + func TestIntegrationTeamMembershipCollector(t *testing.T) { testutil.SkipIntegrationTestInShortMode(t) diff --git a/pkg/services/authz/proto/v1/extention.pb.go b/pkg/services/authz/proto/v1/extention.pb.go index 9f155187ab5..9b197a15d94 100644 --- a/pkg/services/authz/proto/v1/extention.pb.go +++ b/pkg/services/authz/proto/v1/extention.pb.go @@ -24,6 +24,564 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) +type MutateRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Namespace string `protobuf:"bytes,1,opt,name=namespace,proto3" json:"namespace,omitempty"` + Operations []*MutateOperation `protobuf:"bytes,2,rep,name=operations,proto3" json:"operations,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *MutateRequest) Reset() { + *x = MutateRequest{} + mi := &file_extention_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *MutateRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MutateRequest) ProtoMessage() {} + +func (x *MutateRequest) ProtoReflect() protoreflect.Message { + mi := &file_extention_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MutateRequest.ProtoReflect.Descriptor instead. +func (*MutateRequest) Descriptor() ([]byte, []int) { + return file_extention_proto_rawDescGZIP(), []int{0} +} + +func (x *MutateRequest) GetNamespace() string { + if x != nil { + return x.Namespace + } + return "" +} + +func (x *MutateRequest) GetOperations() []*MutateOperation { + if x != nil { + return x.Operations + } + return nil +} + +type MutateResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *MutateResponse) Reset() { + *x = MutateResponse{} + mi := &file_extention_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *MutateResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MutateResponse) ProtoMessage() {} + +func (x *MutateResponse) ProtoReflect() protoreflect.Message { + mi := &file_extention_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MutateResponse.ProtoReflect.Descriptor instead. +func (*MutateResponse) Descriptor() ([]byte, []int) { + return file_extention_proto_rawDescGZIP(), []int{1} +} + +type MutateOperation struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Types that are valid to be assigned to Operation: + // + // *MutateOperation_SetFolderParent + // *MutateOperation_DeleteFolder + // *MutateOperation_CreatePermission + // *MutateOperation_DeletePermission + Operation isMutateOperation_Operation `protobuf_oneof:"operation"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *MutateOperation) Reset() { + *x = MutateOperation{} + mi := &file_extention_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *MutateOperation) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MutateOperation) ProtoMessage() {} + +func (x *MutateOperation) ProtoReflect() protoreflect.Message { + mi := &file_extention_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MutateOperation.ProtoReflect.Descriptor instead. +func (*MutateOperation) Descriptor() ([]byte, []int) { + return file_extention_proto_rawDescGZIP(), []int{2} +} + +func (x *MutateOperation) GetOperation() isMutateOperation_Operation { + if x != nil { + return x.Operation + } + return nil +} + +func (x *MutateOperation) GetSetFolderParent() *SetFolderParentOperation { + if x != nil { + if x, ok := x.Operation.(*MutateOperation_SetFolderParent); ok { + return x.SetFolderParent + } + } + return nil +} + +func (x *MutateOperation) GetDeleteFolder() *DeleteFolderOperation { + if x != nil { + if x, ok := x.Operation.(*MutateOperation_DeleteFolder); ok { + return x.DeleteFolder + } + } + return nil +} + +func (x *MutateOperation) GetCreatePermission() *CreatePermissionOperation { + if x != nil { + if x, ok := x.Operation.(*MutateOperation_CreatePermission); ok { + return x.CreatePermission + } + } + return nil +} + +func (x *MutateOperation) GetDeletePermission() *DeletePermissionOperation { + if x != nil { + if x, ok := x.Operation.(*MutateOperation_DeletePermission); ok { + return x.DeletePermission + } + } + return nil +} + +type isMutateOperation_Operation interface { + isMutateOperation_Operation() +} + +type MutateOperation_SetFolderParent struct { + SetFolderParent *SetFolderParentOperation `protobuf:"bytes,1,opt,name=set_folder_parent,json=setFolderParent,proto3,oneof"` +} + +type MutateOperation_DeleteFolder struct { + DeleteFolder *DeleteFolderOperation `protobuf:"bytes,2,opt,name=delete_folder,json=deleteFolder,proto3,oneof"` +} + +type MutateOperation_CreatePermission struct { + CreatePermission *CreatePermissionOperation `protobuf:"bytes,3,opt,name=create_permission,json=createPermission,proto3,oneof"` +} + +type MutateOperation_DeletePermission struct { + DeletePermission *DeletePermissionOperation `protobuf:"bytes,4,opt,name=delete_permission,json=deletePermission,proto3,oneof"` +} + +func (*MutateOperation_SetFolderParent) isMutateOperation_Operation() {} + +func (*MutateOperation_DeleteFolder) isMutateOperation_Operation() {} + +func (*MutateOperation_CreatePermission) isMutateOperation_Operation() {} + +func (*MutateOperation_DeletePermission) isMutateOperation_Operation() {} + +type SetFolderParentOperation struct { + state protoimpl.MessageState `protogen:"open.v1"` + // UID of the folder + Folder string `protobuf:"bytes,1,opt,name=folder,proto3" json:"folder,omitempty"` + // UID of the parent folder + Parent string `protobuf:"bytes,2,opt,name=parent,proto3" json:"parent,omitempty"` + // If true, delete all existing parent relations associated with the folder + DeleteExisting bool `protobuf:"varint,3,opt,name=delete_existing,json=deleteExisting,proto3" json:"delete_existing,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SetFolderParentOperation) Reset() { + *x = SetFolderParentOperation{} + mi := &file_extention_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SetFolderParentOperation) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SetFolderParentOperation) ProtoMessage() {} + +func (x *SetFolderParentOperation) ProtoReflect() protoreflect.Message { + mi := &file_extention_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SetFolderParentOperation.ProtoReflect.Descriptor instead. +func (*SetFolderParentOperation) Descriptor() ([]byte, []int) { + return file_extention_proto_rawDescGZIP(), []int{3} +} + +func (x *SetFolderParentOperation) GetFolder() string { + if x != nil { + return x.Folder + } + return "" +} + +func (x *SetFolderParentOperation) GetParent() string { + if x != nil { + return x.Parent + } + return "" +} + +func (x *SetFolderParentOperation) GetDeleteExisting() bool { + if x != nil { + return x.DeleteExisting + } + return false +} + +type DeleteFolderOperation struct { + state protoimpl.MessageState `protogen:"open.v1"` + // UID of the folder to delete + Folder string `protobuf:"bytes,1,opt,name=folder,proto3" json:"folder,omitempty"` + // UID of the parent folder + Parent string `protobuf:"bytes,2,opt,name=parent,proto3" json:"parent,omitempty"` + // If true, delete all existing parent relations associated with the folder + DeleteExisting bool `protobuf:"varint,3,opt,name=delete_existing,json=deleteExisting,proto3" json:"delete_existing,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DeleteFolderOperation) Reset() { + *x = DeleteFolderOperation{} + mi := &file_extention_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DeleteFolderOperation) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteFolderOperation) ProtoMessage() {} + +func (x *DeleteFolderOperation) ProtoReflect() protoreflect.Message { + mi := &file_extention_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteFolderOperation.ProtoReflect.Descriptor instead. +func (*DeleteFolderOperation) Descriptor() ([]byte, []int) { + return file_extention_proto_rawDescGZIP(), []int{4} +} + +func (x *DeleteFolderOperation) GetFolder() string { + if x != nil { + return x.Folder + } + return "" +} + +func (x *DeleteFolderOperation) GetParent() string { + if x != nil { + return x.Parent + } + return "" +} + +func (x *DeleteFolderOperation) GetDeleteExisting() bool { + if x != nil { + return x.DeleteExisting + } + return false +} + +type CreatePermissionOperation struct { + state protoimpl.MessageState `protogen:"open.v1"` + Resource *Resource `protobuf:"bytes,1,opt,name=resource,proto3" json:"resource,omitempty"` + Permission *Permission `protobuf:"bytes,2,opt,name=permission,proto3" json:"permission,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CreatePermissionOperation) Reset() { + *x = CreatePermissionOperation{} + mi := &file_extention_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CreatePermissionOperation) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreatePermissionOperation) ProtoMessage() {} + +func (x *CreatePermissionOperation) ProtoReflect() protoreflect.Message { + mi := &file_extention_proto_msgTypes[5] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreatePermissionOperation.ProtoReflect.Descriptor instead. +func (*CreatePermissionOperation) Descriptor() ([]byte, []int) { + return file_extention_proto_rawDescGZIP(), []int{5} +} + +func (x *CreatePermissionOperation) GetResource() *Resource { + if x != nil { + return x.Resource + } + return nil +} + +func (x *CreatePermissionOperation) GetPermission() *Permission { + if x != nil { + return x.Permission + } + return nil +} + +type DeletePermissionOperation struct { + state protoimpl.MessageState `protogen:"open.v1"` + Resource *Resource `protobuf:"bytes,1,opt,name=resource,proto3" json:"resource,omitempty"` + Permission *Permission `protobuf:"bytes,2,opt,name=permission,proto3" json:"permission,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DeletePermissionOperation) Reset() { + *x = DeletePermissionOperation{} + mi := &file_extention_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DeletePermissionOperation) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeletePermissionOperation) ProtoMessage() {} + +func (x *DeletePermissionOperation) ProtoReflect() protoreflect.Message { + mi := &file_extention_proto_msgTypes[6] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeletePermissionOperation.ProtoReflect.Descriptor instead. +func (*DeletePermissionOperation) Descriptor() ([]byte, []int) { + return file_extention_proto_rawDescGZIP(), []int{6} +} + +func (x *DeletePermissionOperation) GetResource() *Resource { + if x != nil { + return x.Resource + } + return nil +} + +func (x *DeletePermissionOperation) GetPermission() *Permission { + if x != nil { + return x.Permission + } + return nil +} + +type Resource struct { + state protoimpl.MessageState `protogen:"open.v1"` + // group of the resource (e.g: "dashboard.grafana.app") + Group string `protobuf:"bytes,1,opt,name=group,proto3" json:"group,omitempty"` + // kind of the resource (e.g: "dashboards") + Resource string `protobuf:"bytes,2,opt,name=resource,proto3" json:"resource,omitempty"` + // uid of the resource + Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Resource) Reset() { + *x = Resource{} + mi := &file_extention_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Resource) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Resource) ProtoMessage() {} + +func (x *Resource) ProtoReflect() protoreflect.Message { + mi := &file_extention_proto_msgTypes[7] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Resource.ProtoReflect.Descriptor instead. +func (*Resource) Descriptor() ([]byte, []int) { + return file_extention_proto_rawDescGZIP(), []int{7} +} + +func (x *Resource) GetGroup() string { + if x != nil { + return x.Group + } + return "" +} + +func (x *Resource) GetResource() string { + if x != nil { + return x.Resource + } + return "" +} + +func (x *Resource) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +type Permission struct { + state protoimpl.MessageState `protogen:"open.v1"` + // kind of the identity getting the permission (e.g: "user", "team", "serviceaccount") + Kind string `protobuf:"bytes,1,opt,name=kind,proto3" json:"kind,omitempty"` + // uid of the identity getting the permission + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + // action set granted to the user (e.g. "admin" or "edit", "view") + Verb string `protobuf:"bytes,3,opt,name=verb,proto3" json:"verb,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Permission) Reset() { + *x = Permission{} + mi := &file_extention_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Permission) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Permission) ProtoMessage() {} + +func (x *Permission) ProtoReflect() protoreflect.Message { + mi := &file_extention_proto_msgTypes[8] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Permission.ProtoReflect.Descriptor instead. +func (*Permission) Descriptor() ([]byte, []int) { + return file_extention_proto_rawDescGZIP(), []int{8} +} + +func (x *Permission) GetKind() string { + if x != nil { + return x.Kind + } + return "" +} + +func (x *Permission) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *Permission) GetVerb() string { + if x != nil { + return x.Verb + } + return "" +} + type TupleKey struct { state protoimpl.MessageState `protogen:"open.v1"` User string `protobuf:"bytes,1,opt,name=user,proto3" json:"user,omitempty"` @@ -36,7 +594,7 @@ type TupleKey struct { func (x *TupleKey) Reset() { *x = TupleKey{} - mi := &file_extention_proto_msgTypes[0] + mi := &file_extention_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -48,7 +606,7 @@ func (x *TupleKey) String() string { func (*TupleKey) ProtoMessage() {} func (x *TupleKey) ProtoReflect() protoreflect.Message { - mi := &file_extention_proto_msgTypes[0] + mi := &file_extention_proto_msgTypes[9] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -61,7 +619,7 @@ func (x *TupleKey) ProtoReflect() protoreflect.Message { // Deprecated: Use TupleKey.ProtoReflect.Descriptor instead. func (*TupleKey) Descriptor() ([]byte, []int) { - return file_extention_proto_rawDescGZIP(), []int{0} + return file_extention_proto_rawDescGZIP(), []int{9} } func (x *TupleKey) GetUser() string { @@ -102,7 +660,7 @@ type Tuple struct { func (x *Tuple) Reset() { *x = Tuple{} - mi := &file_extention_proto_msgTypes[1] + mi := &file_extention_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -114,7 +672,7 @@ func (x *Tuple) String() string { func (*Tuple) ProtoMessage() {} func (x *Tuple) ProtoReflect() protoreflect.Message { - mi := &file_extention_proto_msgTypes[1] + mi := &file_extention_proto_msgTypes[10] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -127,7 +685,7 @@ func (x *Tuple) ProtoReflect() protoreflect.Message { // Deprecated: Use Tuple.ProtoReflect.Descriptor instead. func (*Tuple) Descriptor() ([]byte, []int) { - return file_extention_proto_rawDescGZIP(), []int{1} + return file_extention_proto_rawDescGZIP(), []int{10} } func (x *Tuple) GetKey() *TupleKey { @@ -155,7 +713,7 @@ type TupleKeyWithoutCondition struct { func (x *TupleKeyWithoutCondition) Reset() { *x = TupleKeyWithoutCondition{} - mi := &file_extention_proto_msgTypes[2] + mi := &file_extention_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -167,7 +725,7 @@ func (x *TupleKeyWithoutCondition) String() string { func (*TupleKeyWithoutCondition) ProtoMessage() {} func (x *TupleKeyWithoutCondition) ProtoReflect() protoreflect.Message { - mi := &file_extention_proto_msgTypes[2] + mi := &file_extention_proto_msgTypes[11] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -180,7 +738,7 @@ func (x *TupleKeyWithoutCondition) ProtoReflect() protoreflect.Message { // Deprecated: Use TupleKeyWithoutCondition.ProtoReflect.Descriptor instead. func (*TupleKeyWithoutCondition) Descriptor() ([]byte, []int) { - return file_extention_proto_rawDescGZIP(), []int{2} + return file_extention_proto_rawDescGZIP(), []int{11} } func (x *TupleKeyWithoutCondition) GetUser() string { @@ -214,7 +772,7 @@ type RelationshipCondition struct { func (x *RelationshipCondition) Reset() { *x = RelationshipCondition{} - mi := &file_extention_proto_msgTypes[3] + mi := &file_extention_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -226,7 +784,7 @@ func (x *RelationshipCondition) String() string { func (*RelationshipCondition) ProtoMessage() {} func (x *RelationshipCondition) ProtoReflect() protoreflect.Message { - mi := &file_extention_proto_msgTypes[3] + mi := &file_extention_proto_msgTypes[12] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -239,7 +797,7 @@ func (x *RelationshipCondition) ProtoReflect() protoreflect.Message { // Deprecated: Use RelationshipCondition.ProtoReflect.Descriptor instead. func (*RelationshipCondition) Descriptor() ([]byte, []int) { - return file_extention_proto_rawDescGZIP(), []int{3} + return file_extention_proto_rawDescGZIP(), []int{12} } func (x *RelationshipCondition) GetName() string { @@ -268,7 +826,7 @@ type ReadRequest struct { func (x *ReadRequest) Reset() { *x = ReadRequest{} - mi := &file_extention_proto_msgTypes[4] + mi := &file_extention_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -280,7 +838,7 @@ func (x *ReadRequest) String() string { func (*ReadRequest) ProtoMessage() {} func (x *ReadRequest) ProtoReflect() protoreflect.Message { - mi := &file_extention_proto_msgTypes[4] + mi := &file_extention_proto_msgTypes[13] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -293,7 +851,7 @@ func (x *ReadRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ReadRequest.ProtoReflect.Descriptor instead. func (*ReadRequest) Descriptor() ([]byte, []int) { - return file_extention_proto_rawDescGZIP(), []int{4} + return file_extention_proto_rawDescGZIP(), []int{13} } func (x *ReadRequest) GetNamespace() string { @@ -335,7 +893,7 @@ type ReadRequestTupleKey struct { func (x *ReadRequestTupleKey) Reset() { *x = ReadRequestTupleKey{} - mi := &file_extention_proto_msgTypes[5] + mi := &file_extention_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -347,7 +905,7 @@ func (x *ReadRequestTupleKey) String() string { func (*ReadRequestTupleKey) ProtoMessage() {} func (x *ReadRequestTupleKey) ProtoReflect() protoreflect.Message { - mi := &file_extention_proto_msgTypes[5] + mi := &file_extention_proto_msgTypes[14] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -360,7 +918,7 @@ func (x *ReadRequestTupleKey) ProtoReflect() protoreflect.Message { // Deprecated: Use ReadRequestTupleKey.ProtoReflect.Descriptor instead. func (*ReadRequestTupleKey) Descriptor() ([]byte, []int) { - return file_extention_proto_rawDescGZIP(), []int{5} + return file_extention_proto_rawDescGZIP(), []int{14} } func (x *ReadRequestTupleKey) GetUser() string { @@ -394,7 +952,7 @@ type ReadResponse struct { func (x *ReadResponse) Reset() { *x = ReadResponse{} - mi := &file_extention_proto_msgTypes[6] + mi := &file_extention_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -406,7 +964,7 @@ func (x *ReadResponse) String() string { func (*ReadResponse) ProtoMessage() {} func (x *ReadResponse) ProtoReflect() protoreflect.Message { - mi := &file_extention_proto_msgTypes[6] + mi := &file_extention_proto_msgTypes[15] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -419,7 +977,7 @@ func (x *ReadResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ReadResponse.ProtoReflect.Descriptor instead. func (*ReadResponse) Descriptor() ([]byte, []int) { - return file_extention_proto_rawDescGZIP(), []int{6} + return file_extention_proto_rawDescGZIP(), []int{15} } func (x *ReadResponse) GetTuples() []*Tuple { @@ -445,7 +1003,7 @@ type WriteRequestWrites struct { func (x *WriteRequestWrites) Reset() { *x = WriteRequestWrites{} - mi := &file_extention_proto_msgTypes[7] + mi := &file_extention_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -457,7 +1015,7 @@ func (x *WriteRequestWrites) String() string { func (*WriteRequestWrites) ProtoMessage() {} func (x *WriteRequestWrites) ProtoReflect() protoreflect.Message { - mi := &file_extention_proto_msgTypes[7] + mi := &file_extention_proto_msgTypes[16] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -470,7 +1028,7 @@ func (x *WriteRequestWrites) ProtoReflect() protoreflect.Message { // Deprecated: Use WriteRequestWrites.ProtoReflect.Descriptor instead. func (*WriteRequestWrites) Descriptor() ([]byte, []int) { - return file_extention_proto_rawDescGZIP(), []int{7} + return file_extention_proto_rawDescGZIP(), []int{16} } func (x *WriteRequestWrites) GetTupleKeys() []*TupleKey { @@ -489,7 +1047,7 @@ type WriteRequestDeletes struct { func (x *WriteRequestDeletes) Reset() { *x = WriteRequestDeletes{} - mi := &file_extention_proto_msgTypes[8] + mi := &file_extention_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -501,7 +1059,7 @@ func (x *WriteRequestDeletes) String() string { func (*WriteRequestDeletes) ProtoMessage() {} func (x *WriteRequestDeletes) ProtoReflect() protoreflect.Message { - mi := &file_extention_proto_msgTypes[8] + mi := &file_extention_proto_msgTypes[17] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -514,7 +1072,7 @@ func (x *WriteRequestDeletes) ProtoReflect() protoreflect.Message { // Deprecated: Use WriteRequestDeletes.ProtoReflect.Descriptor instead. func (*WriteRequestDeletes) Descriptor() ([]byte, []int) { - return file_extention_proto_rawDescGZIP(), []int{8} + return file_extention_proto_rawDescGZIP(), []int{17} } func (x *WriteRequestDeletes) GetTupleKeys() []*TupleKeyWithoutCondition { @@ -535,7 +1093,7 @@ type WriteRequest struct { func (x *WriteRequest) Reset() { *x = WriteRequest{} - mi := &file_extention_proto_msgTypes[9] + mi := &file_extention_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -547,7 +1105,7 @@ func (x *WriteRequest) String() string { func (*WriteRequest) ProtoMessage() {} func (x *WriteRequest) ProtoReflect() protoreflect.Message { - mi := &file_extention_proto_msgTypes[9] + mi := &file_extention_proto_msgTypes[18] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -560,7 +1118,7 @@ func (x *WriteRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use WriteRequest.ProtoReflect.Descriptor instead. func (*WriteRequest) Descriptor() ([]byte, []int) { - return file_extention_proto_rawDescGZIP(), []int{9} + return file_extention_proto_rawDescGZIP(), []int{18} } func (x *WriteRequest) GetNamespace() string { @@ -592,7 +1150,7 @@ type WriteResponse struct { func (x *WriteResponse) Reset() { *x = WriteResponse{} - mi := &file_extention_proto_msgTypes[10] + mi := &file_extention_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -604,7 +1162,7 @@ func (x *WriteResponse) String() string { func (*WriteResponse) ProtoMessage() {} func (x *WriteResponse) ProtoReflect() protoreflect.Message { - mi := &file_extention_proto_msgTypes[10] + mi := &file_extention_proto_msgTypes[19] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -617,7 +1175,7 @@ func (x *WriteResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use WriteResponse.ProtoReflect.Descriptor instead. func (*WriteResponse) Descriptor() ([]byte, []int) { - return file_extention_proto_rawDescGZIP(), []int{10} + return file_extention_proto_rawDescGZIP(), []int{19} } type BatchCheckRequest struct { @@ -631,7 +1189,7 @@ type BatchCheckRequest struct { func (x *BatchCheckRequest) Reset() { *x = BatchCheckRequest{} - mi := &file_extention_proto_msgTypes[11] + mi := &file_extention_proto_msgTypes[20] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -643,7 +1201,7 @@ func (x *BatchCheckRequest) String() string { func (*BatchCheckRequest) ProtoMessage() {} func (x *BatchCheckRequest) ProtoReflect() protoreflect.Message { - mi := &file_extention_proto_msgTypes[11] + mi := &file_extention_proto_msgTypes[20] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -656,7 +1214,7 @@ func (x *BatchCheckRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use BatchCheckRequest.ProtoReflect.Descriptor instead. func (*BatchCheckRequest) Descriptor() ([]byte, []int) { - return file_extention_proto_rawDescGZIP(), []int{11} + return file_extention_proto_rawDescGZIP(), []int{20} } func (x *BatchCheckRequest) GetSubject() string { @@ -694,7 +1252,7 @@ type BatchCheckItem struct { func (x *BatchCheckItem) Reset() { *x = BatchCheckItem{} - mi := &file_extention_proto_msgTypes[12] + mi := &file_extention_proto_msgTypes[21] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -706,7 +1264,7 @@ func (x *BatchCheckItem) String() string { func (*BatchCheckItem) ProtoMessage() {} func (x *BatchCheckItem) ProtoReflect() protoreflect.Message { - mi := &file_extention_proto_msgTypes[12] + mi := &file_extention_proto_msgTypes[21] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -719,7 +1277,7 @@ func (x *BatchCheckItem) ProtoReflect() protoreflect.Message { // Deprecated: Use BatchCheckItem.ProtoReflect.Descriptor instead. func (*BatchCheckItem) Descriptor() ([]byte, []int) { - return file_extention_proto_rawDescGZIP(), []int{12} + return file_extention_proto_rawDescGZIP(), []int{21} } func (x *BatchCheckItem) GetVerb() string { @@ -773,7 +1331,7 @@ type BatchCheckResponse struct { func (x *BatchCheckResponse) Reset() { *x = BatchCheckResponse{} - mi := &file_extention_proto_msgTypes[13] + mi := &file_extention_proto_msgTypes[22] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -785,7 +1343,7 @@ func (x *BatchCheckResponse) String() string { func (*BatchCheckResponse) ProtoMessage() {} func (x *BatchCheckResponse) ProtoReflect() protoreflect.Message { - mi := &file_extention_proto_msgTypes[13] + mi := &file_extention_proto_msgTypes[22] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -798,7 +1356,7 @@ func (x *BatchCheckResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use BatchCheckResponse.ProtoReflect.Descriptor instead. func (*BatchCheckResponse) Descriptor() ([]byte, []int) { - return file_extention_proto_rawDescGZIP(), []int{13} + return file_extention_proto_rawDescGZIP(), []int{22} } func (x *BatchCheckResponse) GetGroups() map[string]*BatchCheckGroupResource { @@ -817,7 +1375,7 @@ type BatchCheckGroupResource struct { func (x *BatchCheckGroupResource) Reset() { *x = BatchCheckGroupResource{} - mi := &file_extention_proto_msgTypes[14] + mi := &file_extention_proto_msgTypes[23] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -829,7 +1387,7 @@ func (x *BatchCheckGroupResource) String() string { func (*BatchCheckGroupResource) ProtoMessage() {} func (x *BatchCheckGroupResource) ProtoReflect() protoreflect.Message { - mi := &file_extention_proto_msgTypes[14] + mi := &file_extention_proto_msgTypes[23] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -842,7 +1400,7 @@ func (x *BatchCheckGroupResource) ProtoReflect() protoreflect.Message { // Deprecated: Use BatchCheckGroupResource.ProtoReflect.Descriptor instead. func (*BatchCheckGroupResource) Descriptor() ([]byte, []int) { - return file_extention_proto_rawDescGZIP(), []int{14} + return file_extention_proto_rawDescGZIP(), []int{23} } func (x *BatchCheckGroupResource) GetItems() map[string]bool { @@ -863,150 +1421,231 @@ var file_extention_proto_rawDesc = string([]byte{ 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x73, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x9b, 0x01, 0x0a, 0x08, 0x54, 0x75, 0x70, 0x6c, 0x65, 0x4b, 0x65, + 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x72, 0x0a, 0x0d, 0x4d, 0x75, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, + 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, + 0x61, 0x63, 0x65, 0x12, 0x43, 0x0a, 0x0a, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x7a, 0x2e, + 0x65, 0x78, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x75, 0x74, + 0x61, 0x74, 0x65, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x6f, 0x70, + 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x10, 0x0a, 0x0e, 0x4d, 0x75, 0x74, 0x61, + 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x88, 0x03, 0x0a, 0x0f, 0x4d, + 0x75, 0x74, 0x61, 0x74, 0x65, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x5a, + 0x0a, 0x11, 0x73, 0x65, 0x74, 0x5f, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x5f, 0x70, 0x61, 0x72, + 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x61, 0x75, 0x74, 0x68, + 0x7a, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x53, + 0x65, 0x74, 0x46, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x4f, 0x70, + 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x0f, 0x73, 0x65, 0x74, 0x46, 0x6f, + 0x6c, 0x64, 0x65, 0x72, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x12, 0x50, 0x0a, 0x0d, 0x64, 0x65, + 0x6c, 0x65, 0x74, 0x65, 0x5f, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x29, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x7a, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x74, + 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x46, 0x6f, 0x6c, + 0x64, 0x65, 0x72, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x0c, + 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x46, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x12, 0x5c, 0x0a, 0x11, + 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, + 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x7a, 0x2e, + 0x65, 0x78, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x4f, 0x70, 0x65, + 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x10, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x5c, 0x0a, 0x11, 0x64, 0x65, + 0x6c, 0x65, 0x74, 0x65, 0x5f, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x7a, 0x2e, 0x65, 0x78, + 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, + 0x65, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x4f, 0x70, 0x65, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x10, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x65, + 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x42, 0x0b, 0x0a, 0x09, 0x6f, 0x70, 0x65, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x73, 0x0a, 0x18, 0x53, 0x65, 0x74, 0x46, 0x6f, 0x6c, 0x64, + 0x65, 0x72, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x06, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x61, 0x72, + 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, + 0x74, 0x12, 0x27, 0x0a, 0x0f, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x5f, 0x65, 0x78, 0x69, 0x73, + 0x74, 0x69, 0x6e, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x64, 0x65, 0x6c, 0x65, + 0x74, 0x65, 0x45, 0x78, 0x69, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x22, 0x70, 0x0a, 0x15, 0x44, 0x65, + 0x6c, 0x65, 0x74, 0x65, 0x46, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x06, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x70, + 0x61, 0x72, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x61, 0x72, + 0x65, 0x6e, 0x74, 0x12, 0x27, 0x0a, 0x0f, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x5f, 0x65, 0x78, + 0x69, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x64, 0x65, + 0x6c, 0x65, 0x74, 0x65, 0x45, 0x78, 0x69, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x22, 0x95, 0x01, 0x0a, + 0x19, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, + 0x6e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x38, 0x0a, 0x08, 0x72, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x61, + 0x75, 0x74, 0x68, 0x7a, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, + 0x31, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x08, 0x72, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x12, 0x3e, 0x0a, 0x0a, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, + 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x7a, + 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x65, + 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, + 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x95, 0x01, 0x0a, 0x19, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, + 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x12, 0x38, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x7a, 0x2e, 0x65, 0x78, 0x74, + 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x52, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x3e, 0x0a, 0x0a, + 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1e, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x7a, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x74, 0x69, + 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, + 0x52, 0x0a, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x50, 0x0a, 0x08, + 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x67, 0x72, 0x6f, 0x75, + 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x1a, + 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, + 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x48, + 0x0a, 0x0a, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, + 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6b, 0x69, 0x6e, 0x64, + 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x76, 0x65, 0x72, 0x62, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x76, 0x65, 0x72, 0x62, 0x22, 0x9b, 0x01, 0x0a, 0x08, 0x54, 0x75, 0x70, + 0x6c, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x6c, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x6c, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x47, 0x0a, + 0x09, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x29, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x7a, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x74, 0x69, + 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x68, + 0x69, 0x70, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x09, 0x63, 0x6f, 0x6e, + 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x71, 0x0a, 0x05, 0x54, 0x75, 0x70, 0x6c, 0x65, 0x12, + 0x2e, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x61, + 0x75, 0x74, 0x68, 0x7a, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, + 0x31, 0x2e, 0x54, 0x75, 0x70, 0x6c, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, + 0x38, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, + 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0x62, 0x0a, 0x18, 0x54, 0x75, 0x70, + 0x6c, 0x65, 0x4b, 0x65, 0x79, 0x57, 0x69, 0x74, 0x68, 0x6f, 0x75, 0x74, 0x43, 0x6f, 0x6e, 0x64, + 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x6c, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x6c, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x22, 0x5e, 0x0a, + 0x15, 0x52, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x68, 0x69, 0x70, 0x43, 0x6f, 0x6e, + 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x31, 0x0a, 0x07, 0x63, 0x6f, + 0x6e, 0x74, 0x65, 0x78, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, + 0x72, 0x75, 0x63, 0x74, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x22, 0xda, 0x01, + 0x0a, 0x0b, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, + 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x44, 0x0a, 0x09, 0x74, + 0x75, 0x70, 0x6c, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, + 0x2e, 0x61, 0x75, 0x74, 0x68, 0x7a, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, + 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, + 0x75, 0x70, 0x6c, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x08, 0x74, 0x75, 0x70, 0x6c, 0x65, 0x4b, 0x65, + 0x79, 0x12, 0x38, 0x0a, 0x09, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, + 0x65, 0x52, 0x08, 0x70, 0x61, 0x67, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x2d, 0x0a, 0x12, 0x63, + 0x6f, 0x6e, 0x74, 0x69, 0x6e, 0x75, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x6f, 0x6b, 0x65, + 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x63, 0x6f, 0x6e, 0x74, 0x69, 0x6e, 0x75, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x5d, 0x0a, 0x13, 0x52, 0x65, + 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x75, 0x70, 0x6c, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x47, 0x0a, 0x09, 0x63, 0x6f, 0x6e, - 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x61, - 0x75, 0x74, 0x68, 0x7a, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, - 0x31, 0x2e, 0x52, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x68, 0x69, 0x70, 0x43, 0x6f, - 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, - 0x6f, 0x6e, 0x22, 0x71, 0x0a, 0x05, 0x54, 0x75, 0x70, 0x6c, 0x65, 0x12, 0x2e, 0x0a, 0x03, 0x6b, - 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x7a, - 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x75, - 0x70, 0x6c, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x38, 0x0a, 0x09, 0x74, - 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, - 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, - 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, - 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0x62, 0x0a, 0x18, 0x54, 0x75, 0x70, 0x6c, 0x65, 0x4b, 0x65, - 0x79, 0x57, 0x69, 0x74, 0x68, 0x6f, 0x75, 0x74, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, - 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x04, 0x75, 0x73, 0x65, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x22, 0x5e, 0x0a, 0x15, 0x52, 0x65, 0x6c, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x68, 0x69, 0x70, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, - 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x31, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, - 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, - 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x22, 0xda, 0x01, 0x0a, 0x0b, 0x52, 0x65, - 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, - 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, - 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x44, 0x0a, 0x09, 0x74, 0x75, 0x70, 0x6c, 0x65, - 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x61, 0x75, 0x74, + 0x09, 0x52, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x22, 0x70, 0x0a, 0x0c, 0x52, 0x65, 0x61, + 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x31, 0x0a, 0x06, 0x74, 0x75, 0x70, + 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x61, 0x75, 0x74, 0x68, + 0x7a, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x54, + 0x75, 0x70, 0x6c, 0x65, 0x52, 0x06, 0x74, 0x75, 0x70, 0x6c, 0x65, 0x73, 0x12, 0x2d, 0x0a, 0x12, + 0x63, 0x6f, 0x6e, 0x74, 0x69, 0x6e, 0x75, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x6f, 0x6b, + 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x63, 0x6f, 0x6e, 0x74, 0x69, 0x6e, + 0x75, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x51, 0x0a, 0x12, 0x57, + 0x72, 0x69, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x57, 0x72, 0x69, 0x74, 0x65, + 0x73, 0x12, 0x3b, 0x0a, 0x0a, 0x74, 0x75, 0x70, 0x6c, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x73, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x7a, 0x2e, 0x65, 0x78, + 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x75, 0x70, 0x6c, 0x65, + 0x4b, 0x65, 0x79, 0x52, 0x09, 0x74, 0x75, 0x70, 0x6c, 0x65, 0x4b, 0x65, 0x79, 0x73, 0x22, 0x62, + 0x0a, 0x13, 0x57, 0x72, 0x69, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x44, 0x65, + 0x6c, 0x65, 0x74, 0x65, 0x73, 0x12, 0x4b, 0x0a, 0x0a, 0x74, 0x75, 0x70, 0x6c, 0x65, 0x5f, 0x6b, + 0x65, 0x79, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x61, 0x75, 0x74, 0x68, + 0x7a, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x54, + 0x75, 0x70, 0x6c, 0x65, 0x4b, 0x65, 0x79, 0x57, 0x69, 0x74, 0x68, 0x6f, 0x75, 0x74, 0x43, 0x6f, + 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x09, 0x74, 0x75, 0x70, 0x6c, 0x65, 0x4b, 0x65, + 0x79, 0x73, 0x22, 0xaf, 0x01, 0x0a, 0x0c, 0x57, 0x72, 0x69, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, + 0x65, 0x12, 0x3e, 0x0a, 0x06, 0x77, 0x72, 0x69, 0x74, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x26, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x7a, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x74, + 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x72, 0x69, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x57, 0x72, 0x69, 0x74, 0x65, 0x73, 0x52, 0x06, 0x77, 0x72, 0x69, 0x74, 0x65, + 0x73, 0x12, 0x41, 0x0a, 0x07, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x7a, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, + 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x72, 0x69, 0x74, 0x65, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x73, 0x52, 0x07, 0x64, 0x65, 0x6c, + 0x65, 0x74, 0x65, 0x73, 0x22, 0x0f, 0x0a, 0x0d, 0x57, 0x72, 0x69, 0x74, 0x65, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x85, 0x01, 0x0a, 0x11, 0x42, 0x61, 0x74, 0x63, 0x68, 0x43, + 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x73, + 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x75, + 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, + 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, + 0x61, 0x63, 0x65, 0x12, 0x38, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x03, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x7a, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, + 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x43, 0x68, 0x65, + 0x63, 0x6b, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x22, 0xa4, 0x01, + 0x0a, 0x0e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x49, 0x74, 0x65, 0x6d, + 0x12, 0x12, 0x0a, 0x04, 0x76, 0x65, 0x72, 0x62, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x76, 0x65, 0x72, 0x62, 0x12, 0x14, 0x0a, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x73, 0x75, + 0x62, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0b, 0x73, 0x75, 0x62, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x16, 0x0a, 0x06, + 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x66, 0x6f, + 0x6c, 0x64, 0x65, 0x72, 0x22, 0xc8, 0x01, 0x0a, 0x12, 0x42, 0x61, 0x74, 0x63, 0x68, 0x43, 0x68, + 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4a, 0x0a, 0x06, 0x67, + 0x72, 0x6f, 0x75, 0x70, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x61, 0x75, + 0x74, 0x68, 0x7a, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, + 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, + 0x06, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x1a, 0x66, 0x0a, 0x0b, 0x47, 0x72, 0x6f, 0x75, 0x70, + 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x41, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x7a, 0x2e, + 0x65, 0x78, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x61, 0x74, + 0x63, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, + 0xa1, 0x01, 0x0a, 0x17, 0x42, 0x61, 0x74, 0x63, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x47, 0x72, + 0x6f, 0x75, 0x70, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x4c, 0x0a, 0x05, 0x69, + 0x74, 0x65, 0x6d, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x7a, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, - 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x75, 0x70, 0x6c, 0x65, - 0x4b, 0x65, 0x79, 0x52, 0x08, 0x74, 0x75, 0x70, 0x6c, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x38, 0x0a, - 0x09, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x1b, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, - 0x75, 0x66, 0x2e, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x08, 0x70, - 0x61, 0x67, 0x65, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x2d, 0x0a, 0x12, 0x63, 0x6f, 0x6e, 0x74, 0x69, - 0x6e, 0x75, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x11, 0x63, 0x6f, 0x6e, 0x74, 0x69, 0x6e, 0x75, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x5d, 0x0a, 0x13, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x75, 0x70, 0x6c, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x12, 0x0a, - 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, 0x73, 0x65, - 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, - 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6f, - 0x62, 0x6a, 0x65, 0x63, 0x74, 0x22, 0x70, 0x0a, 0x0c, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x31, 0x0a, 0x06, 0x74, 0x75, 0x70, 0x6c, 0x65, 0x73, 0x18, - 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x7a, 0x2e, 0x65, 0x78, - 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x75, 0x70, 0x6c, 0x65, - 0x52, 0x06, 0x74, 0x75, 0x70, 0x6c, 0x65, 0x73, 0x12, 0x2d, 0x0a, 0x12, 0x63, 0x6f, 0x6e, 0x74, - 0x69, 0x6e, 0x75, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x63, 0x6f, 0x6e, 0x74, 0x69, 0x6e, 0x75, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x51, 0x0a, 0x12, 0x57, 0x72, 0x69, 0x74, 0x65, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x57, 0x72, 0x69, 0x74, 0x65, 0x73, 0x12, 0x3b, 0x0a, - 0x0a, 0x74, 0x75, 0x70, 0x6c, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x1c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x7a, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x74, - 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x75, 0x70, 0x6c, 0x65, 0x4b, 0x65, 0x79, 0x52, - 0x09, 0x74, 0x75, 0x70, 0x6c, 0x65, 0x4b, 0x65, 0x79, 0x73, 0x22, 0x62, 0x0a, 0x13, 0x57, 0x72, - 0x69, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, - 0x73, 0x12, 0x4b, 0x0a, 0x0a, 0x74, 0x75, 0x70, 0x6c, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x73, 0x18, - 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x7a, 0x2e, 0x65, 0x78, - 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x75, 0x70, 0x6c, 0x65, - 0x4b, 0x65, 0x79, 0x57, 0x69, 0x74, 0x68, 0x6f, 0x75, 0x74, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, - 0x69, 0x6f, 0x6e, 0x52, 0x09, 0x74, 0x75, 0x70, 0x6c, 0x65, 0x4b, 0x65, 0x79, 0x73, 0x22, 0xaf, - 0x01, 0x0a, 0x0c, 0x57, 0x72, 0x69, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, - 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x3e, 0x0a, - 0x06, 0x77, 0x72, 0x69, 0x74, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, - 0x61, 0x75, 0x74, 0x68, 0x7a, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x2e, - 0x76, 0x31, 0x2e, 0x57, 0x72, 0x69, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x57, - 0x72, 0x69, 0x74, 0x65, 0x73, 0x52, 0x06, 0x77, 0x72, 0x69, 0x74, 0x65, 0x73, 0x12, 0x41, 0x0a, - 0x07, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, + 0x42, 0x61, 0x74, 0x63, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x45, 0x6e, 0x74, + 0x72, 0x79, 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x1a, 0x38, 0x0a, 0x0a, 0x49, 0x74, 0x65, + 0x6d, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, + 0x02, 0x38, 0x01, 0x32, 0xde, 0x02, 0x0a, 0x15, 0x41, 0x75, 0x74, 0x68, 0x7a, 0x45, 0x78, 0x74, + 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x5b, 0x0a, + 0x0a, 0x42, 0x61, 0x74, 0x63, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x12, 0x25, 0x2e, 0x61, 0x75, + 0x74, 0x68, 0x7a, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, + 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x7a, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, + 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x43, 0x68, 0x65, + 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x49, 0x0a, 0x04, 0x52, 0x65, + 0x61, 0x64, 0x12, 0x1f, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x7a, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, + 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x7a, 0x2e, 0x65, 0x78, 0x74, 0x65, + 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4c, 0x0a, 0x05, 0x57, 0x72, 0x69, 0x74, 0x65, 0x12, 0x20, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x7a, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x72, 0x69, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x73, 0x52, 0x07, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x73, - 0x22, 0x0f, 0x0a, 0x0d, 0x57, 0x72, 0x69, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x22, 0x85, 0x01, 0x0a, 0x11, 0x42, 0x61, 0x74, 0x63, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, - 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, - 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, - 0x38, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, - 0x2e, 0x61, 0x75, 0x74, 0x68, 0x7a, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, - 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x49, 0x74, - 0x65, 0x6d, 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x22, 0xa4, 0x01, 0x0a, 0x0e, 0x42, 0x61, - 0x74, 0x63, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x12, 0x0a, 0x04, - 0x76, 0x65, 0x72, 0x62, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x76, 0x65, 0x72, 0x62, - 0x12, 0x14, 0x0a, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x73, 0x75, 0x62, 0x72, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x75, 0x62, - 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x6f, 0x6c, 0x64, - 0x65, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, - 0x22, 0xc8, 0x01, 0x0a, 0x12, 0x42, 0x61, 0x74, 0x63, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4a, 0x0a, 0x06, 0x67, 0x72, 0x6f, 0x75, 0x70, - 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x7a, 0x2e, - 0x65, 0x78, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x61, 0x74, - 0x63, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, - 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x06, 0x67, 0x72, 0x6f, - 0x75, 0x70, 0x73, 0x1a, 0x66, 0x0a, 0x0b, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x45, 0x6e, 0x74, - 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x03, 0x6b, 0x65, 0x79, 0x12, 0x41, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x7a, 0x2e, 0x65, 0x78, 0x74, 0x65, - 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x43, 0x68, - 0x65, 0x63, 0x6b, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xa1, 0x01, 0x0a, 0x17, - 0x42, 0x61, 0x74, 0x63, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x4c, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, - 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x7a, 0x2e, 0x65, - 0x78, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x61, 0x74, 0x63, - 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x2e, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, - 0x69, 0x74, 0x65, 0x6d, 0x73, 0x1a, 0x38, 0x0a, 0x0a, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x45, 0x6e, - 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x32, - 0x8d, 0x02, 0x0a, 0x15, 0x41, 0x75, 0x74, 0x68, 0x7a, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x74, 0x69, - 0x6f, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x5b, 0x0a, 0x0a, 0x42, 0x61, 0x74, - 0x63, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x12, 0x25, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x7a, 0x2e, - 0x65, 0x78, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x61, 0x74, - 0x63, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, - 0x2e, 0x61, 0x75, 0x74, 0x68, 0x7a, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, - 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x49, 0x0a, 0x04, 0x52, 0x65, 0x61, 0x64, 0x12, 0x1f, - 0x2e, 0x61, 0x75, 0x74, 0x68, 0x7a, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, - 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x20, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x7a, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, - 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x4c, 0x0a, 0x05, 0x57, 0x72, 0x69, 0x74, 0x65, 0x12, 0x20, 0x2e, 0x61, 0x75, 0x74, - 0x68, 0x7a, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, - 0x57, 0x72, 0x69, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x61, - 0x75, 0x74, 0x68, 0x7a, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, - 0x31, 0x2e, 0x57, 0x72, 0x69, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, - 0x38, 0x5a, 0x36, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x72, - 0x61, 0x66, 0x61, 0x6e, 0x61, 0x2f, 0x67, 0x72, 0x61, 0x66, 0x61, 0x6e, 0x61, 0x2f, 0x70, 0x6b, - 0x67, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x61, 0x75, 0x74, 0x68, 0x7a, - 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x33, + 0x1a, 0x21, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x7a, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x74, 0x69, + 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x72, 0x69, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x4f, 0x0a, 0x06, 0x4d, 0x75, 0x74, 0x61, 0x74, 0x65, 0x12, 0x21, 0x2e, + 0x61, 0x75, 0x74, 0x68, 0x7a, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x2e, + 0x76, 0x31, 0x2e, 0x4d, 0x75, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x22, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x7a, 0x2e, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x74, 0x69, + 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x75, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x38, 0x5a, 0x36, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x67, 0x72, 0x61, 0x66, 0x61, 0x6e, 0x61, 0x2f, 0x67, 0x72, 0x61, 0x66, 0x61, + 0x6e, 0x61, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, + 0x61, 0x75, 0x74, 0x68, 0x7a, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x76, 0x31, 0x62, 0x06, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, }) var ( @@ -1021,56 +1660,76 @@ func file_extention_proto_rawDescGZIP() []byte { return file_extention_proto_rawDescData } -var file_extention_proto_msgTypes = make([]protoimpl.MessageInfo, 17) +var file_extention_proto_msgTypes = make([]protoimpl.MessageInfo, 26) var file_extention_proto_goTypes = []any{ - (*TupleKey)(nil), // 0: authz.extention.v1.TupleKey - (*Tuple)(nil), // 1: authz.extention.v1.Tuple - (*TupleKeyWithoutCondition)(nil), // 2: authz.extention.v1.TupleKeyWithoutCondition - (*RelationshipCondition)(nil), // 3: authz.extention.v1.RelationshipCondition - (*ReadRequest)(nil), // 4: authz.extention.v1.ReadRequest - (*ReadRequestTupleKey)(nil), // 5: authz.extention.v1.ReadRequestTupleKey - (*ReadResponse)(nil), // 6: authz.extention.v1.ReadResponse - (*WriteRequestWrites)(nil), // 7: authz.extention.v1.WriteRequestWrites - (*WriteRequestDeletes)(nil), // 8: authz.extention.v1.WriteRequestDeletes - (*WriteRequest)(nil), // 9: authz.extention.v1.WriteRequest - (*WriteResponse)(nil), // 10: authz.extention.v1.WriteResponse - (*BatchCheckRequest)(nil), // 11: authz.extention.v1.BatchCheckRequest - (*BatchCheckItem)(nil), // 12: authz.extention.v1.BatchCheckItem - (*BatchCheckResponse)(nil), // 13: authz.extention.v1.BatchCheckResponse - (*BatchCheckGroupResource)(nil), // 14: authz.extention.v1.BatchCheckGroupResource - nil, // 15: authz.extention.v1.BatchCheckResponse.GroupsEntry - nil, // 16: authz.extention.v1.BatchCheckGroupResource.ItemsEntry - (*timestamppb.Timestamp)(nil), // 17: google.protobuf.Timestamp - (*structpb.Struct)(nil), // 18: google.protobuf.Struct - (*wrapperspb.Int32Value)(nil), // 19: google.protobuf.Int32Value + (*MutateRequest)(nil), // 0: authz.extention.v1.MutateRequest + (*MutateResponse)(nil), // 1: authz.extention.v1.MutateResponse + (*MutateOperation)(nil), // 2: authz.extention.v1.MutateOperation + (*SetFolderParentOperation)(nil), // 3: authz.extention.v1.SetFolderParentOperation + (*DeleteFolderOperation)(nil), // 4: authz.extention.v1.DeleteFolderOperation + (*CreatePermissionOperation)(nil), // 5: authz.extention.v1.CreatePermissionOperation + (*DeletePermissionOperation)(nil), // 6: authz.extention.v1.DeletePermissionOperation + (*Resource)(nil), // 7: authz.extention.v1.Resource + (*Permission)(nil), // 8: authz.extention.v1.Permission + (*TupleKey)(nil), // 9: authz.extention.v1.TupleKey + (*Tuple)(nil), // 10: authz.extention.v1.Tuple + (*TupleKeyWithoutCondition)(nil), // 11: authz.extention.v1.TupleKeyWithoutCondition + (*RelationshipCondition)(nil), // 12: authz.extention.v1.RelationshipCondition + (*ReadRequest)(nil), // 13: authz.extention.v1.ReadRequest + (*ReadRequestTupleKey)(nil), // 14: authz.extention.v1.ReadRequestTupleKey + (*ReadResponse)(nil), // 15: authz.extention.v1.ReadResponse + (*WriteRequestWrites)(nil), // 16: authz.extention.v1.WriteRequestWrites + (*WriteRequestDeletes)(nil), // 17: authz.extention.v1.WriteRequestDeletes + (*WriteRequest)(nil), // 18: authz.extention.v1.WriteRequest + (*WriteResponse)(nil), // 19: authz.extention.v1.WriteResponse + (*BatchCheckRequest)(nil), // 20: authz.extention.v1.BatchCheckRequest + (*BatchCheckItem)(nil), // 21: authz.extention.v1.BatchCheckItem + (*BatchCheckResponse)(nil), // 22: authz.extention.v1.BatchCheckResponse + (*BatchCheckGroupResource)(nil), // 23: authz.extention.v1.BatchCheckGroupResource + nil, // 24: authz.extention.v1.BatchCheckResponse.GroupsEntry + nil, // 25: authz.extention.v1.BatchCheckGroupResource.ItemsEntry + (*timestamppb.Timestamp)(nil), // 26: google.protobuf.Timestamp + (*structpb.Struct)(nil), // 27: google.protobuf.Struct + (*wrapperspb.Int32Value)(nil), // 28: google.protobuf.Int32Value } var file_extention_proto_depIdxs = []int32{ - 3, // 0: authz.extention.v1.TupleKey.condition:type_name -> authz.extention.v1.RelationshipCondition - 0, // 1: authz.extention.v1.Tuple.key:type_name -> authz.extention.v1.TupleKey - 17, // 2: authz.extention.v1.Tuple.timestamp:type_name -> google.protobuf.Timestamp - 18, // 3: authz.extention.v1.RelationshipCondition.context:type_name -> google.protobuf.Struct - 5, // 4: authz.extention.v1.ReadRequest.tuple_key:type_name -> authz.extention.v1.ReadRequestTupleKey - 19, // 5: authz.extention.v1.ReadRequest.page_size:type_name -> google.protobuf.Int32Value - 1, // 6: authz.extention.v1.ReadResponse.tuples:type_name -> authz.extention.v1.Tuple - 0, // 7: authz.extention.v1.WriteRequestWrites.tuple_keys:type_name -> authz.extention.v1.TupleKey - 2, // 8: authz.extention.v1.WriteRequestDeletes.tuple_keys:type_name -> authz.extention.v1.TupleKeyWithoutCondition - 7, // 9: authz.extention.v1.WriteRequest.writes:type_name -> authz.extention.v1.WriteRequestWrites - 8, // 10: authz.extention.v1.WriteRequest.deletes:type_name -> authz.extention.v1.WriteRequestDeletes - 12, // 11: authz.extention.v1.BatchCheckRequest.items:type_name -> authz.extention.v1.BatchCheckItem - 15, // 12: authz.extention.v1.BatchCheckResponse.groups:type_name -> authz.extention.v1.BatchCheckResponse.GroupsEntry - 16, // 13: authz.extention.v1.BatchCheckGroupResource.items:type_name -> authz.extention.v1.BatchCheckGroupResource.ItemsEntry - 14, // 14: authz.extention.v1.BatchCheckResponse.GroupsEntry.value:type_name -> authz.extention.v1.BatchCheckGroupResource - 11, // 15: authz.extention.v1.AuthzExtentionService.BatchCheck:input_type -> authz.extention.v1.BatchCheckRequest - 4, // 16: authz.extention.v1.AuthzExtentionService.Read:input_type -> authz.extention.v1.ReadRequest - 9, // 17: authz.extention.v1.AuthzExtentionService.Write:input_type -> authz.extention.v1.WriteRequest - 13, // 18: authz.extention.v1.AuthzExtentionService.BatchCheck:output_type -> authz.extention.v1.BatchCheckResponse - 6, // 19: authz.extention.v1.AuthzExtentionService.Read:output_type -> authz.extention.v1.ReadResponse - 10, // 20: authz.extention.v1.AuthzExtentionService.Write:output_type -> authz.extention.v1.WriteResponse - 18, // [18:21] is the sub-list for method output_type - 15, // [15:18] is the sub-list for method input_type - 15, // [15:15] is the sub-list for extension type_name - 15, // [15:15] is the sub-list for extension extendee - 0, // [0:15] is the sub-list for field type_name + 2, // 0: authz.extention.v1.MutateRequest.operations:type_name -> authz.extention.v1.MutateOperation + 3, // 1: authz.extention.v1.MutateOperation.set_folder_parent:type_name -> authz.extention.v1.SetFolderParentOperation + 4, // 2: authz.extention.v1.MutateOperation.delete_folder:type_name -> authz.extention.v1.DeleteFolderOperation + 5, // 3: authz.extention.v1.MutateOperation.create_permission:type_name -> authz.extention.v1.CreatePermissionOperation + 6, // 4: authz.extention.v1.MutateOperation.delete_permission:type_name -> authz.extention.v1.DeletePermissionOperation + 7, // 5: authz.extention.v1.CreatePermissionOperation.resource:type_name -> authz.extention.v1.Resource + 8, // 6: authz.extention.v1.CreatePermissionOperation.permission:type_name -> authz.extention.v1.Permission + 7, // 7: authz.extention.v1.DeletePermissionOperation.resource:type_name -> authz.extention.v1.Resource + 8, // 8: authz.extention.v1.DeletePermissionOperation.permission:type_name -> authz.extention.v1.Permission + 12, // 9: authz.extention.v1.TupleKey.condition:type_name -> authz.extention.v1.RelationshipCondition + 9, // 10: authz.extention.v1.Tuple.key:type_name -> authz.extention.v1.TupleKey + 26, // 11: authz.extention.v1.Tuple.timestamp:type_name -> google.protobuf.Timestamp + 27, // 12: authz.extention.v1.RelationshipCondition.context:type_name -> google.protobuf.Struct + 14, // 13: authz.extention.v1.ReadRequest.tuple_key:type_name -> authz.extention.v1.ReadRequestTupleKey + 28, // 14: authz.extention.v1.ReadRequest.page_size:type_name -> google.protobuf.Int32Value + 10, // 15: authz.extention.v1.ReadResponse.tuples:type_name -> authz.extention.v1.Tuple + 9, // 16: authz.extention.v1.WriteRequestWrites.tuple_keys:type_name -> authz.extention.v1.TupleKey + 11, // 17: authz.extention.v1.WriteRequestDeletes.tuple_keys:type_name -> authz.extention.v1.TupleKeyWithoutCondition + 16, // 18: authz.extention.v1.WriteRequest.writes:type_name -> authz.extention.v1.WriteRequestWrites + 17, // 19: authz.extention.v1.WriteRequest.deletes:type_name -> authz.extention.v1.WriteRequestDeletes + 21, // 20: authz.extention.v1.BatchCheckRequest.items:type_name -> authz.extention.v1.BatchCheckItem + 24, // 21: authz.extention.v1.BatchCheckResponse.groups:type_name -> authz.extention.v1.BatchCheckResponse.GroupsEntry + 25, // 22: authz.extention.v1.BatchCheckGroupResource.items:type_name -> authz.extention.v1.BatchCheckGroupResource.ItemsEntry + 23, // 23: authz.extention.v1.BatchCheckResponse.GroupsEntry.value:type_name -> authz.extention.v1.BatchCheckGroupResource + 20, // 24: authz.extention.v1.AuthzExtentionService.BatchCheck:input_type -> authz.extention.v1.BatchCheckRequest + 13, // 25: authz.extention.v1.AuthzExtentionService.Read:input_type -> authz.extention.v1.ReadRequest + 18, // 26: authz.extention.v1.AuthzExtentionService.Write:input_type -> authz.extention.v1.WriteRequest + 0, // 27: authz.extention.v1.AuthzExtentionService.Mutate:input_type -> authz.extention.v1.MutateRequest + 22, // 28: authz.extention.v1.AuthzExtentionService.BatchCheck:output_type -> authz.extention.v1.BatchCheckResponse + 15, // 29: authz.extention.v1.AuthzExtentionService.Read:output_type -> authz.extention.v1.ReadResponse + 19, // 30: authz.extention.v1.AuthzExtentionService.Write:output_type -> authz.extention.v1.WriteResponse + 1, // 31: authz.extention.v1.AuthzExtentionService.Mutate:output_type -> authz.extention.v1.MutateResponse + 28, // [28:32] is the sub-list for method output_type + 24, // [24:28] is the sub-list for method input_type + 24, // [24:24] is the sub-list for extension type_name + 24, // [24:24] is the sub-list for extension extendee + 0, // [0:24] is the sub-list for field type_name } func init() { file_extention_proto_init() } @@ -1078,13 +1737,19 @@ func file_extention_proto_init() { if File_extention_proto != nil { return } + file_extention_proto_msgTypes[2].OneofWrappers = []any{ + (*MutateOperation_SetFolderParent)(nil), + (*MutateOperation_DeleteFolder)(nil), + (*MutateOperation_CreatePermission)(nil), + (*MutateOperation_DeletePermission)(nil), + } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_extention_proto_rawDesc), len(file_extention_proto_rawDesc)), NumEnums: 0, - NumMessages: 17, + NumMessages: 26, NumExtensions: 0, NumServices: 1, }, diff --git a/pkg/services/authz/proto/v1/extention.proto b/pkg/services/authz/proto/v1/extention.proto index 9d64c718b56..a7e52a99627 100644 --- a/pkg/services/authz/proto/v1/extention.proto +++ b/pkg/services/authz/proto/v1/extention.proto @@ -13,6 +13,70 @@ service AuthzExtentionService { rpc Read(ReadRequest) returns (ReadResponse); rpc Write(WriteRequest) returns (WriteResponse); + + rpc Mutate(MutateRequest) returns (MutateResponse); +} + +message MutateRequest { + string namespace = 1; + repeated MutateOperation operations = 2; +} + +message MutateResponse {} + +message MutateOperation { + oneof operation { + SetFolderParentOperation set_folder_parent = 1; + DeleteFolderOperation delete_folder = 2; + CreatePermissionOperation create_permission = 3; + DeletePermissionOperation delete_permission = 4; + } +} + +message SetFolderParentOperation { + // UID of the folder + string folder = 1; + // UID of the parent folder + string parent = 2; + // If true, delete all existing parent relations associated with the folder + bool delete_existing = 3; +} + +message DeleteFolderOperation { + // UID of the folder to delete + string folder = 1; + // UID of the parent folder + string parent = 2; + // If true, delete all existing parent relations associated with the folder + bool delete_existing = 3; +} + +message CreatePermissionOperation { + Resource resource = 1; + Permission permission = 2; +} + +message DeletePermissionOperation { + Resource resource = 1; + Permission permission = 2; +} + +message Resource { + // group of the resource (e.g: "dashboard.grafana.app") + string group = 1; + // kind of the resource (e.g: "dashboards") + string resource = 2; + // uid of the resource + string name = 3; +} + +message Permission { + // kind of the identity getting the permission (e.g: "user", "team", "serviceaccount") + string kind = 1; + // uid of the identity getting the permission + string name = 2; + // action set granted to the user (e.g. "admin" or "edit", "view") + string verb = 3; } message TupleKey { diff --git a/pkg/services/authz/proto/v1/extention_grpc.pb.go b/pkg/services/authz/proto/v1/extention_grpc.pb.go index 78eb6e30b58..f83b14c1c8d 100644 --- a/pkg/services/authz/proto/v1/extention_grpc.pb.go +++ b/pkg/services/authz/proto/v1/extention_grpc.pb.go @@ -22,6 +22,7 @@ const ( AuthzExtentionService_BatchCheck_FullMethodName = "/authz.extention.v1.AuthzExtentionService/BatchCheck" AuthzExtentionService_Read_FullMethodName = "/authz.extention.v1.AuthzExtentionService/Read" AuthzExtentionService_Write_FullMethodName = "/authz.extention.v1.AuthzExtentionService/Write" + AuthzExtentionService_Mutate_FullMethodName = "/authz.extention.v1.AuthzExtentionService/Mutate" ) // AuthzExtentionServiceClient is the client API for AuthzExtentionService service. @@ -31,6 +32,7 @@ type AuthzExtentionServiceClient interface { BatchCheck(ctx context.Context, in *BatchCheckRequest, opts ...grpc.CallOption) (*BatchCheckResponse, error) Read(ctx context.Context, in *ReadRequest, opts ...grpc.CallOption) (*ReadResponse, error) Write(ctx context.Context, in *WriteRequest, opts ...grpc.CallOption) (*WriteResponse, error) + Mutate(ctx context.Context, in *MutateRequest, opts ...grpc.CallOption) (*MutateResponse, error) } type authzExtentionServiceClient struct { @@ -71,6 +73,16 @@ func (c *authzExtentionServiceClient) Write(ctx context.Context, in *WriteReques return out, nil } +func (c *authzExtentionServiceClient) Mutate(ctx context.Context, in *MutateRequest, opts ...grpc.CallOption) (*MutateResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(MutateResponse) + err := c.cc.Invoke(ctx, AuthzExtentionService_Mutate_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + // AuthzExtentionServiceServer is the server API for AuthzExtentionService service. // All implementations should embed UnimplementedAuthzExtentionServiceServer // for forward compatibility @@ -78,6 +90,7 @@ type AuthzExtentionServiceServer interface { BatchCheck(context.Context, *BatchCheckRequest) (*BatchCheckResponse, error) Read(context.Context, *ReadRequest) (*ReadResponse, error) Write(context.Context, *WriteRequest) (*WriteResponse, error) + Mutate(context.Context, *MutateRequest) (*MutateResponse, error) } // UnimplementedAuthzExtentionServiceServer should be embedded to have forward compatible implementations. @@ -93,6 +106,9 @@ func (UnimplementedAuthzExtentionServiceServer) Read(context.Context, *ReadReque func (UnimplementedAuthzExtentionServiceServer) Write(context.Context, *WriteRequest) (*WriteResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method Write not implemented") } +func (UnimplementedAuthzExtentionServiceServer) Mutate(context.Context, *MutateRequest) (*MutateResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Mutate not implemented") +} // UnsafeAuthzExtentionServiceServer may be embedded to opt out of forward compatibility for this service. // Use of this interface is not recommended, as added methods to AuthzExtentionServiceServer will @@ -159,6 +175,24 @@ func _AuthzExtentionService_Write_Handler(srv interface{}, ctx context.Context, return interceptor(ctx, in, info, handler) } +func _AuthzExtentionService_Mutate_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MutateRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AuthzExtentionServiceServer).Mutate(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: AuthzExtentionService_Mutate_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AuthzExtentionServiceServer).Mutate(ctx, req.(*MutateRequest)) + } + return interceptor(ctx, in, info, handler) +} + // AuthzExtentionService_ServiceDesc is the grpc.ServiceDesc for AuthzExtentionService service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -178,6 +212,10 @@ var AuthzExtentionService_ServiceDesc = grpc.ServiceDesc{ MethodName: "Write", Handler: _AuthzExtentionService_Write_Handler, }, + { + MethodName: "Mutate", + Handler: _AuthzExtentionService_Mutate_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "extention.proto", diff --git a/pkg/services/authz/rbac.go b/pkg/services/authz/rbac.go index ed58f7ed686..349fd0d4013 100644 --- a/pkg/services/authz/rbac.go +++ b/pkg/services/authz/rbac.go @@ -33,6 +33,7 @@ import ( "github.com/grafana/grafana/pkg/services/authz/rbac" "github.com/grafana/grafana/pkg/services/authz/rbac/store" "github.com/grafana/grafana/pkg/services/authz/zanzana" + zClient "github.com/grafana/grafana/pkg/services/authz/zanzana/client" "github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/grpcserver" "github.com/grafana/grafana/pkg/setting" @@ -84,7 +85,7 @@ func ProvideAuthZClient( case clientModeCloud: rbacClient, err := newRemoteRBACClient(authCfg, tracer, reg) if zanzanaEnabled { - return zanzana.WithShadowClient(rbacClient, zanzanaClient, reg) + return zClient.WithShadowClient(rbacClient, zanzanaClient, reg) } return rbacClient, err default: @@ -131,7 +132,7 @@ func ProvideAuthZClient( ) if zanzanaEnabled { - return zanzana.WithShadowClient(rbacClient, zanzanaClient, reg) + return zClient.WithShadowClient(rbacClient, zanzanaClient, reg) } return rbacClient, nil diff --git a/pkg/services/authz/wireset.go b/pkg/services/authz/wireset.go index 4a46f15ea3b..6540413325b 100644 --- a/pkg/services/authz/wireset.go +++ b/pkg/services/authz/wireset.go @@ -6,5 +6,5 @@ import ( var WireSet = wire.NewSet( ProvideAuthZClient, - ProvideZanzana, + ProvideZanzanaClient, ) diff --git a/pkg/services/authz/zanzana.go b/pkg/services/authz/zanzana.go index 36abf4779c1..37fa8c7b59d 100644 --- a/pkg/services/authz/zanzana.go +++ b/pkg/services/authz/zanzana.go @@ -24,26 +24,26 @@ import ( "github.com/grafana/grafana/pkg/infra/tracing" authzextv1 "github.com/grafana/grafana/pkg/services/authz/proto/v1" "github.com/grafana/grafana/pkg/services/authz/zanzana" + zClient "github.com/grafana/grafana/pkg/services/authz/zanzana/client" + zServer "github.com/grafana/grafana/pkg/services/authz/zanzana/server" + zStore "github.com/grafana/grafana/pkg/services/authz/zanzana/store" "github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/grpcserver" "github.com/grafana/grafana/pkg/services/grpcserver/interceptors" "github.com/grafana/grafana/pkg/setting" ) -// ProvideZanzana used to register ZanzanaClient. +// ProvideZanzanaClient used to register ZanzanaClient. // It will also start an embedded ZanzanaSever if mode is set to "embedded". -func ProvideZanzana(cfg *setting.Cfg, db db.DB, tracer tracing.Tracer, features featuremgmt.FeatureToggles, reg prometheus.Registerer) (zanzana.Client, error) { +func ProvideZanzanaClient(cfg *setting.Cfg, db db.DB, tracer tracing.Tracer, features featuremgmt.FeatureToggles, reg prometheus.Registerer) (zanzana.Client, error) { //nolint:staticcheck // not yet migrated to OpenFeature if !features.IsEnabledGlobally(featuremgmt.FlagZanzana) { - return zanzana.NewNoopClient(), nil + return zClient.NewNoopClient(), nil } - logger := log.New("zanzana.server") - - var client zanzana.Client switch cfg.ZanzanaClient.Mode { case setting.ZanzanaModeClient: - return NewZanzanaClient( + return NewRemoteZanzanaClient( fmt.Sprintf("stacks-%s", cfg.StackID), ZanzanaClientConfig{ URL: cfg.ZanzanaClient.Addr, @@ -51,18 +51,20 @@ func ProvideZanzana(cfg *setting.Cfg, db db.DB, tracer tracing.Tracer, features TokenExchangeURL: cfg.ZanzanaClient.TokenExchangeURL, ServerCertFile: cfg.ZanzanaClient.ServerCertFile, }) + case setting.ZanzanaModeEmbedded: - store, err := zanzana.NewEmbeddedStore(cfg, db, logger) + logger := log.New("zanzana.server") + store, err := zStore.NewEmbeddedStore(cfg, db, logger) if err != nil { return nil, fmt.Errorf("failed to start zanzana: %w", err) } - openfga, err := zanzana.NewOpenFGAServer(cfg.ZanzanaServer, store) + openfga, err := zServer.NewOpenFGAServer(cfg.ZanzanaServer, store) if err != nil { return nil, fmt.Errorf("failed to start zanzana: %w", err) } - srv, err := zanzana.NewServer(cfg.ZanzanaServer, openfga, logger, tracer, reg) + srv, err := zServer.NewServer(cfg.ZanzanaServer, openfga, logger, tracer, reg) if err != nil { return nil, fmt.Errorf("failed to start zanzana: %w", err) } @@ -82,16 +84,15 @@ func ProvideZanzana(cfg *setting.Cfg, db db.DB, tracer tracing.Tracer, features authzv1.RegisterAuthzServiceServer(channel, srv) authzextv1.RegisterAuthzExtentionServiceServer(channel, srv) - client, err = zanzana.NewClient(channel) + client, err := zClient.New(channel) if err != nil { return nil, fmt.Errorf("failed to initialize zanzana client: %w", err) } + return client, nil default: return nil, fmt.Errorf("unsupported zanzana mode: %s", cfg.ZanzanaClient.Mode) } - - return client, nil } type ZanzanaClientConfig struct { @@ -101,7 +102,8 @@ type ZanzanaClientConfig struct { ServerCertFile string } -func NewZanzanaClient(namespace string, cfg ZanzanaClientConfig) (zanzana.Client, error) { +// NewRemoteZanzanaClient creates a new Zanzana client that connects to remote Zanzana server. +func NewRemoteZanzanaClient(namespace string, cfg ZanzanaClientConfig) (zanzana.Client, error) { tokenClient, err := authnlib.NewTokenExchangeClient(authnlib.TokenExchangeConfig{ Token: cfg.Token, TokenExchangeURL: cfg.TokenExchangeURL, @@ -134,7 +136,7 @@ func NewZanzanaClient(namespace string, cfg ZanzanaClientConfig) (zanzana.Client return nil, fmt.Errorf("failed to create zanzana client to remote server: %w", err) } - client, err := zanzana.NewClient(conn) + client, err := zClient.New(conn) if err != nil { return nil, fmt.Errorf("failed to initialize zanzana client: %w", err) } @@ -186,17 +188,17 @@ func (z *Zanzana) start(ctx context.Context) error { return err } - store, err := zanzana.NewStore(z.cfg, z.logger) + store, err := zStore.NewStore(z.cfg, z.logger) if err != nil { return fmt.Errorf("failed to initilize zanana store: %w", err) } - openfgaServer, err := zanzana.NewOpenFGAServer(z.cfg.ZanzanaServer, store) + openfgaServer, err := zServer.NewOpenFGAServer(z.cfg.ZanzanaServer, store) if err != nil { return fmt.Errorf("failed to start zanzana: %w", err) } - zanzanaServer, err := zanzana.NewServer(z.cfg.ZanzanaServer, openfgaServer, z.logger, tracer, z.reg) + zanzanaServer, err := zServer.NewServer(z.cfg.ZanzanaServer, openfgaServer, z.logger, tracer, z.reg) if err != nil { return fmt.Errorf("failed to start zanzana: %w", err) } @@ -240,7 +242,7 @@ func (z *Zanzana) start(ctx context.Context) error { authzextv1.RegisterAuthzExtentionServiceServer(grpcServer, zanzanaServer) // register grpc health server - healthServer := zanzana.NewHealthServer(zanzanaServer) + healthServer := zServer.NewHealthServer(zanzanaServer) healthv1pb.RegisterHealthServer(grpcServer, healthServer) if _, err := grpcserver.ProvideReflectionService(z.cfg, z.handle); err != nil { @@ -253,7 +255,7 @@ func (z *Zanzana) start(ctx context.Context) error { func (z *Zanzana) running(ctx context.Context) error { if z.cfg.Env == setting.Dev && z.cfg.ZanzanaServer.OpenFGAHttpAddr != "" { go func() { - srv, err := zanzana.NewOpenFGAHttpServer(z.cfg.ZanzanaServer, z.handle) + srv, err := zServer.NewOpenFGAHttpServer(z.cfg.ZanzanaServer, z.handle) if err != nil { z.logger.Error("failed to create OpenFGA HTTP server", "error", err) } else { diff --git a/pkg/services/authz/zanzana/client.go b/pkg/services/authz/zanzana/client.go index 40b672bf759..a95ead698cb 100644 --- a/pkg/services/authz/zanzana/client.go +++ b/pkg/services/authz/zanzana/client.go @@ -3,13 +3,9 @@ package zanzana import ( "context" - "google.golang.org/grpc" - authlib "github.com/grafana/authlib/types" - "github.com/prometheus/client_golang/prometheus" authzextv1 "github.com/grafana/grafana/pkg/services/authz/proto/v1" - "github.com/grafana/grafana/pkg/services/authz/zanzana/client" ) // Client is a wrapper around [openfgav1.OpenFGAServiceClient] @@ -18,16 +14,6 @@ type Client interface { Read(ctx context.Context, req *authzextv1.ReadRequest) (*authzextv1.ReadResponse, error) Write(ctx context.Context, req *authzextv1.WriteRequest) error BatchCheck(ctx context.Context, req *authzextv1.BatchCheckRequest) (*authzextv1.BatchCheckResponse, error) -} -func NewClient(cc grpc.ClientConnInterface) (*client.Client, error) { - return client.New(cc) -} - -func WithShadowClient(accessClient authlib.AccessClient, zanzanaClient authlib.AccessClient, reg prometheus.Registerer) (authlib.AccessClient, error) { - return client.WithShadowClient(accessClient, zanzanaClient, reg), nil -} - -func NewNoopClient() *client.NoopClient { - return client.NewNoop() + Mutate(ctx context.Context, req *authzextv1.MutateRequest) error } diff --git a/pkg/services/authz/zanzana/client/client.go b/pkg/services/authz/zanzana/client/client.go index 05266afba83..68809a84fa8 100644 --- a/pkg/services/authz/zanzana/client/client.go +++ b/pkg/services/authz/zanzana/client/client.go @@ -12,9 +12,11 @@ import ( "github.com/grafana/grafana/pkg/infra/log" authzextv1 "github.com/grafana/grafana/pkg/services/authz/proto/v1" + "github.com/grafana/grafana/pkg/services/authz/zanzana" ) var _ authlib.AccessClient = (*Client)(nil) +var _ zanzana.Client = (*Client)(nil) var tracer = otel.Tracer("github.com/grafana/grafana/pkg/services/authz/zanzana/client") @@ -72,3 +74,19 @@ func (c *Client) BatchCheck(ctx context.Context, req *authzextv1.BatchCheckReque return c.authzext.BatchCheck(ctx, req) } + +func (c *Client) WriteNew(ctx context.Context, req *authzextv1.WriteRequest) error { + ctx, span := tracer.Start(ctx, "authlib.zanzana.client.Write") + defer span.End() + + _, err := c.authzext.Write(ctx, req) + return err +} + +func (c *Client) Mutate(ctx context.Context, req *authzextv1.MutateRequest) error { + ctx, span := tracer.Start(ctx, "authlib.zanzana.client.Mutate") + defer span.End() + + _, err := c.authzext.Mutate(ctx, req) + return err +} diff --git a/pkg/services/authz/zanzana/client/noop.go b/pkg/services/authz/zanzana/client/noop.go index 419a9b73201..d0397740b5e 100644 --- a/pkg/services/authz/zanzana/client/noop.go +++ b/pkg/services/authz/zanzana/client/noop.go @@ -6,11 +6,13 @@ import ( authlib "github.com/grafana/authlib/types" authzextv1 "github.com/grafana/grafana/pkg/services/authz/proto/v1" + "github.com/grafana/grafana/pkg/services/authz/zanzana" ) var _ authlib.AccessClient = (*NoopClient)(nil) +var _ zanzana.Client = (*NoopClient)(nil) -func NewNoop() *NoopClient { +func NewNoopClient() *NoopClient { return &NoopClient{} } @@ -35,3 +37,7 @@ func (nc NoopClient) Write(ctx context.Context, req *authzextv1.WriteRequest) er func (nc NoopClient) BatchCheck(ctx context.Context, req *authzextv1.BatchCheckRequest) (*authzextv1.BatchCheckResponse, error) { return nil, nil } + +func (nc NoopClient) Mutate(ctx context.Context, req *authzextv1.MutateRequest) error { + return nil +} diff --git a/pkg/services/authz/zanzana/client/shadow_client.go b/pkg/services/authz/zanzana/client/shadow_client.go index 4fb4c545ff0..f2f0ec7d4f1 100644 --- a/pkg/services/authz/zanzana/client/shadow_client.go +++ b/pkg/services/authz/zanzana/client/shadow_client.go @@ -6,6 +6,7 @@ import ( "github.com/prometheus/client_golang/prometheus" authlib "github.com/grafana/authlib/types" + "github.com/grafana/grafana/pkg/infra/log" ) @@ -19,14 +20,14 @@ type ShadowClient struct { } // WithShadowClient returns a new access client that runs zanzana checks in the background. -func WithShadowClient(accessClient authlib.AccessClient, zanzanaClient authlib.AccessClient, reg prometheus.Registerer) authlib.AccessClient { +func WithShadowClient(accessClient authlib.AccessClient, zanzanaClient authlib.AccessClient, reg prometheus.Registerer) (authlib.AccessClient, error) { client := &ShadowClient{ logger: log.New("zanzana-shadow-client"), accessClient: accessClient, zanzanaClient: zanzanaClient, metrics: newShadowClientMetrics(reg), } - return client + return client, nil } func (c *ShadowClient) Check(ctx context.Context, id authlib.AuthInfo, req authlib.CheckRequest, folder string) (authlib.CheckResponse, error) { diff --git a/pkg/services/authz/zanzana/translations.go b/pkg/services/authz/zanzana/common/translations.go similarity index 67% rename from pkg/services/authz/zanzana/translations.go rename to pkg/services/authz/zanzana/common/translations.go index 0abefcf2e29..ce5625d698b 100644 --- a/pkg/services/authz/zanzana/translations.go +++ b/pkg/services/authz/zanzana/common/translations.go @@ -1,6 +1,8 @@ -package zanzana +package common import ( + authlib "github.com/grafana/authlib/types" + dashboards "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v1beta1" folders "github.com/grafana/grafana/apps/folder/pkg/apis/folder/v1beta1" ) @@ -79,3 +81,60 @@ var resourceTranslations = map[string]resourceTranslation{ }, }, } + +func TranslateToCheckRequest(namespace, action, kind, name string) (*authlib.CheckRequest, bool) { + translation, ok := resourceTranslations[kind] + + if !ok { + return nil, false + } + + m, ok := translation.mapping[action] + if !ok { + return nil, false + } + + verb, ok := RelationToVerbMapping[m.relation] + if !ok { + return nil, false + } + + req := &authlib.CheckRequest{ + Namespace: namespace, + Verb: verb, + Group: translation.group, + Resource: translation.resource, + Name: name, + } + + return req, true +} + +func TranslateToListRequest(namespace, action, kind string) (*authlib.ListRequest, bool) { + translation, ok := resourceTranslations[kind] + + if !ok { + return nil, false + } + + // FIXME: support different verbs + req := &authlib.ListRequest{ + Namespace: namespace, + Group: translation.group, + Resource: translation.resource, + } + + return req, true +} + +func TranslateToGroupResource(kind string) string { + translation, ok := resourceTranslations[kind] + if !ok { + return "" + } + return FormatGroupResource(translation.group, translation.resource, "") +} + +func TranslateBasicRole(name string) string { + return basicRolesTranslations[name] +} diff --git a/pkg/services/authz/zanzana/common/tuple.go b/pkg/services/authz/zanzana/common/tuple.go index 41ed7c2a85b..9349453054c 100644 --- a/pkg/services/authz/zanzana/common/tuple.go +++ b/pkg/services/authz/zanzana/common/tuple.go @@ -1,12 +1,14 @@ package common import ( + "fmt" "strings" openfgav1 "github.com/openfga/api/proto/openfga/v1" "google.golang.org/protobuf/types/known/structpb" dashboardV1 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v1beta1" + folderV1 "github.com/grafana/grafana/apps/folder/pkg/apis/folder/v1beta1" "github.com/grafana/grafana/pkg/apimachinery/utils" authzextv1 "github.com/grafana/grafana/pkg/services/authz/proto/v1" ) @@ -33,6 +35,11 @@ const ( TypeTeamPrefix string = TypeTeam + ":" ) +const ( + KindDashboards string = dashboardV1.DASHBOARD_RESOURCE + KindFolders string = folderV1.RESOURCE +) + const ( RelationTeamMember string = "member" RelationTeamAdmin string = "admin" @@ -144,6 +151,10 @@ func isValidRelation(relation string, valid []string) bool { return false } +func IsFolderResourceTuple(t *openfgav1.TupleKey) bool { + return strings.HasPrefix(t.Object, TypeFolder) && strings.HasPrefix(t.Relation, "resource_") +} + func SubresourceRelation(relation string) string { return TypeResource + "_" + relation } @@ -178,6 +189,69 @@ func FormatGroupResource(group, resource, subresource string) string { return b.String() } +// NewTupleEntry constructs new openfga entry type:name[#relation]. +// Relation allows to specify group of users (subjects) related to type:name +// (for example, team:devs#member refers to users which are members of team devs) +func NewTupleEntry(objectType, name, relation string) string { + obj := fmt.Sprintf("%s:%s", objectType, name) + if relation != "" { + obj = fmt.Sprintf("%s#%s", obj, relation) + } + return obj +} + +func NewObjectEntry(objectType, group, resource, subresource, name string) string { + if objectType == TypeFolder { + return TypeFolder + ":" + name + } + + obj := fmt.Sprintf("%s:%s/%s", objectType, group, resource) + if subresource != "" { + obj = fmt.Sprintf("%s/%s", obj, subresource) + } + if name != "" { + obj = fmt.Sprintf("%s/%s", obj, name) + } + return obj +} + +func TranslateToResourceTuple(subject string, action, kind, name string) (*openfgav1.TupleKey, bool) { + translation, ok := resourceTranslations[kind] + + if !ok { + return nil, false + } + + m, ok := translation.mapping[action] + if !ok { + return nil, false + } + + if name == "*" { + return NewGroupResourceTuple(subject, m.relation, translation.group, translation.resource, m.subresource), true + } + + if translation.typ == TypeResource { + return NewResourceTuple(subject, m.relation, translation.group, translation.resource, m.subresource, name), true + } + + if translation.typ == TypeFolder { + if m.group != "" && m.resource != "" { + return NewFolderResourceTuple(subject, m.relation, m.group, m.resource, m.subresource, name), true + } + + return NewFolderTuple(subject, m.relation, name), true + } + + return NewTypedTuple(translation.typ, subject, m.relation, name), true +} + +func MergeFolderResourceTuples(a, b *openfgav1.TupleKey) { + va := a.Condition.Context.Fields["subresources"] + vb := b.Condition.Context.Fields["subresources"] + va.GetListValue().Values = append(va.GetListValue().Values, vb.GetListValue().Values...) +} + func NewResourceTuple(subject, relation, group, resource, subresource, name string) *openfgav1.TupleKey { return &openfgav1.TupleKey{ User: subject, @@ -200,6 +274,18 @@ func isSubresourceRelationSet(relation string) bool { relation == RelationSubresourceSetAdmin } +func NewFolderParentTuple(folder, parent string) *openfgav1.TupleKey { + return &openfgav1.TupleKey{ + Object: NewFolderIdent(folder), + Relation: RelationParent, + User: NewFolderIdent(parent), + } +} + +func NewFolderTuple(subject, relation, name string) *openfgav1.TupleKey { + return NewTypedTuple(TypeFolder, subject, relation, name) +} + func NewFolderResourceTuple(subject, relation, group, resource, subresource, folder string) *openfgav1.TupleKey { relation = SubresourceRelation(relation) var condition *openfgav1.RelationshipCondition @@ -256,18 +342,6 @@ func NewGroupResourceTuple(subject, relation, group, resource, subresource strin } } -func NewFolderParentTuple(folder, parent string) *openfgav1.TupleKey { - return &openfgav1.TupleKey{ - Object: NewFolderIdent(folder), - Relation: RelationParent, - User: NewFolderIdent(parent), - } -} - -func NewFolderTuple(subject, relation, name string) *openfgav1.TupleKey { - return NewTypedTuple(TypeFolder, subject, relation, name) -} - func NewTypedTuple(typ, subject, relation, name string) *openfgav1.TupleKey { return &openfgav1.TupleKey{ User: subject, diff --git a/pkg/services/authz/zanzana/server.go b/pkg/services/authz/zanzana/server.go index 91a9800efbd..3505f0dcec1 100644 --- a/pkg/services/authz/zanzana/server.go +++ b/pkg/services/authz/zanzana/server.go @@ -1,31 +1 @@ package zanzana - -import ( - "net/http" - - openfgaserver "github.com/openfga/openfga/pkg/server" - openfgastorage "github.com/openfga/openfga/pkg/storage" - "github.com/prometheus/client_golang/prometheus" - - "github.com/grafana/grafana/pkg/infra/log" - "github.com/grafana/grafana/pkg/infra/tracing" - "github.com/grafana/grafana/pkg/services/authz/zanzana/server" - "github.com/grafana/grafana/pkg/services/grpcserver" - "github.com/grafana/grafana/pkg/setting" -) - -func NewServer(cfg setting.ZanzanaServerSettings, openfga server.OpenFGAServer, logger log.Logger, tracer tracing.Tracer, reg prometheus.Registerer) (*server.Server, error) { - return server.NewServer(cfg, openfga, logger, tracer, reg) -} - -func NewHealthServer(target server.DiagnosticServer) *server.HealthServer { - return server.NewHealthServer(target) -} - -func NewOpenFGAServer(cfg setting.ZanzanaServerSettings, store openfgastorage.OpenFGADatastore) (*openfgaserver.Server, error) { - return server.NewOpenFGAServer(cfg, store) -} - -func NewOpenFGAHttpServer(cfg setting.ZanzanaServerSettings, srv grpcserver.Provider) (*http.Server, error) { - return server.NewOpenFGAHttpServer(cfg, srv) -} diff --git a/pkg/services/authz/zanzana/server/server_mutate.go b/pkg/services/authz/zanzana/server/server_mutate.go new file mode 100644 index 00000000000..348d9512e72 --- /dev/null +++ b/pkg/services/authz/zanzana/server/server_mutate.go @@ -0,0 +1,90 @@ +package server + +import ( + "context" + "errors" + "fmt" + "time" + + authzextv1 "github.com/grafana/grafana/pkg/services/authz/proto/v1" +) + +type OperationGroup string + +const ( + OperationGroupFolder OperationGroup = "folder" + OperationGroupPermission OperationGroup = "permission" +) + +func (s *Server) Mutate(ctx context.Context, req *authzextv1.MutateRequest) (*authzextv1.MutateResponse, error) { + ctx, span := s.tracer.Start(ctx, "server.Mutate") + defer span.End() + + defer func(t time.Time) { + s.metrics.requestDurationSeconds.WithLabelValues("server.Mutate", req.GetNamespace()).Observe(time.Since(t).Seconds()) + }(time.Now()) + + res, err := s.mutate(ctx, req) + if err != nil { + s.logger.Error("failed to perform mutate request", "error", err, "namespace", req.GetNamespace()) + return nil, errors.New("failed to perform mutate request") + } + + return res, nil +} + +func (s *Server) mutate(ctx context.Context, req *authzextv1.MutateRequest) (*authzextv1.MutateResponse, error) { + if err := authorize(ctx, req.GetNamespace(), s.cfg); err != nil { + return nil, err + } + + storeInf, err := s.getStoreInfo(ctx, req.Namespace) + if err != nil { + return nil, fmt.Errorf("failed to get openfga store: %w", err) + } + + groupedOperations, err := groupByOperation(req.GetOperations()) + if err != nil { + return nil, fmt.Errorf("failed to group operations: %w", err) + } + + for operationGroup, operations := range groupedOperations { + switch operationGroup { + case OperationGroupFolder: + if err := s.mutateFolders(ctx, storeInf, operations); err != nil { + return nil, fmt.Errorf("failed to mutate folder: %w", err) + } + case OperationGroupPermission: + if err := s.mutateResourcePermissions(ctx, storeInf, operations); err != nil { + return nil, fmt.Errorf("failed to mutate resource permissions: %w", err) + } + default: + s.logger.Warn("unsupported operation group", "operationGroup", operationGroup) + } + } + + return &authzextv1.MutateResponse{}, nil +} + +func getOperationGroup(operation *authzextv1.MutateOperation) (OperationGroup, error) { + switch operation.Operation.(type) { + case *authzextv1.MutateOperation_SetFolderParent, *authzextv1.MutateOperation_DeleteFolder: + return OperationGroupFolder, nil + case *authzextv1.MutateOperation_CreatePermission, *authzextv1.MutateOperation_DeletePermission: + return OperationGroupPermission, nil + } + return OperationGroup(""), errors.New("unsupported mutate operation type") +} + +func groupByOperation(operations []*authzextv1.MutateOperation) (map[OperationGroup][]*authzextv1.MutateOperation, error) { + grouped := make(map[OperationGroup][]*authzextv1.MutateOperation) + for _, operation := range operations { + operationGroup, err := getOperationGroup(operation) + if err != nil { + return nil, err + } + grouped[operationGroup] = append(grouped[operationGroup], operation) + } + + return grouped, nil +} diff --git a/pkg/services/authz/zanzana/server/server_mutate_folder.go b/pkg/services/authz/zanzana/server/server_mutate_folder.go new file mode 100644 index 00000000000..3d92347f404 --- /dev/null +++ b/pkg/services/authz/zanzana/server/server_mutate_folder.go @@ -0,0 +1,142 @@ +package server + +import ( + "context" + "fmt" + "strings" + + openfgav1 "github.com/openfga/api/proto/openfga/v1" + + authzextv1 "github.com/grafana/grafana/pkg/services/authz/proto/v1" + zanzana "github.com/grafana/grafana/pkg/services/authz/zanzana/common" +) + +func (s *Server) mutateFolders(ctx context.Context, store *storeInfo, operations []*authzextv1.MutateOperation) error { + ctx, span := s.tracer.Start(ctx, "server.mutateFolder") + defer span.End() + + writeTuples := make([]*openfgav1.TupleKey, 0) + deleteTuples := make([]*openfgav1.TupleKeyWithoutCondition, 0) + + for _, operation := range operations { + switch op := operation.Operation.(type) { + case *authzextv1.MutateOperation_SetFolderParent: + tuple, err := s.getFolderWriteTuple(ctx, store, op.SetFolderParent) + if err != nil { + return err + } + if tuple != nil { + writeTuples = append(writeTuples, tuple) + } + + // Delete existing parent tuples + if op.SetFolderParent.GetDeleteExisting() { + tuples, err := s.getFolderDeleteTuples(ctx, store, op.SetFolderParent.GetFolder(), op.SetFolderParent.GetParent(), true) + if err != nil { + return err + } + deleteTuples = append(deleteTuples, tuples...) + } + case *authzextv1.MutateOperation_DeleteFolder: + tuples, err := s.getFolderDeleteTuples(ctx, store, op.DeleteFolder.GetFolder(), op.DeleteFolder.GetParent(), op.DeleteFolder.GetDeleteExisting()) + if err != nil { + return err + } + deleteTuples = append(deleteTuples, tuples...) + default: + s.logger.Debug("unsupported mutate operation", "operation", op) + } + } + + if len(writeTuples) == 0 && len(deleteTuples) == 0 { + return nil + } + + writeReq := &openfgav1.WriteRequest{ + StoreId: store.ID, + AuthorizationModelId: store.ModelID, + } + if len(writeTuples) > 0 { + writeReq.Writes = &openfgav1.WriteRequestWrites{ + TupleKeys: writeTuples, + OnDuplicate: "ignore", + } + } + if len(deleteTuples) > 0 { + writeReq.Deletes = &openfgav1.WriteRequestDeletes{ + TupleKeys: deleteTuples, + OnMissing: "ignore", + } + } + + _, err := s.openfga.Write(ctx, writeReq) + if err != nil { + s.logger.Error("failed to write folder tuples", "error", err) + return err + } + + return nil +} + +func (s *Server) getFolderWriteTuple(ctx context.Context, store *storeInfo, req *authzextv1.SetFolderParentOperation) (*openfgav1.TupleKey, error) { + // Folder is at the root level + if req.GetParent() == "" { + return nil, nil + } + + if strings.ContainsAny(req.GetFolder(), "#:") { + return nil, fmt.Errorf("folder UID contains invalid characters: %s", req.GetFolder()) + } + + tuple := zanzana.NewFolderParentTuple(req.GetFolder(), req.GetParent()) + return tuple, nil +} + +func (s *Server) getFolderDeleteTuples(ctx context.Context, store *storeInfo, folderUID string, parentUID string, deleteExisting bool) ([]*openfgav1.TupleKeyWithoutCondition, error) { + tupleKeysToDelete := make([]*openfgav1.TupleKeyWithoutCondition, 0) + + if folderUID != "" && parentUID != "" && !deleteExisting { + tuple := zanzana.NewFolderParentTuple(folderUID, parentUID) + tupleKeysToDelete = append(tupleKeysToDelete, &openfgav1.TupleKeyWithoutCondition{ + User: tuple.GetUser(), + Relation: tuple.GetRelation(), + Object: tuple.GetObject(), + }) + } + + if deleteExisting { + parentTuples, err := s.listFolderParents(ctx, store, folderUID) + if err != nil { + return nil, fmt.Errorf("failed to list folder parents: %w", err) + } + + for _, tuple := range parentTuples { + tupleKeysToDelete = append(tupleKeysToDelete, &openfgav1.TupleKeyWithoutCondition{ + User: tuple.Key.User, + Relation: tuple.Key.Relation, + Object: tuple.Key.Object, + }) + } + } + + return tupleKeysToDelete, nil +} + +func (s *Server) listFolderParents(ctx context.Context, store *storeInfo, folderUID string) ([]*openfgav1.Tuple, error) { + ctx, span := s.tracer.Start(ctx, "server.listFolderParents") + defer span.End() + + object := zanzana.NewFolderIdent(folderUID) + resp, err := s.openfga.Read(ctx, &openfgav1.ReadRequest{ + StoreId: store.ID, + TupleKey: &openfgav1.ReadRequestTupleKey{ + Object: object, + Relation: zanzana.RelationParent, + }, + }) + if err != nil { + return nil, fmt.Errorf("failed to list folder parents: %w", err) + } + + return resp.Tuples, nil +} diff --git a/pkg/services/authz/zanzana/server/server_mutate_folder_test.go b/pkg/services/authz/zanzana/server/server_mutate_folder_test.go new file mode 100644 index 00000000000..a01c3b08740 --- /dev/null +++ b/pkg/services/authz/zanzana/server/server_mutate_folder_test.go @@ -0,0 +1,164 @@ +package server + +import ( + "testing" + + openfgav1 "github.com/openfga/api/proto/openfga/v1" + "github.com/stretchr/testify/require" + + v1 "github.com/grafana/grafana/pkg/services/authz/proto/v1" + "github.com/grafana/grafana/pkg/services/authz/zanzana/common" +) + +func setupMutateFolders(t *testing.T, srv *Server) *Server { + t.Helper() + + // seed tuples + tuples := []*openfgav1.TupleKey{ + common.NewFolderParentTuple("11", "1"), + common.NewFolderParentTuple("12", "1"), + common.NewFolderParentTuple("111", "11"), + common.NewFolderParentTuple("112", "11"), + common.NewFolderParentTuple("broken", "foo"), + common.NewFolderParentTuple("broken", "bar"), + } + + return setupOpenFGADatabase(t, srv, tuples) +} + +func testMutateFolders(t *testing.T, srv *Server) { + setupMutateFolders(t, srv) + + t.Run("should create new folder parent relation", func(t *testing.T) { + _, err := srv.Mutate(newContextWithNamespace(), &v1.MutateRequest{ + Namespace: "default", + Operations: []*v1.MutateOperation{ + { + Operation: &v1.MutateOperation_SetFolderParent{ + SetFolderParent: &v1.SetFolderParentOperation{ + Folder: "new-folder", + Parent: "1", + DeleteExisting: false, + }, + }, + }, + }, + }) + require.NoError(t, err) + + res, err := srv.Read(newContextWithNamespace(), &v1.ReadRequest{ + Namespace: "default", + TupleKey: &v1.ReadRequestTupleKey{ + Object: "folder:new-folder", + Relation: "parent", + }, + }) + require.NoError(t, err) + require.Len(t, res.Tuples, 1) + require.Equal(t, "folder:new-folder", res.Tuples[0].Key.Object) + require.Equal(t, "parent", res.Tuples[0].Key.Relation) + require.Equal(t, "folder:1", res.Tuples[0].Key.User) + }) + + t.Run("should delete folder parent relation", func(t *testing.T) { + _, err := srv.Mutate(newContextWithNamespace(), &v1.MutateRequest{ + Namespace: "default", + Operations: []*v1.MutateOperation{ + { + Operation: &v1.MutateOperation_DeleteFolder{ + DeleteFolder: &v1.DeleteFolderOperation{ + Folder: "11", + Parent: "1", + }, + }, + }, + }, + }) + require.NoError(t, err) + + res, err := srv.Read(newContextWithNamespace(), &v1.ReadRequest{ + Namespace: "default", + TupleKey: &v1.ReadRequestTupleKey{ + Object: "folder:11", + Relation: "parent", + }, + }) + require.NoError(t, err) + require.Len(t, res.Tuples, 0) + }) + + t.Run("should clean up all parent relations", func(t *testing.T) { + _, err := srv.Mutate(newContextWithNamespace(), &v1.MutateRequest{ + Namespace: "default", + Operations: []*v1.MutateOperation{ + { + Operation: &v1.MutateOperation_DeleteFolder{ + DeleteFolder: &v1.DeleteFolderOperation{ + Folder: "broken", + DeleteExisting: true, + }, + }, + }, + }, + }) + require.NoError(t, err) + + res, err := srv.Read(newContextWithNamespace(), &v1.ReadRequest{ + Namespace: "default", + TupleKey: &v1.ReadRequestTupleKey{ + Object: "folder:broken", + Relation: "parent", + }, + }) + require.NoError(t, err) + require.Len(t, res.Tuples, 0) + }) + + t.Run("should perform batch mutate if multiple operations are provided", func(t *testing.T) { + _, err := srv.Mutate(newContextWithNamespace(), &v1.MutateRequest{ + Namespace: "default", + Operations: []*v1.MutateOperation{ + { + Operation: &v1.MutateOperation_SetFolderParent{ + SetFolderParent: &v1.SetFolderParentOperation{ + Folder: "new-folder-2", + Parent: "1", + }, + }, + }, + { + Operation: &v1.MutateOperation_DeleteFolder{ + DeleteFolder: &v1.DeleteFolderOperation{ + Folder: "12", + Parent: "1", + }, + }, + }, + }, + }) + require.NoError(t, err) + + res, err := srv.Read(newContextWithNamespace(), &v1.ReadRequest{ + Namespace: "default", + TupleKey: &v1.ReadRequestTupleKey{ + Object: "folder:new-folder-2", + Relation: "parent", + }, + }) + require.NoError(t, err) + require.Len(t, res.Tuples, 1) + require.Equal(t, "folder:new-folder-2", res.Tuples[0].Key.Object) + require.Equal(t, "parent", res.Tuples[0].Key.Relation) + require.Equal(t, "folder:1", res.Tuples[0].Key.User) + + res, err = srv.Read(newContextWithNamespace(), &v1.ReadRequest{ + Namespace: "default", + TupleKey: &v1.ReadRequestTupleKey{ + Object: "folder:12", + Relation: "parent", + }, + }) + require.NoError(t, err) + require.Len(t, res.Tuples, 0) + }) +} diff --git a/pkg/services/authz/zanzana/server/server_mutate_resourcepermissions.go b/pkg/services/authz/zanzana/server/server_mutate_resourcepermissions.go new file mode 100644 index 00000000000..fa8b5467235 --- /dev/null +++ b/pkg/services/authz/zanzana/server/server_mutate_resourcepermissions.go @@ -0,0 +1,173 @@ +package server + +import ( + "context" + "errors" + "fmt" + "strings" + + "google.golang.org/protobuf/types/known/structpb" + + openfgav1 "github.com/openfga/api/proto/openfga/v1" + + iamv0 "github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1" + authzextv1 "github.com/grafana/grafana/pkg/services/authz/proto/v1" + zanzana "github.com/grafana/grafana/pkg/services/authz/zanzana/common" +) + +var ( + errEmptyName = errors.New("name cannot be empty") + errInvalidBasicRole = errors.New("invalid basic role") + errUnknownKind = errors.New("unknown permission kind") +) + +func (s *Server) mutateResourcePermissions(ctx context.Context, store *storeInfo, operations []*authzextv1.MutateOperation) error { + ctx, span := s.tracer.Start(ctx, "server.mutateResourcePermissions") + defer span.End() + + writeTuples := make([]*openfgav1.TupleKey, 0) + deleteTuples := make([]*openfgav1.TupleKeyWithoutCondition, 0) + + for _, operation := range operations { + switch op := operation.Operation.(type) { + case *authzextv1.MutateOperation_CreatePermission: + tuple, err := s.getPermissionWriteTuple(ctx, op.CreatePermission) + if err != nil { + return err + } + writeTuples = append(writeTuples, tuple) + case *authzextv1.MutateOperation_DeletePermission: + tuple, err := s.getPermissionDeleteTuple(ctx, op.DeletePermission) + if err != nil { + return err + } + deleteTuples = append(deleteTuples, tuple) + default: + s.logger.Debug("unsupported mutate operation", "operation", op) + } + } + + writeReq := &openfgav1.WriteRequest{ + StoreId: store.ID, + AuthorizationModelId: store.ModelID, + } + if len(writeTuples) > 0 { + writeReq.Writes = &openfgav1.WriteRequestWrites{ + TupleKeys: writeTuples, + OnDuplicate: "ignore", + } + } + if len(deleteTuples) > 0 { + writeReq.Deletes = &openfgav1.WriteRequestDeletes{ + TupleKeys: deleteTuples, + OnMissing: "ignore", + } + } + + _, err := s.openfga.Write(ctx, writeReq) + if err != nil { + s.logger.Error("failed to write resource permission tuples", "error", err) + return err + } + + return nil +} + +func (s *Server) getPermissionWriteTuple(ctx context.Context, req *authzextv1.CreatePermissionOperation) (*openfgav1.TupleKey, error) { + resource := req.GetResource() + permission := req.GetPermission() + object := zanzana.NewObjectEntry(toZanzanaType(resource.GetGroup()), resource.GetGroup(), resource.GetResource(), "", resource.GetName()) + tuple, err := NewResourceTuple(object, resource, permission) + if err != nil { + return nil, err + } + + return tuple, nil +} + +func (s *Server) getPermissionDeleteTuple(ctx context.Context, req *authzextv1.DeletePermissionOperation) (*openfgav1.TupleKeyWithoutCondition, error) { + resource := req.GetResource() + permission := req.GetPermission() + object := zanzana.NewObjectEntry(toZanzanaType(resource.GetGroup()), resource.GetGroup(), resource.GetResource(), "", resource.GetName()) + tuple, err := NewResourceTuple(object, resource, permission) + if err != nil { + return nil, err + } + + return &openfgav1.TupleKeyWithoutCondition{ + User: tuple.GetUser(), + Relation: tuple.GetRelation(), + Object: tuple.GetObject(), + }, nil +} + +func toZanzanaType(apiGroup string) string { + if apiGroup == "folder.grafana.app" { + return zanzana.TypeFolder + } + return zanzana.TypeResource +} + +func NewResourceTuple(object string, resource *authzextv1.Resource, perm *authzextv1.Permission) (*openfgav1.TupleKey, error) { + // Typ is "folder" or "resource" + typ := toZanzanaType(resource.Group) + + // subject + subject, err := toZanzanaSubject(perm.GetKind(), perm.GetName()) + if err != nil { + return nil, err + } + + key := &openfgav1.TupleKey{ + // e.g. "user:{uid}", "serviceaccount:{uid}", "team:{uid}", "basicrole:{viewer|editor|admin}" + User: subject, + // "view", "edit", "admin" + Relation: strings.ToLower(perm.Verb), + // e.g. "folder:{name}" or "resource:{apiGroup}/{resource}/{name}" + Object: object, + } + + // For resources we add a condition to filter by apiGroup/resource + // e.g "group_filter": {"group_resource": "dashboards.grafana.app/dashboards"} + if typ == zanzana.TypeResource { + key.Condition = &openfgav1.RelationshipCondition{ + Name: "group_filter", + Context: &structpb.Struct{ + Fields: map[string]*structpb.Value{ + "group_resource": structpb.NewStringValue( + resource.GetGroup() + "/" + resource.GetResource(), + ), + }, + }, + } + } + + return key, nil +} + +func toZanzanaSubject(kind string, name string) (string, error) { + if name == "" { + return "", errEmptyName + } + iamKind := iamv0.ResourcePermissionSpecPermissionKind(kind) + switch iamKind { + case iamv0.ResourcePermissionSpecPermissionKindUser: + return zanzana.NewTupleEntry(zanzana.TypeUser, name, ""), nil + case iamv0.ResourcePermissionSpecPermissionKindServiceAccount: + return zanzana.NewTupleEntry(zanzana.TypeServiceAccount, name, ""), nil + case iamv0.ResourcePermissionSpecPermissionKindTeam: + return zanzana.NewTupleEntry(zanzana.TypeTeam, name, ""), nil + case iamv0.ResourcePermissionSpecPermissionKindBasicRole: + basicRole := zanzana.TranslateBasicRole(name) + if basicRole == "" { + return "", fmt.Errorf("%w: %s", errInvalidBasicRole, name) + } + + // e.g role:basic_viewer#assignee + return zanzana.NewTupleEntry(zanzana.TypeRole, basicRole, zanzana.RelationAssignee), nil + } + + // should not happen since we are after create + // validation webhook should have caught invalid kinds + return "", errUnknownKind +} diff --git a/pkg/services/authz/zanzana/server/server_mutate_resourcepermissions_test.go b/pkg/services/authz/zanzana/server/server_mutate_resourcepermissions_test.go new file mode 100644 index 00000000000..3336d9d813b --- /dev/null +++ b/pkg/services/authz/zanzana/server/server_mutate_resourcepermissions_test.go @@ -0,0 +1,115 @@ +package server + +import ( + "testing" + + openfgav1 "github.com/openfga/api/proto/openfga/v1" + "github.com/stretchr/testify/require" + + iamv0 "github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1" + v1 "github.com/grafana/grafana/pkg/services/authz/proto/v1" + "github.com/grafana/grafana/pkg/services/authz/zanzana/common" +) + +func setupMutateResourcePermissions(t *testing.T, srv *Server) *Server { + t.Helper() + + // seed tuples + tuples := []*openfgav1.TupleKey{ + common.NewResourceTuple("user:1", common.RelationGet, dashboardGroup, dashboardResource, "", "1"), + common.NewResourceTuple("user:1", common.RelationUpdate, dashboardGroup, dashboardResource, "", "1"), + common.NewTypedResourceTuple("user:2", common.RelationGet, common.TypeFolder, folderGroup, folderResource, "", "1"), + } + + return setupOpenFGADatabase(t, srv, tuples) +} + +func testMutateResourcePermissions(t *testing.T, srv *Server) { + setupMutateResourcePermissions(t, srv) + + t.Run("should create new resource permission", func(t *testing.T) { + _, err := srv.Mutate(newContextWithNamespace(), &v1.MutateRequest{ + Namespace: "default", + Operations: []*v1.MutateOperation{ + { + Operation: &v1.MutateOperation_CreatePermission{ + CreatePermission: &v1.CreatePermissionOperation{ + Resource: &v1.Resource{ + Group: "dashboard.grafana.app", + Resource: "dashboards", + Name: "foo", + }, + Permission: &v1.Permission{ + Kind: string(iamv0.ResourcePermissionSpecPermissionKindUser), + Name: "bar", + Verb: common.RelationGet, + }, + }, + }, + }, + }, + }) + require.NoError(t, err) + + res, err := srv.Read(newContextWithNamespace(), &v1.ReadRequest{ + Namespace: "default", + TupleKey: &v1.ReadRequestTupleKey{ + Relation: common.RelationGet, + Object: "resource:dashboard.grafana.app/dashboards/foo", + }, + }) + require.NoError(t, err) + require.Len(t, res.Tuples, 1) + require.Equal(t, "user:bar", res.Tuples[0].Key.User) + require.Equal(t, common.RelationGet, res.Tuples[0].Key.Relation) + require.Equal(t, "resource:dashboard.grafana.app/dashboards/foo", res.Tuples[0].Key.Object) + }) + + t.Run("should delete resource permission", func(t *testing.T) { + res, err := srv.Read(newContextWithNamespace(), &v1.ReadRequest{ + Namespace: "default", + TupleKey: &v1.ReadRequestTupleKey{ + User: "user:1", + Object: "resource:dashboard.grafana.app/dashboards/1", + }, + }) + require.NoError(t, err) + require.Len(t, res.Tuples, 2) + + _, err = srv.Mutate(newContextWithNamespace(), &v1.MutateRequest{ + Namespace: "default", + Operations: []*v1.MutateOperation{ + { + Operation: &v1.MutateOperation_DeletePermission{ + DeletePermission: &v1.DeletePermissionOperation{ + Resource: &v1.Resource{ + Group: "dashboard.grafana.app", + Resource: "dashboards", + Name: "1", + }, + Permission: &v1.Permission{ + Kind: string(iamv0.ResourcePermissionSpecPermissionKindUser), + Name: "1", + Verb: common.RelationUpdate, + }, + }, + }, + }, + }, + }) + require.NoError(t, err) + + res, err = srv.Read(newContextWithNamespace(), &v1.ReadRequest{ + Namespace: "default", + TupleKey: &v1.ReadRequestTupleKey{ + Relation: common.RelationGet, + Object: "resource:dashboard.grafana.app/dashboards/1", + }, + }) + require.NoError(t, err) + require.Len(t, res.Tuples, 1) + require.Equal(t, "user:1", res.Tuples[0].Key.User) + require.Equal(t, common.RelationGet, res.Tuples[0].Key.Relation) + require.Equal(t, "resource:dashboard.grafana.app/dashboards/1", res.Tuples[0].Key.Object) + }) +} diff --git a/pkg/services/authz/zanzana/server/server_mutate_test.go b/pkg/services/authz/zanzana/server/server_mutate_test.go new file mode 100644 index 00000000000..70dc1ea2fb8 --- /dev/null +++ b/pkg/services/authz/zanzana/server/server_mutate_test.go @@ -0,0 +1,135 @@ +package server + +import ( + "testing" + + openfgav1 "github.com/openfga/api/proto/openfga/v1" + "github.com/stretchr/testify/require" + + iamv0 "github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1" + v1 "github.com/grafana/grafana/pkg/services/authz/proto/v1" + "github.com/grafana/grafana/pkg/services/authz/zanzana/common" +) + +func setupMutate(t *testing.T, srv *Server) *Server { + t.Helper() + + // seed tuples + tuples := []*openfgav1.TupleKey{ + common.NewFolderParentTuple("11", "1"), + common.NewFolderParentTuple("12", "1"), + common.NewFolderParentTuple("111", "11"), + common.NewFolderParentTuple("112", "11"), + common.NewResourceTuple("user:1", common.RelationGet, dashboardGroup, dashboardResource, "", "1"), + common.NewResourceTuple("user:1", common.RelationUpdate, dashboardGroup, dashboardResource, "", "1"), + common.NewTypedResourceTuple("user:2", common.RelationGet, common.TypeFolder, folderGroup, folderResource, "", "1"), + } + + return setupOpenFGADatabase(t, srv, tuples) +} + +func testMutate(t *testing.T, srv *Server) { + setupMutate(t, srv) + + t.Run("should perform multiple mutate operations", func(t *testing.T) { + _, err := srv.Mutate(newContextWithNamespace(), &v1.MutateRequest{ + Namespace: "default", + Operations: []*v1.MutateOperation{ + { + Operation: &v1.MutateOperation_SetFolderParent{ + SetFolderParent: &v1.SetFolderParentOperation{ + Folder: "new-folder", + Parent: "1", + DeleteExisting: false, + }, + }, + }, + { + Operation: &v1.MutateOperation_CreatePermission{ + CreatePermission: &v1.CreatePermissionOperation{ + Resource: &v1.Resource{ + Group: "dashboard.grafana.app", + Resource: "dashboards", + Name: "foo", + }, + Permission: &v1.Permission{ + Kind: string(iamv0.ResourcePermissionSpecPermissionKindUser), + Name: "bar", + Verb: common.RelationGet, + }, + }, + }, + }, + { + Operation: &v1.MutateOperation_DeletePermission{ + DeletePermission: &v1.DeletePermissionOperation{ + Resource: &v1.Resource{ + Group: "dashboard.grafana.app", + Resource: "dashboards", + Name: "1", + }, + Permission: &v1.Permission{ + Kind: string(iamv0.ResourcePermissionSpecPermissionKindUser), + Name: "1", + Verb: common.RelationUpdate, + }, + }, + }, + }, + { + Operation: &v1.MutateOperation_DeletePermission{ + DeletePermission: &v1.DeletePermissionOperation{ + Resource: &v1.Resource{ + Group: "dashboard.grafana.app", + Resource: "dashboards", + Name: "1", + }, + Permission: &v1.Permission{ + Kind: string(iamv0.ResourcePermissionSpecPermissionKindUser), + Name: "1", + Verb: common.RelationGet, + }, + }, + }, + }, + }, + }) + require.NoError(t, err) + + res, err := srv.Read(newContextWithNamespace(), &v1.ReadRequest{ + Namespace: "default", + TupleKey: &v1.ReadRequestTupleKey{ + Object: "folder:new-folder", + Relation: "parent", + }, + }) + require.NoError(t, err) + require.Len(t, res.Tuples, 1) + require.Equal(t, "folder:new-folder", res.Tuples[0].Key.Object) + require.Equal(t, "parent", res.Tuples[0].Key.Relation) + require.Equal(t, "folder:1", res.Tuples[0].Key.User) + + res, err = srv.Read(newContextWithNamespace(), &v1.ReadRequest{ + Namespace: "default", + TupleKey: &v1.ReadRequestTupleKey{ + Relation: common.RelationGet, + Object: "resource:dashboard.grafana.app/dashboards/foo", + }, + }) + require.NoError(t, err) + require.Len(t, res.Tuples, 1) + require.Equal(t, "user:bar", res.Tuples[0].Key.User) + require.Equal(t, common.RelationGet, res.Tuples[0].Key.Relation) + require.Equal(t, "resource:dashboard.grafana.app/dashboards/foo", res.Tuples[0].Key.Object) + + res, err = srv.Read(newContextWithNamespace(), &v1.ReadRequest{ + Namespace: "default", + TupleKey: &v1.ReadRequestTupleKey{ + Relation: common.RelationGet, + Object: "resource:dashboard.grafana.app/dashboards/1", + }, + }) + require.NoError(t, err) + require.Len(t, res.Tuples, 0) + }) +} diff --git a/pkg/services/authz/zanzana/server/server_test.go b/pkg/services/authz/zanzana/server/server_test.go index 1a9fe263cee..555b9d928cd 100644 --- a/pkg/services/authz/zanzana/server/server_test.go +++ b/pkg/services/authz/zanzana/server/server_test.go @@ -44,6 +44,36 @@ const ( statusSubresource = "status" ) +func setup(t *testing.T, srv *Server) *Server { + // seed tuples + tuples := []*openfgav1.TupleKey{ + common.NewResourceTuple("user:1", common.RelationGet, dashboardGroup, dashboardResource, "", "1"), + common.NewResourceTuple("user:1", common.RelationUpdate, dashboardGroup, dashboardResource, "", "1"), + common.NewGroupResourceTuple("user:2", common.RelationGet, dashboardGroup, dashboardResource, ""), + common.NewGroupResourceTuple("user:2", common.RelationUpdate, dashboardGroup, dashboardResource, ""), + common.NewResourceTuple("user:3", common.RelationSetView, dashboardGroup, dashboardResource, "", "1"), + common.NewFolderResourceTuple("user:4", common.RelationGet, dashboardGroup, dashboardResource, "", "1"), + common.NewFolderResourceTuple("user:4", common.RelationGet, dashboardGroup, dashboardResource, "", "3"), + common.NewFolderResourceTuple("user:5", common.RelationSetEdit, dashboardGroup, dashboardResource, "", "1"), + common.NewFolderTuple("user:6", common.RelationGet, "1"), + common.NewGroupResourceTuple("user:7", common.RelationGet, folderGroup, folderResource, ""), + common.NewFolderParentTuple("5", "4"), + common.NewFolderParentTuple("6", "5"), + common.NewFolderResourceTuple("user:8", common.RelationSetEdit, dashboardGroup, dashboardResource, "", "5"), + common.NewFolderResourceTuple("user:9", common.RelationCreate, dashboardGroup, dashboardResource, "", "5"), + common.NewResourceTuple("user:10", common.RelationGet, dashboardGroup, dashboardResource, statusSubresource, "10"), + common.NewResourceTuple("user:10", common.RelationGet, dashboardGroup, dashboardResource, statusSubresource, "11"), + common.NewGroupResourceTuple("user:11", common.RelationGet, dashboardGroup, dashboardResource, statusSubresource), + common.NewFolderResourceTuple("user:12", common.RelationGet, dashboardGroup, dashboardResource, statusSubresource, "5"), + common.NewFolderResourceTuple("user:13", common.RelationGet, folderGroup, folderResource, statusSubresource, "5"), + common.NewTypedResourceTuple("user:14", common.RelationGet, common.TypeTeam, teamGroup, teamResource, statusSubresource, "1"), + common.NewTypedResourceTuple("user:15", common.RelationGet, common.TypeUser, userGroup, userResource, statusSubresource, "1"), + common.NewTypedResourceTuple("user:16", common.RelationGet, common.TypeServiceAccount, serviceAccountGroup, serviceAccountResource, statusSubresource, "1"), + } + + return setupOpenFGADatabase(t, srv, tuples) +} + func TestMain(m *testing.M) { testsuite.Run(m) } @@ -64,27 +94,43 @@ func TestIntegrationServer(t *testing.T) { } } - srv := setup(t, testStore, cfg) + srv := setupOpenFGAServer(t, testStore, cfg) t.Run("test check", func(t *testing.T) { + setup(t, srv) testCheck(t, srv) }) t.Run("test list", func(t *testing.T) { + setup(t, srv) testList(t, srv) }) t.Run("test list streaming", func(t *testing.T) { + setup(t, srv) srv.cfg.UseStreamedListObjects = true testList(t, srv) srv.cfg.UseStreamedListObjects = false }) t.Run("test batch check", func(t *testing.T) { + setup(t, srv) testBatchCheck(t, srv) }) + + t.Run("test mutate", func(t *testing.T) { + testMutate(t, srv) + }) + + t.Run("test mutate folders", func(t *testing.T) { + testMutateFolders(t, srv) + }) + + t.Run("test mutate resource permissions", func(t *testing.T) { + testMutateResourcePermissions(t, srv) + }) } -func setup(t *testing.T, testDB db.DB, cfg *setting.Cfg) *Server { +func setupOpenFGAServer(t *testing.T, testDB db.DB, cfg *setting.Cfg) *Server { t.Helper() store, err := store.NewEmbeddedStore(cfg, testDB, log.NewNopLogger()) @@ -95,38 +141,25 @@ func setup(t *testing.T, testDB db.DB, cfg *setting.Cfg) *Server { srv, err := NewServer(cfg.ZanzanaServer, openfga, log.NewNopLogger(), tracing.NewNoopTracerService(), prometheus.NewRegistry()) require.NoError(t, err) + return srv +} + +func setupOpenFGADatabase(t *testing.T, srv *Server, tuples []*openfgav1.TupleKey) *Server { + t.Helper() + storeInf, err := srv.getStoreInfo(context.Background(), namespace) require.NoError(t, err) + // Clean up any existing store + _, err = srv.openfga.DeleteStore(context.Background(), &openfgav1.DeleteStoreRequest{ + StoreId: storeInf.ID, + }) + require.NoError(t, err) + // seed tuples writes := &openfgav1.WriteRequestWrites{ - TupleKeys: []*openfgav1.TupleKey{ - common.NewResourceTuple("user:1", common.RelationGet, dashboardGroup, dashboardResource, "", "1"), - common.NewResourceTuple("user:1", common.RelationUpdate, dashboardGroup, dashboardResource, "", "1"), - common.NewGroupResourceTuple("user:2", common.RelationGet, dashboardGroup, dashboardResource, ""), - common.NewGroupResourceTuple("user:2", common.RelationUpdate, dashboardGroup, dashboardResource, ""), - common.NewResourceTuple("user:3", common.RelationSetView, dashboardGroup, dashboardResource, "", "1"), - common.NewFolderResourceTuple("user:4", common.RelationGet, dashboardGroup, dashboardResource, "", "1"), - common.NewFolderResourceTuple("user:4", common.RelationGet, dashboardGroup, dashboardResource, "", "3"), - common.NewFolderResourceTuple("user:5", common.RelationSetEdit, dashboardGroup, dashboardResource, "", "1"), - common.NewFolderTuple("user:6", common.RelationGet, "1"), - common.NewGroupResourceTuple("user:7", common.RelationGet, folderGroup, folderResource, ""), - common.NewFolderParentTuple("5", "4"), - common.NewFolderParentTuple("6", "5"), - common.NewFolderResourceTuple("user:8", common.RelationSetEdit, dashboardGroup, dashboardResource, "", "5"), - common.NewFolderResourceTuple("user:9", common.RelationCreate, dashboardGroup, dashboardResource, "", "5"), - common.NewResourceTuple("user:10", common.RelationGet, dashboardGroup, dashboardResource, statusSubresource, "10"), - common.NewResourceTuple("user:10", common.RelationGet, dashboardGroup, dashboardResource, statusSubresource, "11"), - common.NewGroupResourceTuple("user:11", common.RelationGet, dashboardGroup, dashboardResource, statusSubresource), - common.NewFolderResourceTuple("user:12", common.RelationGet, dashboardGroup, dashboardResource, statusSubresource, "5"), - common.NewFolderResourceTuple("user:13", common.RelationGet, folderGroup, folderResource, statusSubresource, "5"), - common.NewTypedResourceTuple("user:14", common.RelationGet, common.TypeTeam, teamGroup, teamResource, statusSubresource, "1"), - common.NewTypedResourceTuple("user:15", common.RelationGet, common.TypeUser, userGroup, userResource, statusSubresource, "1"), - common.NewTypedResourceTuple("user:16", common.RelationGet, common.TypeServiceAccount, serviceAccountGroup, serviceAccountResource, statusSubresource, "1"), - }, - } - for _, w := range writes.TupleKeys { - t.Log(w.String()) + TupleKeys: tuples, + OnDuplicate: "ignore", } // First, try to delete any existing tuples to avoid conflicts @@ -140,16 +173,18 @@ func setup(t *testing.T, testDB db.DB, cfg *setting.Cfg) *Server { } // Try to delete existing tuples (ignore errors if they don't exist) - _, _ = openfga.Write(context.Background(), &openfgav1.WriteRequest{ + _, err = srv.openfga.Write(context.Background(), &openfgav1.WriteRequest{ StoreId: storeInf.ID, AuthorizationModelId: storeInf.ModelID, Deletes: &openfgav1.WriteRequestDeletes{ TupleKeys: deletes, + OnMissing: "ignore", }, }) + require.NoError(t, err) // Now write the new tuples - _, err = openfga.Write(context.Background(), &openfgav1.WriteRequest{ + _, err = srv.openfga.Write(context.Background(), &openfgav1.WriteRequest{ StoreId: storeInf.ID, AuthorizationModelId: storeInf.ModelID, Writes: writes, diff --git a/pkg/services/authz/zanzana/store.go b/pkg/services/authz/zanzana/store.go deleted file mode 100644 index 67361386744..00000000000 --- a/pkg/services/authz/zanzana/store.go +++ /dev/null @@ -1,18 +0,0 @@ -package zanzana - -import ( - "github.com/openfga/openfga/pkg/storage" - - "github.com/grafana/grafana/pkg/infra/db" - "github.com/grafana/grafana/pkg/infra/log" - "github.com/grafana/grafana/pkg/setting" - - "github.com/grafana/grafana/pkg/services/authz/zanzana/store" -) - -func NewStore(cfg *setting.Cfg, logger log.Logger) (storage.OpenFGADatastore, error) { - return store.NewStore(cfg, logger) -} -func NewEmbeddedStore(cfg *setting.Cfg, db db.DB, logger log.Logger) (storage.OpenFGADatastore, error) { - return store.NewEmbeddedStore(cfg, db, logger) -} diff --git a/pkg/services/authz/zanzana/zanzana.go b/pkg/services/authz/zanzana/zanzana.go index a63f581b9ca..6cadfc0c199 100644 --- a/pkg/services/authz/zanzana/zanzana.go +++ b/pkg/services/authz/zanzana/zanzana.go @@ -1,12 +1,6 @@ package zanzana import ( - "fmt" - "strings" - - openfgav1 "github.com/openfga/api/proto/openfga/v1" - - authlib "github.com/grafana/authlib/types" "github.com/grafana/grafana/pkg/services/authz/zanzana/common" ) @@ -54,8 +48,8 @@ var ( ) const ( - KindDashboards string = "dashboards" - KindFolders string = "folders" + KindDashboards = common.KindDashboards + KindFolders = common.KindFolders ) var ( @@ -68,128 +62,15 @@ var ( ToOpenFGATuples = common.ToOpenFGATuples ToOpenFGATupleKey = common.ToOpenFGATupleKey ToOpenFGATupleKeyWithoutCondition = common.ToOpenFGATupleKeyWithoutCondition + + NewTupleEntry = common.NewTupleEntry + NewObjectEntry = common.NewObjectEntry + TranslateToResourceTuple = common.TranslateToResourceTuple + IsFolderResourceTuple = common.IsFolderResourceTuple + MergeFolderResourceTuples = common.MergeFolderResourceTuples + + TranslateToCheckRequest = common.TranslateToCheckRequest + TranslateToListRequest = common.TranslateToListRequest + TranslateToGroupResource = common.TranslateToGroupResource + TranslateBasicRole = common.TranslateBasicRole ) - -// NewTupleEntry constructs new openfga entry type:name[#relation]. -// Relation allows to specify group of users (subjects) related to type:name -// (for example, team:devs#member refers to users which are members of team devs) -func NewTupleEntry(objectType, name, relation string) string { - obj := fmt.Sprintf("%s:%s", objectType, name) - if relation != "" { - obj = fmt.Sprintf("%s#%s", obj, relation) - } - return obj -} - -func NewObjectEntry(objectType, group, resource, subresource, name string) string { - if objectType == TypeFolder { - return TypeFolder + ":" + name - } - - obj := fmt.Sprintf("%s:%s/%s", objectType, group, resource) - if subresource != "" { - obj = fmt.Sprintf("%s/%s", obj, subresource) - } - if name != "" { - obj = fmt.Sprintf("%s/%s", obj, name) - } - return obj -} - -func TranslateToResourceTuple(subject string, action, kind, name string) (*openfgav1.TupleKey, bool) { - translation, ok := resourceTranslations[kind] - - if !ok { - return nil, false - } - - m, ok := translation.mapping[action] - if !ok { - return nil, false - } - - if name == "*" { - return common.NewGroupResourceTuple(subject, m.relation, translation.group, translation.resource, m.subresource), true - } - - if translation.typ == TypeResource { - return common.NewResourceTuple(subject, m.relation, translation.group, translation.resource, m.subresource, name), true - } - - if translation.typ == TypeFolder { - if m.group != "" && m.resource != "" { - return common.NewFolderResourceTuple(subject, m.relation, m.group, m.resource, m.subresource, name), true - } - - return common.NewFolderTuple(subject, m.relation, name), true - } - - return common.NewTypedTuple(translation.typ, subject, m.relation, name), true -} - -func IsFolderResourceTuple(t *openfgav1.TupleKey) bool { - return strings.HasPrefix(t.Object, TypeFolder) && strings.HasPrefix(t.Relation, "resource_") -} - -func MergeFolderResourceTuples(a, b *openfgav1.TupleKey) { - va := a.Condition.Context.Fields["subresources"] - vb := b.Condition.Context.Fields["subresources"] - va.GetListValue().Values = append(va.GetListValue().Values, vb.GetListValue().Values...) -} - -func TranslateToCheckRequest(namespace, action, kind, name string) (*authlib.CheckRequest, bool) { - translation, ok := resourceTranslations[kind] - - if !ok { - return nil, false - } - - m, ok := translation.mapping[action] - if !ok { - return nil, false - } - - verb, ok := common.RelationToVerbMapping[m.relation] - if !ok { - return nil, false - } - - req := &authlib.CheckRequest{ - Namespace: namespace, - Verb: verb, - Group: translation.group, - Resource: translation.resource, - Name: name, - } - - return req, true -} - -func TranslateToListRequest(namespace, action, kind string) (*authlib.ListRequest, bool) { - translation, ok := resourceTranslations[kind] - - if !ok { - return nil, false - } - - // FIXME: support different verbs - req := &authlib.ListRequest{ - Namespace: namespace, - Group: translation.group, - Resource: translation.resource, - } - - return req, true -} - -func TranslateToGroupResource(kind string) string { - translation, ok := resourceTranslations[kind] - if !ok { - return "" - } - return common.FormatGroupResource(translation.group, translation.resource, "") -} - -func TranslateBasicRole(name string) string { - return basicRolesTranslations[name] -} From 74a9a288e265fc94a63e7b91ca421cb5f844d468 Mon Sep 17 00:00:00 2001 From: Christian Simon Date: Tue, 28 Oct 2025 10:39:00 +0000 Subject: [PATCH 045/378] grafana-flamegraph: Improve prompt for open assistant to analyze flamegraph (#113071) * feat: Improve prompt for open assistant Existing prompt is not specific enough and uses a new visual tool, which will result in taking a screenshot to analyze the flame graph. * Apply suggestion from @cyriltovena less instructions for now. --------- Co-authored-by: Cyril Tovena --- packages/grafana-flamegraph/src/FlameGraphHeader.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/grafana-flamegraph/src/FlameGraphHeader.tsx b/packages/grafana-flamegraph/src/FlameGraphHeader.tsx index 46f6cde182f..fbeb0ad3c6a 100644 --- a/packages/grafana-flamegraph/src/FlameGraphHeader.tsx +++ b/packages/grafana-flamegraph/src/FlameGraphHeader.tsx @@ -90,7 +90,11 @@ const FlameGraphHeader = ({
{!!assistantContext?.length && (
- +
)} {showResetButton && ( From b39708e4398d06d72e5b53d7882cfc8829b56281 Mon Sep 17 00:00:00 2001 From: Ashley Harrison Date: Tue, 28 Oct 2025 10:48:44 +0000 Subject: [PATCH 046/378] Accessibility: Wrap data source info onto 2 lines at small viewports (#113033) * wrap data source info onto 2 lines at small viewports * undo other changes * need flex-start --- .../datasources/components/picker/DataSourceCard.tsx | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/public/app/features/datasources/components/picker/DataSourceCard.tsx b/public/app/features/datasources/components/picker/DataSourceCard.tsx index 989673d8829..dbdbdc2512a 100644 --- a/public/app/features/datasources/components/picker/DataSourceCard.tsx +++ b/public/app/features/datasources/components/picker/DataSourceCard.tsx @@ -89,6 +89,12 @@ function getStyles(theme: GrafanaTheme2, builtIn = false) { justifyContent: 'space-between', columnGap: theme.spacing(1), alignItems: 'center', + + [theme.breakpoints.down('sm')]: { + display: 'grid', + gridTemplateColumns: '1fr', + gridTemplateRows: 'repeat(2, 1fr)', + }, }), rightSection: css({ display: 'flex', @@ -99,6 +105,9 @@ function getStyles(theme: GrafanaTheme2, builtIn = false) { justifyContent: 'flex-end', overflow: 'hidden', textOverflow: 'ellipsis', + [theme.breakpoints.down('sm')]: { + justifyContent: 'flex-start', + }, }), logo: css({ width: '32px', From 68bc0f80768fe848fb43165011b34ddf875ef82c Mon Sep 17 00:00:00 2001 From: Konrad Lalik Date: Tue, 28 Oct 2025 12:09:41 +0100 Subject: [PATCH 047/378] Alerting: Use common labels tooltip in Triage (#113072) * Add a tooltip mode for common labels and use it in Triage workbench * Change Tooltip to ToggleTip for displaying common labels --- .../rules/components/labels/AlertLabels.tsx | 65 ++++++++++++++----- .../unified/triage/rows/InstanceRow.tsx | 1 + 2 files changed, 49 insertions(+), 17 deletions(-) diff --git a/packages/grafana-alerting/src/grafana/rules/components/labels/AlertLabels.tsx b/packages/grafana-alerting/src/grafana/rules/components/labels/AlertLabels.tsx index 3646c02a13e..b2bd9fee77d 100644 --- a/packages/grafana-alerting/src/grafana/rules/components/labels/AlertLabels.tsx +++ b/packages/grafana-alerting/src/grafana/rules/components/labels/AlertLabels.tsx @@ -1,10 +1,10 @@ import { css } from '@emotion/css'; import { chain } from 'lodash'; -import { useState } from 'react'; +import { useMemo, useState } from 'react'; import { GrafanaTheme2 } from '@grafana/data'; import { Trans, t } from '@grafana/i18n'; -import { Button, useStyles2 } from '@grafana/ui'; +import { Button, Stack, Toggletip, useStyles2 } from '@grafana/ui'; import { findCommonLabels, isPrivateLabel } from '../../utils/labels'; @@ -16,14 +16,24 @@ export interface AlertLabelsProps { labelSets?: Array>; size?: LabelSize; onClick?: ([value, key]: [string | undefined, string | undefined]) => void; + commonLabelsMode?: 'expand' | 'tooltip'; } -export const AlertLabels = ({ labels, displayCommonLabels, labelSets, size, onClick }: AlertLabelsProps) => { +export const AlertLabels = ({ + labels, + displayCommonLabels, + labelSets, + size, + onClick, + commonLabelsMode = 'expand', +}: AlertLabelsProps) => { const styles = useStyles2(getStyles, size); const [showCommonLabels, setShowCommonLabels] = useState(false); - const computedCommonLabels = - displayCommonLabels && Array.isArray(labelSets) && labelSets.length > 1 ? findCommonLabels(labelSets) : {}; + const computedCommonLabels = useMemo( + () => (displayCommonLabels && Array.isArray(labelSets) && labelSets.length > 1 ? findCommonLabels(labelSets) : {}), + [displayCommonLabels, labelSets] + ); const labelsToShow = chain(labels) .toPairs() @@ -35,6 +45,17 @@ export const AlertLabels = ({ labels, displayCommonLabels, labelSets, size, onCl const hasCommonLabels = commonLabelsCount > 0; const tooltip = t('alert-labels.button.show.tooltip', 'Show common labels'); + const commonLabelsTooltip = useMemo( + () => ( + + {Object.entries(computedCommonLabels).map(([label, value]) => ( + + ))} + + ), + [computedCommonLabels, size] + ); + return (
{labelsToShow.map(([label, value]) => { @@ -53,18 +74,28 @@ export const AlertLabels = ({ labels, displayCommonLabels, labelSets, size, onCl {!showCommonLabels && hasCommonLabels && (
- + {commonLabelsMode === 'expand' ? ( + + ) : ( + + + + )}
)} {showCommonLabels && hasCommonLabels && ( diff --git a/public/app/features/alerting/unified/triage/rows/InstanceRow.tsx b/public/app/features/alerting/unified/triage/rows/InstanceRow.tsx index e18898aa48e..6bff83f9b20 100644 --- a/public/app/features/alerting/unified/triage/rows/InstanceRow.tsx +++ b/public/app/features/alerting/unified/triage/rows/InstanceRow.tsx @@ -112,6 +112,7 @@ export function InstanceRow({ displayCommonLabels={true} labelSets={[instance.labels, commonLabels]} size="xs" + commonLabelsMode="tooltip" /> ) } From 7df95261f374c985977da9cd130edf1970b0ec3a Mon Sep 17 00:00:00 2001 From: Oscar Kilhed Date: Tue, 28 Oct 2025 13:55:20 +0100 Subject: [PATCH 048/378] Dynamic dashboards: Refactor ungroup rows and tabs (#112575) * refactor ungroup * deleting last row/tab no longer ungroups * Change test for deleting last row to not test for ungroup * fix comment with correct pull request * use isLayoutGroup instead * fix implementations * missing import --- .../AutoGridLayoutManager.tsx | 17 +++---- .../DefaultGridLayoutManager.tsx | 14 +++--- .../layout-rows/RowsLayoutManager.test.tsx | 6 ++- .../scene/layout-rows/RowsLayoutManager.tsx | 27 +++++------ .../layout-rows/RowsLayoutManagerRenderer.tsx | 18 ++++---- .../scene/layout-tabs/TabsLayoutManager.tsx | 45 +++++-------------- .../scene/types/DashboardLayoutGrid.ts | 12 +++++ .../scene/types/DashboardLayoutGroup.ts | 21 +++++++++ .../scene/types/DashboardLayoutManager.ts | 5 --- 9 files changed, 84 insertions(+), 81 deletions(-) create mode 100644 public/app/features/dashboard-scene/scene/types/DashboardLayoutGrid.ts create mode 100644 public/app/features/dashboard-scene/scene/types/DashboardLayoutGroup.ts diff --git a/public/app/features/dashboard-scene/scene/layout-auto-grid/AutoGridLayoutManager.tsx b/public/app/features/dashboard-scene/scene/layout-auto-grid/AutoGridLayoutManager.tsx index a83da646ca8..737629562fc 100644 --- a/public/app/features/dashboard-scene/scene/layout-auto-grid/AutoGridLayoutManager.tsx +++ b/public/app/features/dashboard-scene/scene/layout-auto-grid/AutoGridLayoutManager.tsx @@ -16,6 +16,7 @@ import { } from '../../utils/utils'; import { DashboardGridItem } from '../layout-default/DashboardGridItem'; import { clearClipboard, getAutoGridItemFromClipboard } from '../layouts-shared/paste'; +import { DashboardLayoutGrid } from '../types/DashboardLayoutGrid'; import { DashboardLayoutManager } from '../types/DashboardLayoutManager'; import { LayoutRegistryItem } from '../types/LayoutRegistryItem'; @@ -38,10 +39,7 @@ export const AUTO_GRID_DEFAULT_MAX_COLUMN_COUNT = 3; export const AUTO_GRID_DEFAULT_COLUMN_WIDTH = 'standard'; export const AUTO_GRID_DEFAULT_ROW_HEIGHT = 'standard'; -export class AutoGridLayoutManager - extends SceneObjectBase - implements DashboardLayoutManager -{ +export class AutoGridLayoutManager extends SceneObjectBase implements DashboardLayoutGrid { public static Component = AutoGridLayoutManagerRenderer; public readonly isDashboardLayoutManager = true; @@ -200,12 +198,11 @@ export class AutoGridLayoutManager }); } - public merge(other: DashboardLayoutManager) { - if (!(other instanceof AutoGridLayoutManager)) { - throw new Error('Cannot merge non-auto grid layout'); - } - - const sourceLayout = other.state.layout; + public mergeGrid(other: DashboardLayoutGrid) { + const sourceLayout = + other instanceof AutoGridLayoutManager + ? other.state.layout + : AutoGridLayoutManager.createFromLayout(other).state.layout; const movedChildren = [...sourceLayout.state.children]; // Remove from source and append to destination diff --git a/public/app/features/dashboard-scene/scene/layout-default/DefaultGridLayoutManager.tsx b/public/app/features/dashboard-scene/scene/layout-default/DefaultGridLayoutManager.tsx index 8c62ed47db0..294dc4230f7 100644 --- a/public/app/features/dashboard-scene/scene/layout-default/DefaultGridLayoutManager.tsx +++ b/public/app/features/dashboard-scene/scene/layout-default/DefaultGridLayoutManager.tsx @@ -48,6 +48,7 @@ import { CanvasGridAddActions } from '../layouts-shared/CanvasGridAddActions'; import { clearClipboard, getDashboardGridItemFromClipboard } from '../layouts-shared/paste'; import { dashboardCanvasAddButtonHoverStyles } from '../layouts-shared/styles'; import { getIsLazy } from '../layouts-shared/utils'; +import { DashboardLayoutGrid } from '../types/DashboardLayoutGrid'; import { DashboardLayoutManager } from '../types/DashboardLayoutManager'; import { LayoutRegistryItem } from '../types/LayoutRegistryItem'; @@ -62,7 +63,7 @@ interface DefaultGridLayoutManagerState extends SceneObjectState { export class DefaultGridLayoutManager extends SceneObjectBase - implements DashboardLayoutManager + implements DashboardLayoutGrid { public static Component = DefaultGridLayoutManagerRenderer; @@ -93,11 +94,7 @@ export class DefaultGridLayoutManager this.addActivationHandler(() => this._activationHandler()); } - public merge(other: DashboardLayoutManager) { - if (!(other instanceof DefaultGridLayoutManager)) { - throw new Error('Cannot merge non-default grid layout'); - } - + public mergeGrid(other: DashboardLayoutGrid) { let offset = 0; for (const child of this.state.grid.state.children) { const newOffset = (child.state.y ?? 0) + (child.state.height ?? 0); @@ -106,7 +103,10 @@ export class DefaultGridLayoutManager } } - const sourceGrid = other.state.grid; + const sourceGrid = + other instanceof DefaultGridLayoutManager + ? other.state.grid + : DefaultGridLayoutManager.createFromLayout(other).state.grid; const movedChildren = [...sourceGrid.state.children]; for (const child of movedChildren) { diff --git a/public/app/features/dashboard-scene/scene/layout-rows/RowsLayoutManager.test.tsx b/public/app/features/dashboard-scene/scene/layout-rows/RowsLayoutManager.test.tsx index dbadd5def5e..ba8063aeb26 100644 --- a/public/app/features/dashboard-scene/scene/layout-rows/RowsLayoutManager.test.tsx +++ b/public/app/features/dashboard-scene/scene/layout-rows/RowsLayoutManager.test.tsx @@ -117,12 +117,14 @@ describe('RowsLayoutManager', () => { expect(manager.state.rows).toContain(row2); }); - it('should call ungroupLayout when removing the last row', () => { + it('should not call ungroupLayout when removing the last row', () => { const manager = new RowsLayoutManager({ rows: [] }); const row = manager.addNewRow(new RowItem({ title: 'Only Row' })); expect(manager.state.rows).toHaveLength(1); manager.removeRow(row); - expect(ungroupLayoutCalled).toBe(true); + // This behavior was changed in the PR https://github.com/grafana/grafana/pull/112575 + // The delete row button should have one consistent behavior, no matter if it's the last row or not. + expect(ungroupLayoutCalled).toBe(false); }); }); }); diff --git a/public/app/features/dashboard-scene/scene/layout-rows/RowsLayoutManager.tsx b/public/app/features/dashboard-scene/scene/layout-rows/RowsLayoutManager.tsx index 3a2cd8df171..49c3e0fd0a9 100644 --- a/public/app/features/dashboard-scene/scene/layout-rows/RowsLayoutManager.tsx +++ b/public/app/features/dashboard-scene/scene/layout-rows/RowsLayoutManager.tsx @@ -22,6 +22,8 @@ import { findAllGridTypes } from '../layouts-shared/findAllGridTypes'; import { getRowFromClipboard } from '../layouts-shared/paste'; import { showConvertMixedGridsModal, showUngroupConfirmation } from '../layouts-shared/ungroupConfirmation'; import { generateUniqueTitle, ungroupLayout, GridLayoutType, mapIdToGridLayoutType } from '../layouts-shared/utils'; +import { isDashboardLayoutGrid } from '../types/DashboardLayoutGrid'; +import { DashboardLayoutGroup, isDashboardLayoutGroup } from '../types/DashboardLayoutGroup'; import { DashboardLayoutManager } from '../types/DashboardLayoutManager'; import { isLayoutParent } from '../types/LayoutParent'; import { LayoutRegistryItem } from '../types/LayoutRegistryItem'; @@ -33,7 +35,7 @@ interface RowsLayoutManagerState extends SceneObjectState { rows: RowItem[]; } -export class RowsLayoutManager extends SceneObjectBase implements DashboardLayoutManager { +export class RowsLayoutManager extends SceneObjectBase implements DashboardLayoutGroup { public static Component = RowLayoutManagerRenderer; public readonly isDashboardLayoutManager = true; @@ -134,7 +136,7 @@ export class RowsLayoutManager extends SceneObjectBase i return outlineChildren; } - public convertAllRowsLayouts(gridLayoutType: GridLayoutType) { + public convertAllGridLayouts(gridLayoutType: GridLayoutType) { for (const row of this.state.rows) { switch (gridLayoutType) { case GridLayoutType.AutoGridLayout: @@ -189,7 +191,7 @@ export class RowsLayoutManager extends SceneObjectBase i description: t('dashboard.rows-layout.edit.ungroup-rows', 'Ungroup rows'), source: scene, perform: () => { - this._ungroupRows(gridLayoutType); + this.ungroup(gridLayoutType); }, undo: () => { parent.switchLayout(previousLayout); @@ -197,15 +199,15 @@ export class RowsLayoutManager extends SceneObjectBase i }); } - private _ungroupRows(gridLayoutType: GridLayoutType) { + public ungroup(gridLayoutType: GridLayoutType) { const hasNonGridLayout = this.state.rows.some((row) => !row.getLayout().descriptor.isGridLayout); if (hasNonGridLayout) { for (const row of this.state.rows) { const layout = row.getLayout(); if (!layout.descriptor.isGridLayout) { - if (layout instanceof RowsLayoutManager) { - layout._ungroupRows(gridLayoutType); + if (isDashboardLayoutGroup(layout)) { + layout.ungroup(gridLayoutType); } else { throw new Error(`Ungrouping not supported for layout type: ${layout.descriptor.name}`); } @@ -213,7 +215,7 @@ export class RowsLayoutManager extends SceneObjectBase i } } - this.convertAllRowsLayouts(gridLayoutType); + this.convertAllGridLayouts(gridLayoutType); const firstRow = this.state.rows[0]; const firstRowLayout = firstRow.getLayout(); @@ -221,8 +223,8 @@ export class RowsLayoutManager extends SceneObjectBase i for (const row of otherRows) { const layout = row.getLayout(); - if (firstRowLayout.merge) { - firstRowLayout.merge(layout); + if (isDashboardLayoutGrid(firstRowLayout) && isDashboardLayoutGrid(layout)) { + firstRowLayout.mergeGrid(layout); } else { throw new Error(`Layout type ${firstRowLayout.descriptor.name} does not support merging`); } @@ -230,15 +232,10 @@ export class RowsLayoutManager extends SceneObjectBase i this.setState({ rows: [firstRow] }); this.removeRow(firstRow, true); + ungroupLayout(this, firstRow.state.layout, true); } public removeRow(row: RowItem, skipUndo?: boolean) { - // When removing last row replace ourselves with the inner row layout - if (this.shouldUngroup()) { - ungroupLayout(this, row.state.layout, skipUndo ?? false); - return; - } - const indexOfRowToRemove = this.state.rows.findIndex((r) => r === row); const perform = () => this.setState({ rows: this.state.rows.filter((r) => r !== row) }); diff --git a/public/app/features/dashboard-scene/scene/layout-rows/RowsLayoutManagerRenderer.tsx b/public/app/features/dashboard-scene/scene/layout-rows/RowsLayoutManagerRenderer.tsx index 85310dc65bf..ce58ed2c5ef 100644 --- a/public/app/features/dashboard-scene/scene/layout-rows/RowsLayoutManagerRenderer.tsx +++ b/public/app/features/dashboard-scene/scene/layout-rows/RowsLayoutManagerRenderer.tsx @@ -53,15 +53,6 @@ export function RowLayoutManagerRenderer({ model }: SceneComponentProps - )} +
)}
diff --git a/public/app/features/dashboard-scene/scene/layout-tabs/TabsLayoutManager.tsx b/public/app/features/dashboard-scene/scene/layout-tabs/TabsLayoutManager.tsx index 33229cc8964..10933b9c0b2 100644 --- a/public/app/features/dashboard-scene/scene/layout-tabs/TabsLayoutManager.tsx +++ b/public/app/features/dashboard-scene/scene/layout-tabs/TabsLayoutManager.tsx @@ -21,6 +21,8 @@ import { findAllGridTypes } from '../layouts-shared/findAllGridTypes'; import { getTabFromClipboard } from '../layouts-shared/paste'; import { showConvertMixedGridsModal, showUngroupConfirmation } from '../layouts-shared/ungroupConfirmation'; import { generateUniqueTitle, ungroupLayout, GridLayoutType, mapIdToGridLayoutType } from '../layouts-shared/utils'; +import { isDashboardLayoutGrid } from '../types/DashboardLayoutGrid'; +import { DashboardLayoutGroup, isDashboardLayoutGroup } from '../types/DashboardLayoutGroup'; import { DashboardLayoutManager } from '../types/DashboardLayoutManager'; import { isLayoutParent } from '../types/LayoutParent'; import { LayoutRegistryItem } from '../types/LayoutRegistryItem'; @@ -33,7 +35,7 @@ interface TabsLayoutManagerState extends SceneObjectState { currentTabSlug?: string; } -export class TabsLayoutManager extends SceneObjectBase implements DashboardLayoutManager { +export class TabsLayoutManager extends SceneObjectBase implements DashboardLayoutGroup { public static Component = TabsLayoutManagerRenderer; public readonly isDashboardLayoutManager = true; @@ -71,21 +73,6 @@ export class TabsLayoutManager extends SceneObjectBase i throw new Error('Method not implemented.'); } - public merge(other: DashboardLayoutManager) { - if (!(other instanceof TabsLayoutManager)) { - throw new Error('Cannot merge non-tabs layout'); - } - - // Merge all tabs from the other layout into this one - const otherTabs = other.state.tabs; - const mergedTabs = [...this.state.tabs, ...otherTabs]; - - // Clear parent from merged tabs to avoid conflicts - otherTabs.forEach((tab) => tab.clearParent()); - - this.setState({ tabs: mergedTabs }); - } - public duplicateTab(tab: TabItem) { const newTab = tab.duplicate(); this.addNewTab(newTab); @@ -223,7 +210,7 @@ export class TabsLayoutManager extends SceneObjectBase i return this.state.tabs.length === 1; } - public convertAllTabsLayouts(gridLayoutType: GridLayoutType) { + public convertAllGridLayouts(gridLayoutType: GridLayoutType) { for (const tab of this.state.tabs) { switch (gridLayoutType) { case GridLayoutType.AutoGridLayout: @@ -278,7 +265,7 @@ export class TabsLayoutManager extends SceneObjectBase i description: t('dashboard.tabs-layout.edit.ungroup-tabs', 'Ungroup tabs'), source: scene, perform: () => { - this._ungroupTabs(gridLayoutType); + this.ungroup(gridLayoutType); }, undo: () => { parent.switchLayout(previousLayout); @@ -286,17 +273,15 @@ export class TabsLayoutManager extends SceneObjectBase i }); } - private _ungroupTabs(gridLayoutType: GridLayoutType) { + public ungroup(gridLayoutType: GridLayoutType) { const hasNonGridLayout = this.state.tabs.some((tab) => !tab.getLayout().descriptor.isGridLayout); if (hasNonGridLayout) { for (const tab of this.state.tabs) { const layout = tab.getLayout(); if (!layout.descriptor.isGridLayout) { - if (layout instanceof TabsLayoutManager) { - layout._ungroupTabs(gridLayoutType); - } else if (layout instanceof RowsLayoutManager) { - layout.ungroupRows(); + if (isDashboardLayoutGroup(layout)) { + layout.ungroup(gridLayoutType); } else { throw new Error(`Ungrouping not supported for layout type: ${layout.descriptor.name}`); } @@ -304,7 +289,7 @@ export class TabsLayoutManager extends SceneObjectBase i } } - this.convertAllTabsLayouts(gridLayoutType); + this.convertAllGridLayouts(gridLayoutType); const firstTab = this.state.tabs[0]; const firstTabLayout = firstTab.getLayout(); @@ -312,24 +297,18 @@ export class TabsLayoutManager extends SceneObjectBase i for (const tab of otherTabs) { const layout = tab.getLayout(); - if (firstTabLayout.merge) { - firstTabLayout.merge(layout); + if (isDashboardLayoutGrid(firstTabLayout) && isDashboardLayoutGrid(layout)) { + firstTabLayout.mergeGrid(layout); } else { throw new Error(`Layout type ${firstTabLayout.descriptor.name} does not support merging`); } } this.setState({ tabs: [firstTab] }); - this.removeTab(firstTab, true); + ungroupLayout(this, firstTab.state.layout, true); } public removeTab(tabToRemove: TabItem, skipUndo?: boolean) { - // When removing last tab replace ourselves with the inner tab layout - if (this.shouldUngroup()) { - ungroupLayout(this, tabToRemove.state.layout, skipUndo ?? false); - return; - } - const tabIndex = this.state.tabs.findIndex((t) => t === tabToRemove); const perform = () => { diff --git a/public/app/features/dashboard-scene/scene/types/DashboardLayoutGrid.ts b/public/app/features/dashboard-scene/scene/types/DashboardLayoutGrid.ts new file mode 100644 index 00000000000..3f6bcb2bcc6 --- /dev/null +++ b/public/app/features/dashboard-scene/scene/types/DashboardLayoutGrid.ts @@ -0,0 +1,12 @@ +import { DashboardLayoutManager } from './DashboardLayoutManager'; + +export interface DashboardLayoutGrid extends DashboardLayoutManager { + /** + * Merge the layout with another layout + */ + mergeGrid(other: DashboardLayoutGrid): void; +} + +export function isDashboardLayoutGrid(obj: DashboardLayoutManager): obj is DashboardLayoutGrid { + return 'mergeGrid' in obj; +} diff --git a/public/app/features/dashboard-scene/scene/types/DashboardLayoutGroup.ts b/public/app/features/dashboard-scene/scene/types/DashboardLayoutGroup.ts new file mode 100644 index 00000000000..034eb8642e2 --- /dev/null +++ b/public/app/features/dashboard-scene/scene/types/DashboardLayoutGroup.ts @@ -0,0 +1,21 @@ +import { GridLayoutType } from '../layouts-shared/utils'; + +import { DashboardLayoutManager } from './DashboardLayoutManager'; + +export interface DashboardLayoutGroup extends DashboardLayoutManager { + /** + * Ungroup the group + * @param gridLayoutType + */ + ungroup(gridLayoutType: GridLayoutType): void; + + /** + * Convert all layouts to the given grid layout type + * @param gridLayoutType + */ + convertAllGridLayouts(gridLayoutType: GridLayoutType): void; +} + +export function isDashboardLayoutGroup(obj: DashboardLayoutManager): obj is DashboardLayoutGroup { + return 'ungroup' in obj && 'convertAllGridLayouts' in obj; +} diff --git a/public/app/features/dashboard-scene/scene/types/DashboardLayoutManager.ts b/public/app/features/dashboard-scene/scene/types/DashboardLayoutManager.ts index 0db0463bc22..73a9d7329e0 100644 --- a/public/app/features/dashboard-scene/scene/types/DashboardLayoutManager.ts +++ b/public/app/features/dashboard-scene/scene/types/DashboardLayoutManager.ts @@ -86,11 +86,6 @@ export interface DashboardLayoutManager extends SceneObject { * Get children for outline */ getOutlineChildren(): SceneObject[]; - - /** - * Merge the layout with another layout - */ - merge?(other: DashboardLayoutManager): void; } export interface LayoutManagerSerializer { From 5670f1c34c2bd8908da337c912cda072a1c23540 Mon Sep 17 00:00:00 2001 From: Gilles De Mey Date: Tue, 28 Oct 2025 14:23:29 +0100 Subject: [PATCH 049/378] Alerting: Normalize health when filtering rules (#113087) --- .../src/grafana/rules/components/state/types.ts | 2 +- .../unified/rule-list/components/util.ts | 2 +- .../unified/rule-list/hooks/filters.test.ts | 17 +++++++++++++++++ .../alerting/unified/rule-list/hooks/filters.ts | 3 ++- 4 files changed, 21 insertions(+), 3 deletions(-) diff --git a/packages/grafana-alerting/src/grafana/rules/components/state/types.ts b/packages/grafana-alerting/src/grafana/rules/components/state/types.ts index c37ff0851f4..65e2c165f2f 100644 --- a/packages/grafana-alerting/src/grafana/rules/components/state/types.ts +++ b/packages/grafana-alerting/src/grafana/rules/components/state/types.ts @@ -1,3 +1,3 @@ -export type Health = 'nodata' | 'error'; +export type Health = 'ok' | 'nodata' | 'error'; export type State = 'normal' | 'firing' | 'pending' | 'unknown' | 'recovering'; export type Type = 'alerting' | 'recording'; diff --git a/public/app/features/alerting/unified/rule-list/components/util.ts b/public/app/features/alerting/unified/rule-list/components/util.ts index c04ad5b3f0b..60e5f6d5352 100644 --- a/public/app/features/alerting/unified/rule-list/components/util.ts +++ b/public/app/features/alerting/unified/rule-list/components/util.ts @@ -93,7 +93,7 @@ export function normalizeHealth(health?: RuleHealth): NormalizedHealth { } function isValidHealth(health: string): health is NonNullable { - const valid: Array> = ['nodata', 'error'] as const; + const valid: Array> = ['ok', 'nodata', 'error'] as const; return valid.some((v) => v === health); } diff --git a/public/app/features/alerting/unified/rule-list/hooks/filters.test.ts b/public/app/features/alerting/unified/rule-list/hooks/filters.test.ts index 18e4af4f40f..729576da9f2 100644 --- a/public/app/features/alerting/unified/rule-list/hooks/filters.test.ts +++ b/public/app/features/alerting/unified/rule-list/hooks/filters.test.ts @@ -138,9 +138,26 @@ describe('ruleFilter', () => { health: RuleHealth.Error, }); + const prometheusErrorRule = mockPromAlertingRule({ + name: 'Error Rule', + health: 'err', + }); + expect(ruleFilter(healthyRule, getFilter({ ruleHealth: RuleHealth.Ok }))).toBe(true); expect(ruleFilter(healthyRule, getFilter({ ruleHealth: RuleHealth.Error }))).toBe(false); expect(ruleFilter(errorRule, getFilter({ ruleHealth: RuleHealth.Error }))).toBe(true); + expect(ruleFilter(prometheusErrorRule, getFilter({ ruleHealth: RuleHealth.Error }))).toBe(true); + }); + + it('should normalize health values when filtering', () => { + // Legacy Prometheus health value 'err' should be normalized to 'error' + const legacyErrorRule = mockPromAlertingRule({ + name: 'Legacy Error Rule', + health: 'err', + }); + + // When filtering for 'error', it should match rules with health 'err' (legacy) or 'error' + expect(ruleFilter(legacyErrorRule, getFilter({ ruleHealth: RuleHealth.Error }))).toBe(true); }); it('should filter by dashboard UID', () => { diff --git a/public/app/features/alerting/unified/rule-list/hooks/filters.ts b/public/app/features/alerting/unified/rule-list/hooks/filters.ts index 2e9535dd97f..96db43ad35a 100644 --- a/public/app/features/alerting/unified/rule-list/hooks/filters.ts +++ b/public/app/features/alerting/unified/rule-list/hooks/filters.ts @@ -11,6 +11,7 @@ import { getDatasourceAPIUid } from '../../utils/datasource'; import { fuzzyMatches } from '../../utils/fuzzySearch'; import { parseMatcher } from '../../utils/matchers'; import { isPluginProvidedRule, prometheusRuleType } from '../../utils/rules'; +import { normalizeHealth } from '../components/util'; /** * @returns True if the group matches the filter, false otherwise. Keeps rules intact @@ -79,7 +80,7 @@ export function ruleFilter(rule: PromRuleDTO, filterState: RulesFilter) { } } - if (filterState.ruleHealth && health !== filterState.ruleHealth) { + if (filterState.ruleHealth && normalizeHealth(health) !== filterState.ruleHealth) { return false; } From e1ddbda1bbd3377ba7a47d258041fb0b5f713629 Mon Sep 17 00:00:00 2001 From: Ryan McKinley Date: Tue, 28 Oct 2025 16:30:39 +0300 Subject: [PATCH 050/378] LibraryPanels: Remove unique name constraints (#113077) --- go.work.sum | 495 ++++++++++++++++++ .../libraryelements_create_test.go | 4 +- .../libraryelements_patch_test.go | 8 +- .../sqlstore/migrations/libraryelements.go | 8 + 4 files changed, 509 insertions(+), 6 deletions(-) diff --git a/go.work.sum b/go.work.sum index 07474527d3f..d78d14d4bb1 100644 --- a/go.work.sum +++ b/go.work.sum @@ -8,6 +8,12 @@ buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.6-2025042515311 buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.6-20250425153114-8976f5be98c1.1/go.mod h1:avRlCjnFzl98VPaeCtJ24RrV/wwHFzB8sWXhj26+n/U= buf.build/go/protovalidate v0.12.0 h1:4GKJotbspQjRCcqZMGVSuC8SjwZ/FmgtSuKDpKUTZew= buf.build/go/protovalidate v0.12.0/go.mod h1:q3PFfbzI05LeqxSwq+begW2syjy2Z6hLxZSkP1OH/D0= +cel.dev/expr v0.15.0/go.mod h1:TRSuuV7DlVCE/uwv5QbAiW/v8l5O8C4eEPHeu7gf7Sg= +cel.dev/expr v0.23.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw= +cel.dev/expr v0.23.1/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw= +cloud.google.com/go v0.82.0/go.mod h1:vlKccHJGuFBFufnAnuB08dfEH9Y3H7dzDzRECFdC2TA= +cloud.google.com/go v0.121.0/go.mod h1:rS7Kytwheu/y9buoDmu5EIpMMCI4Mb8ND4aeN4Vwj7Q= +cloud.google.com/go v0.121.1/go.mod h1:nRFlrHq39MNVWu+zESP2PosMWA0ryJw8KUBZ2iZpxbw= cloud.google.com/go/accessapproval v1.8.7 h1:Sc9ZjxFBEM/PoAxNlUwVGDcv8DYyjLYWDxHlzPG0q5I= cloud.google.com/go/accessapproval v1.8.7/go.mod h1:BFvZOW4GJjJnl6aA/YDEg0TGViFHyusa/bMdcVFmh8A= cloud.google.com/go/accesscontextmanager v1.9.6 h1:2LnncRqfYB8NEdh9+FeYxAt9POTW/0zVboktnRlO11w= @@ -33,6 +39,8 @@ cloud.google.com/go/asset v1.21.1 h1:i55wWC/EwVdHMyJgRfbLp/L6ez4nQuOpZwSxkuqN9ek cloud.google.com/go/asset v1.21.1/go.mod h1:7AzY1GCC+s1O73yzLM1IpHFLHz3ws2OigmCpOQHwebk= cloud.google.com/go/assuredworkloads v1.12.6 h1:ip/shfJYx6lrHBWYADjrrrubcm7uZzy50TTF5tPG7ek= cloud.google.com/go/assuredworkloads v1.12.6/go.mod h1:QyZHd7nH08fmZ+G4ElihV1zoZ7H0FQCpgS0YWtwjCKo= +cloud.google.com/go/auth v0.16.1/go.mod h1:1howDHJ5IETh/LwYs3ZxvlkXF48aSqqJUM+5o02dNOI= +cloud.google.com/go/auth v0.16.2/go.mod h1:sRBas2Y1fB1vZTdurouM0AzuYQBMZinrUYL8EufhtEA= cloud.google.com/go/automl v1.14.7 h1:ZLj48Ur2Qcso4M3bgOtjsOmeV5Ee92N14wuOc8OW+L0= cloud.google.com/go/automl v1.14.7/go.mod h1:8a4XbIH5pdvrReOU72oB+H3pOw2JBxo9XTk39oljObE= cloud.google.com/go/baremetalsolution v1.3.6 h1:9bdGlpY1LgLONQjFsDwrkjLzdPTlROpfU+GhA97YpOk= @@ -61,6 +69,7 @@ cloud.google.com/go/cloudtasks v1.13.6 h1:Fwan19UiNoFD+3KY0MnNHE5DyixOxNzS1mZ4Ch cloud.google.com/go/cloudtasks v1.13.6/go.mod h1:/IDaQqGKMixD+ayM43CfsvWF2k36GeomEuy9gL4gLmU= cloud.google.com/go/compute v1.40.0 h1:dlEzKo/BtyEGNc+SflXwwoBh52dNl/A5BaSYurT0k0k= cloud.google.com/go/compute v1.40.0/go.mod h1:P1doTJnlwurJDzIQFMp4mgU+vyCe9HU2NWTlqTfq3MY= +cloud.google.com/go/compute/metadata v0.5.0/go.mod h1:aHnloV2TPI38yx4s9+wAZhHykWvVCfu7hQbF+9CWoiY= cloud.google.com/go/contactcenterinsights v1.17.3 h1:lenyU3uzHwKDveCwmpfNxHYvLS3uEBWdn+O7+rSxy+Q= cloud.google.com/go/contactcenterinsights v1.17.3/go.mod h1:7Uu2CpxS3f6XxhRdlEzYAkrChpR5P5QfcdGAFEdHOG8= cloud.google.com/go/container v1.43.0 h1:A6J92FJPfxTvyX7MHF+w4t2W9WCqvHOi9UB5SAeSy3w= @@ -244,6 +253,7 @@ codeberg.org/go-latex/latex v0.1.0/go.mod h1:LA0q/AyWIYrqVd+A9Upkgsb+IqPcmSTKc9D codeberg.org/go-pdf/fpdf v0.10.0 h1:u+w669foDDx5Ds43mpiiayp40Ov6sZalgcPMDBcZRd4= codeberg.org/go-pdf/fpdf v0.10.0/go.mod h1:Y0DGRAdZ0OmnZPvjbMp/1bYxmIPxm0ws4tfoPOc4LjU= contrib.go.opencensus.io/exporter/ocagent v0.6.0 h1:Z1n6UAyr0QwM284yUuh5Zd8JlvxUGAhFZcgMJkMPrGM= +dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9 h1:VpgP7xuJadIUuKccphEpTJnWhS2jkQyMt6Y7pJCD7fY= gioui.org v0.0.0-20210308172011-57750fc8a0a6 h1:K72hopUosKG3ntOPNG4OzzbuhxGuVf06fa2la1/H/Ho= git.sr.ht/~sbinet/gg v0.6.0 h1:RIzgkizAk+9r7uPzf/VfbJHBMKUr0F5hRFxTUGMnt38= @@ -252,14 +262,21 @@ github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 h1:He8af github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8= github.com/Azure/azure-amqp-common-go/v3 v3.2.3 h1:uDF62mbd9bypXWi19V1bN5NZEO84JqgmI5G73ibAmrk= github.com/Azure/azure-amqp-common-go/v3 v3.2.3/go.mod h1:7rPmbSfszeovxGfc5fSAXE4ehlXQZHpMja2OtxC2Tas= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.1/go.mod h1:Ot/6aikWnKWi4l9QB7qVSwa8iMphQNqkWALMoNT3rzM= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.10.1/go.mod h1:JdM5psgjfBf5fo2uWOZhflPWyDBZ/O/CNAH9CtsuZE4= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1/go.mod h1:j2chePtV91HrC22tGoRX3sGY42uF13WzmmV80/OdVAA= github.com/Azure/azure-sdk-for-go/sdk/messaging/azservicebus v1.9.1 h1:CRZwf68N55u7ZZo3Xx2ynuqEA6k5GZfwsEUkU8qsAPk= github.com/Azure/azure-sdk-for-go/sdk/messaging/azservicebus v1.9.1/go.mod h1:NydgUaroiShkgOcb+X6OUdS3RalWBrvDNtOyFHJtsZY= +github.com/Azure/go-amqp v0.17.0/go.mod h1:9YJ3RhxRT1gquYnzpZO1vcYMMpAdJT+QEg6fwmw9Zlg= github.com/Azure/go-amqp v1.4.0 h1:Xj3caqi4comOF/L1Uc5iuBxR/pB6KumejC01YQOqOR4= github.com/Azure/go-amqp v1.4.0/go.mod h1:vZAogwdrkbyK3Mla8m/CxSc/aKdnTZ4IbPxl51Y5WZE= +github.com/Azure/go-autorest/autorest v0.11.18/go.mod h1:dSiJPy22c3u0OtOKDNttNgqpNFY/GeWa7GH/Pz56QRA= github.com/Azure/go-autorest/autorest/azure/auth v0.5.13 h1:Ov8avRZi2vmrE2JcXw+tu5K/yB41r7xK9GZDiBF7NdM= github.com/Azure/go-autorest/autorest/azure/auth v0.5.13/go.mod h1:5BAVfWLWXihP47vYrPuBKKf4cS0bXI+KM9Qx6ETDJYo= github.com/Azure/go-autorest/autorest/azure/cli v0.4.6 h1:w77/uPk80ZET2F+AfQExZyEWtn+0Rk/uw17m9fv5Ajc= github.com/Azure/go-autorest/autorest/azure/cli v0.4.6/go.mod h1:piCfgPho7BiIDdEQ1+g4VmKyD5y+p/XtSNqE6Hc4QD0= +github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= +github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802 h1:1BDTz0u9nC3//pOCMdNH+CiXJVYJh5UQNCOBG7jbELc= github.com/ClickHouse/ch-go v0.67.0 h1:18MQF6vZHj+4/hTRaK7JbS/TIzn4I55wC+QzO24uiqc= github.com/ClickHouse/ch-go v0.67.0/go.mod h1:2MSAeyVmgt+9a2k2SQPPG1b4qbTPzdGDpf1+bcHh+18= @@ -269,6 +286,7 @@ github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53 h1:sR+/8Yb4s github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53/go.mod h1:+3IMCy2vIlbG1XG/0ggNQv0SvxCAIpPM5b1nCz56Xno= github.com/CloudyKit/jet/v6 v6.2.0 h1:EpcZ6SR9n28BUGtNJSvlBqf90IpjeFr36Tizxhn/oME= github.com/CloudyKit/jet/v6 v6.2.0/go.mod h1:d3ypHeIRNo2+XyqnGA8s+aphtcVpjP5hPwP/Lzo7Ro4= +github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= github.com/DataDog/datadog-go v3.2.0+incompatible h1:qSG2N4FghB1He/r2mFrWKCaL7dXCilEuNEeAn20fdD4= github.com/DataDog/sketches-go v1.4.6 h1:acd5fb+QdUzGrosfNLwrIhqyrbMORpvBy7mE+vHlT3I= github.com/DataDog/sketches-go v1.4.6/go.mod h1:7Y8GN8Jf66DLyDhc94zuWA3uHEt/7ttt8jHOBWWrSOg= @@ -278,8 +296,11 @@ github.com/DmitriyVTitov/size v1.5.0 h1:/PzqxYrOyOUX1BXj6J9OuVRVGe+66VL4D9FlUaW5 github.com/DmitriyVTitov/size v1.5.0/go.mod h1:le6rNI4CoLQV1b9gzp1+3d7hMAD/uu2QcJ+aYbNgiU0= github.com/GoogleCloudPlatform/cloudsql-proxy v1.37.8 h1:9aTh5GPncdE8BjUn+xanuF/BT3m2BJiyvS50Mmws/fw= github.com/GoogleCloudPlatform/cloudsql-proxy v1.37.8/go.mod h1:exon/I6I+5u/ab7AHmGh0eCXGoYZO5cjqA3wHJlYFFQ= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.27.0/go.mod h1:yAZHSGnqScoU556rBOVkwLze6WP5N+U11RHuWaGVxwY= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.51.0/go.mod h1:BnBReJLvVYx2CS/UHOgVz2BXKXD9wsQPxZug20nZhd0= github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/trace v1.29.0 h1:YVtMlmfRUTaWs3+1acwMBp7rBUo6zrxl6Kn13/R9YW4= github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/trace v1.29.0/go.mod h1:rKOFVIPbNs2wZeh7ZeQ0D9p/XLgbNiTr5m7x6KuAshk= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.51.0/go.mod h1:otE2jQekW/PqXk1Awf5lmfokJx4uwuqcj1ab5SpGeW0= github.com/GoogleCloudPlatform/opentelemetry-operations-go/propagator v0.53.0 h1:RAHqDHJmNMLe6JvDoRIlXmb72w+62Ue/k5p/qP9yfAg= github.com/GoogleCloudPlatform/opentelemetry-operations-go/propagator v0.53.0/go.mod h1:dtCRwgvytbGKWdlrjMOg9geBoRwRpCYWIOM/JhVsDIc= github.com/IBM/go-sdk-core/v5 v5.17.4 h1:VGb9+mRrnS2HpHZFM5hy4J6ppIWnwNrw0G+tLSgcJLc= @@ -295,6 +316,14 @@ github.com/KimMachineGun/automemlimit v0.7.1 h1:QcG/0iCOLChjfUweIMC3YL5Xy9C3VBeN github.com/KimMachineGun/automemlimit v0.7.1/go.mod h1:QZxpHaGOQoYvFhv/r4u3U0JTC2ZcOwbSr11UZF46UBM= github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= +github.com/MarvinJWendt/testza v0.1.0/go.mod h1:7AxNvlfeHP7Z/hDQ5JtE3OKYT3XFUeLCDE2DQninSqs= +github.com/MarvinJWendt/testza v0.2.1/go.mod h1:God7bhG8n6uQxwdScay+gjm9/LnO4D3kkcZX4hv9Rp8= +github.com/MarvinJWendt/testza v0.2.8/go.mod h1:nwIcjmr0Zz+Rcwfh3/4UhBp7ePKVhuBExvZqnKYWlII= +github.com/MarvinJWendt/testza v0.2.10/go.mod h1:pd+VWsoGUiFtq+hRKSU1Bktnn+DMCSrDrXDpX2bG66k= +github.com/MarvinJWendt/testza v0.2.12/go.mod h1:JOIegYyV7rX+7VZ9r77L/eH6CfJHHzXjB69adAhzZkI= +github.com/MarvinJWendt/testza v0.3.0/go.mod h1:eFcL4I0idjtIx8P9C6KkAuLgATNKpX4/2oUqKc6bF2c= +github.com/MarvinJWendt/testza v0.4.2/go.mod h1:mSdhXiKH8sg/gQehJ63bINcCKp7RtYewEjXsvsVUPbE= +github.com/Masterminds/semver/v3 v3.3.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= github.com/MicahParks/keyfunc/v2 v2.1.0 h1:6ZXKb9Rp6qp1bDbJefnG7cTH8yMN1IC/4nf+GVjO99k= github.com/MicahParks/keyfunc/v2 v2.1.0/go.mod h1:rW42fi+xgLJ2FRRXAfNx9ZA8WpD4OeE/yHVMteCkw9k= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= @@ -330,6 +359,7 @@ github.com/alexflint/go-arg v1.5.1 h1:nBuWUCpuRy0snAG+uIJ6N0UvYxpxA0/ghA/AaHxlT8 github.com/alexflint/go-arg v1.5.1/go.mod h1:A7vTJzvjoaSTypg4biM5uYNTkJ27SkNTArtYXnlqVO8= github.com/alexflint/go-scalar v1.2.0 h1:WR7JPKkeNpnYIOfHRa7ivM21aWAdHD0gEWHCx+WQBRw= github.com/alexflint/go-scalar v1.2.0/go.mod h1:LoFvNMqS1CPrMVltza4LvnGKhaSpc3oyLEBUZVhhS2o= +github.com/alicebob/miniredis v2.5.0+incompatible h1:yBHoLpsyjupjz3NL3MhKMVkR41j82Yjf3KFv7ApYzUI= github.com/aliyun/aliyun-oss-go-sdk v2.2.10+incompatible h1:ROMcuN61gI8SfQ+AEMh4d7GZ3gwTZLIhPjtd05TQCG4= github.com/aliyun/aliyun-oss-go-sdk v2.2.10+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8= github.com/andybalholm/cascadia v1.3.3 h1:AG2YHrzJIm4BZ19iwJ/DAua6Btl3IwJX+VI4kktS1LM= @@ -339,6 +369,9 @@ github.com/antchfx/xmlquery v1.4.4/go.mod h1:AEPEEPYE9GnA2mj5Ur2L5Q5/2PycJ0N9Fus github.com/antchfx/xpath v1.3.4 h1:1ixrW1VnXd4HurCj7qnqnR0jo14g8JMe20Fshg1Vgz4= github.com/antchfx/xpath v1.3.4/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwqzXNcs= github.com/antihax/optional v1.0.0 h1:xK2lYat7ZLaVVcIuj82J8kIro4V6kDe0AUDFboUCwcg= +github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g= +github.com/apache/arrow-go/v18 v18.3.0/go.mod h1:eEM1DnUTHhgGAjf/ChvOAQbUQ+EPohtDrArffvUjPg8= +github.com/apache/arrow-go/v18 v18.4.0/go.mod h1:Aawvwhj8x2jURIzD9Moy72cF0FyJXOpkYpdmGRHcw14= github.com/apache/arrow/go/arrow v0.0.0-20211112161151-bc219186db40 h1:q4dksr6ICHXqG5hm0ZW5IHyeEJXoIJSOZeBLmWPNeIQ= github.com/apache/arrow/go/arrow v0.0.0-20211112161151-bc219186db40/go.mod h1:Q7yQnSMnLvcXlZ8RV+jwz/6y1rQTqbX6C82SndT52Zs= github.com/apache/arrow/go/v10 v10.0.1 h1:n9dERvixoC/1JjDmBcs9FPaEryoANa2sCgVFo6ez9cI= @@ -347,22 +380,37 @@ github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e h1:QEF07wC0T1rKkctt1 github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6 h1:G1bPvciwNyF7IUmKXNt9Ak3m6u9DE1rF+RmtIkBpVdA= github.com/atc0005/go-teams-notify/v2 v2.13.0 h1:nbDeHy89NjYlF/PEfLVF6lsserY9O5SnN1iOIw3AxXw= github.com/atc0005/go-teams-notify/v2 v2.13.0/go.mod h1:WSv9moolRsBcpZbwEf6gZxj7h0uJlJskJq5zkEWKO8Y= +github.com/atomicgo/cursor v0.0.1/go.mod h1:cBON2QmmrysudxNBFthvMtN32r3jxVRIvzkUiF/RuIk= github.com/aws/aws-lambda-go v1.47.0 h1:0H8s0vumYx/YKs4sE7YM0ktwL2eWse+kfopsRI1sXVI= github.com/aws/aws-lambda-go v1.47.0/go.mod h1:dpMpZgvWx5vuQJfBt0zqBha60q7Dd7RfgJv23DymV8A= github.com/aws/aws-msk-iam-sasl-signer-go v1.0.1 h1:nMp7diZObd4XEVUR0pEvn7/E13JIgManMX79Q6quV6E= github.com/aws/aws-msk-iam-sasl-signer-go v1.0.1/go.mod h1:MVYeeOhILFFemC/XlYTClvBjYZrg/EPd3ts885KrNTI= +github.com/aws/aws-sdk-go-v2 v1.36.5/go.mod h1:EYrzvCCN9CMUTa5+6lf6MM4tq3Zjp8UhSGR/cBsjai0= +github.com/aws/aws-sdk-go-v2/config v1.29.17/go.mod h1:9P4wwACpbeXs9Pm9w1QTh6BwWwJjwYvJ1iCt5QbCXh8= +github.com/aws/aws-sdk-go-v2/credentials v1.17.70/go.mod h1:M+lWhhmomVGgtuPOhO85u4pEa3SmssPTdcYpP/5J/xc= github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.19.5 h1:oUEqVqonG3xuarrsze1KVJ30KagNYDemikTbdu8KlN8= github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue v1.19.5/go.mod h1:VNM08cHlOsIbSHRqb6D/M2L4kKXfJv3A2/f0GNbOQSc= github.com/aws/aws-sdk-go-v2/feature/dynamodb/expression v1.7.87 h1:oDPArGgCrG/4aTi86ij3S2PB59XXkTSKYVNQlmqRHXQ= github.com/aws/aws-sdk-go-v2/feature/dynamodb/expression v1.7.87/go.mod h1:ZeQC4gVarhdcWeM1c90DyBLaBCNhEeAbKUXwVI/byvw= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.32/go.mod h1:h4Sg6FQdexC1yYG9RDnOvLbW1a/P986++/Y/a+GyEM8= +github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.69/go.mod h1:GJj8mmO6YT6EqgduWocwhMoxTLFitkhIrK+owzrYL2I= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.36/go.mod h1:Q1lnJArKRXkenyog6+Y+zr7WDpk4e6XlR6gs20bbeNo= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.36/go.mod h1:UdyGa7Q91id/sdyHPwth+043HhmP6yP9MBHgbZM0xo8= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.34/go.mod h1:zf7Vcd1ViW7cPqYWEHLHJkS50X0JS2IKz9Cgaj6ugrs= github.com/aws/aws-sdk-go-v2/service/dynamodb v1.44.0 h1:A99gjqZDbdhjtjJVZrmVzVKO2+p3MSg35bDWtbMQVxw= github.com/aws/aws-sdk-go-v2/service/dynamodb v1.44.0/go.mod h1:mWB0GE1bqcVSvpW7OtFA0sKuHk52+IqtnsYU2jUfYAs= github.com/aws/aws-sdk-go-v2/service/dynamodbstreams v1.26.0 h1:0wOCTKrmwkyC8Bk76hYH/B4IJn5MGt6gMkSXc0A2uyc= github.com/aws/aws-sdk-go-v2/service/dynamodbstreams v1.26.0/go.mod h1:He/RikglWUczbkV+fkdpcV/3GdL/rTRNVy7VaUiezMo= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.4/go.mod h1:/xFi9KtvBXP97ppCz1TAEvU1Uf66qvid89rbem3wCzQ= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.7.0/go.mod h1:iu6FSzgt+M2/x3Dk8zhycdIcHjEFb36IS8HVUVFoMg0= github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.10.17 h1:x187MqiHwBGjMGAed8Y8K1VGuCtFvQvXb24r+bwmSdo= github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.10.17/go.mod h1:mC9qMbA6e1pwEq6X3zDGtZRXMG2YaElJkbJlMVHLs5I= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.17/go.mod h1:ygpklyoaypuyDvOM5ujWGrYWpAK3h7ugnmKCU/76Ys4= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.15/go.mod h1:ZH34PJUc8ApjBIfgQCFvkWcUDBtl/WTD+uiYHjd8igA= github.com/aws/aws-sdk-go-v2/service/kinesis v1.33.0 h1:JPXkrQk5OS/+Q81fKH97Ll/Vmmy0p9vwHhxw+V+tVjg= github.com/aws/aws-sdk-go-v2/service/kinesis v1.33.0/go.mod h1:dJngkoVMrq0K7QvRkdRZYM4NUp6cdWa2GBdpm8zoY8U= +github.com/aws/aws-sdk-go-v2/service/kms v1.38.1/go.mod h1:cQn6tAF77Di6m4huxovNM7NVAozWTZLsDRp9t8Z/WYk= +github.com/aws/aws-sdk-go-v2/service/s3 v1.78.2/go.mod h1:U5SNqwhXB3Xe6F47kXvWihPl/ilGaEDe8HD/50Z9wxc= github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.35.7 h1:d+mnMa4JbJlooSbYQfrJpit/YINaB30JEVgrhtjZneA= github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.35.7/go.mod h1:1X1NotbcGHH7PCQJ98PsExSxsJj/VWzz8MfFz43+02M= github.com/aws/aws-sdk-go-v2/service/sns v1.34.7 h1:OBuZE9Wt8h2imuRktu+WfjiTGrnYdCIJg8IX92aalHE= @@ -371,6 +419,11 @@ github.com/aws/aws-sdk-go-v2/service/sqs v1.38.8 h1:80dpSqWMwx2dAm30Ib7J6ucz1ZHf github.com/aws/aws-sdk-go-v2/service/sqs v1.38.8/go.mod h1:IzNt/udsXlETCdvBOL0nmyMe2t9cGmXmZgsdoZGYYhI= github.com/aws/aws-sdk-go-v2/service/ssm v1.60.1 h1:OwMzNDe5VVTXD4kGmeK/FtqAITiV8Mw4TCa8IyNO0as= github.com/aws/aws-sdk-go-v2/service/ssm v1.60.1/go.mod h1:IyVabkWrs8SNdOEZLyFFcW9bUltV4G6OQS0s6H20PHg= +github.com/aws/aws-sdk-go-v2/service/sso v1.25.5/go.mod h1:b7SiVprpU+iGazDUqvRSLf5XmCdn+JtT1on7uNL6Ipc= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.3/go.mod h1:vq/GQR1gOFLquZMSrxUK/cpvKCNVYibNyJ1m7JrU88E= +github.com/aws/aws-sdk-go-v2/service/sts v1.34.0/go.mod h1:7ph2tGpfQvwzgistp2+zga9f+bCjlQJPkPUmMgDSD7w= +github.com/aws/smithy-go v1.22.4/go.mod h1:t1ufH5HMublsJYulve2RKmHDC15xu1f26kHCp/HgceI= +github.com/aws/smithy-go v1.22.5/go.mod h1:t1ufH5HMublsJYulve2RKmHDC15xu1f26kHCp/HgceI= github.com/awslabs/aws-lambda-go-api-proxy v0.16.2 h1:CJyGEyO1CIwOnXTU40urf0mchf6t3voxpvUDikOU9LY= github.com/awslabs/aws-lambda-go-api-proxy v0.16.2/go.mod h1:vxxjwBHe/KbgFeNlAP/Tvp4SsVRL3WQamcWRxqVh0z0= github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= @@ -405,21 +458,26 @@ github.com/bytedance/sonic v1.10.0-rc3 h1:uNSnscRapXTwUgTyOF0GVljYD08p9X/Lbr9Mwe github.com/bytedance/sonic v1.10.0-rc3/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4= github.com/campoy/embedmd v1.0.0 h1:V4kI2qTJJLf4J29RzI/MAt2c3Bl4dQSYPuflzwFH2hY= github.com/campoy/embedmd v1.0.0/go.mod h1:oxyr9RCiSXg0M3VJ3ks0UGfp98BpSSGr0kpiX3MzVl8= +github.com/cenkalti/backoff/v5 v5.0.2/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= github.com/census-instrumentation/opencensus-proto v0.4.1 h1:iKLQ0xPNFxR/2hzXZMrBo8f1j86j5WHzznCCQxV/b8g= github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ0g/qfRdp61a3Uu/AWrgIq2s0ClJV1g0= github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d/go.mod h1:8EPpVsBuRksnlj1mLy4AWzRNQYxauNi62uWcE3to6eA= github.com/chenzhuoyu/iasm v0.9.0 h1:9fhXjVzq5hUy2gkhhgHl95zG2cEAhw9OSGs8toWWAwo= github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog= +github.com/chromedp/cdproto v0.0.0-20250429231605-6ed5b53462d4/go.mod h1:NItd7aLkcfOA/dcMXvl8p1u+lQqioRMq/SqDp71Pb/k= github.com/chromedp/sysutil v1.1.0 h1:PUFNv5EcprjqXZD9nJb9b/c9ibAbxiYo4exNWZyipwM= github.com/chromedp/sysutil v1.1.0/go.mod h1:WiThHUdltqCNKGc4gaU50XgYjwjYIhKWoHGPTUfWTJ8= github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE= +github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ= github.com/chzyer/readline v1.5.1 h1:upd/6fQk4src78LMRzh5vItIt361/o4uq553V8B5sGI= github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 h1:q763qf9huN11kDQavWsoZXJNW3xEE4JJyHa5Q25/sd8= +github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8= github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible h1:C29Ae4G5GtYyYMm1aztcyj/J5ckgJm2zwdDajFbx1NY= github.com/circonus-labs/circonusllhist v0.1.3 h1:TJH+oke8D16535+jHExHj4nQvzlZrj7ug5D7I/orNUA= github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI= github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe h1:QQ3GSy+MqSHxm/d8nCtnAiZdYFd45cYZPs8vOOIYKfk= +github.com/cncf/xds/go v0.0.0-20250326154945-ae57f3c0d45f/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= github.com/cockroachdb/cockroach-go v0.0.0-20181001143604-e0a95dfd547c h1:2zRrJWIt/f9c9HhNHAgrRgq0San5gRRUJTBXLkchal0= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd h1:qMd81Ts1T2OTKmB4acZcyKaMtRnY5Y44NuXGX2GFJ1w= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= @@ -427,6 +485,7 @@ github.com/coder/quartz v0.1.0 h1:cLL+0g5l7xTf6ordRnUMMiZtRE8Sq5LxpghS63vEXrQ= github.com/coder/quartz v0.1.0/go.mod h1:vsiCc+AHViMKH2CQpGIpFgdHIEQsxwm8yCscqKmzbRA= github.com/coder/websocket v1.8.12 h1:5bUXkEPPIbewrnkU8LTCLVaxi4N4J8ahufH2vlo4NAo= github.com/coder/websocket v1.8.12/go.mod h1:LNVeNrXQZfe5qhS9ALED3uA+l5pPqvwXg3CKoDBB2gs= +github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= github.com/containerd/console v1.0.5 h1:R0ymNeydRqH2DmakFNdmjR2k0t7UPuiOV/N/27/qqsc= github.com/containerd/console v1.0.5/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk= github.com/containerd/containerd v1.7.18 h1:jqjZTQNfXGoEaZdW1WwPU0RqSn1Bm2Ay/KJPUuO8nao= @@ -453,7 +512,11 @@ github.com/couchbase/moss v0.2.0/go.mod h1:9MaHIaRuy9pvLPUJxB8sh8OrLfyDczECVL37g github.com/cpuguy83/dockercfg v0.3.2 h1:DlJTyZGBDlXqUZ2Dk2Q3xHs/FtnooJJVaad2S9GKorA= github.com/cpuguy83/dockercfg v0.3.2/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc= github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk= +github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9 h1:uDmaGzcdjhF4i/plgjmEsriH11Y0o7RKapEf/LDaM3w= +github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/creasty/defaults v1.8.0 h1:z27FJxCAa0JKt3utc0sCImAEb+spPucmKoOdLHvHYKk= github.com/creasty/defaults v1.8.0/go.mod h1:iGzKe6pbEHnpMPtfDXZEr0NVxWnPTjb1bbDy08fPzYM= github.com/crewjam/httperr v0.2.0 h1:b2BfXR8U3AlIHwNeFFvZ+BV1LFvKLlzMjzaTnZMybNo= @@ -468,6 +531,7 @@ github.com/cucumber/godog v0.15.1 h1:rb/6oHDdvVZKS66hrhpjFQFHjthFSrQBCOI1LwshNTI github.com/cucumber/godog v0.15.1/go.mod h1:qju+SQDewOljHuq9NSM66s0xEhogx0q30flfxL4WUk8= github.com/cucumber/messages/go/v21 v21.0.1 h1:wzA0LxwjlWQYZd32VTlAVDTkW6inOFmSM+RuOwHZiMI= github.com/cucumber/messages/go/v21 v21.0.1/go.mod h1:zheH/2HS9JLVFukdrsPWoPdmUtmYQAQPLk7w5vWsk5s= +github.com/cucumber/messages/go/v22 v22.0.0/go.mod h1:aZipXTKc0JnjCsXrJnuZpWhtay93k7Rn3Dee7iyPJjs= github.com/cznic/b v0.0.0-20180115125044-35e9bbe41f07 h1:UHFGPvSxX4C4YBApSPvmUfL8tTvWLj2ryqvT9K4Jcuk= github.com/cznic/fileutil v0.0.0-20180108211300-6a051e75936f h1:7uSNgsgcarNk4oiN/nNkO0J7KAjlsF5Yv5Gf/tFdHas= github.com/cznic/golex v0.0.0-20170803123110-4ab7c5e190e4 h1:CVAqftqbj+exlab+8KJQrE+kNIVlQfJt58j4GxCMF1s= @@ -482,9 +546,13 @@ github.com/d4l3k/messagediff v1.2.1 h1:ZcAIMYsUg0EAp9X+tt8/enBE/Q8Yd5kzPynLyKptt github.com/d4l3k/messagediff v1.2.1/go.mod h1:Oozbb1TVXFac9FtSIxHBMnBCq2qeH/2KkEQxENCrlLo= github.com/davecgh/go-xdr v0.0.0-20161123171359-e6a2ba005892 h1:qg9VbHo1TlL0KDM0vYvBG9EY0X0Yku5WYIPoFWt8f6o= github.com/davecgh/go-xdr v0.0.0-20161123171359-e6a2ba005892/go.mod h1:CTDl0pzVzE5DEzZhPfvhY/9sPFMQIxaJ9VAMs9AagrE= +github.com/dchest/siphash v1.2.3/go.mod h1:0NvQU092bT0ipiFN++/rXm69QG9tVxLAlQHIXMPAkHc= github.com/dchest/uniuri v1.2.0 h1:koIcOUdrTIivZgSLhHQvKgqdWZq5d7KdMEWF1Ud6+5g= github.com/dchest/uniuri v1.2.0/go.mod h1:fSzm4SLHzNZvWLvWJew423PhAzkpNQYq+uNLq4kxhkY= github.com/denisenkom/go-mssqldb v0.0.0-20190515213511-eb9f6a1743f3 h1:tkum0XDgfR0jcVVXuTsYv/erY2NnEDqwRojbxR1rBYA= +github.com/denisenkom/go-mssqldb v0.10.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= +github.com/devigned/tab v0.1.1/go.mod h1:XG9mPq0dFghrYvoBF3xdRrJzSTX1b7IQrvaL9mzjeJY= +github.com/dgryski/go-ddmin v0.0.0-20210904190556-96a6d69f1034/go.mod h1:zz4KxBkcXUWKjIcrc+uphJ1gPh/t18ymGm3PmQ+VGTk= github.com/dgryski/go-sip13 v0.0.0-20190329191031-25c5027a8c7b h1:Yqiad0+sloMPdd/0Fg22actpFx0dekpzt1xJmVNVkU0= github.com/dhui/dktest v0.3.0 h1:kwX5a7EkLcjo7VpsPQSYJcKGbXBXdjI9FGjuUj1jn6I= github.com/dimchansky/utfbom v1.1.1 h1:vV6w1AhK4VMnhBno/TPVCoK9U/LP0PkLCS9tbxHdi/U= @@ -500,10 +568,16 @@ github.com/docker/go-plugins-helpers v0.0.0-20240701071450-45e2431495c8 h1:IMfrF github.com/docker/go-plugins-helpers v0.0.0-20240701071450-45e2431495c8/go.mod h1:LFyLie6XcDbyKGeVK6bHe+9aJTYCxWLBg5IrJZOaXKA= github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96 h1:cenwrSVm+Z7QLSV/BsnenAOcDXdX4cMv4wP0B/5QbPg= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815 h1:bWDMxwH3px2JBh6AyO7hdCn/PkvCZXii8TGj7sbtEbQ= +github.com/dolthub/go-icu-regex v0.0.0-20250916051405-78a38d478790 h1:zxMsH7RLiG+dlZ/y0LgJHTV26XoiSJcuWq+em6t6VVc= +github.com/dolthub/go-icu-regex v0.0.0-20250916051405-78a38d478790/go.mod h1:F3cnm+vMRK1HaU6+rNqQrOCyR03HHhR1GWG2gnPOqaE= +github.com/dolthub/go-mysql-server v0.20.1-0.20251009205227-b4366f30538c h1:vElww7wlYrlu1dldciCcYOvVuh73gw8i6mkcTUvH6nQ= +github.com/dolthub/go-mysql-server v0.20.1-0.20251009205227-b4366f30538c/go.mod h1:EeYR0apo+8j2Dyxmn2ghkPlirO2S5mT1xHBrA+Efys8= github.com/dolthub/sqllogictest/go v0.0.0-20201107003712-816f3ae12d81 h1:7/v8q9XGFa6q5Ap4Z/OhNkAMBaK5YeuEzwJt+NZdhiE= github.com/dolthub/sqllogictest/go v0.0.0-20201107003712-816f3ae12d81/go.mod h1:siLfyv2c92W1eN/R4QqG/+RjjX5W2+gCTRjZxBjI3TY= github.com/dolthub/swiss v0.2.1 h1:gs2osYs5SJkAaH5/ggVJqXQxRXtWshF6uE0lgR/Y3Gw= github.com/dolthub/swiss v0.2.1/go.mod h1:8AhKZZ1HK7g18j7v7k6c5cYIGEZJcPn0ARsai8cUrh0= +github.com/dolthub/vitess v0.0.0-20250930230441-70c2c6a98e33 h1:ScHTwNbcVC6JH1OSyXzj8S4w67BIpRXwTSjrac3/PSw= +github.com/dolthub/vitess v0.0.0-20250930230441-70c2c6a98e33/go.mod h1:8pvvk5OLaLN9LLxghyczUapn/97l+mBgIb10qC1LG84= github.com/drone/envsubst v1.0.3 h1:PCIBwNDYjs50AsLZPYdfhSATKaRg/FJmDc2D6+C2x8g= github.com/drone/envsubst v1.0.3/go.mod h1:N2jZmlMufstn1KEqvbHjw40h1KyTmnVzHcSc9bFiJ2g= github.com/dvyukov/go-fuzz v0.0.0-20210103155950-6a8e9d1f2415 h1:q1oJaUPdmpDm/VyXosjgPgr6wS7c5iV2p0PwJD73bUI= @@ -530,6 +604,15 @@ github.com/elastic/go-windows v1.0.2/go.mod h1:bGcDpBzXgYSqM0Gx3DM4+UxFj300SZLix github.com/elastic/lunes v0.1.0 h1:amRtLPjwkWtzDF/RKzcEPMvSsSseLDLW+bnhfNSLRe4= github.com/elastic/lunes v0.1.0/go.mod h1:xGphYIt3XdZRtyWosHQTErsQTd4OP1p9wsbVoHelrd4= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633 h1:H2pdYOb3KQ1/YsqVWoWNLQO+fusocsw354rqGTZtAgw= +github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/emicklei/go-restful/v3 v3.12.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/emicklei/go-restful/v3 v3.12.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/emicklei/proto v1.10.0/go.mod h1:rn1FgRS/FANiZdD2djyH7TMA9jdRDcYQ9IEN9yvjX0A= +github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew= +github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= +github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= +github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI= github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/felixge/fgprof v0.9.4 h1:ocDNwMFlnA0NU0zSB3I52xkO4sFXk80VK9lXjLClu88= @@ -540,10 +623,14 @@ github.com/fluent/fluent-bit-go v0.0.0-20230731091245-a7a013e2473c h1:yKN46XJHYC github.com/fluent/fluent-bit-go v0.0.0-20230731091245-a7a013e2473c/go.mod h1:L92h+dgwElEyUuShEwjbiHjseW410WIcNz+Bjutc8YQ= github.com/fogleman/gg v1.3.0 h1:/7zJX8F6AaYQc57WQCyN9cAIz+4bCJGO9B+dyW29am8= github.com/form3tech-oss/jwt-go v3.2.2+incompatible h1:TcekIExNqud5crz4xD2pavyTgWiPvpYe4Xau31I0PRk= +github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= +github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/fsouza/fake-gcs-server v1.52.2 h1:j6ne83nqHrlX5EEor7WWVIKdBsztGtwJ1J2mL+k+iio= github.com/fsouza/fake-gcs-server v1.52.2/go.mod h1:47HKyIkz6oLTes1R8vEaHLwXfzYsGfmDUk1ViHHAUsA= +github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= +github.com/getkin/kin-openapi v0.132.0/go.mod h1:3OlG51PCYNsPByuiMB0t4fjnNlIDnaEDsjiKUV8nL58= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= @@ -560,13 +647,29 @@ github.com/go-fonts/liberation v0.2.0 h1:jAkAWJP4S+OsrPLZM4/eC9iW7CtHy+HBXrEwZXW github.com/go-fonts/stix v0.1.0 h1:UlZlgrvvmT/58o573ot7NFw0vZasZ5I6bcIft/oMdgg= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1 h1:QbL/5oDUmRBzO9/Z7Seo6zf912W/a6Sr4Eu0G/3Jho0= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4 h1:WtGNWLvXpe6ZudgnXrq0barxBImvnnJoMEhXAzcbM0I= +github.com/go-jose/go-jose/v4 v4.0.5/go.mod h1:s3P1lRrkT8igV8D9OjyL4WRyHvjB6a4JSllnOrmmBOA= +github.com/go-jose/go-jose/v4 v4.1.1/go.mod h1:BdsZGqgdO3b6tTc6LSE56wcDbMMLuPsw5d4ZD5f94kA= github.com/go-json-experiment/json v0.0.0-20250211171154-1ae217ad3535 h1:yE7argOs92u+sSCRgqqe6eF+cDaVhSPlioy1UkA0p/w= github.com/go-json-experiment/json v0.0.0-20250211171154-1ae217ad3535/go.mod h1:BWmvoE1Xia34f3l/ibJweyhrT+aROb/FQ6d+37F0e2s= github.com/go-kit/kit v0.12.0 h1:e4o3o3IsBfAKQh5Qbbiqyfu97Ku7jrO/JbohvztANh4= github.com/go-kit/kit v0.12.0/go.mod h1:lHd+EkCZPIwYItmGDDRdhinkzX2A1sj+M9biaEaizzs= github.com/go-latex/latex v0.0.0-20210823091927-c0d11ff05a81 h1:6zl3BbBhdnMkpSj2YY30qV3gDcVBGtFgVsV3+/i+mKQ= +github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-openapi/analysis v0.23.0/go.mod h1:9mz9ZWaSlV8TvjQHLl2mUW2PbZtemkE8yA5v22ohupo= +github.com/go-openapi/errors v0.22.0/go.mod h1:J3DmZScxCDufmIMsdOuDHxJbdOGC0xtUynjIx092vXE= +github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= +github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= +github.com/go-openapi/jsonreference v0.20.1/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= +github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= +github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= +github.com/go-openapi/loads v0.22.0/go.mod h1:yLsaTCS92mnSAZX5WWoxszLj0u+Ojl+Zs5Stn1oF+rs= +github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk= +github.com/go-openapi/strfmt v0.23.0/go.mod h1:NrtIpfKtWIygRkKVsxh7XQMDQW5HKQl6S5ik2elW+K4= +github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-openapi/validate v0.24.0/go.mod h1:iyeX1sEufmv3nPbBdX3ieNviWnOZaJ1+zquzJEf2BAQ= github.com/go-pdf/fpdf v0.6.0 h1:MlgtGIfsdMEEQJr2le6b/HNr1ZlQwxyWr77r2aj2U/8= github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= @@ -576,6 +679,8 @@ github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91 github.com/go-playground/validator/v10 v10.19.0 h1:ol+5Fu+cSq9JD7SoSqe04GMI92cbn0+wvQ3bZ8b/AU4= github.com/go-playground/validator/v10 v10.19.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= +github.com/go-test/deep v1.0.2/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= +github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:56xuuqnHyryaerycW3BfssRdxQstACi0Epw/yC5E2xM= github.com/goccmack/gocc v0.0.0-20230228185258-2292f9e40198 h1:FSii2UQeSLngl3jFoR4tUKZLprO7qUlh/TKKticc0BM= github.com/goccmack/gocc v0.0.0-20230228185258-2292f9e40198/go.mod h1:DTh/Y2+NbnOVVoypCCQrovMPDKUGp4yZpSbWg5D0XIM= github.com/goccy/go-yaml v1.17.1 h1:LI34wktB2xEE3ONG/2Ar54+/HJVBriAGJ55PHls4YuY= @@ -587,25 +692,45 @@ github.com/gocraft/dbr/v2 v2.7.2/go.mod h1:5bCqyIXO5fYn3jEp/L06QF4K1siFdhxChMjdN github.com/godbus/dbus/v5 v5.0.4 h1:9349emZab16e7zQvpmsbtjc18ykshndd8y2PG3sgJbA= github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= +github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gofrs/uuid v4.3.1+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gogo/status v1.1.0/go.mod h1:BFv9nrluPLmrS0EmGVvLaPNmRosr9KapBYd5/hpY1WM= github.com/golang-jwt/jwt v3.2.1+incompatible h1:73Z+4BJcrTC+KczS6WvTPvRGOp1WmfEP4Q1lOd9Z/+c= github.com/golang-jwt/jwt v3.2.1+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= +github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= +github.com/golang-jwt/jwt/v5 v5.2.3/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= +github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g= github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ= github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw= github.com/gomarkdown/markdown v0.0.0-20230716120725-531d2d74bc12 h1:uK3X/2mt4tbSGoHvbLBHUny7CKiuwUip3MArtukol4E= github.com/gomarkdown/markdown v0.0.0-20230716120725-531d2d74bc12/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA= +github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= +github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= +github.com/google/cel-go v0.25.0/go.mod h1:hjEb6r5SuOSlhCHmFoLzu8HGCERvIsDAbxDAyNU/MmI= +github.com/google/cel-go v0.26.0/go.mod h1:A9O8OU9rdvrK5MQyrqfIxo1a0u4g3sF8KB6PUIaryMM= +github.com/google/gnostic-models v0.6.9/go.mod h1:CiWsm0s6BSQd1hRn8/QmxqB6BesYcbSZxsz9b0KuDBw= github.com/google/go-pkcs11 v0.3.0 h1:PVRnTgtArZ3QQqTGtbtjtnIkzl2iY2kt24yqbrf7td8= github.com/google/go-pkcs11 v0.3.0/go.mod h1:6eQoGcuNJpa7jnd5pMGdkSaQpNDYvPlXWMcjXXThLlY= 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-20210506205249-923b5ab0fc1a/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= +github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= +github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= +github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= github.com/google/renameio v0.1.0 h1:GOZbcHa3HfsPKPlmyPyN2KEohoMXOhdMbHrvbpl2QaA= github.com/google/renameio/v2 v2.0.0 h1:UifI23ZTGY8Tt29JbYFiuyIU3eX+RNFtUwefq9qAhxg= github.com/google/renameio/v2 v2.0.0/go.mod h1:BtmJXm5YlszgC+TD4HOEEUFgkJP3nLxehU6hfe7jRt4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= +github.com/google/wire v0.6.0/go.mod h1:F4QhpQ9EDIdJ1Mbop/NZBRB+5yrR6qg3BnctaoUk6NA= +github.com/googleapis/gax-go/v2 v2.14.2/go.mod h1:ON64QhlJkhVtSqp4v1uaK92VyZ2gmvDQsweuyLV+8+w= github.com/googleapis/gnostic v0.3.0 h1:CcQijm0XKekKjP/YCz28LXVSpgguuB+nCxaSjCe09y0= github.com/googleapis/go-type-adapters v1.0.0 h1:9XdMn+d/G57qq1s8dNc5IesGCXHf6V2HZ2JwRxfA2tA= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8 h1:tlyzajkF3030q6M8SvmJSemC9DTHL/xaMa18b65+JM4= +github.com/gookit/color v1.4.2/go.mod h1:fqRyamkC1W8uxl+lxCQxOT09l/vYfZ+QeiX3rKQHCoQ= +github.com/gookit/color v1.5.0/go.mod h1:43aQb+Zerm/BWh2GnrgOQm7ffz7tvQXEKV6BFMl7wAo= github.com/gookit/color v1.5.4 h1:FZmqs7XOyGgCAxmWyPslpiok1k05wmY3SJTytgvYFs0= github.com/gookit/color v1.5.4/go.mod h1:pZJOeOS8DM43rXbp4AZo1n9zCU2qjpcRko0b6/QJi9w= github.com/gophercloud/gophercloud v1.13.0/go.mod h1:aAVqcocTSXh2vYFZ1JTvx4EQmfgzxRcNupUfxZbBNDM= @@ -614,33 +739,72 @@ github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY= github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c= github.com/gorilla/handlers v1.5.2 h1:cLTUSsNkgcwhgRqvCNmdbRWG0A3N4F+M2nWKdScwyEE= github.com/gorilla/handlers v1.5.2/go.mod h1:dX+xVpaxdSw+q0Qek8SSsl3dfMk3jNddUkMzo0GtH0w= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/grafana/alerting v0.0.0-20250729175202-b4b881b7b263/go.mod h1:VKxaR93Gff0ZlO2sPcdPVob1a/UzArFEW5zx3Bpyhls= +github.com/grafana/authlib v0.0.0-20250710201142-9542f2f28d43/go.mod h1:1fWkOiL+m32NBgRHZtlZGz2ji868tPZACYbqP3nBRJI= +github.com/grafana/authlib/types v0.0.0-20250710201142-9542f2f28d43/go.mod h1:qeWYbnWzaYGl88JlL9+DsP1GT2Cudm58rLtx13fKZdw= github.com/grafana/cloudflare-go v0.0.0-20230110200409-c627cf6792f2 h1:qhugDMdQ4Vp68H0tp/0iN17DM2ehRo1rLEdOFe/gB8I= github.com/grafana/cloudflare-go v0.0.0-20230110200409-c627cf6792f2/go.mod h1:w/aiO1POVIeXUQyl0VQSZjl5OAGDTL5aX+4v0RA1tcw= +github.com/grafana/dskit v0.0.0-20250611075409-46f51e1ce914/go.mod h1:OiN4P4aC6LwLzLbEupH3Ue83VfQoNMfG48rsna8jI/E= +github.com/grafana/dskit v0.0.0-20250818234656-8ff9c6532e85/go.mod h1:kImsvJ1xnmeT9Z6StK+RdEKLzlpzBsKwJbEQfmBJdFs= github.com/grafana/go-gelf/v2 v2.0.1 h1:BOChP0h/jLeD+7F9mL7tq10xVkDG15he3T1zHuQaWak= github.com/grafana/go-gelf/v2 v2.0.1/go.mod h1:lexHie0xzYGwCgiRGcvZ723bSNyNI8ZRD4s0CLobh90= +github.com/grafana/grafana-app-sdk v0.40.2/go.mod h1:BbNXPNki3mtbkWxYqJsyA1Cj9AShSyaY33z8WkyfVv0= +github.com/grafana/grafana-app-sdk/logging v0.40.2/go.mod h1:otUD9XpJD7A5sCLb8mcs9hIXGdeV6lnhzVwe747g4RU= +github.com/grafana/grafana-app-sdk/logging v0.48.0/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA= +github.com/grafana/grafana-aws-sdk v1.1.0/go.mod h1:7e+47EdHynteYWGoT5Ere9KeOXQObsk8F0vkOLQ1tz8= +github.com/grafana/grafana-azure-sdk-go/v2 v2.2.0/go.mod h1:H9sVh9A4yg5egMGZeh0mifxT1Q/uqwKe1LBjBJU6pN8= +github.com/grafana/grafana-plugin-sdk-go v0.278.0/go.mod h1:+8NXT/XUJ/89GV6FxGQ366NZ3nU+cAXDMd0OUESF9H4= +github.com/grafana/grafana-plugin-sdk-go v0.279.0/go.mod h1:/7oGN6Z7DGTGaLHhgIYrRr6Wvmdsb3BLw5hL4Kbjy88= +github.com/grafana/pyroscope-go/godeltaprof v0.1.8/go.mod h1:2+l7K7twW49Ct4wFluZD3tZ6e0SjanjcUUBPVD/UuGU= +github.com/grafana/sqlds/v4 v4.2.4/go.mod h1:BQRjUG8rOqrBI4NAaeoWrIMuoNgfi8bdhCJ+5cgEfLU= github.com/grafana/tail v0.0.0-20230510142333-77b18831edf0 h1:bjh0PVYSVVFxzINqPFYJmAmJNrWPgnVjuSdYJGHmtFU= github.com/grafana/tail v0.0.0-20230510142333-77b18831edf0/go.mod h1:7t5XR+2IA8P2qggOAHTj/GCZfoLBle3OvNSYh1VkRBU= github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA= github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +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/go.mod h1:XKMd7iuf/RGPSMJ/U4HP0zS2Z9Fh8Ps9a+6X26m/tmI= +github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.0/go.mod h1:qOchhhIlmRcqk/O9uCo/puJlyo07YINaIqdZfZG3Jkc= github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3/go.mod h1:ndYquD05frm2vACXE1nsccT4oJzjhw2arTS2cpUD1PI= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1/go.mod h1:Zanoh4+gvIgluNqcfMVTJueD4wSS5hT7zTt4Mrutd90= github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645 h1:MJG/KsmcqMwFAkh8mTnAwhyKoB+sTAnY4CACC110tbU= github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645/go.mod h1:6iZfnjpejD4L/4DwD7NryNaJyCQdzwWwH2MWhCA90Kw= github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed h1:5upAirOpQc1Q53c0bnx2ufif5kANL7bfZWcc6VJWJd8= github.com/hamba/avro/v2 v2.29.0 h1:fkqoWEPxfygZxrkktgSHEpd0j/P7RKTBTDbcEeMdVEY= github.com/hamba/avro/v2 v2.29.0/go.mod h1:Pk3T+x74uJoJOFmHrdJ8PRdgSEL/kEKteJ31NytCKxI= +github.com/hashicorp/consul/api v1.15.3/go.mod h1:/g/qgcoBcEXALCNZgRRisyTW0nY86++L0KbeAMXYCeY= +github.com/hashicorp/consul/sdk v0.11.0/go.mod h1:yPkX5Q6CsxTFMjQQDJwzeNmUUF5NUGGbrDsv9wTb8cw= +github.com/hashicorp/go-hclog v0.14.1/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.3.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-memdb v1.3.4 h1:XSL3NR682X/cVk2IeV0d70N4DZ9ljI885xAEU8IoK3c= github.com/hashicorp/go-memdb v1.3.4/go.mod h1:uBTr1oQbtuMgd1SSGoR8YV27eT3sBHbYiNm53bMpgSg= github.com/hashicorp/go-msgpack v1.1.5 h1:9byZdVjKTe5mce63pRVNP1L7UAmdHOTEMGehn6KvJWs= github.com/hashicorp/go-msgpack v1.1.5/go.mod h1:gWVc3sv/wbDmR3rQsj1CAktEZzoz1YNK9NfGLXJ69/4= +github.com/hashicorp/go-msgpack/v2 v2.1.1/go.mod h1:upybraOAblm4S7rx0+jeNy+CWWhzywQsSRV5033mMu4= +github.com/hashicorp/go-plugin v1.6.3/go.mod h1:MRobyh+Wc/nYy1V4KAXUiYfzxoYhs7V1mlH1Z7iY2h0= +github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.6/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-sockaddr v1.0.5/go.mod h1:uoUUmtwU7n9Dv3O4SNLeFvg0SxQ3lyjsj6+CCykpaxI= github.com/hashicorp/go-syslog v1.0.0 h1:KaodqZuhUoZereWVIYmpUgZysurB1kBLX2j0MwMrUAE= +github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go.net v0.0.1 h1:sNCoNyDEvN1xa+X0baata4RdcpKwcMS6DH+xwfqPgjw= +github.com/hashicorp/golang-lru/v2 v2.0.5/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/hashicorp/logutils v1.0.0 h1:dLEQVugN8vlakKOUE3ihGLTZJRB4j+M2cdTm/ORI65Y= github.com/hashicorp/mdns v1.0.5 h1:1M5hW1cunYeoXOqHwEb/GBDDHAFo0Yqb/uz/beC6LbE= github.com/hashicorp/mdns v1.0.5/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= +github.com/hashicorp/memberlist v0.3.1/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= github.com/hashicorp/raft v1.7.0 h1:4u24Qn6lQ6uwziM++UgsyiT64Q8GyRn43CV41qPiz1o= github.com/hashicorp/raft v1.7.0/go.mod h1:N1sKh6Vn47mrWvEArQgILTyng8GoDRNYlgKyK7PMjs0= github.com/hashicorp/raft-wal v0.4.1 h1:aU8XZ6x8R9BAIB/83Z1dTDtXvDVmv9YVYeXxd/1QBSA= github.com/hashicorp/raft-wal v0.4.1/go.mod h1:A6vP5o8hGOs1LHfC1Okh9xPwWDcmb6Vvuz/QyqUXlOE= +github.com/hashicorp/serf v0.10.1/go.mod h1:yL2t6BqATOLGc5HF7qbFkTfXoPIY0WZdWHfEvMqbG+4= +github.com/hashicorp/vault/api v1.16.0/go.mod h1:KhuUhzOD8lDSk29AtzNjgAu2kxRA9jL9NAbkFlqvkBA= +github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= github.com/heroku/x v0.0.61 h1:yfoAAtnFWSFZj+UlS+RZL/h8QYEp1R4wHVEg0G+Hwh4= github.com/heroku/x v0.0.61/go.mod h1:C7xYbpMdond+s6L5VpniDUSVPRwm3kZum1o7XiD5ZHk= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= @@ -664,6 +828,8 @@ github.com/jedib0t/go-pretty/v6 v6.6.7 h1:m+LbHpm0aIAPLzLbMfn8dc3Ht8MW7lsSO4MPIt github.com/jedib0t/go-pretty/v6 v6.6.7/go.mod h1:YwC5CE4fJ1HFUDeivSV1r//AmANFHyqczZk+U6BDALU= github.com/jhump/gopoet v0.1.0 h1:gYjOPnzHd2nzB37xYQZxj4EIQNpBrBskRqQQ3q4ZgSg= github.com/jhump/goprotoc v0.5.0 h1:Y1UgUX+txUznfqcGdDef8ZOVlyQvnV0pKWZH08RmZuo= +github.com/jmoiron/sqlx v1.3.4/go.mod h1:2BljVx/86SuTyjE+aPYlHCTNvZrnJXghYGpNiXLBMCQ= +github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/jon-whit/go-grpc-prometheus v1.4.0 h1:/wmpGDJcLXuEjXryWhVYEGt9YBRhtLwFEN7T+Flr8sw= @@ -695,8 +861,14 @@ github.com/kevinmbeaulieu/eq-go v1.0.0/go.mod h1:G3S8ajA56gKBZm4UB9AOyoOS37JO3ro github.com/kisielk/errcheck v1.5.0 h1:e8esj/e4R+SAOwFwN+n3zr0nYeCyeweozKfO23MvHzY= github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg= github.com/kisielk/sqlstruct v0.0.0-20201105191214-5f3e10d3ab46 h1:veS9QfglfvqAw2e+eeNT/SbGySq8ajECXJ9e4fPoLhY= +github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/klauspost/cpuid v1.3.1 h1:5JNjFYYQrZeKRJ0734q51WCEEn2huer72Dc7K+R/b6s= github.com/klauspost/cpuid v1.3.1/go.mod h1:bYW4mA6ZgKPob1/Dlai2LviZJO7KGI3uoWLd42rAQw4= +github.com/klauspost/cpuid/v2 v2.0.10/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= +github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= +github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= +github.com/klauspost/cpuid/v2 v2.2.11/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU= github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= github.com/knadh/koanf v1.5.0 h1:q2TSd/3Pyc/5yP9ldIrSdIz26MCcyNQzW0pEAugLPNs= @@ -736,6 +908,7 @@ github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= github.com/leodido/ragel-machinery v0.0.0-20190525184631-5f46317e436b h1:11UHH39z1RhZ5dc4y4r/4koJo6IYFgTRMe/LlwRTEw0= github.com/leodido/ragel-machinery v0.0.0-20190525184631-5f46317e436b/go.mod h1:WZxr2/6a/Ar9bMDc2rN/LJrE/hF6bXE4LPyDSIxwAfg= +github.com/lib/pq v1.10.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lightstep/go-expohisto v1.0.0 h1:UPtTS1rGdtehbbAF7o/dhkWLTDI73UifG8LbfQI7cA4= github.com/lightstep/go-expohisto v1.0.0/go.mod h1:xDXD0++Mu2FOaItXtdDfksfgxfV0z1TMPa+e/EUd0cs= github.com/lithammer/fuzzysearch v1.1.8 h1:/HIuJnjHuXS8bKaiTMeeDlW2/AyIWk2brx1V8LFgLN4= @@ -755,6 +928,10 @@ github.com/mailgun/raymond/v2 v2.0.48 h1:5dmlB680ZkFG2RN/0lvTAghrSxIESeu9/2aeDqA github.com/mailgun/raymond/v2 v2.0.48/go.mod h1:lsgvL50kgt1ylcFJYZiULi5fjPBkkhNfj4KA0W54Z18= github.com/matryer/moq v0.5.2 h1:b2bsanSaO6IdraaIvPBzHnqcrkkQmk1/310HdT2nNQs= github.com/matryer/moq v0.5.2/go.mod h1:W/k5PLfou4f+bzke9VPXTbfJljxoeR1tLHigsmbshmU= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-sqlite3 v1.14.7/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg= github.com/maxbrunsfeld/counterfeiter/v6 v6.11.2 h1:yVCLo4+ACVroOEr4iFU1iH46Ldlzz2rTuu18Ra7M8sU= github.com/maxbrunsfeld/counterfeiter/v6 v6.11.2/go.mod h1:VzB2VoMh1Y32/QqDfg9ZJYHj99oM4LiGtqPZydTiQSQ= @@ -762,6 +939,7 @@ github.com/mfridman/xflag v0.1.0 h1:TWZrZwG1QklFX5S4j1vxfF1sZbZeZSGofMwPMLAF29M= github.com/mfridman/xflag v0.1.0/go.mod h1:/483ywM5ZO5SuMVjrIGquYNE5CzLrj5Ux/LxWWnjRaE= github.com/microcosm-cc/bluemonday v1.0.25 h1:4NEwSfiJ+Wva0VxN5B8OwMicaJvD8r9tlJWm9rtloEg= github.com/microcosm-cc/bluemonday v1.0.25/go.mod h1:ZIOjCQp1OrzBBPIJmfX4qDYFuhU02nx4bn030ixfHLE= +github.com/miekg/dns v1.1.56/go.mod h1:cRm6Oo2C8TY9ZS/TqsSrseAcncm74lfK5G+ikN2SWWY= github.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU= github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= github.com/mitchellh/cli v1.1.5 h1:OxRIeJXpAMztws/XHlN2vu6imG5Dpq+j61AzAX5fLng= @@ -769,8 +947,10 @@ github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2Em github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw= 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/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= github.com/mitchellh/gox v0.4.0 h1:lfGJxY7ToLJQjHHwi0EX6uYBdK78egf954SQl13PQJc= github.com/mitchellh/iochan v1.0.0 h1:C+X3KsSTLFVBr/tK1eYN/vs4rJcvsiLU338UhYPJWeY= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mithrandie/readline-csvq v1.3.0 h1:VTJEOGouJ8j27jJCD4kBBbNTxM0OdBvE1aY1tMhlqE8= github.com/mithrandie/readline-csvq v1.3.0/go.mod h1:FKyYqDgf/G4SNov7SMFXRWO6LQLXIOeTog/NB97FZl0= github.com/moby/moby v27.5.1+incompatible h1:/pN59F/t3U7Q4FPzV88nzqf7Fp0qqCSL2KzhZaiKcKw= @@ -781,6 +961,7 @@ github.com/moby/sys/user v0.1.0 h1:WmZ93f5Ux6het5iituh9x2zAG7NFY9Aqi49jjE1PaQg= github.com/moby/sys/user v0.1.0/go.mod h1:fKJhFOnsCN6xZ5gSfbM6zaHGgDJMrqt9/reuj4T7MmU= github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g= github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28= +github.com/montanaflynn/stats v0.7.0/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE= github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= github.com/mostynb/go-grpc-compression v1.2.3 h1:42/BKWMy0KEJGSdWvzqIyOZ95YcR9mLPqKctH7Uo//I= @@ -801,6 +982,15 @@ github.com/nsf/jsondiff v0.0.0-20230430225905-43f6cf3098c1 h1:dOYG7LS/WK00RWZc8X github.com/nsf/jsondiff v0.0.0-20230430225905-43f6cf3098c1/go.mod h1:mpRZBD8SJ55OIICQ3iWH0Yz3cjzA61JdqMLoWXeB2+8= github.com/olivere/elastic v6.2.37+incompatible h1:UfSGJem5czY+x/LqxgeCBgjDn6St+z8OnsCuxwD3L0U= github.com/olivere/elastic v6.2.37+incompatible/go.mod h1:J+q1zQJTgAz9woqsbVRqGeB5G1iqDKVBWLNSYW8yfJ8= +github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To= +github.com/onsi/ginkgo/v2 v2.21.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo= +github.com/onsi/ginkgo/v2 v2.22.1/go.mod h1:S6aTpoRsSq2cZOd+pssHAlKW/Q/jZt6cPrPlnj4a1xM= +github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0= +github.com/onsi/gomega v1.35.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog= +github.com/open-feature/go-sdk v1.14.1/go.mod h1:t337k0VB/t/YxJ9S0prT30ISUHwYmUd/jhUZgFcOvGg= +github.com/open-feature/go-sdk v1.15.1/go.mod h1:2WAFYzt8rLYavcubpCoiym3iSCXiHdPB6DxtMkv2wyo= +github.com/open-feature/go-sdk-contrib/providers/go-feature-flag v0.2.3/go.mod h1:dPUHjAIFzg+ci/wt6XxlNiiMkOh5Yw4SGyeRY0AFT0g= +github.com/open-feature/go-sdk-contrib/providers/ofrep v0.1.5/go.mod h1:jrD4UG3ZCzuwImKHlyuIN2iWeYjlOX5+zJ/sX45efuE= github.com/open-telemetry/opentelemetry-collector-contrib/connector/spanmetricsconnector v0.121.0 h1:gX7HGoRE0OTMS8ZVh/zPeQe+ZEASKxAo6Wn9dIcsgRE= github.com/open-telemetry/opentelemetry-collector-contrib/connector/spanmetricsconnector v0.121.0/go.mod h1:y6UqtUREKcyDzLPQC5wSPbOlZR2HLUrNp/2ITZalVKA= github.com/open-telemetry/opentelemetry-collector-contrib/exporter/kafkaexporter v0.121.0 h1:1J3XbT944dDqif4TINht6SBz1l+HXpOeyZglaUfdY+0= @@ -865,6 +1055,7 @@ github.com/open-telemetry/opentelemetry-collector-contrib/receiver/opencensusrec github.com/open-telemetry/opentelemetry-collector-contrib/receiver/opencensusreceiver v0.124.1/go.mod h1:4+9pSfniXXdRpkKf0QNdElOd7yIWD4ux8D260tSPV54= github.com/open-telemetry/opentelemetry-collector-contrib/receiver/zipkinreceiver v0.124.1 h1:XkxqUEoukMWXF+EpEWeM9itXKt62yKi13Lzd8ZEASP4= github.com/open-telemetry/opentelemetry-collector-contrib/receiver/zipkinreceiver v0.124.1/go.mod h1:CuCZVPz+yn88b5vhZPAlxaMrVuhAVexUV6f8b07lpUc= +github.com/opentracing-contrib/go-grpc v0.0.0-20210225150812-73cb765af46e/go.mod h1:DYR5Eij8rJl8h7gblRrOZ8g0kW1umSpKqYIBTgeDtLo= github.com/oschwald/geoip2-golang v1.11.0 h1:hNENhCn1Uyzhf9PTmquXENiWS6AlxAEnBII6r8krA3w= github.com/oschwald/geoip2-golang v1.11.0/go.mod h1:P9zG+54KPEFOliZ29i7SeYZ/GM6tfEL+rgSn03hYuUo= github.com/oschwald/maxminddb-golang v1.13.0 h1:R8xBorY71s84yO06NgTmQvqvTvlS/bnYZrrWX1MElnU= @@ -886,6 +1077,7 @@ github.com/philhofer/fwd v1.1.2/go.mod h1:qkPdfjR2SIEbspLqpe1tO4n5yICnr2DY7mqEx2 github.com/phpdave11/gofpdf v1.4.2 h1:KPKiIbfwbvC/wOncwhrpRdXVj2CZTCFlw4wnoyjtHfQ= github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e h1:aoZm08cpOy4WuID//EZDgcC4zIxODThtZNPirFr42+A= github.com/pkg/sftp v1.13.1 h1:I2qBYMChEhIjOgazfJmV3/mZM256btk6wkCDRmW7JYs= github.com/pkg/xattr v0.4.10 h1:Qe0mtiNFHQZ296vRgUjRCoPHPqH7VdTOrZx3g0T+pGA= @@ -897,9 +1089,24 @@ github.com/pquerna/cachecontrol v0.1.0 h1:yJMy84ti9h/+OEWa752kBTKv4XC30OtVVHYv/8 github.com/pquerna/cachecontrol v0.1.0/go.mod h1:NrUG3Z7Rdu85UNR3vm7SOsl1nFIeSiQnrHV5K9mBcUI= github.com/pquerna/ffjson v0.0.0-20190930134022-aa0246cd15f7 h1:xoIK0ctDddBMnc74udxJYBqlo9Ylnsp1waqjLsnef20= github.com/pquerna/ffjson v0.0.0-20190930134022-aa0246cd15f7/go.mod h1:YARuvh7BUWHNhzDq2OM5tzR2RiCcN2D7sapiKyCel/M= +github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= +github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0= +github.com/prometheus/client_golang v1.23.0/go.mod h1:i/o0R9ByOnHX0McrTMTyhYvKE4haaf2mW08I+jGAjEE= +github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I= +github.com/prometheus/common v0.64.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8= +github.com/prometheus/common v0.65.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8= +github.com/prometheus/common v0.66.1/go.mod h1:gcaUsgf3KfRSwHY4dIMXLPV0K/Wg1oZ8+SbZk/HH/dA= github.com/prometheus/common/assets v0.2.0 h1:0P5OrzoHrYBOSM1OigWL3mY8ZvV2N4zIE/5AahrSrfM= +github.com/prometheus/exporter-toolkit v0.10.1-0.20230714054209-2f4150c63f97/go.mod h1:LoBCZeRh+5hX+fSULNyFnagYlQG/gBsyA/deNzROkq8= github.com/prometheus/statsd_exporter v0.26.1 h1:ucbIAdPmwAUcA+dU+Opok8Qt81Aw8HanlO+2N/Wjv7w= github.com/prometheus/statsd_exporter v0.26.1/go.mod h1:XlDdjAmRmx3JVvPPYuFNUg+Ynyb5kR69iPPkQjxXFMk= +github.com/pterm/pterm v0.12.27/go.mod h1:PhQ89w4i95rhgE+xedAoqous6K9X+r6aSOI2eFF7DZI= +github.com/pterm/pterm v0.12.29/go.mod h1:WI3qxgvoQFFGKGjGnJR849gU0TsEOvKn5Q8LlY1U7lg= +github.com/pterm/pterm v0.12.30/go.mod h1:MOqLIyMOgmTDz9yorcYbcw+HsgoZo3BQfg2wtl3HEFE= +github.com/pterm/pterm v0.12.31/go.mod h1:32ZAWZVXD7ZfG0s8qqHXePte42kdz8ECtRyEejaWgXU= +github.com/pterm/pterm v0.12.33/go.mod h1:x+h2uL+n7CP/rel9+bImHD5lF3nM9vJj80k9ybiiTTE= +github.com/pterm/pterm v0.12.36/go.mod h1:NjiL09hFhT/vWjQHSj1athJpx6H8cjpHXNAK5bUw8T8= +github.com/pterm/pterm v0.12.40/go.mod h1:ffwPLwlbXxP+rxT0GsgDTzS3y3rmpAO1NMjUkGTYf8s= github.com/pterm/pterm v0.12.81 h1:ju+j5I2++FO1jBKMmscgh5h5DPFDFMB7epEjSoKehKA= github.com/pterm/pterm v0.12.81/go.mod h1:TyuyrPjnxfwP+ccJdBTeWHtd/e0ybQHkOS/TakajZCw= github.com/r3labs/diff/v3 v3.0.1 h1:CBKqf3XmNRHXKmdU7mZP1w7TV0pDyVCis1AUHtA4Xtg= @@ -912,10 +1119,14 @@ github.com/relvacode/iso8601 v1.6.0 h1:eFXUhMJN3Gz8Rcq82f9DTMW0svjtAVuIEULglM7QH github.com/relvacode/iso8601 v1.6.0/go.mod h1:FlNp+jz+TXpyRqgmM7tnzHHzBnz776kmAH2h3sZCn0I= github.com/richardartoul/molecule v1.0.0 h1:+LFA9cT7fn8KF39zy4dhOnwcOwRoqKiBkPqKqya+8+U= github.com/richardartoul/molecule v1.0.0/go.mod h1:uvX/8buq8uVeiZiFht+0lqSLBHF+uGV8BrTv8W/SIwk= +github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rogpeppe/fastuuid v1.2.0 h1:Ppwyp6VYCF1nvBTXL3trRso7mXMlRrw9ooo375wvi2s= +github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/russross/blackfriday v1.6.0 h1:KqfZb0pUVN2lYqZUYRddxF4OR8ZMURnJIG5Y3VRLtww= github.com/russross/blackfriday v1.6.0/go.mod h1:ti0ldHuxg49ri4ksnFxlkCfN+hvslNlmVHqNRXXJNAY= github.com/ruudk/golang-pdf417 v0.0.0-20201230142125-a7e3863a1245 h1:K1Xf3bKttbF+koVGaX5xngRIZ5bVjbmPnaxE/dR08uY= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/ryanuber/columnize v2.1.2+incompatible h1:C89EOx/XBWwIXl8wm8OPJBd7kPF25UfsK2X7Ph/zCAk= github.com/sagikazarmark/crypt v0.6.0 h1:REOEXCs/NFY/1jOCEouMuT4zEniE5YoXbvpC5X/TLF8= github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= @@ -936,17 +1147,31 @@ github.com/segmentio/fasthash v1.0.3 h1:EI9+KE1EwvMLBWwjpRDc+fEM+prwxDYbslddQGtr github.com/segmentio/fasthash v1.0.3/go.mod h1:waKX8l2N8yckOgmSsXJi7x1ZfdKZ4x7KRMzBtS3oedY= github.com/sercand/kuberesolver/v5 v5.1.1 h1:CYH+d67G0sGBj7q5wLK61yzqJJ8gLLC8aeprPTHb6yY= github.com/sercand/kuberesolver/v5 v5.1.1/go.mod h1:Fs1KbKhVRnB2aDWN12NjKCB+RgYMWZJ294T3BtmVCpQ= +github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/shirou/gopsutil/v3 v3.23.12 h1:z90NtUkp3bMtmICZKpC4+WaknU1eXtp5vtbQ11DgpE4= github.com/shirou/gopsutil/v3 v3.23.12/go.mod h1:1FrWgea594Jp7qmjHUUPlJDTPgcsb9mGnXDxavtikzM= github.com/shirou/gopsutil/v4 v4.25.3 h1:SeA68lsu8gLggyMbmCn8cmp97V1TI9ld9sVzAUcKcKE= github.com/shirou/gopsutil/v4 v4.25.3/go.mod h1:xbuxyoZj+UsgnZrENu3lQivsngRR5BdjbJwf2fv4szA= github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= +github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shurcooL/go v0.0.0-20200502201357-93f07166e636 h1:aSISeOcal5irEhJd1M+IrApc0PdcN7e7Aj4yuEnOrfQ= github.com/shurcooL/go v0.0.0-20200502201357-93f07166e636/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/spf13/afero v1.10.0/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= +github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g= +github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= +github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= +github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/pflag v1.0.7/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad h1:fiWzISvDn0Csy5H0iwgAuJGQTUpVfEMJJd4nRFXogbc= +github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= +github.com/stoewer/go-strcase v1.3.0/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo= +github.com/stretchr/testify v1.11.0/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/substrait-io/substrait v0.69.0 h1:qfwUe1qKa3PsCclMpubQOF6nqIqS14geUuvzJ1P7gsM= github.com/substrait-io/substrait v0.69.0/go.mod h1:MPFNw6sToJgpD5Z2rj0rQrdP/Oq8HG7Z2t3CAEHtkHw= github.com/substrait-io/substrait-go/v4 v4.4.0 h1:mFArMNFxlOLyTuhPcaPzZCwYh6kUopTExTy7XOqtYBM= @@ -971,6 +1196,7 @@ github.com/testcontainers/testcontainers-go/modules/mongodb v0.35.0 h1:i1Kh9fmXg github.com/testcontainers/testcontainers-go/modules/mongodb v0.35.0/go.mod h1:SD8nVMK1m7b/K2YJqYjYNzfHmZfqHtqNOlI44nfxjdg= github.com/testcontainers/testcontainers-go/modules/redis v0.35.0 h1:RBgVefU5j5IWapp3TNKqMTYX+M22OSjtuORjPd4+g08= github.com/testcontainers/testcontainers-go/modules/redis v0.35.0/go.mod h1:UgghVXQ0//D3MjC8X71Bpb/lUCChidjNCRILD+btqfU= +github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY= github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= @@ -1007,6 +1233,10 @@ github.com/twmb/murmur3 v1.1.8 h1:8Yt9taO/WN3l08xErzjeschgZU2QSrwm1kclYq+0aRg= github.com/twmb/murmur3 v1.1.8/go.mod h1:Qq/R7NUyOfr65zD+6Q5IHKsJLwP7exErjN6lyyq3OSQ= github.com/uber-go/atomic v1.4.0 h1:yOuPqEq4ovnhEjpHmfFwsqBXDYbQeT6Nb0bwD6XnD5o= github.com/uber-go/atomic v1.4.0/go.mod h1:/Ct5t2lcmbJ4OSe/waGBoaVvVqtO0bmtfVNex1PFV8g= +github.com/uber/jaeger-client-go v2.28.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= +github.com/uber/jaeger-lib v2.2.0+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U= +github.com/urfave/cli v1.22.16/go.mod h1:EeJR6BKodywf4zciqrdw6hpCPk68JO9z5LazXZMn5Po= +github.com/urfave/cli/v3 v3.4.1/go.mod h1:FJSKtM/9AiiTOJL4fJ6TbMUkxBXn7GO9guZqoZtpYpo= github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= github.com/vertica/vertica-sql-go v1.3.3 h1:fL+FKEAEy5ONmsvya2WH5T8bhkvY27y/Ik3ReR2T+Qw= @@ -1037,6 +1267,7 @@ github.com/xitongsys/parquet-go v1.6.2 h1:MhCaXii4eqceKPu9BwrjLqyK10oX9WF+xGhwvw github.com/xitongsys/parquet-go v1.6.2/go.mod h1:IulAQyalCm0rPiZVNnCgm/PCL64X2tdSVGMQ/UeKqWA= github.com/xitongsys/parquet-go-source v0.0.0-20230830030807-0dd610dbff1d h1:VVWj8KWdzpebBaXpTVpOaQW32y2UCWy3JXJ5lVDa/e8= github.com/xitongsys/parquet-go-source v0.0.0-20230830030807-0dd610dbff1d/go.mod h1:HaLl1OAA7RAuQURU3Enxn7aRAI9yezsPPaxiGrbzxW4= +github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs= github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no= github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77 h1:ESFSdwYZvkeru3RtdrYueztKhOBCSAAzS4Gf+k0tEow= @@ -1057,9 +1288,14 @@ github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wK gitlab.com/nyarla/go-crypt v0.0.0-20160106005555-d9a5dc2b789b h1:7gd+rd8P3bqcn/96gOZa3F5dpJr/vEiDQYlNb/y2uNs= go.einride.tech/aip v0.68.1 h1:16/AfSxcQISGN5z9C5lM+0mLYXihrHbQ1onvYTr93aQ= go.einride.tech/aip v0.68.1/go.mod h1:XaFtaj4HuA3Zwk9xoBtTWgNubZ0ZZXv9BZJCkuKuWbg= +go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= +go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= go.etcd.io/etcd/client/v2 v2.305.4 h1:Dcx3/MYyfKcPNLpR4VVQUP5KgYrBeJtktBwEKkw08Ao= +go.etcd.io/etcd/client/v3 v3.5.0/go.mod h1:AIKXXVX/DQXtfTEqBryiLTUXwON+GuvO6Z7lLS/oTh0= go.etcd.io/gofail v0.2.0 h1:p19drv16FKK345a09a1iubchlw/vmRuksmRzgBIGjcA= go.etcd.io/gofail v0.2.0/go.mod h1:nL3ILMGfkXTekKI3clMBNazKnjUZjYLKmBHzsVAnC1o= +go.mongodb.org/mongo-driver v1.14.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c= +go.mongodb.org/mongo-driver v1.17.3/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opentelemetry.io/collector v0.124.0/go.mod h1:QzERYfmHUedawjr8Ph/CBEEkVqWS8IlxRLAZt+KHlCg= go.opentelemetry.io/collector/client v1.30.0 h1:QbvOrvwUGcnVjnIBn2zyLLubisOjgh7kMgkzDAiYpHg= @@ -1150,6 +1386,7 @@ go.opentelemetry.io/collector/extension/xextension v0.124.0 h1:Yzf11HXaiMHfS50Zy go.opentelemetry.io/collector/extension/xextension v0.124.0/go.mod h1:GeM0aSgwVSba3Bvvspuy1E+1aa/Q1CDxoK+e/xcJFVg= go.opentelemetry.io/collector/extension/zpagesextension v0.121.0 h1:zCnIPyZwHkqq33MRROQN2JTKxpLadTq8ppiR1x9rbOM= go.opentelemetry.io/collector/extension/zpagesextension v0.121.0/go.mod h1:W2ZcPYdyN7ux7AD5fA0/YzW8EA2aOpUSia/YoDsh7ck= +go.opentelemetry.io/collector/featuregate v1.43.0/go.mod h1:d0tiRzVYrytB6LkcYgz2ESFTv7OktRPQe0QEQcPt1L4= go.opentelemetry.io/collector/internal/fanoutconsumer v0.124.0 h1:8+xc3OxriK1nZNBApFCzF7lszXyBQxyJ/Nnzy5Q4hCM= go.opentelemetry.io/collector/internal/fanoutconsumer v0.124.0/go.mod h1:CoT5fVYpTT4RWUE9DihSMlxXqGP/VnILnBBGld8Bu6o= go.opentelemetry.io/collector/internal/memorylimiter v0.121.0 h1:0QZGL5zwaHMAJqUVfyRtXNCJWhG47eyDBoRNSeQvEEc= @@ -1160,6 +1397,7 @@ go.opentelemetry.io/collector/internal/telemetry v0.124.0 h1:kzd1/ZYhLj4bt2pDB52 go.opentelemetry.io/collector/internal/telemetry v0.124.0/go.mod h1:ZjXjqV0dJ+6D4XGhTOxg/WHjnhdmXsmwmUSgALea66Y= go.opentelemetry.io/collector/otelcol v0.124.0 h1:q/+ebTZgEZX+yFbvO7FeqpEtvtRPJ+YzZzHsVzqA71s= go.opentelemetry.io/collector/otelcol v0.124.0/go.mod h1:mFGJZn5YuffdMVO/lPBavbW+R64Dgd3jOMgw2WAmJEM= +go.opentelemetry.io/collector/pdata v1.43.0/go.mod h1:KsJzdDG9e5BaHlmYr0sqdSEKeEiSfKzoF+rdWU7J//w= go.opentelemetry.io/collector/pdata/testdata v0.124.0 h1:vY+pWG7CQfzzGSB5+zGYHQOltRQr59Ek9QiPe+rI+NY= go.opentelemetry.io/collector/pdata/testdata v0.124.0/go.mod h1:lNH48lGhGv4CYk27fJecpsR1zYHmZjKgNrAprwjym0o= go.opentelemetry.io/collector/pipeline v0.124.0 h1:hKvhDyH2GPnNO8LGL34ugf36sY7EOXPjBvlrvBhsOdw= @@ -1202,31 +1440,200 @@ go.opentelemetry.io/contrib/config v0.14.0 h1:QAG8uHNp5ZiCkpT7XggSmg5AyW1sA0Lgyp go.opentelemetry.io/contrib/config v0.14.0/go.mod h1:77rDmFPqBae5jtQ2C78RuDTHz4P27C8LzoN0MZyumYQ= go.opentelemetry.io/contrib/detectors/aws/ec2 v1.37.0 h1:BJnWw8+FULhuuF/6R6B/JYqAlCTCy9E4J8qmLpo/7KU= go.opentelemetry.io/contrib/detectors/aws/ec2 v1.37.0/go.mod h1:gs3y8jvJscW5D+FzrZvJZEsGj+xlMCF0S1x4R6ktiNo= +go.opentelemetry.io/contrib/detectors/gcp v1.36.0/go.mod h1:IbBN8uAIIx734PTonTPxAxnjc2pQTxWNkwfstZ+6H2k= go.opentelemetry.io/contrib/instrumentation/github.com/labstack/echo/otelecho v0.59.0 h1:I8k9HW4yl8SRYNmECKKtjhcOvq9lAP9riqYPixBU3qw= go.opentelemetry.io/contrib/instrumentation/github.com/labstack/echo/otelecho v0.59.0/go.mod h1:/vTiuiSKBQAerQeMB3CsVJbXd+cvTbhcdOk5AV5Z5R0= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0/go.mod h1:rg+RlpR5dKwaS95IyyZqj5Wd4E13lk/msnTS0Xl9lJM= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0/go.mod h1:snMWehoOh2wsEwnvvwtDyFCxVeDAODenXHtn5vzrKjo= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.62.0/go.mod h1:ru6KHrNtNHxM4nD/vd6QrLVWgKhxPYgblq4VAtNawTQ= +go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.60.0/go.mod h1:CosX/aS4eHnG9D7nESYpV753l4j9q5j3SL/PUYd2lR8= +go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.61.0/go.mod h1:HfvuU0kW9HewH14VCOLImqKvUgONodURG7Alj/IrnGI= +go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.62.0/go.mod h1:WfEApdZDMlLUAev/0QQpr8EJ/z0VWDKYZ5tF5RH5T1U= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0/go.mod h1:umTcuxiv1n/s/S6/c2AT/g2CQ7u5C59sHDNmfSwgz7Q= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0/go.mod h1:69uWxva0WgAA/4bu2Yy70SLDBwZXuQ6PbBpbsa5iZrQ= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0/go.mod h1:NfchwuyNoMcZ5MLHwPrODwUF1HWCXWrL31s8gSAdIKY= go.opentelemetry.io/contrib/otelconf v0.15.0 h1:BLNiIUsrNcqhSKpsa6CnhE6LdrpY1A8X0szMVsu99eo= go.opentelemetry.io/contrib/otelconf v0.15.0/go.mod h1:OPH1seO5z9dp1P26gnLtoM9ht7JDvh3Ws6XRHuXqImY= go.opentelemetry.io/contrib/propagators/aws v1.37.0 h1:cp8AFiM/qjBm10C/ATIRnEDXpD5MBknrA0ANw4T2/ss= go.opentelemetry.io/contrib/propagators/aws v1.37.0/go.mod h1:Cy8Hk2E2iSGEbsLnPUdeigrexaAOAGIAmBFK919EQs0= go.opentelemetry.io/contrib/propagators/b3 v1.35.0 h1:DpwKW04LkdFRFCIgM3sqwTJA/QREHMeMHYPWP1WeaPQ= go.opentelemetry.io/contrib/propagators/b3 v1.35.0/go.mod h1:9+SNxwqvCWo1qQwUpACBY5YKNVxFJn5mlbXg/4+uKBg= +go.opentelemetry.io/contrib/propagators/jaeger v1.35.0/go.mod h1:0ciyFyYZxE6JqRAQvIgGRabKWDUmNdW3GAQb6y/RlFU= +go.opentelemetry.io/contrib/propagators/jaeger v1.36.0/go.mod h1:VHu48l0YTRKSObdPQ+Sb8xMZvdnJlN7yhHuHoPgNqHM= +go.opentelemetry.io/contrib/propagators/jaeger v1.37.0/go.mod h1:x7bd+t034hxLTve1hF9Yn9qQJlO/pP8H5pWIt7+gsFM= +go.opentelemetry.io/contrib/samplers/jaegerremote v0.30.0/go.mod h1:9b8Q9rH52NgYH3ShiTFB5wf18Vt3RTH/VMB7LDcC1ug= +go.opentelemetry.io/contrib/samplers/jaegerremote v0.31.0/go.mod h1:XAOSk4bqj5vtoiY08bexeiafzxdXeLlxKFnwscvn8Fc= go.opentelemetry.io/contrib/zpages v0.60.0 h1:wOM9ie1Hz4H88L9KE6GrGbKJhfm+8F1NfW/Y3q9Xt+8= go.opentelemetry.io/contrib/zpages v0.60.0/go.mod h1:xqfToSRGh2MYUsfyErNz8jnNDPlnpZqWM/y6Z2Cx7xw= +go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= +go.opentelemetry.io/otel v1.31.0/go.mod h1:O0C14Yl9FgkjqcCZAsE053C13OaddMYr/hz6clDkEJE= +go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y= +go.opentelemetry.io/otel v1.36.0/go.mod h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E= +go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I= go.opentelemetry.io/otel/bridge/opencensus v1.35.0 h1:4nJfffRbozhqnuukfRkiahA94mnpryCLJLiduMIDJKI= go.opentelemetry.io/otel/bridge/opencensus v1.35.0/go.mod h1:359S30saRYNsB4A46EDx91SpXsQFNgkma7ftg2/L5/M= go.opentelemetry.io/otel/bridge/opentracing v1.35.0 h1:qT4jl1fYl0hHuRopNcwS94QosLFhGYcS0HacPUeXmT4= go.opentelemetry.io/otel/bridge/opentracing v1.35.0/go.mod h1:p5CbIL4v7uQz7mnQD6T/AZc1pPUzwz+2wZ1zrGY9Kgs= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.36.0/go.mod h1:rUKCPscaRWWcqGT6HnEmYrK+YNe5+Sw64xgQTOJ5b30= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.37.0/go.mod h1:hOfBCz8kv/wuq73Mx2H2QnWokh/kHZxkh6SNF2bdKtw= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.36.0/go.mod h1:RboSDkp7N292rgu+T0MgVt2qgFGu6qa1RpZDOtpL76w= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0/go.mod h1:7Bept48yIeqxP2OZ9/AqIpYS94h2or0aB4FypJTc8ZM= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.36.0/go.mod h1:90PoxvaEB5n6AOdZvi+yWJQoE95U8Dhhw2bSyRqnTD0= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0/go.mod h1:MJTqhM0im3mRLw1i8uGHnCvUEeS7VwRyxlLC78PA18M= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.34.0/go.mod h1:U7HYyW0zt/a9x5J1Kjs+r1f/d4ZHnYFclhYY2+YbeoE= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.36.0/go.mod h1:179AK5aar5R3eS9FucPy6rggvU0g52cvKId8pv4+v0c= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0/go.mod h1:QjUEoiGCPkvFZ/MjK6ZZfNOS6mfVEVKYE99dFhuN2LI= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.36.0/go.mod h1:r49hO7CgrxY9Voaj3Xe8pANWtr0Oq916d0XAmOoCZAQ= +go.opentelemetry.io/otel/exporters/prometheus v0.58.0/go.mod h1:7qo/4CLI+zYSNbv0GMNquzuss2FVZo3OYrGh96n4HNc= +go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.36.0/go.mod h1:dowW6UsM9MKbJq5JTz2AMVp3/5iW5I/TStsk8S+CfHw= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.36.0/go.mod h1:PD57idA/AiFD5aqoxGxCvT/ILJPeHy3MjqU/NS7KogY= +go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= +go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE= +go.opentelemetry.io/otel/metric v1.36.0/go.mod h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zLbVjV2PzT6qzbs= +go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E= +go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg= +go.opentelemetry.io/otel/sdk v1.34.0/go.mod h1:0e/pNiaMAqaykJGKbi+tSjWfNNHMTxoC9qANsCzbyxU= +go.opentelemetry.io/otel/sdk v1.36.0/go.mod h1:+lC+mTgD+MUWfjJubi2vvXWcVxyr9rmlshZni72pXeY= +go.opentelemetry.io/otel/sdk v1.37.0/go.mod h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg= +go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4= +go.opentelemetry.io/otel/sdk/metric v1.37.0/go.mod h1:cNen4ZWfiD37l5NhS+Keb5RXVWZWpRE+9WyVCpbo5ps= +go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= +go.opentelemetry.io/otel/trace v1.31.0/go.mod h1:TXZkRk7SM2ZQLtR6eoAWQFIHPvzQ06FJAsO1tJg480A= +go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc= +go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA= +go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0= +go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4= +go.opentelemetry.io/proto/otlp v1.6.0/go.mod h1:cicgGehlFuNdgZkcALOCh3VE6K/u2tAjzlRhDwmVpZc= +go.opentelemetry.io/proto/otlp v1.7.0/go.mod h1:fSKjH6YJ7HDlwzltzyMj036AJ3ejJLCgCSHGj4efDDo= +go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs= go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8= +go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o= +go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU= +go.yaml.in/yaml/v3 v3.0.3/go.mod h1:tBHosrYAkRZjRAOREWbDnBXUf08JOwYq++0QNwQiWzI= +gocloud.dev v0.42.0/go.mod h1:zkaYAapZfQisXOA4bzhsbA4ckiStGQ3Psvs9/OQ5dPM= +gocloud.dev/secrets/hashivault v0.42.0/go.mod h1:LXprr1XLEAT7BVZ+Y66dJEHQMzDsowIExj5Ktr9HLvM= golang.org/x/arch v0.4.0 h1:A8WCeEWhLwPBKNbFi5Wv5UTCBx5zzubnXDlMOFAzFMc= golang.org/x/arch v0.4.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= +golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= +golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= +golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw= +golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= +golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY= +golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc= +golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8= +golang.org/x/exp v0.0.0-20230321023759-10a507213a29/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= +golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w= +golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8/go.mod h1:CQ1k9gNrJ50XIzaKCRR2hssIjF07kZFEiieALBM/ARQ= +golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc= +golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= +golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY= +golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8/go.mod h1:tujkw807nyEEAamNbDrEGzRav+ilXA7PCRAd6xsmwiU= +golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0/go.mod h1:S9Xr4PYopiDyqSyp5NjCrhFrqg6A5zA2E/iPHPhqnS8= +golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6/go.mod h1:U6Lno4MTRCDY+Ba7aCcauB9T60gsv5s4ralQzP72ZoQ= +golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b/go.mod h1:3//PLf8L/X+8b4vuAfHzxeRUl04Adcb341+IGKfnqS8= +golang.org/x/exp v0.0.0-20250811191247-51f88131bc50/go.mod h1:rT6SFzZ7oxADUDx58pcaKFTcZ+inxAa9fTrYx/uVYwg= golang.org/x/exp/typeparams v0.0.0-20220218215828-6cf2b201936e h1:qyrTQ++p1afMkO4DPEeLGq/3oTsdlvdH4vqZUBWzUKM= golang.org/x/exp/typeparams v0.0.0-20220218215828-6cf2b201936e/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/image v0.25.0 h1:Y6uW6rH1y5y/LK1J8BPWZtr6yZ7hrsy6hFrXjgsc2fQ= golang.org/x/image v0.25.0/go.mod h1:tCAmOEGthTtkalusGp1g3xa2gke8J6c2N565dTyl9Rs= golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028 h1:4+4C/Iv2U4fMZBiMCc98MG1In4gJY5YRhtpDNeDeHWs= +golang.org/x/mod v0.6.0-dev.0.20220818022119-ed83ed61efb9/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= +golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= +golang.org/x/mod v0.26.0/go.mod h1:/j6NAhSk8iQ723BGAUyoAcn7SlD7s15Dp9Nd/SfeaFQ= +golang.org/x/mod v0.27.0/go.mod h1:rWI627Fq0DEoudcK+MBkNkCe0EetEaDSwJJkCcjpazc= +golang.org/x/mod v0.28.0/go.mod h1:yfB/L0NOf/kmEbXjzCPOx1iK1fRutOydrCMsqRhEBxI= +golang.org/x/net v0.0.0-20190921015927-1a5e07d1ff72/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20211123203042-d83791d6bcd9/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= +golang.org/x/net v0.16.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= +golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM= +golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= +golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= +golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= +golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= +golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= +golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds= +golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= +golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= +golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg= +golang.org/x/net v0.44.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY= +golang.org/x/net v0.45.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY= +golang.org/x/oauth2 v0.0.0-20210427180440-81ed05c6b58c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.22.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/oauth2 v0.28.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= +golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= +golang.org/x/oauth2 v0.31.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= +golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sys v0.0.0-20210503080704-8803ae5d1324/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211013075003-97ac67df715c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/telemetry v0.0.0-20250908211612-aef8a434d053/go.mod h1:+nZKN+XVh4LCiA9DV3ywrzN4gumyCnKjau3NGb9SGoE= +golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g= +golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ= +golang.org/x/term v0.33.0/go.mod h1:s18+ql9tYWp1IfpV9DmCtQDDSRBUjKaw9M1eAv5UeF0= +golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw= +golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= +golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= +golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA= +golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= +golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU= +golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU= +golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4= +golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= +golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= +golang.org/x/tools v0.0.0-20190424220101-1e8e1cfdf96b/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ= +golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= +golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps= +golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c= +golang.org/x/tools v0.24.1/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ= +golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0= +golang.org/x/tools v0.28.0/go.mod h1:dcIOrVd3mfQKTgrDVQHqCPMWy6lnhfhtX3hLXYVLfRw= +golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI= +golang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw= +golang.org/x/tools v0.36.0/go.mod h1:WBDiHKJK8YgLHlcQPYQzNCkUxUypCaa5ZegCVutKm+s= +golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w= +golang.org/x/tools/go/expect v0.1.0-deprecated/go.mod h1:eihoPOH+FgIqa3FpoTwguz/bVUSGBlGQU67vpBeOrBY= golang.org/x/tools/go/expect v0.1.1-deprecated h1:jpBZDwmgPhXsKZC6WhL20P4b/wmnpsEAGHaNy0n/rJM= golang.org/x/tools/go/expect v0.1.1-deprecated/go.mod h1:eihoPOH+FgIqa3FpoTwguz/bVUSGBlGQU67vpBeOrBY= golang.org/x/tools/go/packages/packagestest v0.1.1-deprecated h1:1h2MnaIAIXISqTFKdENegdpAgUXz6NrPEsbIeWaBRvM= @@ -1234,14 +1641,77 @@ golang.org/x/tools/go/packages/packagestest v0.1.1-deprecated/go.mod h1:RVAQXBGN gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0 h1:OE9mWmgKkjJyEmDAAtGMPjXu+YNeGvK9VTSHY6+Qihc= gonum.org/v1/plot v0.15.2 h1:Tlfh/jBk2tqjLZ4/P8ZIwGrLEWQSPDLRm/SNWKNXiGI= gonum.org/v1/plot v0.15.2/go.mod h1:DX+x+DWso3LTha+AdkJEv5Txvi+Tql3KAGkehP0/Ubg= +google.golang.org/api v0.46.0/go.mod h1:ceL4oozhkAiTID8XMmJBsIxID/9wMXJVVFXPg4ylg3I= +google.golang.org/api v0.234.0/go.mod h1:QpeJkemzkFKe5VCE/PMv7GsUfn9ZF+u+q1Q7w6ckxTg= +google.golang.org/api v0.235.0/go.mod h1:QpeJkemzkFKe5VCE/PMv7GsUfn9ZF+u+q1Q7w6ckxTg= +google.golang.org/api v0.239.0/go.mod h1:cOVEm2TpdAGHL2z+UwyS+kmlGr3bVWQQ6sYEqkKje50= google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= +google.golang.org/genproto v0.0.0-20190926190326-7ee9db18f195/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20210429181445-86c259c2b4ab/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= +google.golang.org/genproto v0.0.0-20210517163617-5e0236093d7a/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= +google.golang.org/genproto v0.0.0-20250505200425-f936aa4a68b2/go.mod h1:49MsLSx0oWMOZqcpB3uL8ZOkAh1+TndpJ8ONoCBWiZk= +google.golang.org/genproto v0.0.0-20250603155806-513f23925822/go.mod h1:HubltRL7rMh0LfnQPkMH4NPDFEWp0jw3vixw7jEM53s= +google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d/go.mod h1:KjSP20unUpOx5kyQUFa7k4OJg0qeJ7DEZflGDu2p6Bk= +google.golang.org/genproto/googleapis/api v0.0.0-20240826202546-f6391c0de4c7/go.mod h1:OCdP9MfskevB/rbYvHTsXTtKC+3bHWajPdoKgjcYkfo= +google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:jbe3Bkdp+Dh2IrslsFCklNhweNTBgSYanP1UXhJDhKg= +google.golang.org/genproto/googleapis/api v0.0.0-20250505200425-f936aa4a68b2/go.mod h1:pKLAc5OolXC3ViWGI62vvC0n10CpwAtRcTNCFwTKBEw= +google.golang.org/genproto/googleapis/api v0.0.0-20250512202823-5a2f75b736a9/go.mod h1:W3S/3np0/dPWsWLi1h/UymYctGXaGBM2StwzD0y140U= +google.golang.org/genproto/googleapis/api v0.0.0-20250519155744-55703ea1f237/go.mod h1:ezi0AVyMKDWy5xAncvjLWH7UcLBB5n7y2fQ8MzjJcto= +google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822/go.mod h1:h3c4v36UTKzUiuaOKQ6gr3S+0hovBtUrXzTG/i3+XEc= +google.golang.org/genproto/googleapis/api v0.0.0-20250707201910-8d1bb00bc6a7/go.mod h1:kXqgZtrWaf6qS3jZOCnCH7WYfrvFjkC51bM8fz3RsCA= +google.golang.org/genproto/googleapis/api v0.0.0-20250715232539-7130f93afb79/go.mod h1:HKJDgKsFUnv5VAGeQjz8kxcgDP0HoE0iZNp0OdZNlhE= +google.golang.org/genproto/googleapis/api v0.0.0-20250728155136-f173205681a0/go.mod h1:8ytArBbtOy2xfht+y2fqKd5DRDJRUQhqbyEnQ4bDChs= +google.golang.org/genproto/googleapis/api v0.0.0-20250804133106-a7a43d27e69b/go.mod h1:oDOGiMSXHL4sDTJvFvIB9nRQCGdLP1o/iVaqQK8zB+M= +google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c/go.mod h1:ea2MjsO70ssTfCjiwHgI0ZFqcw45Ksuk2ckf9G468GA= +google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5/go.mod h1:j3QtIyytwqGr1JUDtYXwtMXWPKsEa5LtzIFN1Wn5WvE= google.golang.org/genproto/googleapis/bytestream v0.0.0-20250603155806-513f23925822 h1:zWFRixYR5QlotL+Uv3YfsPRENIrQFXiGs+iwqel6fOQ= google.golang.org/genproto/googleapis/bytestream v0.0.0-20250603155806-513f23925822/go.mod h1:h6yxum/C2qRb4txaZRLDHK8RyS0H/o2oEDeKY4onY/Y= +google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:oQ5rr10WTTMvP4A36n8JpR1OrO1BEiV4f78CneXZxkA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240415180920-8c6c420018be/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240826202546-f6391c0de4c7/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:LuRYeWDFV6WOn90g357N17oMCaxpgCnbi/44qJvDn2I= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250519155744-55703ea1f237/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250715232539-7130f93afb79/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250728155136-f173205681a0/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250804133106-a7a43d27e69b/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250811230008-5f3141c8851a/go.mod h1:gw1tLEfykwDz2ET4a12jcXt4couGAm7IwsVaTy0Sflo= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c/go.mod h1:gw1tLEfykwDz2ET4a12jcXt4couGAm7IwsVaTy0Sflo= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5/go.mod h1:M4/wBTSeyLxupu3W3tJtOgB14jILAS/XWPSSa3TAlJc= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250826171959-ef028d996bc1/go.mod h1:GmFNa4BdJZ2a8G+wCe9Bg3wwThLrJun751XstdJt5Og= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090/go.mod h1:GmFNa4BdJZ2a8G+wCe9Bg3wwThLrJun751XstdJt5Og= +google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= +google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= +google.golang.org/grpc v1.61.0/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs= +google.golang.org/grpc v1.63.2/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA= +google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= +google.golang.org/grpc v1.69.4/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4= +google.golang.org/grpc v1.71.0/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec= +google.golang.org/grpc v1.71.1/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec= +google.golang.org/grpc v1.72.1/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= +google.golang.org/grpc v1.72.2/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= +google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc= +google.golang.org/grpc v1.74.2/go.mod h1:CtQ+BGjaAIXHs/5YS3i473GqwBBa1zGQNevxdeBEXrM= +google.golang.org/grpc v1.75.0/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ= +google.golang.org/grpc v1.75.1/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0 h1:M1YKkFIboKNieVO5DLUEVzQfGwJD30Nv2jfUgzb5UcE= google.golang.org/grpc/examples v0.0.0-20230224211313-3775f633ce20 h1:MLBCGN1O7GzIx+cBiwfYPwtmZ41U3Mn/cotLJciaArI= google.golang.org/grpc/examples v0.0.0-20230224211313-3775f633ce20/go.mod h1:Nr5H8+MlGWr5+xX/STzdoEqJrO+YteqFbMyCsrb6mH0= +google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/protobuf v1.36.3/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= +google.golang.org/protobuf v1.36.7/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= +google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU= +google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU= gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc= +gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0 h1:0vLT13EuvQ0hNvakwLuFZ/jYrLp5F3kcWHXdRggjCE8= gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/go-jose/go-jose.v2 v2.6.3 h1:nt80fvSDlhKWQgSWyHyy5CfmlQr+asih51R8PTWNKKs= @@ -1257,13 +1727,24 @@ honnef.co/go/tools v0.3.2 h1:ytYb4rOqyp1TSa2EPvNVwtPQJctSELKaMyLfqNP4+34= honnef.co/go/tools v0.3.2/go.mod h1:jzwdWgg7Jdq75wlfblQxO4neNaFFSvgc1tD5Wv8U0Yw= howett.net/plist v1.0.1 h1:37GdZ8tP09Q35o9ych3ehygcsL+HqKSwzctveSlarvM= howett.net/plist v1.0.1/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g= +k8s.io/api v0.33.3/go.mod h1:01Y/iLUjNBM3TAvypct7DIj0M0NIZc+PzAHCIo0CYGE= +k8s.io/apiextensions-apiserver v0.33.3/go.mod h1:oROuctgo27mUsyp9+Obahos6CWcMISSAPzQ77CAQGz8= +k8s.io/apimachinery v0.33.3/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM= +k8s.io/apiserver v0.33.3/go.mod h1:05632ifFEe6TxwjdAIrwINHWE2hLwyADFk5mBsQa15E= +k8s.io/client-go v0.33.3/go.mod h1:luqKBQggEf3shbxHY4uVENAxrDISLOarxpTKMiUuujg= k8s.io/code-generator v0.34.1 h1:WpphT26E+j7tEgIUfFr5WfbJrktCGzB3JoJH9149xYc= k8s.io/code-generator v0.34.1/go.mod h1:DeWjekbDnJWRwpw3s0Jat87c+e0TgkxoR4ar608yqvg= +k8s.io/component-base v0.33.3/go.mod h1:ktBVsBzkI3imDuxYXmVxZ2zxJnYTZ4HAsVj9iF09qp4= k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6 h1:4s3/R4+OYYYUKptXPhZKjQ04WJ6EhQQVFdjOFvCazDk= k8s.io/gengo/v2 v2.0.0-20250604051438-85fd79dbfd9f h1:SLb+kxmzfA87x4E4brQzB33VBbT2+x7Zq9ROIHmGn9Q= k8s.io/gengo/v2 v2.0.0-20250604051438-85fd79dbfd9f/go.mod h1:EJykeLsmFC60UQbYJezXkEsG2FLrt0GPNkU5iK5GWxU= k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= +k8s.io/klog/v2 v2.80.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff/go.mod h1:5jIi+8yX4RIb8wk3XwBo5Pq2ccx4FP10ohkbSKCZoK8= +k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b/go.mod h1:UZ2yyWbFTpuhSbFhv24aGNOdoRdJZgsIObGBUaYVsts= +k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +k8s.io/utils v0.0.0-20241210054802-24370beab758/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= lukechampine.com/uint128 v1.2.0 h1:mBi/5l91vocEN8otkC5bDLhi2KdCticRiwbdB0O+rjI= modernc.org/cc/v3 v3.36.3 h1:uISP3F66UlixxWEcKuIWERa4TwrZENHSL8tWxZz8bHg= modernc.org/ccgo/v3 v3.16.9 h1:AXquSwg7GuMk11pIdw7fmO1Y/ybgazVkMhsZWCV0mHM= @@ -1271,6 +1752,14 @@ modernc.org/ccorpus v1.11.6 h1:J16RXiiqiCgua6+ZvQot4yUuUy8zxgqbqEEUuGPlISk= modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 h1:5D53IMaUuA5InSeMu9eJtlQXS2NxAhyWQvkKEgXZhHI= modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6/go.mod h1:Qz0X07sNOR1jWYCrJMEnbW/X55x206Q7Vt4mz6/wHp4= modernc.org/httpfs v1.0.6 h1:AAgIpFZRXuYnkjftxTAZwMIiwEqAfk8aVB2/oA6nAeM= +modernc.org/libc v1.41.0/go.mod h1:w0eszPsiXoOnoMJgrXjglgLuDy/bt5RR4y3QzUUeodY= +modernc.org/libc v1.65.0/go.mod h1:7m9VzGq7APssBTydds2zBcxGREwvIGpuUBaKTXdm2Qs= +modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo= +modernc.org/memory v1.7.2/go.mod h1:NO4NVCQy0N7ln+T9ngWqOQfi7ley4vpwvARR+Hjw95E= +modernc.org/memory v1.10.0/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw= +modernc.org/sqlite v1.29.6/go.mod h1:S02dvcmm7TnTRvGhv8IGYyLnIt7AS2KPaB1F/71p75U= +modernc.org/sqlite v1.38.0/go.mod h1:1Bj+yES4SVvBZ4cBOpVZ6QgesMCKpJZDq0nxYzOpmNE= +modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0= modernc.org/tcl v1.13.1 h1:npxzTwFTZYM8ghWicVIX1cRWzj7Nd8i6AqqX2p+IYao= modernc.org/z v1.5.1 h1:RTNHdsrOpeoSeOF4FbzTo8gBYByaJ5xT7NgZ9ZqRiJM= rsc.io/binaryregexp v0.2.0 h1:HfqmD5MEmC0zvwBuF187nq9mdnXjXsSivRiXN7SmRkE= @@ -1279,6 +1768,12 @@ rsc.io/quote/v3 v3.1.0 h1:9JKUTTIUgS6kzR9mK1YuGKv6Nl+DijDNIc0ghT58FaY= rsc.io/sampler v1.3.0 h1:7uVkIFmeBqHfdjD+gZwtXXI+RODJ2Wc4O7MPEh/QiW4= sigs.k8s.io/controller-runtime v0.22.1 h1:Ah1T7I+0A7ize291nJZdS1CabF/lB4E++WizgV24Eqg= sigs.k8s.io/controller-runtime v0.22.1/go.mod h1:FwiwRjkRPbiN+zp2QRp7wlTCzbUXxZ/D4OzuQUDwBHY= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= +sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e h1:4Z09Hglb792X0kfOBBJUPFEyvVfQWrYT/l8h5EKA6JQ= sigs.k8s.io/structured-merge-diff/v4 v4.5.0 h1:nbCitCK2hfnhyiKo6uf2HxUPTCodY6Qaf85SbDIaMBk= sigs.k8s.io/structured-merge-diff/v4 v4.5.0/go.mod h1:N8f93tFZh9U6vpxwRArLiikrE5/2tiu1w1AGfACIGE4= +sigs.k8s.io/structured-merge-diff/v6 v6.2.0/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= +sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= +sigs.k8s.io/yaml v1.5.0/go.mod h1:wZs27Rbxoai4C0f8/9urLZtZtF3avA3gKvGyPdDqTO4= +xorm.io/builder v0.3.6/go.mod h1:LEFAPISnRzG+zxaxj2vPicRwz67BdhFreKg8yv8/TgU= diff --git a/pkg/services/libraryelements/libraryelements_create_test.go b/pkg/services/libraryelements/libraryelements_create_test.go index 36f2100308c..a48082a8d5e 100644 --- a/pkg/services/libraryelements/libraryelements_create_test.go +++ b/pkg/services/libraryelements/libraryelements_create_test.go @@ -14,13 +14,13 @@ import ( func TestIntegration_CreateLibraryElement(t *testing.T) { testutil.SkipIntegrationTestInShortMode(t) - scenarioWithPanel(t, "When an admin tries to create a library panel that already exists, it should fail", + scenarioWithPanel(t, "When an admin tries to create a library panel with the same name, it should succeed", func(t *testing.T, sc scenarioContext) { // nolint:staticcheck command := getCreatePanelCommand(sc.folder.ID, sc.folder.UID, "Text - Library Panel") sc.reqContext.Req.Body = mockRequestBody(command) resp := sc.service.createHandler(sc.reqContext) - require.Equal(t, 400, resp.Status()) + require.Equal(t, 200, resp.Status()) }) scenarioWithPanel(t, "When an admin tries to create a library panel that does not exists, it should succeed", diff --git a/pkg/services/libraryelements/libraryelements_patch_test.go b/pkg/services/libraryelements/libraryelements_patch_test.go index 0cf29a83857..68f61302f41 100644 --- a/pkg/services/libraryelements/libraryelements_patch_test.go +++ b/pkg/services/libraryelements/libraryelements_patch_test.go @@ -332,7 +332,7 @@ func TestIntegration_PatchLibraryElement(t *testing.T) { } }) - scenarioWithPanel(t, "When an admin tries to patch a library panel with a name that already exists, it should fail", + scenarioWithPanel(t, "When an admin tries to patch a library panel with a name that already exists, it should pass", func(t *testing.T, sc scenarioContext) { // nolint:staticcheck command := getCreatePanelCommand(sc.folder.ID, sc.folder.UID, "Another Panel") @@ -348,10 +348,10 @@ func TestIntegration_PatchLibraryElement(t *testing.T) { sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": result.Result.UID}) sc.ctx.Req.Body = mockRequestBody(cmd) resp = sc.service.patchHandler(sc.reqContext) - require.Equal(t, 400, resp.Status()) + require.Equal(t, 200, resp.Status()) }) - scenarioWithPanel(t, "When an admin tries to patch a library panel with a folder where a library panel with the same name already exists, it should fail", + scenarioWithPanel(t, "When an admin tries to patch a library panel with a folder where a library panel with the same name already exists, it should pass", func(t *testing.T, sc scenarioContext) { newFolder := &folder.Folder{ ID: 2, @@ -375,7 +375,7 @@ func TestIntegration_PatchLibraryElement(t *testing.T) { sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": sc.initialResult.Result.UID}) sc.ctx.Req.Body = mockRequestBody(cmd) resp := sc.service.patchHandler(sc.reqContext) - require.Equal(t, 400, resp.Status()) + require.Equal(t, 200, resp.Status()) }) scenarioWithPanel(t, "When an admin tries to patch a library panel in another org, it should fail", diff --git a/pkg/services/sqlstore/migrations/libraryelements.go b/pkg/services/sqlstore/migrations/libraryelements.go index 903411997ac..55395fa51a8 100644 --- a/pkg/services/sqlstore/migrations/libraryelements.go +++ b/pkg/services/sqlstore/migrations/libraryelements.go @@ -83,4 +83,12 @@ func addLibraryElementsMigrations(mg *migrator.Migrator) { mg.AddMigration("populate library_element folder_uid", migrator.NewRawSQLMigration(q)) mg.AddMigration("add index library_element org_id-folder_uid-name-kind", migrator.NewAddIndexMigration(libraryElementsV1, &migrator.Index{Cols: []string{"org_id", "folder_uid", "name", "kind"}, Type: migrator.UniqueIndex})) + + mg.AddMigration("drop unique name in folder index (id)", + migrator.NewDropIndexMigration(libraryElementsV1, + &migrator.Index{Cols: []string{"org_id", "folder_id", "name", "kind"}, Type: migrator.UniqueIndex})) + + mg.AddMigration("drop unique name in folder index", + migrator.NewDropIndexMigration(libraryElementsV1, + &migrator.Index{Cols: []string{"org_id", "folder_uid", "name", "kind"}, Type: migrator.UniqueIndex})) } From 2a5ce2f03187dc814e2659d1695a15e36a4bf140 Mon Sep 17 00:00:00 2001 From: Paul Marbach Date: Tue, 28 Oct 2025 09:31:20 -0400 Subject: [PATCH 051/378] Gauge: Fix migration version targeting and gdev dashboard (#112974) --- .../panel-gauge/gauge_tests_new.v42.json | 202 +++++++----------- .../panel-gauge/gauge_tests_new.json | 200 +++++++---------- .../panel/radialbar/GaugeMigrations.test.ts | 28 +++ .../panel/radialbar/GaugeMigrations.ts | 7 +- 4 files changed, 182 insertions(+), 255 deletions(-) diff --git a/apps/dashboard/pkg/migration/testdata/dev-dashboards-output/panel-gauge/gauge_tests_new.v42.json b/apps/dashboard/pkg/migration/testdata/dev-dashboards-output/panel-gauge/gauge_tests_new.v42.json index a85230fd842..2c63e2eb953 100644 --- a/apps/dashboard/pkg/migration/testdata/dev-dashboards-output/panel-gauge/gauge_tests_new.v42.json +++ b/apps/dashboard/pkg/migration/testdata/dev-dashboards-output/panel-gauge/gauge_tests_new.v42.json @@ -36,8 +36,7 @@ }, { "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "fieldConfig": { "defaults": { @@ -95,13 +94,12 @@ "showThresholdMarkers": false, "sparkline": false }, - "pluginVersion": "12.2.0-pre", + "pluginVersion": "13.0.0-pre", "targets": [ { "alias": "1", "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "max": 100, "min": 1, @@ -117,8 +115,7 @@ }, { "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "fieldConfig": { "defaults": { @@ -176,13 +173,12 @@ "showThresholdMarkers": false, "sparkline": false }, - "pluginVersion": "12.2.0-pre", + "pluginVersion": "13.0.0-pre", "targets": [ { "alias": "1", "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "max": 100, "min": 1, @@ -198,8 +194,7 @@ }, { "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "fieldConfig": { "defaults": { @@ -257,13 +252,12 @@ "showThresholdMarkers": false, "sparkline": false }, - "pluginVersion": "12.2.0-pre", + "pluginVersion": "13.0.0-pre", "targets": [ { "alias": "1", "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "max": 100, "min": 1, @@ -279,8 +273,7 @@ }, { "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "fieldConfig": { "defaults": { @@ -338,13 +331,12 @@ "showThresholdMarkers": false, "sparkline": false }, - "pluginVersion": "12.2.0-pre", + "pluginVersion": "13.0.0-pre", "targets": [ { "alias": "1", "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "max": 100, "min": 1, @@ -360,8 +352,7 @@ }, { "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "fieldConfig": { "defaults": { @@ -419,13 +410,12 @@ "showThresholdMarkers": false, "sparkline": true }, - "pluginVersion": "12.2.0-pre", + "pluginVersion": "13.0.0-pre", "targets": [ { "alias": "1", "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "max": 100, "min": 1, @@ -441,8 +431,7 @@ }, { "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "fieldConfig": { "defaults": { @@ -500,13 +489,12 @@ "showThresholdMarkers": false, "sparkline": false }, - "pluginVersion": "12.2.0-pre", + "pluginVersion": "13.0.0-pre", "targets": [ { "alias": "1", "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "max": 100, "min": 1, @@ -522,8 +510,7 @@ }, { "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "fieldConfig": { "defaults": { @@ -581,13 +568,12 @@ "showThresholdMarkers": false, "sparkline": false }, - "pluginVersion": "12.2.0-pre", + "pluginVersion": "13.0.0-pre", "targets": [ { "alias": "1", "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "max": 100, "min": 1, @@ -616,8 +602,7 @@ }, { "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "fieldConfig": { "defaults": { @@ -675,13 +660,12 @@ "showThresholdMarkers": false, "sparkline": false }, - "pluginVersion": "12.2.0-pre", + "pluginVersion": "13.0.0-pre", "targets": [ { "alias": "1", "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "max": 100, "min": 1, @@ -697,8 +681,7 @@ }, { "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "fieldConfig": { "defaults": { @@ -756,13 +739,12 @@ "showThresholdMarkers": false, "sparkline": false }, - "pluginVersion": "12.2.0-pre", + "pluginVersion": "13.0.0-pre", "targets": [ { "alias": "1", "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "max": 100, "min": 1, @@ -778,8 +760,7 @@ }, { "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "fieldConfig": { "defaults": { @@ -837,13 +818,12 @@ "showThresholdMarkers": false, "sparkline": false }, - "pluginVersion": "12.2.0-pre", + "pluginVersion": "13.0.0-pre", "targets": [ { "alias": "1", "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "max": 100, "min": 1, @@ -859,8 +839,7 @@ }, { "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "fieldConfig": { "defaults": { @@ -918,13 +897,12 @@ "showThresholdMarkers": false, "sparkline": false }, - "pluginVersion": "12.2.0-pre", + "pluginVersion": "13.0.0-pre", "targets": [ { "alias": "1", "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "max": 100, "min": 1, @@ -953,8 +931,7 @@ }, { "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "fieldConfig": { "defaults": { @@ -1016,13 +993,12 @@ "showThresholdMarkers": true, "sparkline": false }, - "pluginVersion": "12.2.0-pre", + "pluginVersion": "13.0.0-pre", "targets": [ { "alias": "1", "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "refId": "A", "scenarioId": "csv_metric_values", @@ -1034,8 +1010,7 @@ }, { "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "fieldConfig": { "defaults": { @@ -1097,13 +1072,12 @@ "showThresholdMarkers": true, "sparkline": false }, - "pluginVersion": "12.2.0-pre", + "pluginVersion": "13.0.0-pre", "targets": [ { "alias": "1", "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "refId": "A", "scenarioId": "csv_metric_values", @@ -1115,8 +1089,7 @@ }, { "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "fieldConfig": { "defaults": { @@ -1178,13 +1151,12 @@ "showThresholdMarkers": true, "sparkline": false }, - "pluginVersion": "12.2.0-pre", + "pluginVersion": "13.0.0-pre", "targets": [ { "alias": "1", "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "refId": "A", "scenarioId": "csv_metric_values", @@ -1196,8 +1168,7 @@ }, { "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "fieldConfig": { "defaults": { @@ -1259,13 +1230,12 @@ "showThresholdMarkers": true, "sparkline": false }, - "pluginVersion": "12.2.0-pre", + "pluginVersion": "13.0.0-pre", "targets": [ { "alias": "1", "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "refId": "A", "scenarioId": "csv_metric_values", @@ -1277,8 +1247,7 @@ }, { "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "fieldConfig": { "defaults": { @@ -1340,13 +1309,12 @@ "showThresholdMarkers": true, "sparkline": false }, - "pluginVersion": "12.2.0-pre", + "pluginVersion": "13.0.0-pre", "targets": [ { "alias": "1", "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "refId": "A", "scenarioId": "csv_metric_values", @@ -1371,8 +1339,7 @@ }, { "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "fieldConfig": { "defaults": { @@ -1438,13 +1405,12 @@ "showThresholdMarkers": true, "sparkline": false }, - "pluginVersion": "12.2.0-pre", + "pluginVersion": "13.0.0-pre", "targets": [ { "alias": "1", "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "refId": "A", "scenarioId": "csv_metric_values", @@ -1456,8 +1422,7 @@ }, { "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "fieldConfig": { "defaults": { @@ -1523,13 +1488,12 @@ "showThresholdMarkers": false, "sparkline": false }, - "pluginVersion": "12.2.0-pre", + "pluginVersion": "13.0.0-pre", "targets": [ { "alias": "1", "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "refId": "A", "scenarioId": "csv_metric_values", @@ -1541,8 +1505,7 @@ }, { "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "fieldConfig": { "defaults": { @@ -1608,13 +1571,12 @@ "showThresholdMarkers": true, "sparkline": false }, - "pluginVersion": "12.2.0-pre", + "pluginVersion": "13.0.0-pre", "targets": [ { "alias": "1", "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "refId": "A", "scenarioId": "csv_metric_values", @@ -1639,8 +1601,7 @@ }, { "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "description": "", "fieldConfig": { @@ -1704,12 +1665,11 @@ "sparkline": false, "spotlight": true }, - "pluginVersion": "12.2.0-pre", + "pluginVersion": "13.0.0-pre", "targets": [ { "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "hide": false, "max": 98, @@ -1727,8 +1687,7 @@ }, { "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "description": "", "fieldConfig": { @@ -1792,12 +1751,11 @@ "sparkline": true, "spotlight": true }, - "pluginVersion": "12.2.0-pre", + "pluginVersion": "13.0.0-pre", "targets": [ { "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "hide": false, "max": 98, @@ -1828,8 +1786,7 @@ }, { "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "description": "", "fieldConfig": { @@ -1894,12 +1851,11 @@ "sparkline": false, "spotlight": true }, - "pluginVersion": "12.2.0-pre", + "pluginVersion": "13.0.0-pre", "targets": [ { "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "hide": false, "max": 8, @@ -1917,8 +1873,7 @@ }, { "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "description": "", "fieldConfig": { @@ -1984,12 +1939,11 @@ "sparkline": false, "spotlight": true }, - "pluginVersion": "12.2.0-pre", + "pluginVersion": "13.0.0-pre", "targets": [ { "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "hide": false, "max": 12, @@ -2007,8 +1961,7 @@ }, { "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "description": "", "fieldConfig": { @@ -2072,12 +2025,11 @@ "sparkline": false, "spotlight": true }, - "pluginVersion": "12.2.0-pre", + "pluginVersion": "13.0.0-pre", "targets": [ { "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "hide": false, "max": 100, @@ -2095,8 +2047,7 @@ }, { "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "description": "", "fieldConfig": { @@ -2160,12 +2111,11 @@ "sparkline": false, "spotlight": true }, - "pluginVersion": "12.2.0-pre", + "pluginVersion": "13.0.0-pre", "targets": [ { "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "hide": false, "max": 100, @@ -2197,4 +2147,4 @@ "title": "Panel tests - Gauge (new)", "uid": "panel-tests-gauge-new", "weekStart": "" -} \ No newline at end of file +} diff --git a/devenv/dev-dashboards/panel-gauge/gauge_tests_new.json b/devenv/dev-dashboards/panel-gauge/gauge_tests_new.json index 2eb527326e7..9cb204da48a 100644 --- a/devenv/dev-dashboards/panel-gauge/gauge_tests_new.json +++ b/devenv/dev-dashboards/panel-gauge/gauge_tests_new.json @@ -36,8 +36,7 @@ }, { "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "fieldConfig": { "defaults": { @@ -93,13 +92,12 @@ "showThresholdMarkers": false, "sparkline": false }, - "pluginVersion": "12.2.0-pre", + "pluginVersion": "13.0.0-pre", "targets": [ { "alias": "1", "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "max": 100, "min": 1, @@ -115,8 +113,7 @@ }, { "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "fieldConfig": { "defaults": { @@ -172,13 +169,12 @@ "showThresholdMarkers": false, "sparkline": false }, - "pluginVersion": "12.2.0-pre", + "pluginVersion": "13.0.0-pre", "targets": [ { "alias": "1", "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "max": 100, "min": 1, @@ -194,8 +190,7 @@ }, { "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "fieldConfig": { "defaults": { @@ -251,13 +246,12 @@ "showThresholdMarkers": false, "sparkline": false }, - "pluginVersion": "12.2.0-pre", + "pluginVersion": "13.0.0-pre", "targets": [ { "alias": "1", "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "max": 100, "min": 1, @@ -273,8 +267,7 @@ }, { "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "fieldConfig": { "defaults": { @@ -330,13 +323,12 @@ "showThresholdMarkers": false, "sparkline": false }, - "pluginVersion": "12.2.0-pre", + "pluginVersion": "13.0.0-pre", "targets": [ { "alias": "1", "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "max": 100, "min": 1, @@ -352,8 +344,7 @@ }, { "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "fieldConfig": { "defaults": { @@ -409,13 +400,12 @@ "showThresholdMarkers": false, "sparkline": true }, - "pluginVersion": "12.2.0-pre", + "pluginVersion": "13.0.0-pre", "targets": [ { "alias": "1", "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "max": 100, "min": 1, @@ -431,8 +421,7 @@ }, { "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "fieldConfig": { "defaults": { @@ -488,13 +477,12 @@ "showThresholdMarkers": false, "sparkline": false }, - "pluginVersion": "12.2.0-pre", + "pluginVersion": "13.0.0-pre", "targets": [ { "alias": "1", "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "max": 100, "min": 1, @@ -510,8 +498,7 @@ }, { "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "fieldConfig": { "defaults": { @@ -567,13 +554,12 @@ "showThresholdMarkers": false, "sparkline": false }, - "pluginVersion": "12.2.0-pre", + "pluginVersion": "13.0.0-pre", "targets": [ { "alias": "1", "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "max": 100, "min": 1, @@ -602,8 +588,7 @@ }, { "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "fieldConfig": { "defaults": { @@ -659,13 +644,12 @@ "showThresholdMarkers": false, "sparkline": false }, - "pluginVersion": "12.2.0-pre", + "pluginVersion": "13.0.0-pre", "targets": [ { "alias": "1", "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "max": 100, "min": 1, @@ -681,8 +665,7 @@ }, { "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "fieldConfig": { "defaults": { @@ -738,13 +721,12 @@ "showThresholdMarkers": false, "sparkline": false }, - "pluginVersion": "12.2.0-pre", + "pluginVersion": "13.0.0-pre", "targets": [ { "alias": "1", "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "max": 100, "min": 1, @@ -760,8 +742,7 @@ }, { "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "fieldConfig": { "defaults": { @@ -817,13 +798,12 @@ "showThresholdMarkers": false, "sparkline": false }, - "pluginVersion": "12.2.0-pre", + "pluginVersion": "13.0.0-pre", "targets": [ { "alias": "1", "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "max": 100, "min": 1, @@ -839,8 +819,7 @@ }, { "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "fieldConfig": { "defaults": { @@ -896,13 +875,12 @@ "showThresholdMarkers": false, "sparkline": false }, - "pluginVersion": "12.2.0-pre", + "pluginVersion": "13.0.0-pre", "targets": [ { "alias": "1", "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "max": 100, "min": 1, @@ -931,8 +909,7 @@ }, { "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "fieldConfig": { "defaults": { @@ -992,13 +969,12 @@ "showThresholdMarkers": true, "sparkline": false }, - "pluginVersion": "12.2.0-pre", + "pluginVersion": "13.0.0-pre", "targets": [ { "alias": "1", "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "refId": "A", "scenarioId": "csv_metric_values", @@ -1010,8 +986,7 @@ }, { "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "fieldConfig": { "defaults": { @@ -1071,13 +1046,12 @@ "showThresholdMarkers": true, "sparkline": false }, - "pluginVersion": "12.2.0-pre", + "pluginVersion": "13.0.0-pre", "targets": [ { "alias": "1", "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "refId": "A", "scenarioId": "csv_metric_values", @@ -1089,8 +1063,7 @@ }, { "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "fieldConfig": { "defaults": { @@ -1150,13 +1123,12 @@ "showThresholdMarkers": true, "sparkline": false }, - "pluginVersion": "12.2.0-pre", + "pluginVersion": "13.0.0-pre", "targets": [ { "alias": "1", "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "refId": "A", "scenarioId": "csv_metric_values", @@ -1168,8 +1140,7 @@ }, { "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "fieldConfig": { "defaults": { @@ -1229,13 +1200,12 @@ "showThresholdMarkers": true, "sparkline": false }, - "pluginVersion": "12.2.0-pre", + "pluginVersion": "13.0.0-pre", "targets": [ { "alias": "1", "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "refId": "A", "scenarioId": "csv_metric_values", @@ -1247,8 +1217,7 @@ }, { "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "fieldConfig": { "defaults": { @@ -1308,13 +1277,12 @@ "showThresholdMarkers": true, "sparkline": false }, - "pluginVersion": "12.2.0-pre", + "pluginVersion": "13.0.0-pre", "targets": [ { "alias": "1", "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "refId": "A", "scenarioId": "csv_metric_values", @@ -1339,8 +1307,7 @@ }, { "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "fieldConfig": { "defaults": { @@ -1404,13 +1371,12 @@ "showThresholdMarkers": true, "sparkline": false }, - "pluginVersion": "12.2.0-pre", + "pluginVersion": "13.0.0-pre", "targets": [ { "alias": "1", "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "refId": "A", "scenarioId": "csv_metric_values", @@ -1422,8 +1388,7 @@ }, { "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "fieldConfig": { "defaults": { @@ -1487,13 +1452,12 @@ "showThresholdMarkers": false, "sparkline": false }, - "pluginVersion": "12.2.0-pre", + "pluginVersion": "13.0.0-pre", "targets": [ { "alias": "1", "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "refId": "A", "scenarioId": "csv_metric_values", @@ -1505,8 +1469,7 @@ }, { "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "fieldConfig": { "defaults": { @@ -1570,13 +1533,12 @@ "showThresholdMarkers": true, "sparkline": false }, - "pluginVersion": "12.2.0-pre", + "pluginVersion": "13.0.0-pre", "targets": [ { "alias": "1", "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "refId": "A", "scenarioId": "csv_metric_values", @@ -1601,8 +1563,7 @@ }, { "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "description": "", "fieldConfig": { @@ -1664,12 +1625,11 @@ "sparkline": false, "spotlight": true }, - "pluginVersion": "12.2.0-pre", + "pluginVersion": "13.0.0-pre", "targets": [ { "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "hide": false, "max": 98, @@ -1687,8 +1647,7 @@ }, { "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "description": "", "fieldConfig": { @@ -1750,12 +1709,11 @@ "sparkline": true, "spotlight": true }, - "pluginVersion": "12.2.0-pre", + "pluginVersion": "13.0.0-pre", "targets": [ { "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "hide": false, "max": 98, @@ -1786,8 +1744,7 @@ }, { "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "description": "", "fieldConfig": { @@ -1850,12 +1807,11 @@ "sparkline": false, "spotlight": true }, - "pluginVersion": "12.2.0-pre", + "pluginVersion": "13.0.0-pre", "targets": [ { "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "hide": false, "max": 8, @@ -1873,8 +1829,7 @@ }, { "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "description": "", "fieldConfig": { @@ -1938,12 +1893,11 @@ "sparkline": false, "spotlight": true }, - "pluginVersion": "12.2.0-pre", + "pluginVersion": "13.0.0-pre", "targets": [ { "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "hide": false, "max": 12, @@ -1961,8 +1915,7 @@ }, { "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "description": "", "fieldConfig": { @@ -2024,12 +1977,11 @@ "sparkline": false, "spotlight": true }, - "pluginVersion": "12.2.0-pre", + "pluginVersion": "13.0.0-pre", "targets": [ { "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "hide": false, "max": 100, @@ -2047,8 +1999,7 @@ }, { "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "description": "", "fieldConfig": { @@ -2110,12 +2061,11 @@ "sparkline": false, "spotlight": true }, - "pluginVersion": "12.2.0-pre", + "pluginVersion": "13.0.0-pre", "targets": [ { "datasource": { - "type": "grafana-testdata-datasource", - "uid": "PD8C576611E62080A" + "type": "grafana-testdata-datasource" }, "hide": false, "max": 100, diff --git a/public/app/plugins/panel/radialbar/GaugeMigrations.test.ts b/public/app/plugins/panel/radialbar/GaugeMigrations.test.ts index 3eeee61c841..55f879f1d80 100644 --- a/public/app/plugins/panel/radialbar/GaugeMigrations.test.ts +++ b/public/app/plugins/panel/radialbar/GaugeMigrations.test.ts @@ -32,6 +32,34 @@ describe('Gauge Panel Migrations', () => { expect(result.sparkline).toBe(false); }); + it('does not overwrite new gauge', () => { + const panel = { + id: 2, + options: { + reduceOptions: { + calcs: ['lastNotNull'], + }, + showThresholdLabels: false, + showThresholdMarkers: true, + sparkline: true, + }, + fieldConfig: { + defaults: { + color: { + mode: FieldColorModeId.Fixed, + fixedColor: 'blue', + }, + }, + overrides: [], + }, + pluginVersion: '13.0.0', + type: 'gauge', + } as Omit; + + const result = gaugePanelMigrationHandler(panel as PanelModel); + expect(result.sparkline).toBe(true); + }); + it('from 6.1.1', () => { const panel = { datasource: '-- Grafana --', diff --git a/public/app/plugins/panel/radialbar/GaugeMigrations.ts b/public/app/plugins/panel/radialbar/GaugeMigrations.ts index 40b291233d2..b5877ac9bf3 100644 --- a/public/app/plugins/panel/radialbar/GaugeMigrations.ts +++ b/public/app/plugins/panel/radialbar/GaugeMigrations.ts @@ -9,10 +9,9 @@ export function gaugePanelMigrationHandler(panel: PanelModel): Partial< const sharedOptions = sharedSingleStatMigrationHandler(panel); const newOptions: Partial = { ...sharedOptions }; - const previousVersion = parseFloat(panel.pluginVersion || '8'); - const fieldConfig = panel.fieldConfig; + if (shouldMigrateGauge(panel)) { + const fieldConfig = panel.fieldConfig; - if (previousVersion <= 12.3) { // This option had no effect in old gauge unless color mode was 'From thresholds' if (newOptions.showThresholdMarkers && fieldConfig?.defaults?.color?.mode !== FieldColorModeId.Thresholds) { newOptions.showThresholdMarkers = false; @@ -41,7 +40,7 @@ export function gaugePanelMigrationHandler(panel: PanelModel): Partial< export function shouldMigrateGauge(panel: PanelModel): boolean { const previousVersion = parseFloat(panel.pluginVersion ?? '8'); - return previousVersion <= 12.3; + return previousVersion < 13; } // This is called when the panel changes from another panel From 238244fe5c36ce4048d6217be3dedf3b1d3c38fd Mon Sep 17 00:00:00 2001 From: Yunwen Zheng Date: Tue, 28 Oct 2025 09:34:18 -0400 Subject: [PATCH 052/378] SaveProvisionedDashboardForm: Show preview banner when pushing to non-configured existing branch (#112947) * SaveProvisionedDashboardForm: Show preview banner when pushing to non-configured existing branch * useProvisionedRequestHandler: use ref to prevent handler triggered twice --- .../SaveProvisionedDashboardForm.tsx | 92 ++++++++++++------- .../hooks/useProvisionedRequestHandler.ts | 9 +- 2 files changed, 64 insertions(+), 37 deletions(-) diff --git a/public/app/features/provisioning/components/Dashboards/SaveProvisionedDashboardForm.tsx b/public/app/features/provisioning/components/Dashboards/SaveProvisionedDashboardForm.tsx index f278c2e436c..6af33a5cbea 100644 --- a/public/app/features/provisioning/components/Dashboards/SaveProvisionedDashboardForm.tsx +++ b/public/app/features/provisioning/components/Dashboards/SaveProvisionedDashboardForm.tsx @@ -1,4 +1,4 @@ -import { useEffect } from 'react'; +import { useCallback, useEffect } from 'react'; import { Controller, useForm, FormProvider } from 'react-hook-form'; import { useNavigate } from 'react-router-dom-v5-compat'; @@ -56,7 +56,7 @@ export function SaveProvisionedDashboardForm({ const methods = useForm({ defaultValues }); const { handleSubmit, watch, control, reset, register } = methods; - const [workflow] = watch(['workflow']); + const [workflow, ref, path] = watch(['workflow', 'ref', 'path']); // Update the form if default values change useEffect(() => { @@ -70,46 +70,35 @@ export function SaveProvisionedDashboardForm({ }); }; - const handleNewDashboard = (upsert: Resource) => { - // Navigation for new dashboards - const url = locationUtil.assureBaseUrl( - getDashboardUrl({ - uid: upsert.metadata.name, - slug: kbn.slugifyForUrl(upsert.spec.title ?? ''), - currentQueryParams: window.location.search, - }) - ); - navigate(url); - }; + const handleNewDashboard = useCallback( + (upsert: Resource) => { + // Navigation for new dashboards + const url = locationUtil.assureBaseUrl( + getDashboardUrl({ + uid: upsert.metadata.name, + slug: kbn.slugifyForUrl(upsert.spec.title ?? ''), + currentQueryParams: window.location.search, + }) + ); + navigate(url); + }, + [navigate] + ); - const onWriteSuccess = (_: ProvisionedOperationInfo, upsert: Resource) => { - handleDismiss(); - if (isNew && upsert?.metadata.name) { - handleNewDashboard(upsert); - } else { - locationService.partial({ - viewPanel: null, - editPanel: null, - }); - } - }; - - const onBranchSuccess = (ref: string, path: string, info: ProvisionedOperationInfo, upsert: Resource) => { - handleDismiss(); - if (isNew && upsert?.metadata?.name) { - handleNewDashboard(upsert); - } else { + const navigateToPreview = useCallback( + (ref: string, path: string, repoType: string) => { const url = buildResourceBranchRedirectUrl({ baseUrl: `${PROVISIONING_URL}/${defaultValues.repo}/dashboard/preview/${path}`, paramName: 'ref', paramValue: ref, - repoType: info.repoType, + repoType, }); navigate(url); - } - }; + }, + [navigate, defaultValues.repo] + ); - const handleDismiss = () => { + const handleDismiss = useCallback(() => { panelEditor?.onDiscard(); const model = dashboard.getSaveModel(); @@ -118,7 +107,40 @@ export function SaveProvisionedDashboardForm({ dashboard.saveCompleted(model, saveResponse, defaultValues.folder?.uid); drawer.onClose(); - }; + }, [dashboard, defaultValues.folder?.uid, drawer, panelEditor, request?.data?.resource]); + + const onWriteSuccess = useCallback( + ({ repoType }: ProvisionedOperationInfo, upsert: Resource) => { + handleDismiss(); + if (isNew && upsert?.metadata.name) { + handleNewDashboard(upsert); + } + + // if pushed to an existing but non-configured branch, navigate to preview page + if (ref !== repository?.branch && ref) { + navigateToPreview(ref, path, repoType); + return; + } + + locationService.partial({ + viewPanel: null, + editPanel: null, + }); + }, + [isNew, path, ref, repository?.branch, handleDismiss, handleNewDashboard, navigateToPreview] + ); + + const onBranchSuccess = useCallback( + (ref: string, path: string, info: ProvisionedOperationInfo, upsert: Resource) => { + handleDismiss(); + if (isNew && upsert?.metadata?.name) { + handleNewDashboard(upsert); + } else { + navigateToPreview(ref, path, info.repoType); + } + }, + [isNew, navigateToPreview, handleNewDashboard, handleDismiss] + ); useProvisionedRequestHandler({ folderUID: defaultValues.folder?.uid, diff --git a/public/app/features/provisioning/hooks/useProvisionedRequestHandler.ts b/public/app/features/provisioning/hooks/useProvisionedRequestHandler.ts index 98675545294..7fc3bb052fe 100644 --- a/public/app/features/provisioning/hooks/useProvisionedRequestHandler.ts +++ b/public/app/features/provisioning/hooks/useProvisionedRequestHandler.ts @@ -1,4 +1,4 @@ -import { useEffect } from 'react'; +import { useEffect, useRef } from 'react'; import { AppEvents } from '@grafana/data'; import { t } from '@grafana/i18n'; @@ -74,6 +74,9 @@ export function useProvisionedRequestHandler({ resourceType, }: Props) { const dispatch = useDispatch(); + // useRef to ensure handlers are only called once per request + const hasHandled = useRef(false); + useEffect(() => { const repoType = repository?.type || 'git'; const info: ProvisionedOperationInfo = { @@ -83,11 +86,13 @@ export function useProvisionedRequestHandler({ }; if (request.isError) { + hasHandled.current = true; handlers.onError?.(request.error, info); return; } - if (request.isSuccess && request.data) { + if (request.isSuccess && request.data && !hasHandled.current) { + hasHandled.current = true; const { ref, path, urls, resource } = request.data; // eslint-disable-next-line @typescript-eslint/consistent-type-assertions const resourceData = resource.upsert as Resource; From 79a5b024e1cf3ab30f7567446e65d07dc9db89a1 Mon Sep 17 00:00:00 2001 From: Yunwen Zheng Date: Tue, 28 Oct 2025 09:34:33 -0400 Subject: [PATCH 053/378] MegaMenu: Spacing alignment tweaks (#113055) --- .../core/components/AppChrome/MegaMenu/MegaMenuItem.tsx | 6 +++--- .../OrganizationSwitcher/OrganizationSwitcher.tsx | 9 ++------- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/public/app/core/components/AppChrome/MegaMenu/MegaMenuItem.tsx b/public/app/core/components/AppChrome/MegaMenu/MegaMenuItem.tsx index a3e56e4a3a8..0677a902e1f 100644 --- a/public/app/core/components/AppChrome/MegaMenu/MegaMenuItem.tsx +++ b/public/app/core/components/AppChrome/MegaMenu/MegaMenuItem.tsx @@ -175,7 +175,7 @@ const getStyles = (theme: GrafanaTheme2) => ({ menuItem: css({ display: 'flex', alignItems: 'center', - gap: theme.spacing(0.5), + gap: theme.spacing(1.5), height: theme.spacing(4), paddingLeft: theme.spacing(0.5), position: 'relative', @@ -215,13 +215,13 @@ const getStyles = (theme: GrafanaTheme2) => ({ labelWrapper: css({ display: 'flex', alignItems: 'center', - gap: theme.spacing(2), + gap: theme.spacing(0.75), minWidth: 0, paddingLeft: theme.spacing(1), }), labelWrapperWithIcon: css({ paddingLeft: theme.spacing(0.5), - gap: theme.spacing(0.5), + gap: theme.spacing(0.75), }), hasActiveChild: css({ color: theme.colors.text.primary, diff --git a/public/app/core/components/AppChrome/OrganizationSwitcher/OrganizationSwitcher.tsx b/public/app/core/components/AppChrome/OrganizationSwitcher/OrganizationSwitcher.tsx index 67ad47cded0..960b5f4085f 100644 --- a/public/app/core/components/AppChrome/OrganizationSwitcher/OrganizationSwitcher.tsx +++ b/public/app/core/components/AppChrome/OrganizationSwitcher/OrganizationSwitcher.tsx @@ -2,7 +2,7 @@ import { useEffect } from 'react'; import { SelectableValue } from '@grafana/data'; import { locationService } from '@grafana/runtime'; -import { Space, Text } from '@grafana/ui'; +import { Text } from '@grafana/ui'; import { contextSrv } from 'app/core/services/context_srv'; import { getUserOrganizations, setUserOrganization } from 'app/features/org/state/actions'; import { useDispatch, useSelector } from 'app/types/store'; @@ -33,12 +33,7 @@ export function OrganizationSwitcher() { }, [dispatch]); if (orgs?.length <= 1) { - return ( - <> - - {Branding.AppTitle} - - ); + return {Branding.AppTitle}; } return ; From 1cb66d86b0d977678bb2a353fc887534cb5518a5 Mon Sep 17 00:00:00 2001 From: Alyssa Joyner <58453566+alyssajoyner@users.noreply.github.com> Date: Tue, 28 Oct 2025 08:09:43 -0600 Subject: [PATCH 054/378] [InfluxDB]: Update product selection and UI (#112074) --- .../editor/config-v2/ConfigEditor.tsx | 11 +- .../config-v2/DatabaseConnectionSection.tsx | 2 +- .../InfluxInfluxQLDBConnection.test.tsx | 9 +- .../editor/config-v2/LeftSideBar.tsx | 75 +++++++--- .../UrlAndAuthenticationSection.test.tsx | 62 +++++---- .../config-v2/UrlAndAuthenticationSection.tsx | 130 +++++++++++++----- .../components/editor/config-v2/constants.ts | 18 +-- .../components/editor/config-v2/versions.ts | 23 +++- 8 files changed, 235 insertions(+), 95 deletions(-) diff --git a/public/app/plugins/datasource/influxdb/components/editor/config-v2/ConfigEditor.tsx b/public/app/plugins/datasource/influxdb/components/editor/config-v2/ConfigEditor.tsx index 508a9b5617d..a6cc7eb3747 100644 --- a/public/app/plugins/datasource/influxdb/components/editor/config-v2/ConfigEditor.tsx +++ b/public/app/plugins/datasource/influxdb/components/editor/config-v2/ConfigEditor.tsx @@ -15,7 +15,7 @@ export const ConfigEditor: React.FC = ({ onOptionsChange, options }: Prop const styles = useStyles2(getStyles); return ( -
+
@@ -38,7 +38,7 @@ export const ConfigEditor: React.FC = ({ onOptionsChange, options }: Prop to help us make it even better. - + Fields marked with * are required @@ -61,6 +61,13 @@ const getStyles = (theme: GrafanaTheme2) => { display: 'none', }, }), + leftSticky: css({ + position: 'sticky', + top: '100px', + alignSelf: 'flex-start', + maxHeight: 'calc(100vh - 100px)', + overflow: 'hidden', + }), alertHeight: css({ height: '100px', }), diff --git a/public/app/plugins/datasource/influxdb/components/editor/config-v2/DatabaseConnectionSection.tsx b/public/app/plugins/datasource/influxdb/components/editor/config-v2/DatabaseConnectionSection.tsx index e06fa0baf32..46cf67b96ff 100644 --- a/public/app/plugins/datasource/influxdb/components/editor/config-v2/DatabaseConnectionSection.tsx +++ b/public/app/plugins/datasource/influxdb/components/editor/config-v2/DatabaseConnectionSection.tsx @@ -20,7 +20,7 @@ export const DatabaseConnectionSection = ({ options, onOptionsChange }: Props) = minWidth={CONTAINER_MIN_WIDTH} > 2. {CONFIG_SECTION_HEADERS[1].label}} + label={{CONFIG_SECTION_HEADERS[1].label}} isOpen={CONFIG_SECTION_HEADERS[1].isOpen} > {!options.jsonData.version && ( diff --git a/public/app/plugins/datasource/influxdb/components/editor/config-v2/InfluxInfluxQLDBConnection.test.tsx b/public/app/plugins/datasource/influxdb/components/editor/config-v2/InfluxInfluxQLDBConnection.test.tsx index 9351cbda5de..cb4de921fcc 100644 --- a/public/app/plugins/datasource/influxdb/components/editor/config-v2/InfluxInfluxQLDBConnection.test.tsx +++ b/public/app/plugins/datasource/influxdb/components/editor/config-v2/InfluxInfluxQLDBConnection.test.tsx @@ -28,14 +28,17 @@ describe('InfluxInfluxQLDBConnection', () => { it('renders dbName, user and password fields', () => { render(); - expect(screen.getByLabelText(/Database/i)).toBeInTheDocument(); - expect(screen.getByLabelText(/User/i)).toBeInTheDocument(); - expect(screen.getByLabelText(/Password/i)).toBeInTheDocument(); + + expect(screen.getByLabelText(/^Database\b/i)).toBeInTheDocument(); + expect(screen.getByLabelText(/^User\b/i)).toBeInTheDocument(); + expect(screen.getByLabelText(/^Password\b/i)).toBeInTheDocument(); }); it('calls onOptionsChange on input changes', () => { render(); + fireEvent.change(screen.getByLabelText(/User/i), { target: { value: 'newuser' } }); + expect(onOptionsChangeMock).toHaveBeenCalled(); }); }); diff --git a/public/app/plugins/datasource/influxdb/components/editor/config-v2/LeftSideBar.tsx b/public/app/plugins/datasource/influxdb/components/editor/config-v2/LeftSideBar.tsx index cc970f35575..26604ac1f9b 100644 --- a/public/app/plugins/datasource/influxdb/components/editor/config-v2/LeftSideBar.tsx +++ b/public/app/plugins/datasource/influxdb/components/editor/config-v2/LeftSideBar.tsx @@ -1,4 +1,6 @@ -import { Box, InlineField, LinkButton, Space, Stack, Text } from '@grafana/ui'; +import { css } from '@emotion/css'; + +import { Box, Icon, LinkButton, Space, Stack, Text, useStyles2 } from '@grafana/ui'; import { CONFIG_SECTION_HEADERS, CONFIG_SECTION_HEADERS_WITH_PDC } from './constants'; @@ -8,29 +10,40 @@ interface LeftSideBarProps { export const LeftSideBar = ({ pdcInjected }: LeftSideBarProps) => { const headers = pdcInjected ? CONFIG_SECTION_HEADERS_WITH_PDC : CONFIG_SECTION_HEADERS; + const styles = useStyles2(getStyles); + return ( - - - InfluxDB + + Connect data source {headers.map((header, index) => (
- - { - e.preventDefault(); - const target = document.getElementById(header.id); - if (target) { - target.scrollIntoView({ behavior: 'smooth', block: 'start' }); - } - }} - > - {header.label} - - + + { + e.preventDefault(); + const target = document.getElementById(header.id); + if (target) { + const y = target.getBoundingClientRect().top + window.scrollY - 60; + window.scrollTo({ top: y, behavior: 'smooth' }); + } + }} + > +
+
{header.label}
+ {header.isOptional && ( +
+ + optional + +
+ )} +
+
))} @@ -39,3 +52,27 @@ export const LeftSideBar = ({ pdcInjected }: LeftSideBarProps) => {
); }; + +const getStyles = () => ({ + inlineField: css({ + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + }), + sidebarText: css({ + display: 'flex', + flexDirection: 'column', + }), + sidebarLabel: css({ + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + marginBottom: 0, + lineHeight: 1, + }), + sidebarOptional: css({ + marginTop: 0, + marginBottom: 0, + lineHeight: 1, + }), +}); diff --git a/public/app/plugins/datasource/influxdb/components/editor/config-v2/UrlAndAuthenticationSection.test.tsx b/public/app/plugins/datasource/influxdb/components/editor/config-v2/UrlAndAuthenticationSection.test.tsx index 2f6704ea66a..7bc084744df 100644 --- a/public/app/plugins/datasource/influxdb/components/editor/config-v2/UrlAndAuthenticationSection.test.tsx +++ b/public/app/plugins/datasource/influxdb/components/editor/config-v2/UrlAndAuthenticationSection.test.tsx @@ -1,4 +1,16 @@ +const backendSrv = { + fetch: jest.fn(), +} as unknown as BackendSrv; + +jest.mock('@grafana/runtime', () => ({ + ...jest.requireActual('@grafana/runtime'), + getBackendSrv: () => backendSrv, +})); + import { render, screen, fireEvent, waitFor } from '@testing-library/react'; +import { of } from 'rxjs'; + +import { BackendSrv } from '@grafana/runtime'; import { InfluxVersion } from '../../../types'; @@ -11,6 +23,7 @@ describe('UrlAndAuthenticationSection', () => { const defaultProps = createTestProps({ options: { + id: 1234, jsonData: { url: 'http://localhost:8086', product: '', @@ -24,6 +37,29 @@ describe('UrlAndAuthenticationSection', () => { }, }); + const mockFetchPing = ({ build, version, status = 204 }: { build?: string; version?: string; status?: number }) => { + backendSrv.fetch = jest.fn().mockReturnValue( + of({ + status, + ok: status >= 200 && status < 300, + data: status === 204 ? '' : {}, + headers: { + get: (k: string) => { + const key = k.toLowerCase(); + if (key === 'x-influxdb-build') { + return build ?? null; + } + if (key === 'x-influxdb-version') { + return version ?? null; + } + return null; + }, + }, + url: '/api/datasources/proxy/1234/ping', + }) + ); + }; + beforeEach(() => { // Mock console.error to suppress React act() warnings consoleSpy = jest.spyOn(console, 'error').mockImplementation(() => {}); @@ -239,7 +275,7 @@ describe('UrlAndAuthenticationSection', () => { }, }; - mockFetchPing({ ok: true, build: 'OSS', version: '1.8.10' }); + mockFetchPing({ build: 'OSS', version: '1.8.10' }); render(); const input = screen.getByTestId('influxdb-v2-config-url-input'); @@ -268,7 +304,7 @@ describe('UrlAndAuthenticationSection', () => { }, }; - mockFetchPing({ ok: true, build: 'OSS', version: '2.7.1' }); + mockFetchPing({ build: 'OSS', version: '2.7.1' }); render(); const input = screen.getByTestId('influxdb-v2-config-url-input'); @@ -297,7 +333,7 @@ describe('UrlAndAuthenticationSection', () => { }, }; - mockFetchPing({ ok: true, build: undefined, version: undefined }); + mockFetchPing({ build: undefined, version: undefined }); render(); const input = screen.getByTestId('influxdb-v2-config-url-input'); @@ -358,23 +394,3 @@ describe('UrlAndAuthenticationSection', () => { }); }); }); - -export function mockFetchPing(resp: { ok?: boolean; build?: string; version?: string } = {}) { - const { ok = true, build, version } = resp; - - global.fetch = jest.fn().mockResolvedValue({ - ok, - headers: { - get: (key: string) => { - const normalized = key.toLowerCase(); - if (normalized === 'x-influxdb-build') { - return build ?? null; - } - if (normalized === 'x-influxdb-version') { - return version ?? null; - } - return null; - }, - }, - }); -} diff --git a/public/app/plugins/datasource/influxdb/components/editor/config-v2/UrlAndAuthenticationSection.tsx b/public/app/plugins/datasource/influxdb/components/editor/config-v2/UrlAndAuthenticationSection.tsx index 5926ea6703a..df866807b64 100644 --- a/public/app/plugins/datasource/influxdb/components/editor/config-v2/UrlAndAuthenticationSection.tsx +++ b/public/app/plugins/datasource/influxdb/components/editor/config-v2/UrlAndAuthenticationSection.tsx @@ -1,4 +1,8 @@ +import { css } from '@emotion/css'; +import { firstValueFrom } from 'rxjs'; + import { onUpdateDatasourceJsonDataOptionSelect, onUpdateDatasourceOption } from '@grafana/data'; +import { getBackendSrv } from '@grafana/runtime'; import { Box, CollapsableSection, @@ -11,6 +15,7 @@ import { Text, ComboboxOption, Alert, + useStyles2, } from '@grafana/ui'; import { InfluxVersion } from '../../../types'; @@ -33,6 +38,7 @@ const getQueryLanguageOptions = (productName: string): Array<{ value: string }> export const UrlAndAuthenticationSection = (props: Props) => { const { options, onOptionsChange } = props; + const styles = useStyles2(getStyles); const isInfluxVersion = (v: string): v is InfluxVersion => typeof v === 'string' && (v === InfluxVersion.Flux || v === InfluxVersion.InfluxQL || v === InfluxVersion.SQL); @@ -68,13 +74,30 @@ export const UrlAndAuthenticationSection = (props: Props) => { }; const pingInfluxForProductDetection = async (urlValue: string) => { - const base = urlValue.replace(/\/$/, ''); + const dsId = options.id; + if (!dsId) { + return; + } try { - const res = await fetch(`${base}/ping`); + const res = await firstValueFrom( + getBackendSrv().fetch({ + method: 'GET', + url: `/api/datasources/proxy/${dsId}/ping`, + headers: { Accept: 'application/json' }, + responseType: 'text', + showErrorAlert: false, + showSuccessAlert: false, + }) + ); if (res.ok) { - const product = res.headers.get('x-influxdb-build') ?? undefined; - const version = res.headers.get('x-influxdb-version') ?? undefined; + let product: string | undefined; + let version: string | undefined; + + if (res.headers && typeof res.headers.get === 'function') { + product = res.headers.get('x-influxdb-build') ?? undefined; + version = res.headers.get('x-influxdb-version') ?? undefined; + } if (product || version) { return { product, version }; @@ -136,21 +159,19 @@ export const UrlAndAuthenticationSection = (props: Props) => { borderStyle="solid" borderColor="weak" padding={2} - marginBottom={4} id={`${CONFIG_SECTION_HEADERS[0].id}`} minWidth={CONTAINER_MIN_WIDTH} > 1. {CONFIG_SECTION_HEADERS[0].label}} + label={{CONFIG_SECTION_HEADERS[0].label}} isOpen={CONFIG_SECTION_HEADERS[0].isOpen} > Enter the URL of your InfluxDB instance, then select your product and query language. This will determine the available settings and authentication methods in the next steps. - - - URL *
} noMargin required> + + { }} /> - - - - Product *
} noMargin required> - ({ value: name }))} - onChange={onProductChange} - /> - - - - Query language *
} noMargin> - - - + +
+ + + + Use{' '} + + InfluxDB detection + {' '} + to identify the product + +
+ } + noMargin + required + > + ({ value: name }))} + onChange={onProductChange} + /> + + +
+
+ + The query language depends on product selection
} + noMargin + required + > + + + + - - {requiresDbrpMapping && ( {`${options.jsonData.product} requires a Database + Retention Policy (DBRP) mapping via the CLI or @@ -199,7 +245,6 @@ export const UrlAndAuthenticationSection = (props: Props) => { )} - @@ -207,3 +252,20 @@ export const UrlAndAuthenticationSection = (props: Props) => { ); }; + +const getStyles = () => { + return { + dropdown: css({ + display: 'flex', + alignItems: 'center', + height: '18px', + }), + col: css({ + flex: '1 1 48%', + minWidth: '320px', + }), + '@media (max-width: 768px)': { + flexBasis: '100%', + }, + }; +}; diff --git a/public/app/plugins/datasource/influxdb/components/editor/config-v2/constants.ts b/public/app/plugins/datasource/influxdb/components/editor/config-v2/constants.ts index a3c63953d4e..0a795e71dae 100644 --- a/public/app/plugins/datasource/influxdb/components/editor/config-v2/constants.ts +++ b/public/app/plugins/datasource/influxdb/components/editor/config-v2/constants.ts @@ -17,16 +17,16 @@ export const AUTH_RADIO_BUTTON_OPTIONS = [ ]; export const CONFIG_SECTION_HEADERS = [ - { label: 'URL and authentication', id: 'url', isOpen: true }, - { label: 'Database settings', id: 'tls', isOpen: true }, - { label: 'Save & test', id: `${selectors.pages.DataSource.saveAndTest}`, isOpen: true }, + { label: 'URL and authentication', id: 'url', isOpen: true, isOptional: false }, + { label: 'Database settings', id: 'db', isOpen: true, isOptional: false }, + { label: 'Save & test', id: `${selectors.pages.DataSource.saveAndTest}`, isOpen: true, isOptional: null }, ]; export const CONFIG_SECTION_HEADERS_WITH_PDC = [ - { label: 'URL and authentication', id: 'url', isOpen: true }, - { label: 'Database settings', id: 'tls', isOpen: true }, - { label: 'Private data source connect', id: 'pdc', isOpen: true }, - { label: 'Save & test', id: `${selectors.pages.DataSource.saveAndTest}`, isOpen: true }, + { label: 'URL and authentication', id: 'url', isOpen: true, isOptional: false }, + { label: 'Database settings', id: 'db', isOpen: true, isOptional: false }, + { label: 'Private data source connect', id: 'pdc', isOpen: false, isOptional: true }, + { label: 'Save & test', id: `${selectors.pages.DataSource.saveAndTest}`, isOpen: true, isOptional: null }, ]; export const HTTP_MODES: ComboboxOption[] = [ @@ -34,7 +34,7 @@ export const HTTP_MODES: ComboboxOption[] = [ { label: 'GET', value: 'GET' }, ]; -export const getInlineLabelStyles = (theme: GrafanaTheme2, transparent = false, width?: number | 'auto') => { +export const getInlineLabelStyles = (theme: GrafanaTheme2, transparent = false) => { return { label: css({ display: 'flex', @@ -56,5 +56,5 @@ export const getInlineLabelStyles = (theme: GrafanaTheme2, transparent = false, }; }; -export const DB_SETTINGS_LABEL_WIDTH = 18; export const CONTAINER_MIN_WIDTH = '450px'; +export const DB_SETTINGS_LABEL_WIDTH = 22; diff --git a/public/app/plugins/datasource/influxdb/components/editor/config-v2/versions.ts b/public/app/plugins/datasource/influxdb/components/editor/config-v2/versions.ts index f5dc31a75d3..2b2a65111e1 100644 --- a/public/app/plugins/datasource/influxdb/components/editor/config-v2/versions.ts +++ b/public/app/plugins/datasource/influxdb/components/editor/config-v2/versions.ts @@ -63,7 +63,8 @@ export const INFLUXDB_VERSION_MAP: InfluxDBProduct[] = [ ], detectionMethod: { pingHeaderResponse: { - 'x-influxdb-build': 'Enterprise (needs confirmation)', + 'x-influxdb-version': '^v?1\\.', + 'x-influxdb-build': 'Enterprise', }, }, }, @@ -75,7 +76,8 @@ export const INFLUXDB_VERSION_MAP: InfluxDBProduct[] = [ ], detectionMethod: { pingHeaderResponse: { - 'x-influxdb-build': 'TBD', + 'x-influxdb-version': '^v?3\\.', + 'x-influxdb-build': 'Enterprise', }, }, }, @@ -113,7 +115,7 @@ export const INFLUXDB_VERSION_MAP: InfluxDBProduct[] = [ detectionMethod: { pingHeaderResponse: { 'x-influxdb-build': 'OSS', - 'x-influxdb-version': '^1\\.', + 'x-influxdb-version': '^v?1\\.', }, }, }, @@ -134,7 +136,20 @@ export const INFLUXDB_VERSION_MAP: InfluxDBProduct[] = [ detectionMethod: { pingHeaderResponse: { 'x-influxdb-build': 'OSS', - 'x-influxdb-version': '^2\\.', + 'x-influxdb-version': '^v?2\\.', + }, + }, + }, + { + name: 'InfluxDB OSS 3.x', + queryLanguages: [ + { name: InfluxVersion.SQL, fields: ['URL', 'Token'] }, + { name: InfluxVersion.InfluxQL, fields: ['URL', 'Token'] }, + ], + detectionMethod: { + pingHeaderResponse: { + 'x-influxdb-build': 'OSS', + 'x-influxdb-version': '^v?3\\.', }, }, }, From 3131a69f043eabb92d97158ed33b48c9de702e7c Mon Sep 17 00:00:00 2001 From: Levente Balogh Date: Tue, 28 Oct 2025 15:15:54 +0100 Subject: [PATCH 055/378] Switch variable type: Add docs (#113029) * docs: add docs for the switch variable type * chore: prettier fix * docs: fix review notes * Apply suggestions from code review Co-authored-by: Isabel Matwawana <76437239+imatwawana@users.noreply.github.com> * docs: move the switch variable section after ad-hoc variables * fix: vale fixes * Update docs/sources/visualizations/dashboards/variables/add-template-variables/index.md Co-authored-by: Isabel Matwawana <76437239+imatwawana@users.noreply.github.com> --------- Co-authored-by: Isabel Matwawana <76437239+imatwawana@users.noreply.github.com> --- .../schema-v2/variables-schema.md | 45 ++++++++++++++++++ .../variables/add-template-variables/index.md | 47 +++++++++++++++++++ 2 files changed, 92 insertions(+) diff --git a/docs/sources/observability-as-code/schema-v2/variables-schema.md b/docs/sources/observability-as-code/schema-v2/variables-schema.md index 9d6b696eb0f..8706858ea1f 100644 --- a/docs/sources/observability-as-code/schema-v2/variables-schema.md +++ b/docs/sources/observability-as-code/schema-v2/variables-schema.md @@ -29,6 +29,7 @@ The available variable types described in the following sections: - [DatasourceVariableKind](#datasourcevariablekind) - [IntervalVariableKind](#intervalvariablekind) - [CustomVariableKind](#customvariablekind) +- [SwitchVariableKind](#switchvariablekind) - [GroupByVariableKind](#groupbyvariablekind) - [AdhocVariableKind](#adhocvariablekind) @@ -337,6 +338,50 @@ The following table explains the usage of the custom variable JSON fields: | skipUrlSync | bool. Default is `false`. | | description? | string | +## `SwitchVariableKind` + +Following is the JSON for a default switch variable: + +```json + "variables": [ + { + "kind": "SwitchVariable", + "spec": { + "current": "false", + "enabledValue": "true", + "disabledValue": "false", + "hide": "dontHide", + "name": "", + "skipUrlSync": false + } + } + ] +``` + +`SwitchVariableKind` consists of: + +- kind: "SwitchVariable" +- spec: [SwitchVariableSpec](#switchvariablespec) + +### `SwitchVariableSpec` + +The following table explains the usage of the switch variable JSON fields: + + + +| Name | Usage | +| -------------- | -------------------------------------------------------------------------------------------------------------------------------- | +| name | string. Name of the variable. | +| current | string. Current value of the switch variable (either `enabledValue` or `disabledValue`). | +| enabledValue | string. Value when the switch is in the enabled state. | +| disabledValue | string. Value when the switch is in the disabled state. | +| label? | string | +| hide | `VariableHide`. Options are: `dontHide`, `hideLabel`, and `hideVariable`. | +| skipUrlSync | bool. Default is `false`. | +| description? | string | + + + ## `GroupByVariableKind` Following is the JSON for a default group by variable: diff --git a/docs/sources/visualizations/dashboards/variables/add-template-variables/index.md b/docs/sources/visualizations/dashboards/variables/add-template-variables/index.md index 0343d78fb91..42cea78cf57 100644 --- a/docs/sources/visualizations/dashboards/variables/add-template-variables/index.md +++ b/docs/sources/visualizations/dashboards/variables/add-template-variables/index.md @@ -104,6 +104,7 @@ The following table lists the types of variables shipped with Grafana. | Data source | Quickly change the data source for an entire dashboard. [Add a data source variable](#add-a-data-source-variable). | | Interval | Interval variables represent time spans. [Add an interval variable](#add-an-interval-variable). | | Ad hoc filters | Key/value filters that are automatically added to all metric queries for a data source (Prometheus, Loki, InfluxDB, and Elasticsearch only). [Add ad hoc filters](#add-ad-hoc-filters). | +| Switch | Display a switch that allows you to toggle between two configurable values for enabled and disabled states. [Add a switch variable](#add-a-switch-variable). | | Global variables | Built-in variables that can be used in expressions in the query editor. Refer to [Global variables](#global-variables). | | Chained variables | Variable queries can contain other variables. Refer to [Chained variables](#chained-variables). | @@ -135,6 +136,7 @@ To create a variable, follow these steps: - [Data source](#add-a-data-source-variable) - [Interval](#add-an-interval-variable) - [Ad hoc filters](#add-ad-hoc-filters) + - [Switch](#add-a-switch-variable) @@ -384,6 +386,51 @@ If one of the panels in the dashboard using that data source doesn't include tha In cases where the data source you're using doesn't support ad hoc filtering, consider using the special Dashboard data source. For more information, refer to [Filter any data using the Dashboard data source](https://grafana.com/docs/grafana//dashboards/variables/add-template-variables/#filter-any-data-using-the-dashboard-data-source). +## Add a switch variable + +_Switch_ variables display a switch with two configurable values representing enabled and disabled states. This variable type is useful when you need to: + +- Toggle between different query conditions +- Enable or disable specific filters +- Switch between different visualization modes +- Control boolean parameters in your data sources + +1. [Enter general options](#enter-general-options). +1. Under the **Switch options** section of the page, configure the switch values: + + In the **Value pair type** drop-down list, select one of the following predefined options or choose **Custom** to define your own values: + - **True / False** - Uses boolean values `true` and `false` + - **1 / 0** - Uses numeric values `1` and `0` + - **Yes / No** - Uses string values `yes` and `no` + - **Custom** - Allows you to define custom values for both enabled and disabled states + +1. If you selected **Custom** in the previous step, configure the custom values: + - **Enabled value** - Enter the value that represents the enabled state (for example, "on"). + - **Disabled value** - Enter the value that represents the disabled state (for example, "off"). + +1. Click **Save dashboard**. +1. Click **Back to dashboard** and **Exit edit**. + +### Switch variable examples + +The following example shows a switch variable `$debug_mode` used in a Prometheus query to conditionally include debug labels: + +``` +up{job="my-service"} and ($debug_mode == "true" or on() vector(0)) +``` + +The following example shows a switch variable `$show_errors` used to filter log entries: + +``` +{job="application"} |= ($show_errors == "1" ? "ERROR" : "") +``` + +You can also use switch variables in panel titles and other dashboard elements: + +``` +{{#if debug_mode}}Debug Mode: {{/if}}Application Metrics +``` + From 437dcc875cd220fd727c76f10b87b06e4f22e2bf Mon Sep 17 00:00:00 2001 From: Bruno Date: Tue, 28 Oct 2025 11:41:46 -0300 Subject: [PATCH 056/378] QueryCaching: Use CachingServiceClient for query caching (#112128) * Integrate mt querier with query caching * typo * let the caller set cache status response header * fix TestQueryAPI * make gen-go * handle CachingServiceClient being nil and make gen-go * include namespace in cache key * set signed in user namespace in query_test.go * fix test * remove commented out code * undo services/query/query.go changes * make gen-go * remove namespace requirement * fix tests * fix test * remove namespace from SignedInUser in tests * make gen-go --- pkg/api/plugin_resource_test.go | 2 +- pkg/registry/apis/query/query_test.go | 4 + pkg/server/wire.go | 2 + pkg/server/wire_gen.go | 8 +- pkg/services/caching/fake_caching_service.go | 12 +- .../caching_metrics.go => caching/metrics.go} | 2 +- pkg/services/caching/service.go | 169 ++++++++++++++-- pkg/services/caching/service_test.go | 130 ++++++++++++ .../clientmiddleware/caching_middleware.go | 186 +----------------- .../caching_middleware_test.go | 116 ++--------- .../pluginsintegration/pluginsintegration.go | 12 +- pkg/services/query/query_test.go | 7 +- 12 files changed, 345 insertions(+), 305 deletions(-) rename pkg/services/{pluginsintegration/clientmiddleware/caching_metrics.go => caching/metrics.go} (98%) create mode 100644 pkg/services/caching/service_test.go diff --git a/pkg/api/plugin_resource_test.go b/pkg/api/plugin_resource_test.go index 5f0412b5c4c..0ee413447da 100644 --- a/pkg/api/plugin_resource_test.go +++ b/pkg/api/plugin_resource_test.go @@ -173,7 +173,7 @@ func TestIntegrationCallResource(t *testing.T) { Backend: true, }, })) - middlewares := pluginsintegration.CreateMiddlewares(cfg, &oauthtokentest.Service{}, tracing.InitializeTracerForTest(), &caching.OSSCachingService{}, featuremgmt.WithFeatures(), prometheus.DefaultRegisterer, pluginRegistry) + middlewares := pluginsintegration.CreateMiddlewares(cfg, &oauthtokentest.Service{}, tracing.InitializeTracerForTest(), caching.ProvideCachingServiceClient(&caching.OSSCachingService{}, nil), featuremgmt.WithFeatures(), prometheus.DefaultRegisterer, pluginRegistry) pc, err := backend.HandlerFromMiddlewares(&pluginfakes.FakePluginClient{ CallResourceHandlerFunc: backend.CallResourceHandlerFunc(func(ctx context.Context, req *backend.CallResourceRequest, sender backend.CallResourceResponseSender) error { diff --git a/pkg/registry/apis/query/query_test.go b/pkg/registry/apis/query/query_test.go index f94cc92f317..53ee003882b 100644 --- a/pkg/registry/apis/query/query_test.go +++ b/pkg/registry/apis/query/query_test.go @@ -54,6 +54,10 @@ func (mu mockUser) GetOrgID() int64 { return -1 } +func (mu mockUser) GetNamespace() string { + return "ns" +} + func TestQueryAPI(t *testing.T) { testCases := []struct { name string diff --git a/pkg/server/wire.go b/pkg/server/wire.go index d4a98e8a3c9..b06e7e995ad 100644 --- a/pkg/server/wire.go +++ b/pkg/server/wire.go @@ -70,6 +70,7 @@ import ( "github.com/grafana/grafana/pkg/services/auth/jwt" "github.com/grafana/grafana/pkg/services/authn/authnimpl" "github.com/grafana/grafana/pkg/services/authz" + "github.com/grafana/grafana/pkg/services/caching" "github.com/grafana/grafana/pkg/services/cleanup" "github.com/grafana/grafana/pkg/services/cloudmigration/cloudmigrationimpl" "github.com/grafana/grafana/pkg/services/contexthandler" @@ -431,6 +432,7 @@ var wireBasicSet = wire.NewSet( idimpl.ProvideService, wire.Bind(new(auth.IDService), new(*idimpl.Service)), cloudmigrationimpl.ProvideService, + caching.ProvideCachingServiceClient, userimpl.ProvideVerifier, connectors.ProvideOrgRoleMapper, wire.Bind(new(user.Verifier), new(*userimpl.Verifier)), diff --git a/pkg/server/wire_gen.go b/pkg/server/wire_gen.go index ac23bdda879..bb260585b69 100644 --- a/pkg/server/wire_gen.go +++ b/pkg/server/wire_gen.go @@ -583,7 +583,8 @@ func Initialize(ctx context.Context, cfg *setting.Cfg, opts Options, apiOpts api } oauthtokenService := oauthtoken.ProvideService(socialService, authinfoimplService, cfg, registerer, serverLockService, tracingService, userAuthTokenService, featureToggles) ossCachingService := caching.ProvideCachingService() - middlewareHandler, err := pluginsintegration.ProvideClientWithMiddlewares(cfg, inMemory, oauthtokenService, tracingService, ossCachingService, featureToggles, registerer) + cachingServiceClient := caching.ProvideCachingServiceClient(ossCachingService, featureToggles) + middlewareHandler, err := pluginsintegration.ProvideClientWithMiddlewares(cfg, inMemory, oauthtokenService, tracingService, cachingServiceClient, featureToggles, registerer) if err != nil { return nil, err } @@ -1194,7 +1195,8 @@ func InitializeForTest(ctx context.Context, t sqlutil.ITestDB, testingT interfac service14 := service8.ProvideService(fileStoreManager, pluginService) oauthtokentestService := oauthtokentest.ProvideService() ossCachingService := caching.ProvideCachingService() - middlewareHandler, err := pluginsintegration.ProvideClientWithMiddlewares(cfg, inMemory, oauthtokentestService, tracingService, ossCachingService, featureToggles, registerer) + cachingServiceClient := caching.ProvideCachingServiceClient(ossCachingService, featureToggles) + middlewareHandler, err := pluginsintegration.ProvideClientWithMiddlewares(cfg, inMemory, oauthtokentestService, tracingService, cachingServiceClient, featureToggles, registerer) if err != nil { return nil, err } @@ -1712,7 +1714,7 @@ var withOTelSet = wire.NewSet( otelTracer, grpcserver.ProvideService, interceptors.ProvideAuthenticator, ) -var wireBasicSet = wire.NewSet(annotationsimpl.ProvideService, wire.Bind(new(annotations.Repository), new(*annotationsimpl.RepositoryImpl)), New, api.ProvideHTTPServer, query.ProvideService, wire.Bind(new(query.Service), new(*query.ServiceImpl)), bus.ProvideBus, wire.Bind(new(bus.Bus), new(*bus.InProcBus)), rendering.ProvideService, wire.Bind(new(rendering.Service), new(*rendering.RenderingService)), routing.ProvideRegister, wire.Bind(new(routing.RouteRegister), new(*routing.RouteRegisterImpl)), hooks.ProvideService, kvstore.ProvideService, localcache.ProvideService, bundleregistry.ProvideService, wire.Bind(new(supportbundles.Service), new(*bundleregistry.Service)), updatemanager.ProvideGrafanaService, updatemanager.ProvidePluginsService, service.ProvideService, wire.Bind(new(usagestats.Service), new(*service.UsageStats)), validator3.ProvideService, legacy.ProvideLegacyMigrator, pluginsintegration.WireSet, dashboards.ProvideFileStoreManager, wire.Bind(new(dashboards.FileStore), new(*dashboards.FileStoreManager)), cloudwatch.ProvideService, cloudmonitoring.ProvideService, azuremonitor.ProvideService, postgres.ProvideService, mysql.ProvideService, mssql.ProvideService, store.ProvideEntityEventsService, dualwrite.ProvideService, httpclientprovider.New, wire.Bind(new(httpclient.Provider), new(*httpclient2.Provider)), serverlock.ProvideService, wire.Bind(new(installsync.ServerLock), new(*serverlock.ServerLockService)), annotationsimpl.ProvideCleanupService, wire.Bind(new(annotations.Cleaner), new(*annotationsimpl.CleanupServiceImpl)), cleanup.ProvideService, shorturlimpl.ProvideService, wire.Bind(new(shorturls.Service), new(*shorturlimpl.ShortURLService)), queryhistory.ProvideService, wire.Bind(new(queryhistory.Service), new(*queryhistory.QueryHistoryService)), correlations.ProvideService, wire.Bind(new(correlations.Service), new(*correlations.CorrelationsService)), quotaimpl.ProvideService, remotecache.ProvideService, wire.Bind(new(remotecache.CacheStorage), new(*remotecache.RemoteCache)), authinfoimpl.ProvideService, wire.Bind(new(login.AuthInfoService), new(*authinfoimpl.Service)), authinfoimpl.ProvideStore, datasourceproxy.ProvideService, sort.ProvideService, search2.ProvideService, searchV2.ProvideService, searchV2.ProvideSearchHTTPService, store.ProvideService, store.ProvideSystemUsersService, live.ProvideService, pushhttp.ProvideService, contexthandler.ProvideService, service12.ProvideService, wire.Bind(new(service12.LDAP), new(*service12.LDAPImpl)), jwt.ProvideService, wire.Bind(new(jwt.JWTService), new(*jwt.AuthService)), store2.ProvideDBStore, image.ProvideDeleteExpiredService, ngalert.ProvideService, librarypanels.ProvideService, wire.Bind(new(librarypanels.Service), new(*librarypanels.LibraryPanelService)), libraryelements.ProvideService, wire.Bind(new(libraryelements.Service), new(*libraryelements.LibraryElementService)), notifications.ProvideService, notifications.ProvideSmtpService, github.ProvideFactory, tracing.ProvideService, tracing.ProvideTracingConfig, wire.Bind(new(tracing.Tracer), new(*tracing.TracingService)), withOTelSet, testdatasource.ProvideService, api4.ProvideService, opentsdb.ProvideService, socialimpl.ProvideService, influxdb.ProvideService, wire.Bind(new(social.Service), new(*socialimpl.SocialService)), tempo.ProvideService, loki.ProvideService, graphite.ProvideService, prometheus.ProvideService, elasticsearch.ProvideService, pyroscope.ProvideService, parca.ProvideService, zipkin.ProvideService, jaeger.ProvideService, service9.ProvideCacheService, wire.Bind(new(datasources.CacheService), new(*service9.CacheServiceImpl)), service2.ProvideEncryptionService, wire.Bind(new(encryption2.Internal), new(*service2.Service)), manager.ProvideSecretsService, wire.Bind(new(secrets.Service), new(*manager.SecretsService)), database.ProvideSecretsStore, wire.Bind(new(secrets.Store), new(*database.SecretsStoreImpl)), garbagecollectionworker.ProvideWorker, grafanads.ProvideService, wire.Bind(new(dashboardsnapshots.Store), new(*database5.DashboardSnapshotStore)), database5.ProvideStore, wire.Bind(new(dashboardsnapshots.Service), new(*service10.ServiceImpl)), service10.ProvideService, service9.ProvideService, wire.Bind(new(datasources.DataSourceService), new(*service9.Service)), service9.ProvideLegacyDataSourceLookup, retriever.ProvideService, wire.Bind(new(serviceaccounts.ServiceAccountRetriever), new(*retriever.Service)), ossaccesscontrol.ProvideServiceAccountPermissions, wire.Bind(new(accesscontrol.ServiceAccountPermissionsService), new(*ossaccesscontrol.ServiceAccountPermissionsService)), manager3.ProvideServiceAccountsService, proxy.ProvideServiceAccountsProxy, wire.Bind(new(serviceaccounts.Service), new(*proxy.ServiceAccountsProxy)), dsquerierclient.NewNullQSDatasourceClientBuilder, expr.ProvideService, featuremgmt.ProvideManagerService, featuremgmt.ProvideToggles, service7.ProvideDashboardServiceImpl, wire.Bind(new(dashboards2.PermissionsRegistrationService), new(*service7.DashboardServiceImpl)), service7.ProvideDashboardService, service7.ProvideDashboardProvisioningService, service7.ProvideDashboardPluginService, database2.ProvideDashboardStore, folderimpl.ProvideService, wire.Bind(new(folder.Service), new(*folderimpl.Service)), wire.Bind(new(folder.LegacyService), new(*folderimpl.Service)), folderimpl.ProvideStore, wire.Bind(new(folder.Store), new(*folderimpl.FolderStoreImpl)), service11.ProvideService, wire.Bind(new(dashboardimport.Service), new(*service11.ImportDashboardService)), service8.ProvideService, wire.Bind(new(plugindashboards.Service), new(*service8.Service)), service8.ProvideDashboardUpdater, kvstore2.ProvideService, avatar.ProvideAvatarCacheServer, statscollector.ProvideService, csrf.ProvideCSRFFilter, wire.Bind(new(csrf.Service), new(*csrf.CSRF)), ossaccesscontrol.ProvideTeamPermissions, wire.Bind(new(accesscontrol.TeamPermissionsService), new(*ossaccesscontrol.TeamPermissionsService)), ossaccesscontrol.ProvideFolderPermissions, wire.Bind(new(accesscontrol.FolderPermissionsService), new(*ossaccesscontrol.FolderPermissionsService)), ossaccesscontrol.ProvideDashboardPermissions, wire.Bind(new(accesscontrol.DashboardPermissionsService), new(*ossaccesscontrol.DashboardPermissionsService)), ossaccesscontrol.ProvideReceiverPermissionsService, wire.Bind(new(accesscontrol.ReceiverPermissionsService), new(*ossaccesscontrol.ReceiverPermissionsService)), starimpl.ProvideService, playlistimpl.ProvideService, apikeyimpl.ProvideService, dashverimpl.ProvideService, service3.ProvideService, wire.Bind(new(publicdashboards.Service), new(*service3.PublicDashboardServiceImpl)), database3.ProvideStore, wire.Bind(new(publicdashboards.Store), new(*database3.PublicDashboardStoreImpl)), metric.ProvideService, api2.ProvideApi, api3.ProvideApi, userimpl.ProvideService, orgimpl.ProvideService, orgimpl.ProvideDeletionService, statsimpl.ProvideService, grpccontext.ProvideContextHandler, grpcserver.ProvideHealthService, grpcserver.ProvideReflectionService, resolver.ProvideEntityReferenceResolver, teamimpl.ProvideService, teamapi.ProvideTeamAPI, tempuserimpl.ProvideService, loginattemptimpl.ProvideService, wire.Bind(new(loginattempt.Service), new(*loginattemptimpl.Service)), migrations2.ProvideDataSourceMigrationService, migrations2.ProvideSecretMigrationProvider, wire.Bind(new(migrations2.SecretMigrationProvider), new(*migrations2.SecretMigrationProviderImpl)), promtypemigration.ProvideAzurePromMigrationService, promtypemigration.ProvideAmazonPromMigrationService, promtypemigration.ProvidePromTypeMigrationProvider, wire.Bind(new(promtypemigration.PromTypeMigrationProvider), new(*promtypemigration.PromTypeMigrationProviderImpl)), resourcepermissions.NewActionSetService, wire.Bind(new(accesscontrol.ActionResolver), new(resourcepermissions.ActionSetService)), wire.Bind(new(pluginaccesscontrol.ActionSetRegistry), new(resourcepermissions.ActionSetService)), permreg.ProvidePermissionRegistry, acimpl.ProvideAccessControl, accesscontrol.ProvideFixedRolesLoader, dualwrite2.ProvideZanzanaReconciler, navtreeimpl.ProvideService, wire.Bind(new(accesscontrol.AccessControl), new(*acimpl.AccessControl)), wire.Bind(new(notifications.TempUserStore), new(tempuser.Service)), tagimpl.ProvideService, wire.Bind(new(tag.Service), new(*tagimpl.Service)), authnimpl.ProvideService, authnimpl.ProvideIdentitySynchronizer, authnimpl.ProvideAuthnService, authnimpl.ProvideAuthnServiceAuthenticateOnly, authnimpl.ProvideRegistration, supportbundlesimpl.ProvideService, extsvcaccounts.ProvideExtSvcAccountsService, wire.Bind(new(serviceaccounts.ExtSvcAccountsService), new(*extsvcaccounts.ExtSvcAccountsService)), registry2.ProvideExtSvcRegistry, wire.Bind(new(extsvcauth.ExternalServiceRegistry), new(*registry2.Registry)), anonstore.ProvideAnonDBStore, wire.Bind(new(anonstore.AnonStore), new(*anonstore.AnonDBStore)), loggermw.Provide, slogadapter.Provide, signingkeysimpl.ProvideEmbeddedSigningKeysService, wire.Bind(new(signingkeys.Service), new(*signingkeysimpl.Service)), ssosettingsimpl.ProvideService, wire.Bind(new(ssosettings.Service), new(*ssosettingsimpl.Service)), idimpl.ProvideService, wire.Bind(new(auth.IDService), new(*idimpl.Service)), cloudmigrationimpl.ProvideService, userimpl.ProvideVerifier, connectors.ProvideOrgRoleMapper, wire.Bind(new(user.Verifier), new(*userimpl.Verifier)), authz.WireSet, metadata.ProvideSecureValueMetadataStorage, metadata.ProvideKeeperMetadataStorage, metadata.ProvideDecryptStorage, decrypt.ProvideDecryptAuthorizer, wire.Value([]decrypt.ExtraOwnerDecrypter(nil)), decrypt.ProvideDecryptService, inline.ProvideInlineSecureValueService, encryption.ProvideDataKeyStorage, encryption.ProvideGlobalDataKeyStorage, encryption.ProvideEncryptedValueStorage, encryption.ProvideGlobalEncryptedValueStorage, service5.ProvideSecureValueService, validator.ProvideKeeperValidator, validator.ProvideSecureValueValidator, mutator.ProvideKeeperMutator, mutator.ProvideSecureValueMutator, migrator2.NewWithEngine, database4.ProvideDatabase, clock.ProvideClock, wire.Bind(new(contracts.Database), new(*database4.Database)), wire.Bind(new(contracts.Clock), new(*clock.Clock)), manager2.ProvideEncryptionManager, service4.ProvideAESGCMCipherService, resource.ProvideStorageMetrics, resource.ProvideIndexMetrics, apiserver.WireSet, apiregistry.WireSet, appregistry.WireSet, client.ProvideK8sClientWithFallback) +var wireBasicSet = wire.NewSet(annotationsimpl.ProvideService, wire.Bind(new(annotations.Repository), new(*annotationsimpl.RepositoryImpl)), New, api.ProvideHTTPServer, query.ProvideService, wire.Bind(new(query.Service), new(*query.ServiceImpl)), bus.ProvideBus, wire.Bind(new(bus.Bus), new(*bus.InProcBus)), rendering.ProvideService, wire.Bind(new(rendering.Service), new(*rendering.RenderingService)), routing.ProvideRegister, wire.Bind(new(routing.RouteRegister), new(*routing.RouteRegisterImpl)), hooks.ProvideService, kvstore.ProvideService, localcache.ProvideService, bundleregistry.ProvideService, wire.Bind(new(supportbundles.Service), new(*bundleregistry.Service)), updatemanager.ProvideGrafanaService, updatemanager.ProvidePluginsService, service.ProvideService, wire.Bind(new(usagestats.Service), new(*service.UsageStats)), validator3.ProvideService, legacy.ProvideLegacyMigrator, pluginsintegration.WireSet, dashboards.ProvideFileStoreManager, wire.Bind(new(dashboards.FileStore), new(*dashboards.FileStoreManager)), cloudwatch.ProvideService, cloudmonitoring.ProvideService, azuremonitor.ProvideService, postgres.ProvideService, mysql.ProvideService, mssql.ProvideService, store.ProvideEntityEventsService, dualwrite.ProvideService, httpclientprovider.New, wire.Bind(new(httpclient.Provider), new(*httpclient2.Provider)), serverlock.ProvideService, wire.Bind(new(installsync.ServerLock), new(*serverlock.ServerLockService)), annotationsimpl.ProvideCleanupService, wire.Bind(new(annotations.Cleaner), new(*annotationsimpl.CleanupServiceImpl)), cleanup.ProvideService, shorturlimpl.ProvideService, wire.Bind(new(shorturls.Service), new(*shorturlimpl.ShortURLService)), queryhistory.ProvideService, wire.Bind(new(queryhistory.Service), new(*queryhistory.QueryHistoryService)), correlations.ProvideService, wire.Bind(new(correlations.Service), new(*correlations.CorrelationsService)), quotaimpl.ProvideService, remotecache.ProvideService, wire.Bind(new(remotecache.CacheStorage), new(*remotecache.RemoteCache)), authinfoimpl.ProvideService, wire.Bind(new(login.AuthInfoService), new(*authinfoimpl.Service)), authinfoimpl.ProvideStore, datasourceproxy.ProvideService, sort.ProvideService, search2.ProvideService, searchV2.ProvideService, searchV2.ProvideSearchHTTPService, store.ProvideService, store.ProvideSystemUsersService, live.ProvideService, pushhttp.ProvideService, contexthandler.ProvideService, service12.ProvideService, wire.Bind(new(service12.LDAP), new(*service12.LDAPImpl)), jwt.ProvideService, wire.Bind(new(jwt.JWTService), new(*jwt.AuthService)), store2.ProvideDBStore, image.ProvideDeleteExpiredService, ngalert.ProvideService, librarypanels.ProvideService, wire.Bind(new(librarypanels.Service), new(*librarypanels.LibraryPanelService)), libraryelements.ProvideService, wire.Bind(new(libraryelements.Service), new(*libraryelements.LibraryElementService)), notifications.ProvideService, notifications.ProvideSmtpService, github.ProvideFactory, tracing.ProvideService, tracing.ProvideTracingConfig, wire.Bind(new(tracing.Tracer), new(*tracing.TracingService)), withOTelSet, testdatasource.ProvideService, api4.ProvideService, opentsdb.ProvideService, socialimpl.ProvideService, influxdb.ProvideService, wire.Bind(new(social.Service), new(*socialimpl.SocialService)), tempo.ProvideService, loki.ProvideService, graphite.ProvideService, prometheus.ProvideService, elasticsearch.ProvideService, pyroscope.ProvideService, parca.ProvideService, zipkin.ProvideService, jaeger.ProvideService, service9.ProvideCacheService, wire.Bind(new(datasources.CacheService), new(*service9.CacheServiceImpl)), service2.ProvideEncryptionService, wire.Bind(new(encryption2.Internal), new(*service2.Service)), manager.ProvideSecretsService, wire.Bind(new(secrets.Service), new(*manager.SecretsService)), database.ProvideSecretsStore, wire.Bind(new(secrets.Store), new(*database.SecretsStoreImpl)), garbagecollectionworker.ProvideWorker, grafanads.ProvideService, wire.Bind(new(dashboardsnapshots.Store), new(*database5.DashboardSnapshotStore)), database5.ProvideStore, wire.Bind(new(dashboardsnapshots.Service), new(*service10.ServiceImpl)), service10.ProvideService, service9.ProvideService, wire.Bind(new(datasources.DataSourceService), new(*service9.Service)), service9.ProvideLegacyDataSourceLookup, retriever.ProvideService, wire.Bind(new(serviceaccounts.ServiceAccountRetriever), new(*retriever.Service)), ossaccesscontrol.ProvideServiceAccountPermissions, wire.Bind(new(accesscontrol.ServiceAccountPermissionsService), new(*ossaccesscontrol.ServiceAccountPermissionsService)), manager3.ProvideServiceAccountsService, proxy.ProvideServiceAccountsProxy, wire.Bind(new(serviceaccounts.Service), new(*proxy.ServiceAccountsProxy)), dsquerierclient.NewNullQSDatasourceClientBuilder, expr.ProvideService, featuremgmt.ProvideManagerService, featuremgmt.ProvideToggles, service7.ProvideDashboardServiceImpl, wire.Bind(new(dashboards2.PermissionsRegistrationService), new(*service7.DashboardServiceImpl)), service7.ProvideDashboardService, service7.ProvideDashboardProvisioningService, service7.ProvideDashboardPluginService, database2.ProvideDashboardStore, folderimpl.ProvideService, wire.Bind(new(folder.Service), new(*folderimpl.Service)), wire.Bind(new(folder.LegacyService), new(*folderimpl.Service)), folderimpl.ProvideStore, wire.Bind(new(folder.Store), new(*folderimpl.FolderStoreImpl)), service11.ProvideService, wire.Bind(new(dashboardimport.Service), new(*service11.ImportDashboardService)), service8.ProvideService, wire.Bind(new(plugindashboards.Service), new(*service8.Service)), service8.ProvideDashboardUpdater, kvstore2.ProvideService, avatar.ProvideAvatarCacheServer, statscollector.ProvideService, csrf.ProvideCSRFFilter, wire.Bind(new(csrf.Service), new(*csrf.CSRF)), ossaccesscontrol.ProvideTeamPermissions, wire.Bind(new(accesscontrol.TeamPermissionsService), new(*ossaccesscontrol.TeamPermissionsService)), ossaccesscontrol.ProvideFolderPermissions, wire.Bind(new(accesscontrol.FolderPermissionsService), new(*ossaccesscontrol.FolderPermissionsService)), ossaccesscontrol.ProvideDashboardPermissions, wire.Bind(new(accesscontrol.DashboardPermissionsService), new(*ossaccesscontrol.DashboardPermissionsService)), ossaccesscontrol.ProvideReceiverPermissionsService, wire.Bind(new(accesscontrol.ReceiverPermissionsService), new(*ossaccesscontrol.ReceiverPermissionsService)), starimpl.ProvideService, playlistimpl.ProvideService, apikeyimpl.ProvideService, dashverimpl.ProvideService, service3.ProvideService, wire.Bind(new(publicdashboards.Service), new(*service3.PublicDashboardServiceImpl)), database3.ProvideStore, wire.Bind(new(publicdashboards.Store), new(*database3.PublicDashboardStoreImpl)), metric.ProvideService, api2.ProvideApi, api3.ProvideApi, userimpl.ProvideService, orgimpl.ProvideService, orgimpl.ProvideDeletionService, statsimpl.ProvideService, grpccontext.ProvideContextHandler, grpcserver.ProvideHealthService, grpcserver.ProvideReflectionService, resolver.ProvideEntityReferenceResolver, teamimpl.ProvideService, teamapi.ProvideTeamAPI, tempuserimpl.ProvideService, loginattemptimpl.ProvideService, wire.Bind(new(loginattempt.Service), new(*loginattemptimpl.Service)), migrations2.ProvideDataSourceMigrationService, migrations2.ProvideSecretMigrationProvider, wire.Bind(new(migrations2.SecretMigrationProvider), new(*migrations2.SecretMigrationProviderImpl)), promtypemigration.ProvideAzurePromMigrationService, promtypemigration.ProvideAmazonPromMigrationService, promtypemigration.ProvidePromTypeMigrationProvider, wire.Bind(new(promtypemigration.PromTypeMigrationProvider), new(*promtypemigration.PromTypeMigrationProviderImpl)), resourcepermissions.NewActionSetService, wire.Bind(new(accesscontrol.ActionResolver), new(resourcepermissions.ActionSetService)), wire.Bind(new(pluginaccesscontrol.ActionSetRegistry), new(resourcepermissions.ActionSetService)), permreg.ProvidePermissionRegistry, acimpl.ProvideAccessControl, accesscontrol.ProvideFixedRolesLoader, dualwrite2.ProvideZanzanaReconciler, navtreeimpl.ProvideService, wire.Bind(new(accesscontrol.AccessControl), new(*acimpl.AccessControl)), wire.Bind(new(notifications.TempUserStore), new(tempuser.Service)), tagimpl.ProvideService, wire.Bind(new(tag.Service), new(*tagimpl.Service)), authnimpl.ProvideService, authnimpl.ProvideIdentitySynchronizer, authnimpl.ProvideAuthnService, authnimpl.ProvideAuthnServiceAuthenticateOnly, authnimpl.ProvideRegistration, supportbundlesimpl.ProvideService, extsvcaccounts.ProvideExtSvcAccountsService, wire.Bind(new(serviceaccounts.ExtSvcAccountsService), new(*extsvcaccounts.ExtSvcAccountsService)), registry2.ProvideExtSvcRegistry, wire.Bind(new(extsvcauth.ExternalServiceRegistry), new(*registry2.Registry)), anonstore.ProvideAnonDBStore, wire.Bind(new(anonstore.AnonStore), new(*anonstore.AnonDBStore)), loggermw.Provide, slogadapter.Provide, signingkeysimpl.ProvideEmbeddedSigningKeysService, wire.Bind(new(signingkeys.Service), new(*signingkeysimpl.Service)), ssosettingsimpl.ProvideService, wire.Bind(new(ssosettings.Service), new(*ssosettingsimpl.Service)), idimpl.ProvideService, wire.Bind(new(auth.IDService), new(*idimpl.Service)), cloudmigrationimpl.ProvideService, caching.ProvideCachingServiceClient, userimpl.ProvideVerifier, connectors.ProvideOrgRoleMapper, wire.Bind(new(user.Verifier), new(*userimpl.Verifier)), authz.WireSet, metadata.ProvideSecureValueMetadataStorage, metadata.ProvideKeeperMetadataStorage, metadata.ProvideDecryptStorage, decrypt.ProvideDecryptAuthorizer, wire.Value([]decrypt.ExtraOwnerDecrypter(nil)), decrypt.ProvideDecryptService, inline.ProvideInlineSecureValueService, encryption.ProvideDataKeyStorage, encryption.ProvideGlobalDataKeyStorage, encryption.ProvideEncryptedValueStorage, encryption.ProvideGlobalEncryptedValueStorage, service5.ProvideSecureValueService, validator.ProvideKeeperValidator, validator.ProvideSecureValueValidator, mutator.ProvideKeeperMutator, mutator.ProvideSecureValueMutator, migrator2.NewWithEngine, database4.ProvideDatabase, clock.ProvideClock, wire.Bind(new(contracts.Database), new(*database4.Database)), wire.Bind(new(contracts.Clock), new(*clock.Clock)), manager2.ProvideEncryptionManager, service4.ProvideAESGCMCipherService, resource.ProvideStorageMetrics, resource.ProvideIndexMetrics, apiserver.WireSet, apiregistry.WireSet, appregistry.WireSet, client.ProvideK8sClientWithFallback) var wireSet = wire.NewSet( wireBasicSet, metrics.WireSet, sqlstore.ProvideService, metrics2.ProvideService, wire.Bind(new(notifications.Service), new(*notifications.NotificationService)), wire.Bind(new(notifications.WebhookSender), new(*notifications.NotificationService)), wire.Bind(new(notifications.EmailSender), new(*notifications.NotificationService)), wire.Bind(new(db.DB), new(*sqlstore.SQLStore)), prefimpl.ProvideService, oauthtoken.ProvideService, wire.Bind(new(oauthtoken.OAuthTokenService), new(*oauthtoken.Service)), wire.Bind(new(cleanup.AlertRuleService), new(*store2.DBstore)), diff --git a/pkg/services/caching/fake_caching_service.go b/pkg/services/caching/fake_caching_service.go index 522be45f02f..d4afc545bc0 100644 --- a/pkg/services/caching/fake_caching_service.go +++ b/pkg/services/caching/fake_caching_service.go @@ -10,19 +10,20 @@ import ( type FakeOSSCachingService struct { calls map[string]int + ReturnStatus CacheStatus ReturnHit bool ReturnResourceResponse CachedResourceDataResponse ReturnQueryResponse CachedQueryDataResponse } -func (f *FakeOSSCachingService) HandleQueryRequest(ctx context.Context, req *backend.QueryDataRequest) (bool, CachedQueryDataResponse) { +func (f *FakeOSSCachingService) HandleQueryRequest(ctx context.Context, req *backend.QueryDataRequest) (bool, CachedQueryDataResponse, CacheStatus) { f.calls["HandleQueryRequest"]++ - return f.ReturnHit, f.ReturnQueryResponse + return f.ReturnHit, f.ReturnQueryResponse, f.ReturnStatus } -func (f *FakeOSSCachingService) HandleResourceRequest(ctx context.Context, req *backend.CallResourceRequest) (bool, CachedResourceDataResponse) { +func (f *FakeOSSCachingService) HandleResourceRequest(ctx context.Context, req *backend.CallResourceRequest) (bool, CachedResourceDataResponse, CacheStatus) { f.calls["HandleResourceRequest"]++ - return f.ReturnHit, f.ReturnResourceResponse + return f.ReturnHit, f.ReturnResourceResponse, f.ReturnStatus } func (f *FakeOSSCachingService) AssertCalls(t *testing.T, fn string, times int) { @@ -35,7 +36,8 @@ func (f *FakeOSSCachingService) Reset() { func NewFakeOSSCachingService() *FakeOSSCachingService { fake := &FakeOSSCachingService{ - calls: map[string]int{}, + calls: map[string]int{}, + ReturnStatus: "unset", } return fake diff --git a/pkg/services/pluginsintegration/clientmiddleware/caching_metrics.go b/pkg/services/caching/metrics.go similarity index 98% rename from pkg/services/pluginsintegration/clientmiddleware/caching_metrics.go rename to pkg/services/caching/metrics.go index 2f452d550c8..ff9c229afbf 100644 --- a/pkg/services/pluginsintegration/clientmiddleware/caching_metrics.go +++ b/pkg/services/caching/metrics.go @@ -1,4 +1,4 @@ -package clientmiddleware +package caching import ( "github.com/grafana/grafana/pkg/infra/metrics" diff --git a/pkg/services/caching/service.go b/pkg/services/caching/service.go index c3da3d22222..ad494bcaee4 100644 --- a/pkg/services/caching/service.go +++ b/pkg/services/caching/service.go @@ -7,20 +7,34 @@ import ( "encoding/hex" "encoding/json" "io" + + "strconv" "strings" + "time" + + "github.com/grafana/grafana-aws-sdk/pkg/awsds" + "github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana-plugin-sdk-go/backend" + "github.com/grafana/grafana/pkg/services/contexthandler" + "github.com/grafana/grafana/pkg/services/featuremgmt" + "github.com/prometheus/client_golang/prometheus" ) +type CacheStatus string + const ( - XCacheHeader = "X-Cache" - StatusHit = "HIT" - StatusMiss = "MISS" - StatusBypass = "BYPASS" - StatusError = "ERROR" - StatusDisabled = "DISABLED" + XCacheHeader = "X-Cache" + StatusHit CacheStatus = "HIT" + StatusMiss CacheStatus = "MISS" + StatusBypass CacheStatus = "BYPASS" + StatusError CacheStatus = "ERROR" + StatusDisabled CacheStatus = "DISABLED" ) +// needed to mock the function for testing +var ShouldCacheQuery = awsds.ShouldCacheQuery + type CacheQueryResponseFn func(context.Context, *backend.QueryDataResponse) type CacheResourceResponseFn func(context.Context, *backend.CallResourceResponse) @@ -49,22 +63,22 @@ type CachingService interface { // HandleQueryRequest uses a QueryDataRequest to check the cache for any existing results for that query. // If none are found, it should return false and a CachedQueryDataResponse with an UpdateCacheFn which can be used to update the results cache after the fact. // This function may populate any response headers (accessible through the context) with the cache status using the X-Cache header. - HandleQueryRequest(context.Context, *backend.QueryDataRequest) (bool, CachedQueryDataResponse) + HandleQueryRequest(ctx context.Context, req *backend.QueryDataRequest) (bool, CachedQueryDataResponse, CacheStatus) // HandleResourceRequest uses a CallResourceRequest to check the cache for any existing results for that request. If none are found, it should return false. // This function may populate any response headers (accessible through the context) with the cache status using the X-Cache header. - HandleResourceRequest(context.Context, *backend.CallResourceRequest) (bool, CachedResourceDataResponse) + HandleResourceRequest(ctx context.Context, req *backend.CallResourceRequest) (bool, CachedResourceDataResponse, CacheStatus) } // Implementation of interface - does nothing type OSSCachingService struct { } -func (s *OSSCachingService) HandleQueryRequest(ctx context.Context, req *backend.QueryDataRequest) (bool, CachedQueryDataResponse) { - return false, CachedQueryDataResponse{} +func (s *OSSCachingService) HandleQueryRequest(ctx context.Context, req *backend.QueryDataRequest) (bool, CachedQueryDataResponse, CacheStatus) { + return false, CachedQueryDataResponse{}, "" } -func (s *OSSCachingService) HandleResourceRequest(ctx context.Context, req *backend.CallResourceRequest) (bool, CachedResourceDataResponse) { - return false, CachedResourceDataResponse{} +func (s *OSSCachingService) HandleResourceRequest(ctx context.Context, req *backend.CallResourceRequest) (bool, CachedResourceDataResponse, CacheStatus) { + return false, CachedResourceDataResponse{}, "" } var _ CachingService = &OSSCachingService{} @@ -133,3 +147,134 @@ func (e *JSONEncoder) Encode(w io.Writer, v interface{}) error { func (e *JSONEncoder) Decode(r io.Reader, v interface{}) error { return json.NewDecoder(r).Decode(v) } + +// A service that provides methods to cache requests. +// It can be used to cache requests using `caching.CachingService` without reimplementing +// the caching logic at every call site. +type CachingServiceClient struct { + cachingService CachingService + features featuremgmt.FeatureToggles +} + +func ProvideCachingServiceClient(cachingService CachingService, features featuremgmt.FeatureToggles) *CachingServiceClient { + log := log.New("caching_service_client") + if err := prometheus.Register(QueryCachingRequestHistogram); err != nil { + log.Error("Error registering prometheus collector 'QueryRequestHistogram'", "error", err) + } + if err := prometheus.Register(ResourceCachingRequestHistogram); err != nil { + log.Error("Error registering prometheus collector 'ResourceRequestHistogram'", "error", err) + } + return &CachingServiceClient{cachingService: cachingService, features: features} +} + +// WithQueryDataCaching calls `f` and caches the returned value if `req` has not been cached already. +// Returns the cached value otherwise. +func (c *CachingServiceClient) WithQueryDataCaching(ctx context.Context, req *backend.QueryDataRequest, f func() (*backend.QueryDataResponse, error)) (*backend.QueryDataResponse, error) { + if c == nil || req == nil { + return f() + } + + reqCtx := contexthandler.FromContext(ctx) + + // time how long this request takes + start := time.Now() + + // First look in the query cache if enabled + hit, cr, status := c.cachingService.HandleQueryRequest(ctx, req) + + // record request duration if caching was used + if reqCtx != nil { + reqCtx.Resp.Header().Set(XCacheHeader, string(status)) + defer func() { + QueryCachingRequestHistogram.With(prometheus.Labels{ + "datasource_type": getDatasourceType(req.PluginContext), + "cache": string(status), + "query_type": getQueryType(reqCtx), + }).Observe(time.Since(start).Seconds()) + }() + } + + // Cache hit; return the response + if hit { + return cr.Response, nil + } + + // Cache miss; do the actual queries + resp, err := f() + // Update the query cache with the result for this metrics request + if err == nil && cr.UpdateCacheFn != nil { + // If AWS async caching is not enabled, use the old code path + if c.features == nil || !c.features.IsEnabled(ctx, featuremgmt.FlagAwsAsyncQueryCaching) { + cr.UpdateCacheFn(ctx, resp) + } else if reqCtx != nil { + // time how long shouldCacheQuery takes + startShouldCacheQuery := time.Now() + shouldCache := ShouldCacheQuery(resp) + ShouldCacheQueryHistogram.With(prometheus.Labels{ + "datasource_type": req.PluginContext.DataSourceInstanceSettings.Type, + "cache": string(status), + "shouldCache": strconv.FormatBool(shouldCache), + "query_type": getQueryType(reqCtx), + }).Observe(time.Since(startShouldCacheQuery).Seconds()) + + // If AWS async caching is enabled and resp is for a running async query, don't cache it + if shouldCache { + cr.UpdateCacheFn(ctx, resp) + } + } + } + + return resp, err +} + +// WithCallResourceCaching calls `f` and caches the returned value if `req` has not been cached already. +// Returns the cached value otherwise. +func (c *CachingServiceClient) WithCallResourceCaching(ctx context.Context, req *backend.CallResourceRequest, sender backend.CallResourceResponseSender, f func(backend.CallResourceResponseSender) error) error { + if c == nil || req == nil { + return f(sender) + } + + reqCtx := contexthandler.FromContext(ctx) + + // time how long this request takes + start := time.Now() + + // First look in the resource cache if enabled + hit, cr, status := c.cachingService.HandleResourceRequest(ctx, req) + + if reqCtx != nil { + reqCtx.Resp.Header().Set(XCacheHeader, string(status)) + } + // record request duration if caching was used + defer func() { + ResourceCachingRequestHistogram.With(prometheus.Labels{ + "plugin_id": req.PluginContext.PluginID, + "cache": string(status), + }).Observe(time.Since(start).Seconds()) + }() + + // Cache hit; send the response and return + if hit { + return sender.Send(cr.Response) + } + + // Cache miss; do the actual request + // If there is no update cache func, just pass in the original sender + if cr.UpdateCacheFn == nil { + return f(sender) + } + // Otherwise, intercept the responses in a wrapped sender so we can cache them first + cacheSender := backend.CallResourceResponseSenderFunc(func(res *backend.CallResourceResponse) error { + cr.UpdateCacheFn(ctx, res) + return sender.Send(res) + }) + + return f(cacheSender) +} + +func getDatasourceType(pluginCtx backend.PluginContext) string { + if pluginCtx.DataSourceInstanceSettings == nil { + return "unknown" + } + return pluginCtx.DataSourceInstanceSettings.Name +} diff --git a/pkg/services/caching/service_test.go b/pkg/services/caching/service_test.go new file mode 100644 index 00000000000..90864171469 --- /dev/null +++ b/pkg/services/caching/service_test.go @@ -0,0 +1,130 @@ +package caching + +import ( + "context" + "errors" + "net/http/httptest" + "testing" + + "github.com/grafana/grafana-plugin-sdk-go/backend" + "github.com/grafana/grafana/pkg/services/contexthandler/ctxkey" + contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model" + "github.com/grafana/grafana/pkg/web" + "github.com/stretchr/testify/require" +) + +func TestWithQueryDataCaching(t *testing.T) { + t.Run("caching is a no-op when service is nil", func(t *testing.T) { + var s *CachingServiceClient + req := backend.QueryDataRequest{} + fakeResponse := &backend.QueryDataResponse{} + response, err := s.WithQueryDataCaching(t.Context(), &req, func() (*backend.QueryDataResponse, error) { + return fakeResponse, nil + }) + require.NoError(t, err) + require.Equal(t, fakeResponse, response) + }) + + t.Run("cache status is included in the response if a request context is available", func(t *testing.T) { + fakeCachingService := NewFakeOSSCachingService() + fakeCachingService.ReturnStatus = StatusMiss + client := ProvideCachingServiceClient(fakeCachingService, nil) + + req := backend.QueryDataRequest{} + + reqCtx := &contextmodel.ReqContext{ + Context: &web.Context{ + Resp: web.NewResponseWriter("", httptest.NewRecorder()), + }, + } + ctx := context.WithValue(t.Context(), ctxkey.Key{}, reqCtx) + fakeResponse := &backend.QueryDataResponse{} + response, err := client.WithQueryDataCaching(ctx, &req, func() (*backend.QueryDataResponse, error) { + return fakeResponse, nil + }) + require.NoError(t, err) + require.Equal(t, fakeResponse, response) + require.EqualValues(t, StatusMiss, reqCtx.Resp.Header().Get(XCacheHeader)) + }) + + t.Run("caching can be used without a request context", func(t *testing.T) { + fakeCachingService := NewFakeOSSCachingService() + fakeCachingService.ReturnStatus = StatusMiss + client := ProvideCachingServiceClient(fakeCachingService, nil) + + req := backend.QueryDataRequest{} + + fakeResponse := &backend.QueryDataResponse{} + // Using the default test context, no request context. + response, err := client.WithQueryDataCaching(t.Context(), &req, func() (*backend.QueryDataResponse, error) { + return fakeResponse, nil + }) + require.NoError(t, err) + require.Equal(t, fakeResponse, response) + }) +} + +func TestWithCallResourceCaching(t *testing.T) { + t.Run("caching is a no-op when service is nil", func(t *testing.T) { + var s *CachingServiceClient + req := backend.CallResourceRequest{} + fakeErr := errors.New("oops") + err := s.WithCallResourceCaching(t.Context(), &req, nil, func(backend.CallResourceResponseSender) error { + return fakeErr + }) + require.ErrorIs(t, err, fakeErr) + }) + + t.Run("cache status is included in the response if a request context is available", func(t *testing.T) { + fakeCachingService := NewFakeOSSCachingService() + fakeCachingService.ReturnStatus = StatusMiss + client := ProvideCachingServiceClient(fakeCachingService, nil) + + req := backend.CallResourceRequest{} + + reqCtx := &contextmodel.ReqContext{ + Context: &web.Context{ + Resp: web.NewResponseWriter("", httptest.NewRecorder()), + }, + } + ctx := context.WithValue(t.Context(), ctxkey.Key{}, reqCtx) + sender := func(*backend.CallResourceResponse) error { + return nil + } + var fakeErr = errors.New("oops") + err := client.WithCallResourceCaching(ctx, &req, backend.CallResourceResponseSenderFunc(sender), func(backend.CallResourceResponseSender) error { + return fakeErr + }) + require.ErrorIs(t, err, fakeErr) + require.EqualValues(t, StatusMiss, reqCtx.Resp.Header().Get(XCacheHeader)) + }) + + t.Run("caching can be used without a request context", func(t *testing.T) { + fakeCachingService := NewFakeOSSCachingService() + fakeCachingService.ReturnStatus = StatusMiss + client := ProvideCachingServiceClient(fakeCachingService, nil) + + req := backend.CallResourceRequest{} + + sender := func(*backend.CallResourceResponse) error { + return nil + } + var fakeErr = errors.New("oops") + // Using the default test context, no request context. + err := client.WithCallResourceCaching(t.Context(), &req, backend.CallResourceResponseSenderFunc(sender), func(_ backend.CallResourceResponseSender) error { + return fakeErr + }) + require.ErrorIs(t, err, fakeErr) + }) +} + +func TestGetDatasourceType(t *testing.T) { + t.Parallel() + + require.Equal(t, "unknown", getDatasourceType(backend.PluginContext{})) + require.Equal(t, "name", getDatasourceType(backend.PluginContext{ + DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{ + Name: "name", + }, + })) +} diff --git a/pkg/services/pluginsintegration/clientmiddleware/caching_middleware.go b/pkg/services/pluginsintegration/clientmiddleware/caching_middleware.go index 2ef0b24c162..14471178bd9 100644 --- a/pkg/services/pluginsintegration/clientmiddleware/caching_middleware.go +++ b/pkg/services/pluginsintegration/clientmiddleware/caching_middleware.go @@ -2,222 +2,56 @@ package clientmiddleware import ( "context" - "fmt" - "strconv" - "time" - "github.com/grafana/grafana-aws-sdk/pkg/awsds" "github.com/grafana/grafana-plugin-sdk-go/backend" - "github.com/prometheus/client_golang/prometheus" - "golang.org/x/sync/singleflight" - "github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/services/caching" "github.com/grafana/grafana/pkg/services/contexthandler" - "github.com/grafana/grafana/pkg/services/featuremgmt" ) -// needed to mock the function for testing -var shouldCacheQuery = awsds.ShouldCacheQuery - // NewCachingMiddleware creates a new backend.HandlerMiddleware that will // attempt to read and write query results to the cache -func NewCachingMiddleware(cachingService caching.CachingService) backend.HandlerMiddleware { - return NewCachingMiddlewareWithFeatureManager(cachingService, nil) -} - -// NewCachingMiddlewareWithFeatureManager creates a new backend.HandlerMiddleware that will -// attempt to read and write query results to the cache with a feature manager -func NewCachingMiddlewareWithFeatureManager(cachingService caching.CachingService, features featuremgmt.FeatureToggles) backend.HandlerMiddleware { - log := log.New("caching_middleware") - if err := prometheus.Register(QueryCachingRequestHistogram); err != nil { - log.Error("Error registering prometheus collector 'QueryRequestHistogram'", "error", err) - } - if err := prometheus.Register(ResourceCachingRequestHistogram); err != nil { - log.Error("Error registering prometheus collector 'ResourceRequestHistogram'", "error", err) - } +func NewCachingMiddleware(cachingServiceClient *caching.CachingServiceClient) backend.HandlerMiddleware { cachingMiddlewareHandler := func(next backend.Handler) backend.Handler { - cachingMiddleware := &CachingMiddleware{ - BaseHandler: backend.NewBaseHandler(next), - caching: cachingService, - log: log, - features: features, + return &CachingMiddleware{ + BaseHandler: backend.NewBaseHandler(next), + cachingServiceClient: cachingServiceClient, } - if features != nil && features.IsEnabled(context.Background(), featuremgmt.FlagQueryCacheRequestDeduplication) { - return newRequestDeduplicationMiddleware(log, cachingMiddleware) - } - return cachingMiddleware } return backend.HandlerMiddlewareFunc(cachingMiddlewareHandler) } +// An adapter to use CachingServiceClient as a middleware. If possible prefer to use `CachingServiceClient` directly. type CachingMiddleware struct { backend.BaseHandler - caching caching.CachingService - log log.Logger - features featuremgmt.FeatureToggles + cachingServiceClient *caching.CachingServiceClient } // QueryData receives a data request and attempts to access results already stored in the cache for that request. // If data is found, it will return it immediately. Otherwise, it will perform the queries as usual, then write the response to the cache. // If the cache service is implemented, we capture the request duration as a metric. The service is expected to write any response headers. func (m *CachingMiddleware) QueryData(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) { - if req == nil { - return m.BaseHandler.QueryData(ctx, req) - } - reqCtx := contexthandler.FromContext(ctx) if reqCtx == nil { return m.BaseHandler.QueryData(ctx, req) } - - // time how long this request takes - start := time.Now() - - // First look in the query cache if enabled - hit, cr := m.caching.HandleQueryRequest(ctx, req) - - // record request duration if caching was used - ch := reqCtx.Resp.Header().Get(caching.XCacheHeader) - if ch != "" { - defer func() { - QueryCachingRequestHistogram.With(prometheus.Labels{ - "datasource_type": req.PluginContext.DataSourceInstanceSettings.Type, - "cache": ch, - "query_type": getQueryType(reqCtx), - }).Observe(time.Since(start).Seconds()) - }() - } - - // Cache hit; return the response - if hit { - return cr.Response, nil - } - - // Cache miss; do the actual queries - resp, err := m.BaseHandler.QueryData(ctx, req) - - // Update the query cache with the result for this metrics request - if err == nil && cr.UpdateCacheFn != nil { - // If AWS async caching is not enabled, use the old code path - if m.features == nil || !m.features.IsEnabled(ctx, featuremgmt.FlagAwsAsyncQueryCaching) { - cr.UpdateCacheFn(ctx, resp) - } else { - // time how long shouldCacheQuery takes - startShouldCacheQuery := time.Now() - shouldCache := shouldCacheQuery(resp) - ShouldCacheQueryHistogram.With(prometheus.Labels{ - "datasource_type": req.PluginContext.DataSourceInstanceSettings.Type, - "cache": ch, - "shouldCache": strconv.FormatBool(shouldCache), - "query_type": getQueryType(reqCtx), - }).Observe(time.Since(startShouldCacheQuery).Seconds()) - - // If AWS async caching is enabled and resp is for a running async query, don't cache it - if shouldCache { - cr.UpdateCacheFn(ctx, resp) - } - } - } - - return resp, err + return m.cachingServiceClient.WithQueryDataCaching(ctx, req, func() (*backend.QueryDataResponse, error) { + return m.BaseHandler.QueryData(ctx, req) + }) } // CallResource receives a resource request and attempts to access results already stored in the cache for that request. // If data is found, it will return it immediately. Otherwise, it will perform the request as usual. The caller of CallResource is expected to explicitly update the cache with any responses. // If the cache service is implemented, we capture the request duration as a metric. The service is expected to write any response headers. func (m *CachingMiddleware) CallResource(ctx context.Context, req *backend.CallResourceRequest, sender backend.CallResourceResponseSender) error { - if req == nil { - return m.BaseHandler.CallResource(ctx, req, sender) - } - reqCtx := contexthandler.FromContext(ctx) if reqCtx == nil { return m.BaseHandler.CallResource(ctx, req, sender) } - // time how long this request takes - start := time.Now() - - // First look in the resource cache if enabled - hit, cr := m.caching.HandleResourceRequest(ctx, req) - - // record request duration if caching was used - if ch := reqCtx.Resp.Header().Get(caching.XCacheHeader); ch != "" { - defer func() { - ResourceCachingRequestHistogram.With(prometheus.Labels{ - "plugin_id": req.PluginContext.PluginID, - "cache": ch, - }).Observe(time.Since(start).Seconds()) - }() - } - - // Cache hit; send the response and return - if hit { - return sender.Send(cr.Response) - } - - // Cache miss; do the actual request - // If there is no update cache func, just pass in the original sender - if cr.UpdateCacheFn == nil { + return m.cachingServiceClient.WithCallResourceCaching(ctx, req, sender, func(sender backend.CallResourceResponseSender) error { return m.BaseHandler.CallResource(ctx, req, sender) - } - // Otherwise, intercept the responses in a wrapped sender so we can cache them first - cacheSender := backend.CallResourceResponseSenderFunc(func(res *backend.CallResourceResponse) error { - cr.UpdateCacheFn(ctx, res) - return sender.Send(res) }) - - return m.BaseHandler.CallResource(ctx, req, cacheSender) -} - -// Given N requests happening at the same time and issuing the same query, only one request will execute -// and the other ones will wait for the response received by the request being executed. -type requestDeduplicationMiddleware struct { - backend.BaseHandler - log *log.ConcreteLogger - singleflight *singleflight.Group -} - -func newRequestDeduplicationMiddleware(log *log.ConcreteLogger, next backend.Handler) *requestDeduplicationMiddleware { - return &requestDeduplicationMiddleware{log: log, BaseHandler: backend.NewBaseHandler(next), singleflight: &singleflight.Group{}} -} - -func (m *requestDeduplicationMiddleware) QueryData(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) { - if req.PluginContext.DataSourceInstanceSettings == nil || req.PluginContext.DataSourceInstanceSettings.UID == "" { - return m.BaseHandler.QueryData(ctx, req) - } - key, err := caching.GetKey(req.PluginContext.DataSourceInstanceSettings.UID, req) - if err != nil { - m.log.Error("error building cache key for request deduplication, skipping request deduplication", "error", err) - return m.BaseHandler.QueryData(ctx, req) - } - v, err, _ := m.singleflight.Do(key, func() (interface{}, error) { - return m.BaseHandler.QueryData(ctx, req) - }) - if err != nil { - return nil, fmt.Errorf("request deduplication middleware: calling BaseHandler.QueryData: %w", err) - } - return v.(*backend.QueryDataResponse), nil -} - -func (m *requestDeduplicationMiddleware) CallResource(ctx context.Context, req *backend.CallResourceRequest, sender backend.CallResourceResponseSender) error { - if req.PluginContext.DataSourceInstanceSettings == nil || req.PluginContext.DataSourceInstanceSettings.UID == "" { - return m.BaseHandler.CallResource(ctx, req, sender) - } - - key, err := caching.GetKey(req.PluginContext.DataSourceInstanceSettings.UID, req) - if err != nil { - m.log.Error("error building cache key for request deduplication, skipping request deduplication", "error", err) - return m.BaseHandler.CallResource(ctx, req, sender) - } - _, err, _ = m.singleflight.Do(key, func() (interface{}, error) { - return nil, m.BaseHandler.CallResource(ctx, req, sender) - }) - if err != nil { - return fmt.Errorf("request deduplication middleware: calling BaseHandler.CallResource: %w", err) - } - return nil } diff --git a/pkg/services/pluginsintegration/clientmiddleware/caching_middleware_test.go b/pkg/services/pluginsintegration/clientmiddleware/caching_middleware_test.go index 8185a9c66c3..f0e985b3047 100644 --- a/pkg/services/pluginsintegration/clientmiddleware/caching_middleware_test.go +++ b/pkg/services/pluginsintegration/clientmiddleware/caching_middleware_test.go @@ -4,10 +4,7 @@ import ( "context" "encoding/json" "net/http" - "sync" - "sync/atomic" "testing" - "time" "github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/grafana/grafana-plugin-sdk-go/backend/handlertest" @@ -25,9 +22,10 @@ func TestCachingMiddleware(t *testing.T) { require.NoError(t, err) cs := caching.NewFakeOSSCachingService() + cachingServiceClient := caching.ProvideCachingServiceClient(cs, nil) cdt := handlertest.NewHandlerMiddlewareTest(t, WithReqContext(req, &user.SignedInUser{}), - handlertest.WithMiddlewares(NewCachingMiddleware(cs)), + handlertest.WithMiddlewares(NewCachingMiddleware(cachingServiceClient)), ) jsonDataMap := map[string]any{} @@ -78,9 +76,9 @@ func TestCachingMiddleware(t *testing.T) { }) t.Run("If cache returns a miss, queries are issued and the update cache function is called", func(t *testing.T) { - origShouldCacheQuery := shouldCacheQuery + origShouldCacheQuery := caching.ShouldCacheQuery var shouldCacheQueryCalled bool - shouldCacheQuery = func(resp *backend.QueryDataResponse) bool { + caching.ShouldCacheQuery = func(resp *backend.QueryDataResponse) bool { shouldCacheQueryCalled = true return true } @@ -88,7 +86,7 @@ func TestCachingMiddleware(t *testing.T) { t.Cleanup(func() { updateCacheCalled = false shouldCacheQueryCalled = false - shouldCacheQuery = origShouldCacheQuery + caching.ShouldCacheQuery = origShouldCacheQuery cs.Reset() }) @@ -108,15 +106,16 @@ func TestCachingMiddleware(t *testing.T) { }) t.Run("with async queries", func(t *testing.T) { + cachingServiceClient := caching.ProvideCachingServiceClient(cs, featuremgmt.WithFeatures(featuremgmt.FlagAwsAsyncQueryCaching)) asyncCdt := handlertest.NewHandlerMiddlewareTest(t, WithReqContext(req, &user.SignedInUser{}), handlertest.WithMiddlewares( - NewCachingMiddlewareWithFeatureManager(cs, featuremgmt.WithFeatures(featuremgmt.FlagAwsAsyncQueryCaching))), + NewCachingMiddleware(cachingServiceClient)), ) t.Run("If shoudCacheQuery returns true update cache function is called", func(t *testing.T) { - origShouldCacheQuery := shouldCacheQuery + origShouldCacheQuery := caching.ShouldCacheQuery var shouldCacheQueryCalled bool - shouldCacheQuery = func(resp *backend.QueryDataResponse) bool { + caching.ShouldCacheQuery = func(resp *backend.QueryDataResponse) bool { shouldCacheQueryCalled = true return true } @@ -124,7 +123,7 @@ func TestCachingMiddleware(t *testing.T) { t.Cleanup(func() { updateCacheCalled = false shouldCacheQueryCalled = false - shouldCacheQuery = origShouldCacheQuery + caching.ShouldCacheQuery = origShouldCacheQuery cs.Reset() }) @@ -144,9 +143,9 @@ func TestCachingMiddleware(t *testing.T) { }) t.Run("If shoudCacheQuery returns false update cache function is not called", func(t *testing.T) { - origShouldCacheQuery := shouldCacheQuery + origShouldCacheQuery := caching.ShouldCacheQuery var shouldCacheQueryCalled bool - shouldCacheQuery = func(resp *backend.QueryDataResponse) bool { + caching.ShouldCacheQuery = func(resp *backend.QueryDataResponse) bool { shouldCacheQueryCalled = true return false } @@ -154,7 +153,7 @@ func TestCachingMiddleware(t *testing.T) { t.Cleanup(func() { updateCacheCalled = false shouldCacheQueryCalled = false - shouldCacheQuery = origShouldCacheQuery + caching.ShouldCacheQuery = origShouldCacheQuery cs.Reset() }) @@ -199,9 +198,10 @@ func TestCachingMiddleware(t *testing.T) { } cs := caching.NewFakeOSSCachingService() + cachingServiceClient := caching.ProvideCachingServiceClient(cs, nil) cdt := handlertest.NewHandlerMiddlewareTest(t, WithReqContext(req, &user.SignedInUser{}), - handlertest.WithMiddlewares(NewCachingMiddleware(cs)), + handlertest.WithMiddlewares(NewCachingMiddleware(cachingServiceClient)), handlertest.WithResourceResponses([]*backend.CallResourceResponse{simulatedPluginResponse}), ) @@ -275,9 +275,10 @@ func TestCachingMiddleware(t *testing.T) { require.NoError(t, err) cs := caching.NewFakeOSSCachingService() + cachingServiceClient := caching.ProvideCachingServiceClient(cs, nil) cdt := handlertest.NewHandlerMiddlewareTest(t, // Skip the request context in this case - handlertest.WithMiddlewares(NewCachingMiddleware(cs)), + handlertest.WithMiddlewares(NewCachingMiddleware(cachingServiceClient)), ) reqCtx := contexthandler.FromContext(req.Context()) require.Nil(t, reqCtx) @@ -325,86 +326,3 @@ func TestCachingMiddleware(t *testing.T) { }) }) } - -func TestRequestDeduplicationMiddleware(t *testing.T) { - t.Parallel() - - t.Run("deduplicates requests issuing the same query", func(t *testing.T) { - t.Parallel() - - handler := newMockMiddlewareHandler() - middleware := newRequestDeduplicationMiddleware(nil, handler) - - req := backend.QueryDataRequest{ - PluginContext: backend.PluginContext{ - DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{ - UID: "uid", - }, - }, - } - - wg := &sync.WaitGroup{} - wg.Add(2) - - for range 2 { - go func() { - defer wg.Done() - resp, err := middleware.QueryData(t.Context(), &req) - require.NoError(t, err) - require.Equal(t, &backend.QueryDataResponse{}, resp) - }() - } - - wg.Wait() - - require.EqualValues(t, 1, handler.QueryDataCalls) - }) - - t.Run("requests where DataSourceInstanceSettings is nil bypass request deduplication", func(t *testing.T) { - t.Parallel() - - handler := newMockMiddlewareHandler() - middleware := newRequestDeduplicationMiddleware(nil, handler) - - { - req := backend.QueryDataRequest{ - PluginContext: backend.PluginContext{ - DataSourceInstanceSettings: nil, - }, - } - - resp, err := middleware.QueryData(t.Context(), &req) - require.NoError(t, err) - require.Empty(t, resp) - } - - { - req := backend.CallResourceRequest{ - PluginContext: backend.PluginContext{ - DataSourceInstanceSettings: nil, - }, - } - - require.NoError(t, middleware.CallResource(t.Context(), &req, nil)) - } - }) -} - -type mockMiddlewareHandler struct { - backend.BaseHandler - QueryDataCalls int32 -} - -func newMockMiddlewareHandler() *mockMiddlewareHandler { - return &mockMiddlewareHandler{} -} - -func (m *mockMiddlewareHandler) QueryData(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) { - atomic.AddInt32(&m.QueryDataCalls, 1) - time.Sleep(10 * time.Millisecond) - return &backend.QueryDataResponse{}, nil -} - -func (m *mockMiddlewareHandler) CallResource(ctx context.Context, req *backend.CallResourceRequest, sender backend.CallResourceResponseSender) error { - return nil -} diff --git a/pkg/services/pluginsintegration/pluginsintegration.go b/pkg/services/pluginsintegration/pluginsintegration.go index 46bc10cb76b..a510ead1910 100644 --- a/pkg/services/pluginsintegration/pluginsintegration.go +++ b/pkg/services/pluginsintegration/pluginsintegration.go @@ -167,25 +167,25 @@ func ProvideClientWithMiddlewares( pluginRegistry registry.Service, oAuthTokenService oauthtoken.OAuthTokenService, tracer tracing.Tracer, - cachingService caching.CachingService, + cachingServiceClient *caching.CachingServiceClient, features featuremgmt.FeatureToggles, promRegisterer prometheus.Registerer, ) (*backend.MiddlewareHandler, error) { - return NewMiddlewareHandler(cfg, pluginRegistry, oAuthTokenService, tracer, cachingService, features, promRegisterer, pluginRegistry) + return NewMiddlewareHandler(cfg, pluginRegistry, oAuthTokenService, tracer, cachingServiceClient, features, promRegisterer, pluginRegistry) } func NewMiddlewareHandler( cfg *setting.Cfg, pluginRegistry registry.Service, oAuthTokenService oauthtoken.OAuthTokenService, - tracer tracing.Tracer, cachingService caching.CachingService, features featuremgmt.FeatureToggles, + tracer tracing.Tracer, cachingServiceClient *caching.CachingServiceClient, features featuremgmt.FeatureToggles, promRegisterer prometheus.Registerer, registry registry.Service, ) (*backend.MiddlewareHandler, error) { c := client.ProvideService(pluginRegistry) - middlewares := CreateMiddlewares(cfg, oAuthTokenService, tracer, cachingService, features, promRegisterer, registry) + middlewares := CreateMiddlewares(cfg, oAuthTokenService, tracer, cachingServiceClient, features, promRegisterer, registry) return backend.HandlerFromMiddlewares(c, middlewares...) } -func CreateMiddlewares(cfg *setting.Cfg, oAuthTokenService oauthtoken.OAuthTokenService, tracer tracing.Tracer, cachingService caching.CachingService, features featuremgmt.FeatureToggles, promRegisterer prometheus.Registerer, registry registry.Service) []backend.HandlerMiddleware { +func CreateMiddlewares(cfg *setting.Cfg, oAuthTokenService oauthtoken.OAuthTokenService, tracer tracing.Tracer, cachingServiceClient *caching.CachingServiceClient, features featuremgmt.FeatureToggles, promRegisterer prometheus.Registerer, registry registry.Service) []backend.HandlerMiddleware { middlewares := []backend.HandlerMiddleware{ clientmiddleware.NewTracingMiddleware(tracer), clientmiddleware.NewMetricsMiddleware(promRegisterer, registry), @@ -203,7 +203,7 @@ func CreateMiddlewares(cfg *setting.Cfg, oAuthTokenService oauthtoken.OAuthToken clientmiddleware.NewClearAuthHeadersMiddleware(), clientmiddleware.NewOAuthTokenMiddleware(oAuthTokenService), clientmiddleware.NewCookiesMiddleware(skipCookiesNames), - clientmiddleware.NewCachingMiddlewareWithFeatureManager(cachingService, features), + clientmiddleware.NewCachingMiddleware(cachingServiceClient), clientmiddleware.NewForwardIDMiddleware(), clientmiddleware.NewUseAlertHeadersMiddleware(), ) diff --git a/pkg/services/query/query_test.go b/pkg/services/query/query_test.go index aead5e3cc00..02a4dea4824 100644 --- a/pkg/services/query/query_test.go +++ b/pkg/services/query/query_test.go @@ -844,7 +844,7 @@ func setup(t *testing.T, isMultiTenant bool, mockClient clientapi.QueryDataClien secretStore: ss, pluginRequestValidator: rv, queryService: queryService, - signedInUser: &user.SignedInUser{OrgID: 1, Login: "login", Name: "name", Email: "email", OrgRole: identity.RoleAdmin}, + signedInUser: &user.SignedInUser{OrgID: 1, Login: "login", Name: "name", Email: "email", OrgRole: identity.RoleAdmin, Namespace: "ns1"}, } } @@ -928,12 +928,15 @@ func (c *fakePluginClient) QueryData(ctx context.Context, req *backend.QueryData } type testClient struct { - queryDataLastCalledWith data.QueryDataRequest + queryDataLastCalledWith data.QueryDataRequest + // The number of times the QueryData method has been called + queryDataCalls int queryDataStubbedResponse *backend.QueryDataResponse queryDataStubbedError error } func (c *testClient) QueryData(ctx context.Context, req data.QueryDataRequest) (*backend.QueryDataResponse, error) { + c.queryDataCalls++ c.queryDataLastCalledWith = req if c.queryDataStubbedError != nil { return nil, c.queryDataStubbedError From 8863ed9d6f8395808196b5d81d436fb637a43d37 Mon Sep 17 00:00:00 2001 From: Matias Chomicki Date: Tue, 28 Oct 2025 16:11:52 +0100 Subject: [PATCH 057/378] Logs Panel: Improve search terms highlighting for highlighted JSON logs (#113093) * Rename for clarity * New logs panel: improve highlighting of search terms between highlighted JSON logs --- .../features/logs/components/panel/grammar.ts | 8 ++- .../logs/components/panel/processing.test.ts | 51 +++++++++++++++++++ 2 files changed, 54 insertions(+), 5 deletions(-) diff --git a/public/app/features/logs/components/panel/grammar.ts b/public/app/features/logs/components/panel/grammar.ts index 3b81ca8f79c..3f420470b64 100644 --- a/public/app/features/logs/components/panel/grammar.ts +++ b/public/app/features/logs/components/panel/grammar.ts @@ -21,12 +21,10 @@ const jsonGrammar: Grammar = { 'log-token-json-key': { pattern: /(^|[^\\])"(?:\\.|[^\\"\r\n])*"(?=\s*:)/, lookbehind: true, - greedy: true, }, 'log-token-string': { pattern: /(^|[^\\])"(?:\\.|[^\\"\r\n])*"(?!\s*:)/, lookbehind: true, - greedy: true, inside: { ...tokensGrammar, }, @@ -36,17 +34,17 @@ const jsonGrammar: Grammar = { export const generateLogGrammar = (log: LogListModel) => { const labels = Object.keys(log.labels).concat(log.fields.map((field) => field.keys[0])); - const logGrammar: Grammar = { + const labelGrammar: Grammar = { 'log-token-label': new RegExp(`\\b(${labels.join('|')})(?:[=:]{1})\\b`, 'g'), }; if (log.isJSON) { return { - ...logGrammar, + ...labelGrammar, ...jsonGrammar, }; } return { - ...logGrammar, + ...labelGrammar, ...tokensGrammar, ...logsGrammar, }; diff --git a/public/app/features/logs/components/panel/processing.test.ts b/public/app/features/logs/components/panel/processing.test.ts index 1e8cf516325..2b58efeee15 100644 --- a/public/app/features/logs/components/panel/processing.test.ts +++ b/public/app/features/logs/components/panel/processing.test.ts @@ -388,6 +388,57 @@ describe('preProcessLogs', () => { ); }); + test('Highlights search strings within JSON logs', () => { + const jsonLogWithSearch = createLogRow({ + labels: { kind: 'Event', stage: 'ResponseComplete' }, + entry: `{"kind":"Event","key":"value"}`, + logLevel: LogLevel.error, + // Search words + searchWords: ['ven'], + }); + const jsonLogWithoutSearch = createLogRow({ + labels: { kind: 'Event', stage: 'ResponseComplete' }, + entry: `{"kind":"Event","key":"value"}`, + }); + + const [processedLogWithSearch, processedLogWithoutSearch] = preProcessLogs( + [jsonLogWithSearch, jsonLogWithoutSearch], + { + escape: false, + order: LogsSortOrder.Descending, + timeZone: 'browser', + wrapLogMessage: true, + } + ); + + // Current search + processedLogWithSearch.setCurrentSearch('alu'); + + // Search matches + expect(processedLogWithSearch.highlightedBodyTokens).toEqual( + expect.arrayContaining([ + expect.objectContaining({ content: '"kind"' }), + // Search words + expect.objectContaining({ content: 'ven' }), + expect.objectContaining({ content: '"key"' }), + // Current search + expect.objectContaining({ content: 'alu' }), + ]) + ); + + // Original JSON highlight + expect(processedLogWithoutSearch.highlightedBodyTokens).toEqual( + expect.arrayContaining([ + expect.objectContaining({ content: '"kind"' }), + // Search words + expect.objectContaining({ content: ['"Event"'] }), + expect.objectContaining({ content: '"key"' }), + // Current search + expect.objectContaining({ content: ['"value"'] }), + ]) + ); + }); + test('Returns displayed field values', () => { expect(processedLogs[0].getDisplayedFieldValue('logger')).toBe('interceptor'); expect(processedLogs[1].getDisplayedFieldValue('method')).toBe('POST'); From f3e7576f0cd1bc395ff132c8c045e8b34f44f8c1 Mon Sep 17 00:00:00 2001 From: Tom Ratcliffe Date: Tue, 28 Oct 2025 15:22:18 +0000 Subject: [PATCH 058/378] ComboBox: Add loading state to dropdown and prefixIcon (#112967) --- .../src/components/Combobox/Combobox.test.tsx | 18 +++++++++++ .../src/components/Combobox/Combobox.tsx | 10 ++++++- .../src/components/Combobox/ComboboxList.tsx | 7 +++-- .../src/components/Combobox/MessageRows.tsx | 6 ++++ .../Combobox/MultiCombobox.test.tsx | 30 +++++++++++++++---- .../src/components/Combobox/MultiCombobox.tsx | 9 ++++++ .../Combobox/getMultiComboboxStyles.ts | 1 + .../src/components/Combobox/useOptions.ts | 4 ++- public/locales/en-US/grafana.json | 1 + 9 files changed, 76 insertions(+), 10 deletions(-) diff --git a/packages/grafana-ui/src/components/Combobox/Combobox.test.tsx b/packages/grafana-ui/src/components/Combobox/Combobox.test.tsx index 537e26df1c9..b99e58a447b 100644 --- a/packages/grafana-ui/src/components/Combobox/Combobox.test.tsx +++ b/packages/grafana-ui/src/components/Combobox/Combobox.test.tsx @@ -6,6 +6,7 @@ import { Field } from '../Forms/Field'; import { Combobox } from './Combobox'; import { ComboboxOption } from './types'; +import { DEBOUNCE_TIME_MS } from './useOptions'; // Mock data for the Combobox options const options: ComboboxOption[] = [ @@ -613,6 +614,23 @@ describe('Combobox', () => { expect(onChangeHandler).not.toHaveBeenCalled(); expect(input).toHaveValue('Option 1'); }); + + it('shows loading message', async () => { + const loadingMessage = 'Loading options...'; + const asyncOptions = jest.fn(() => Promise.resolve(simpleAsyncOptions)); + render(); + + const input = screen.getByRole('combobox'); + await user.click(input); + + await act(async () => jest.advanceTimersByTime(0)); + + expect(await screen.findByText(loadingMessage)).toBeInTheDocument(); + + await act(async () => jest.advanceTimersByTime(DEBOUNCE_TIME_MS)); + + expect(screen.queryByText(loadingMessage)).not.toBeInTheDocument(); + }); }); }); diff --git a/packages/grafana-ui/src/components/Combobox/Combobox.tsx b/packages/grafana-ui/src/components/Combobox/Combobox.tsx index b81d0e601fa..9c4de9c2d8b 100644 --- a/packages/grafana-ui/src/components/Combobox/Combobox.tsx +++ b/packages/grafana-ui/src/components/Combobox/Combobox.tsx @@ -1,7 +1,7 @@ import { cx } from '@emotion/css'; import { useVirtualizer, type Range } from '@tanstack/react-virtual'; import { useCombobox } from 'downshift'; -import React, { useCallback, useId, useMemo } from 'react'; +import React, { ComponentProps, useCallback, useId, useMemo } from 'react'; import { t } from '@grafana/i18n'; @@ -60,6 +60,11 @@ interface ComboboxStaticProps * Called when the input loses focus. */ onBlur?: () => void; + + /** + * Icon to display at the start of the ComboBox input + */ + prefixIcon?: ComponentProps['name']; } interface ClearableProps { @@ -137,6 +142,7 @@ export const Combobox = (props: ComboboxProps) => disabled, portalContainer, invalid, + prefixIcon, } = props; // Value can be an actual scalar Value (string or number), or an Option (value + label), so @@ -376,6 +382,7 @@ export const Combobox = (props: ComboboxProps) => {...(isAutoSize ? { minWidth, maxWidth } : {})} autoFocus={autoFocus} onBlur={onBlur} + prefix={prefixIcon && } disabled={disabled} invalid={invalid} className={styles.input} @@ -402,6 +409,7 @@ export const Combobox = (props: ComboboxProps) => > {isOpen && ( { enableAllOption?: boolean; isMultiSelect?: boolean; error?: boolean; + loading?: boolean; } export const ComboboxList = ({ @@ -34,6 +35,7 @@ export const ComboboxList = ({ enableAllOption, isMultiSelect = false, error = false, + loading = false, }: ComboboxListProps) => { const styles = useStyles2(getComboboxStyles); @@ -161,7 +163,8 @@ export const ComboboxList = ({
{error && } - {options.length === 0 && !error && } + {!loading && options.length === 0 && !error && } + {loading && options.length === 0 && }
); diff --git a/packages/grafana-ui/src/components/Combobox/MessageRows.tsx b/packages/grafana-ui/src/components/Combobox/MessageRows.tsx index a2d45162c01..46f2a5e4cc3 100644 --- a/packages/grafana-ui/src/components/Combobox/MessageRows.tsx +++ b/packages/grafana-ui/src/components/Combobox/MessageRows.tsx @@ -22,6 +22,12 @@ export const NotFoundError = () => ( ); +export const LoadingOptions = () => ( + + Loading options... + +); + const MessageRow = ({ children }: { children: ReactNode }) => { return ( diff --git a/packages/grafana-ui/src/components/Combobox/MultiCombobox.test.tsx b/packages/grafana-ui/src/components/Combobox/MultiCombobox.test.tsx index 572a9d865a0..2061087828d 100644 --- a/packages/grafana-ui/src/components/Combobox/MultiCombobox.test.tsx +++ b/packages/grafana-ui/src/components/Combobox/MultiCombobox.test.tsx @@ -4,6 +4,7 @@ import React from 'react'; import { MultiCombobox, MultiComboboxProps } from './MultiCombobox'; import { ComboboxOption } from './types'; +import { DEBOUNCE_TIME_MS } from './useOptions'; describe('MultiCombobox', () => { beforeAll(() => { @@ -330,7 +331,7 @@ describe('MultiCombobox', () => { await user.click(input); // Debounce - await act(async () => jest.advanceTimersByTime(200)); + await act(async () => jest.advanceTimersByTime(DEBOUNCE_TIME_MS)); expect(asyncOptions).toHaveBeenCalled(); }); @@ -380,10 +381,10 @@ describe('MultiCombobox', () => { await user.click(input); await user.keyboard('a'); - act(() => jest.advanceTimersByTime(200)); // Skip debounce + act(() => jest.advanceTimersByTime(DEBOUNCE_TIME_MS)); // Skip debounce await user.keyboard('b'); - act(() => jest.advanceTimersByTime(200)); // Skip debounce + act(() => jest.advanceTimersByTime(DEBOUNCE_TIME_MS)); // Skip debounce await user.keyboard('c'); act(() => jest.advanceTimersByTime(500)); // Resolve the second request, should be ignored @@ -422,7 +423,7 @@ describe('MultiCombobox', () => { act(() => jest.advanceTimersByTime(10)); await user.keyboard('c'); - act(() => jest.advanceTimersByTime(200)); + act(() => jest.advanceTimersByTime(DEBOUNCE_TIME_MS)); const item = await screen.findByRole('option', { name: 'Option 3' }); expect(item).toBeInTheDocument(); @@ -439,7 +440,7 @@ describe('MultiCombobox', () => { await user.click(input); // Debounce - await act(async () => jest.advanceTimersByTime(200)); + await act(async () => jest.advanceTimersByTime(DEBOUNCE_TIME_MS)); // Click on Option 1 to deselect it (it should already be selected via value prop) const item = await screen.findByRole('option', { name: 'Option 1' }); @@ -484,7 +485,7 @@ describe('MultiCombobox', () => { await user.click(input); // Wait for async options to load - await act(async () => jest.advanceTimersByTime(200)); + await act(async () => jest.advanceTimersByTime(DEBOUNCE_TIME_MS)); // Integration A should be selected (shown as pill) const pillRemoveButton = screen.getByRole('button', { name: 'Remove Integration A' }); @@ -500,6 +501,23 @@ describe('MultiCombobox', () => { // The pill should be removed expect(screen.queryByRole('button', { name: 'Remove Integration A' })).not.toBeInTheDocument(); }); + + it('shows loading message', async () => { + const loadingMessage = 'Loading options...'; + const asyncOptions = jest.fn(() => Promise.resolve(simpleAsyncOptions)); + render(); + + const input = screen.getByRole('combobox'); + await user.click(input); + + await act(async () => jest.advanceTimersByTime(0)); + + expect(await screen.findByText(loadingMessage)).toBeInTheDocument(); + + await act(async () => jest.advanceTimersByTime(DEBOUNCE_TIME_MS)); + + expect(screen.queryByText(loadingMessage)).not.toBeInTheDocument(); + }); }); }); diff --git a/packages/grafana-ui/src/components/Combobox/MultiCombobox.tsx b/packages/grafana-ui/src/components/Combobox/MultiCombobox.tsx index 13dd02742e4..989bf3d0e2e 100644 --- a/packages/grafana-ui/src/components/Combobox/MultiCombobox.tsx +++ b/packages/grafana-ui/src/components/Combobox/MultiCombobox.tsx @@ -51,6 +51,7 @@ export const MultiCombobox = (props: MultiComboboxPro 'aria-labelledby': ariaLabelledBy, 'data-testid': dataTestId, portalContainer, + prefixIcon, } = props; const styles = useStyles2(getComboboxStyles); @@ -267,6 +268,13 @@ export const MultiCombobox = (props: MultiComboboxPro return (
+ {prefixIcon && ( + + + + + + )} {visibleItems.map((item, index) => ( (props: MultiComboboxPro > {isOpen && ( = const asyncNoop = () => Promise.resolve([]); +export const DEBOUNCE_TIME_MS = 200; + /** * Abstracts away sync/async options for combobox components. * It also filters options based on the user's input. @@ -49,7 +51,7 @@ export function useOptions(rawOptions: AsyncOptions Date: Tue, 28 Oct 2025 11:35:54 -0400 Subject: [PATCH 059/378] Alerting: Ensure state history client has external labels set (#113101) * Ensure state history client has external labels set * Run `make update-workspace` * Add dep owner --- go.mod | 2 +- pkg/services/ngalert/ngalert.go | 2 + pkg/services/ngalert/ngalert_test.go | 83 ++++++++++++++++++++++++++++ 3 files changed, 86 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 08ca8ca8112..6c3cf08f214 100644 --- a/go.mod +++ b/go.mod @@ -104,6 +104,7 @@ require ( github.com/grafana/grafana-google-sdk-go v0.4.2 // @grafana/partner-datasources github.com/grafana/grafana-openapi-client-go v0.0.0-20231213163343-bd475d63fb79 // @grafana/grafana-backend-group github.com/grafana/grafana-plugin-sdk-go v0.281.0 // @grafana/plugins-platform-backend + github.com/grafana/loki/pkg/push v0.0.0-20250823105456-332df2b20000 // @grafana/alerting-backend github.com/grafana/loki/v3 v3.2.1 // @grafana/observability-logs github.com/grafana/nanogit v0.0.0-20250723104447-68f58f5ecec0 // indirect; @grafana/grafana-git-ui-sync-team github.com/grafana/otel-profiling-go v0.5.1 // @grafana/grafana-backend-group @@ -446,7 +447,6 @@ require ( github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect github.com/gopherjs/gopherjs v1.17.2 // indirect github.com/grafana/jsonparser v0.0.0-20240425183733-ea80629e1a32 // indirect - github.com/grafana/loki/pkg/push v0.0.0-20250823105456-332df2b20000 // indirect github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc // indirect github.com/grafana/sqlds/v4 v4.2.7 // indirect github.com/grpc-ecosystem/go-grpc-prometheus v1.2.1-0.20191002090509-6af20e3a5340 // indirect diff --git a/pkg/services/ngalert/ngalert.go b/pkg/services/ngalert/ngalert.go index 77484ba43c4..ebb7e1061c2 100644 --- a/pkg/services/ngalert/ngalert.go +++ b/pkg/services/ngalert/ngalert.go @@ -668,6 +668,8 @@ func configureHistorianBackend( if err != nil { return nil, fmt.Errorf("invalid remote loki configuration: %w", err) } + // Use external labels from state history config + lcfg.ExternalLabels = cfg.ExternalLabels req := lokiclient.NewRequester() logCtx := log.WithContextualAttributes(ctx, []any{"backend", "loki"}) lokiBackendLogger := log.New("ngalert.state.historian").FromContext(logCtx) diff --git a/pkg/services/ngalert/ngalert_test.go b/pkg/services/ngalert/ngalert_test.go index 640a81821c9..c9adb2603cc 100644 --- a/pkg/services/ngalert/ngalert_test.go +++ b/pkg/services/ngalert/ngalert_test.go @@ -3,10 +3,17 @@ package ngalert import ( "bytes" "context" + "io" "math/rand" + "net/http" + "net/http/httptest" "testing" "time" + "github.com/gogo/protobuf/proto" + "github.com/golang/snappy" + "github.com/grafana/grafana-plugin-sdk-go/data" + "github.com/grafana/loki/pkg/push" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/testutil" "github.com/stretchr/testify/assert" @@ -20,9 +27,11 @@ import ( "github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/folder" acfakes "github.com/grafana/grafana/pkg/services/ngalert/accesscontrol/fakes" + "github.com/grafana/grafana/pkg/services/ngalert/eval" "github.com/grafana/grafana/pkg/services/ngalert/metrics" "github.com/grafana/grafana/pkg/services/ngalert/models" "github.com/grafana/grafana/pkg/services/ngalert/state" + history_model "github.com/grafana/grafana/pkg/services/ngalert/state/historian/model" "github.com/grafana/grafana/pkg/services/ngalert/store" "github.com/grafana/grafana/pkg/services/ngalert/tests/fakes" "github.com/grafana/grafana/pkg/setting" @@ -151,6 +160,80 @@ func TestConfigureHistorianBackend(t *testing.T) { require.NoError(t, err) }) + t.Run("Loki backend sends external labels in Record calls", func(t *testing.T) { + var receivedRequest *http.Request + var receivedBody []byte + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + receivedRequest = r + body, _ := io.ReadAll(r.Body) + receivedBody = body + w.WriteHeader(http.StatusNoContent) + })) + defer server.Close() + + met := metrics.NewHistorianMetrics(prometheus.NewRegistry(), metrics.Subsystem) + logger := log.NewNopLogger() + tracer := tracing.InitializeTracerForTest() + cfg := setting.UnifiedAlertingStateHistorySettings{ + Enabled: true, + Backend: "loki", + LokiSettings: setting.UnifiedAlertingLokiSettings{ + LokiReadURL: server.URL, + LokiWriteURL: server.URL, + }, + ExternalLabels: map[string]string{ + "test_label": "test_value", + "cluster": "prod", + }, + } + ac := &acfakes.FakeRuleService{} + + h, err := configureHistorianBackend(context.Background(), cfg, nil, nil, nil, met, logger, tracer, ac, nil, nil, nil, nil, nil) + require.NoError(t, err) + require.NotNil(t, h) + + rule := history_model.RuleMeta{ + OrgID: 1, + UID: "test-rule-uid", + Group: "test-group", + NamespaceUID: "test-namespace", + Title: "Test Rule", + } + states := []state.StateTransition{ + { + PreviousState: eval.Normal, + State: &state.State{ + State: eval.Alerting, + Labels: data.Labels{"instance": "test-instance"}, + LastEvaluationTime: time.Now(), + }, + }, + } + + errCh := h.Record(context.Background(), rule, states) + err = <-errCh + require.NoError(t, err) + + require.NotNil(t, receivedRequest, "Expected HTTP request to be sent to Loki") + require.Contains(t, receivedRequest.URL.Path, "/loki/api/v1/push") + + // Loki uses snappy-compressed protobuf encoding + decompressed, err := snappy.Decode(nil, receivedBody) + require.NoError(t, err) + + var req push.PushRequest + err = proto.Unmarshal(decompressed, &req) + require.NoError(t, err) + + require.Len(t, req.Streams, 1, "Expected exactly one stream") + stream := req.Streams[0] + + require.Contains(t, stream.Labels, `test_label="test_value"`) + require.Contains(t, stream.Labels, `cluster="prod"`) + require.Contains(t, stream.Labels, `from="state-history"`) + require.Contains(t, stream.Labels, `orgID="1"`) + }) + t.Run("fail initialization if prometheus backend missing datasource UID", func(t *testing.T) { met := metrics.NewHistorianMetrics(prometheus.NewRegistry(), metrics.Subsystem) logger := log.NewNopLogger() From 0973a44e6ade3bd8cc8485a271c52bf675a7703d Mon Sep 17 00:00:00 2001 From: Collin Fingar Date: Tue, 28 Oct 2025 11:51:09 -0400 Subject: [PATCH 060/378] Saved Queries: Update query's ds to default if necessary (#112674) --- public/app/features/query/components/QueryEditorRow.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/public/app/features/query/components/QueryEditorRow.tsx b/public/app/features/query/components/QueryEditorRow.tsx index 2331823384b..79bf7b30ee2 100644 --- a/public/app/features/query/components/QueryEditorRow.tsx +++ b/public/app/features/query/components/QueryEditorRow.tsx @@ -393,7 +393,10 @@ export class QueryEditorRow extends PureComponent {!isEditingQueryLibrary && !isUnifiedAlerting && !isExpressionQuery && ( Date: Tue, 28 Oct 2025 17:25:55 +0100 Subject: [PATCH 061/378] kvstore: fix events lookback + startkey (#113092) * fix snowflakes events * add tests --- pkg/storage/unified/resource/eventstore.go | 19 ++- .../unified/resource/eventstore_test.go | 131 ++++++++++++++++++ pkg/storage/unified/resource/notifier.go | 4 +- .../unified/resource/storage_backend.go | 2 +- .../unified/resource/storage_backend_test.go | 23 +-- 5 files changed, 153 insertions(+), 26 deletions(-) diff --git a/pkg/storage/unified/resource/eventstore.go b/pkg/storage/unified/resource/eventstore.go index 828e3cececf..53e15253b15 100644 --- a/pkg/storage/unified/resource/eventstore.go +++ b/pkg/storage/unified/resource/eventstore.go @@ -183,10 +183,8 @@ func (n *eventStore) Get(ctx context.Context, key EventKey) (Event, error) { // ListSince returns a sequence of events since the given resource version. func (n *eventStore) ListKeysSince(ctx context.Context, sinceRV int64) iter.Seq2[string, error] { opts := ListOptions{ - Sort: SortOrderAsc, - StartKey: EventKey{ - ResourceVersion: sinceRV, - }.String(), + Sort: SortOrderAsc, + StartKey: fmt.Sprintf("%d", sinceRV), } return func(yield func(string, error) bool) { for evtKey, err := range n.kv.Keys(ctx, eventsSection, opts) { @@ -275,3 +273,16 @@ func (n *eventStore) batchDelete(ctx context.Context, keys []string) error { func snowflakeFromTime(t time.Time) int64 { return (t.UnixMilli() - snowflake.Epoch) << (snowflake.NodeBits + snowflake.StepBits) } + +// subtractDurationFromSnowflake subtracts a duration from a snowflake ID by +// converting it to time, subtracting the duration, and converting back to a snowflake ID +func subtractDurationFromSnowflake(snowflakeID int64, duration time.Duration) int64 { + // Extract timestamp from snowflake (returns milliseconds since epoch) + timestamp := snowflake.ID(snowflakeID).Time() + // Convert to time.Time + t := time.Unix(0, timestamp*int64(time.Millisecond)) + // Subtract duration + newTime := t.Add(-duration) + // Convert back to snowflake + return snowflakeFromTime(newTime) +} diff --git a/pkg/storage/unified/resource/eventstore_test.go b/pkg/storage/unified/resource/eventstore_test.go index 5744d81c985..a9d2ee93eb4 100644 --- a/pkg/storage/unified/resource/eventstore_test.go +++ b/pkg/storage/unified/resource/eventstore_test.go @@ -6,6 +6,7 @@ import ( "testing" "time" + "github.com/bwmarrin/snowflake" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -660,3 +661,133 @@ func TestEventStore_BatchDelete(t *testing.T) { require.Error(t, err, "Event should have been deleted") } } + +func TestSubtractDurationFromSnowflake(t *testing.T) { + baseTime := time.Date(2025, 1, 1, 12, 0, 0, 0, time.UTC) + + tests := []struct { + name string + addTime time.Duration + }{ + { + name: "subtract 1 hour", + addTime: -1 * time.Hour, + }, + { + name: "subtract 2 hours", + addTime: -2 * time.Hour, + }, + { + name: "subtract 24 hours", + addTime: -24 * time.Hour, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Generate a snowflake from the base time + baseSnowflake := snowflakeFromTime(baseTime) + + // Subtract the duration + resultSnowflake := subtractDurationFromSnowflake(baseSnowflake, tt.addTime) + + // Convert back to timestamp and verify + // Extract timestamp from the result snowflake + timestamp := snowflake.ID(resultSnowflake).Time() + resultTime := time.Unix(0, timestamp*int64(time.Millisecond)) + + // Compare with expected time (allowing for small differences due to snowflake precision) + expectedMillis := baseTime.Add(-tt.addTime).UnixMilli() + resultMillis := resultTime.UnixMilli() + assert.InDelta(t, expectedMillis, resultMillis, 1, + "Expected time %v, got %v (diff: %d ms)", + baseTime, resultTime, expectedMillis-resultMillis) + }) + } +} + +func TestSnowflakeFromTime(t *testing.T) { + testTime := time.Date(2024, 1, 1, 12, 0, 0, 0, time.UTC) + snowflakeID := snowflakeFromTime(testTime) + + // Extract timestamp and verify it matches + timestamp := snowflake.ID(snowflakeID).Time() + reconstructedTime := time.Unix(0, timestamp*int64(time.Millisecond)) + + // The times should match at millisecond precision + expectedMillis := testTime.UnixMilli() + resultMillis := reconstructedTime.UnixMilli() + + assert.Equal(t, expectedMillis, resultMillis, "Snowflake timestamp should match original time at millisecond precision") +} + +func TestListKeysSince_WithSnowflakeTime(t *testing.T) { + ctx := context.Background() + store := setupTestEventStore(t) + + // Create events with snowflake-based resource versions at different times + now := time.Now() + events := []Event{ + { + Namespace: "default", + Group: "apps", + Resource: "resource", + Name: "test-1", + ResourceVersion: snowflakeFromTime(now.Add(-2 * time.Hour)), + Action: DataActionCreated, + }, + { + Namespace: "default", + Group: "apps", + Resource: "resource", + Name: "test-2", + ResourceVersion: snowflakeFromTime(now.Add(-1 * time.Hour)), + Action: DataActionUpdated, + }, + { + Namespace: "default", + Group: "apps", + Resource: "resource", + Name: "test-3", + ResourceVersion: snowflakeFromTime(now.Add(-30 * time.Minute)), + Action: DataActionDeleted, + }, + } + + // Save all events + for _, event := range events { + err := store.Save(ctx, event) + require.NoError(t, err) + } + + // List events since 90 minutes ago using subtractDurationFromSnowflake + sinceRV := subtractDurationFromSnowflake(snowflakeFromTime(now), 90*time.Minute) + retrievedEvents := make([]string, 0) + for eventKey, err := range store.ListKeysSince(ctx, sinceRV) { + require.NoError(t, err) + retrievedEvents = append(retrievedEvents, eventKey) + } + + // Should return events from the last hour and 30 minutes + require.Len(t, retrievedEvents, 2) + evt1, err := ParseEventKey(retrievedEvents[0]) + require.NoError(t, err) + assert.Equal(t, "test-2", evt1.Name) + evt2, err := ParseEventKey(retrievedEvents[1]) + require.NoError(t, err) + assert.Equal(t, "test-3", evt2.Name) + + // List events since 30 minutes ago using subtractDurationFromSnowflake + sinceRV = subtractDurationFromSnowflake(snowflakeFromTime(now), 30*time.Minute) + retrievedEvents = make([]string, 0) + for eventKey, err := range store.ListKeysSince(ctx, sinceRV) { + require.NoError(t, err) + retrievedEvents = append(retrievedEvents, eventKey) + } + + // Should return events from the last hour and 30 minutes + require.Len(t, retrievedEvents, 1) + evt, err := ParseEventKey(retrievedEvents[0]) + require.NoError(t, err) + assert.Equal(t, "test-3", evt.Name) +} diff --git a/pkg/storage/unified/resource/notifier.go b/pkg/storage/unified/resource/notifier.go index d0b27e4ad11..f55db60623a 100644 --- a/pkg/storage/unified/resource/notifier.go +++ b/pkg/storage/unified/resource/notifier.go @@ -73,7 +73,7 @@ func (n *notifier) Watch(ctx context.Context, opts watchOptions) <-chan Event { initialRV, err := n.lastEventResourceVersion(ctx) if errors.Is(err, ErrNotFound) { - initialRV = 0 // No events yet, start from the beginning + initialRV = snowflakeFromTime(time.Now()) // No events yet, start from the beginning } else if err != nil { n.log.Error("Failed to get last event resource version", "error", err) } @@ -86,7 +86,7 @@ func (n *notifier) Watch(ctx context.Context, opts watchOptions) <-chan Event { case <-ctx.Done(): return case <-time.After(opts.PollInterval): - for evt, err := range n.eventStore.ListSince(ctx, lastRV-opts.LookbackPeriod.Nanoseconds()) { + for evt, err := range n.eventStore.ListSince(ctx, subtractDurationFromSnowflake(lastRV, opts.LookbackPeriod)) { if err != nil { n.log.Error("Failed to list events since", "error", err) continue diff --git a/pkg/storage/unified/resource/storage_backend.go b/pkg/storage/unified/resource/storage_backend.go index f7bca33766b..4de28e758d5 100644 --- a/pkg/storage/unified/resource/storage_backend.go +++ b/pkg/storage/unified/resource/storage_backend.go @@ -746,7 +746,7 @@ func (k *kvStorageBackend) listModifiedSinceEventStore(ctx context.Context, key return func(yield func(*ModifiedResource, error) bool) { // store all events ordered by RV for the given tenant here eventKeys := make([]EventKey, 0) - for evtKeyStr, err := range k.eventStore.ListKeysSince(ctx, sinceRv-defaultLookbackPeriod.Nanoseconds()) { + for evtKeyStr, err := range k.eventStore.ListKeysSince(ctx, subtractDurationFromSnowflake(sinceRv, defaultLookbackPeriod)) { if err != nil { yield(&ModifiedResource{}, err) return diff --git a/pkg/storage/unified/resource/storage_backend_test.go b/pkg/storage/unified/resource/storage_backend_test.go index 4ef60d1a4c4..05920a603c4 100644 --- a/pkg/storage/unified/resource/storage_backend_test.go +++ b/pkg/storage/unified/resource/storage_backend_test.go @@ -10,7 +10,6 @@ import ( "testing" "time" - "github.com/bwmarrin/snowflake" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" @@ -764,24 +763,10 @@ func randomStringGenerator() func() string { // creates 2 hour old snowflake for testing func generateOldSnowflake(t *testing.T) int64 { - // Generate a current snowflake first - node, err := snowflake.NewNode(1) - require.NoError(t, err) - currentSnowflake := node.Generate().Int64() - - // Extract its timestamp component by shifting right - currentTimestamp := currentSnowflake >> 22 - - // Subtract 2 hours (in milliseconds) from the timestamp - twoHoursMs := int64(2 * time.Hour / time.Millisecond) - oldTimestamp := currentTimestamp - twoHoursMs - - // Reconstruct snowflake: [timestamp:41][node:10][sequence:12] - // Keep the original node and sequence bits - nodeAndSequence := currentSnowflake & 0x3FFFFF // Bottom 22 bits (10 node + 12 sequence) - snowflakeID := (oldTimestamp << 22) | nodeAndSequence - - return snowflakeID + // Generate a snowflake for 2 hours ago using the snowflakeFromTime utility + // which properly handles the epoch + twoHoursAgo := time.Now().Add(-2 * time.Hour) + return snowflakeFromTime(twoHoursAgo) } // seedBackend seeds the kvstore with data and return the expected result for ListModifiedSince calls From 6a3dfacc954bd687db1f288e62a0efce9278fae9 Mon Sep 17 00:00:00 2001 From: Stephanie Hingtgen Date: Tue, 28 Oct 2025 10:43:03 -0600 Subject: [PATCH 062/378] Datasources: Add service function to get by group, name, and namespace (#113066) --- pkg/services/datasources/datasources.go | 3 ++ .../fakes/fake_datasource_service.go | 14 +++++++ .../datasources/service/datasource.go | 6 +++ .../datasources/service/datasource_test.go | 14 +++++++ pkg/services/datasources/service/store.go | 37 +++++++++++++++++++ .../datasources/service/store_test.go | 37 +++++++++++++++++++ 6 files changed, 111 insertions(+) diff --git a/pkg/services/datasources/datasources.go b/pkg/services/datasources/datasources.go index 5b45fd4d96a..a04f35e3775 100644 --- a/pkg/services/datasources/datasources.go +++ b/pkg/services/datasources/datasources.go @@ -15,6 +15,9 @@ type DataSourceService interface { // GetDataSource gets a datasource. GetDataSource(ctx context.Context, query *GetDataSourceQuery) (*DataSource, error) + // GetDataSourceInNamespace gets a datasource by namespace, name (datasource uid), and group (datasource type). + GetDataSourceInNamespace(ctx context.Context, namespace, name, group string) (*DataSource, error) + // GetDataSources gets datasources. GetDataSources(ctx context.Context, query *GetDataSourcesQuery) ([]*DataSource, error) diff --git a/pkg/services/datasources/fakes/fake_datasource_service.go b/pkg/services/datasources/fakes/fake_datasource_service.go index 4c5fd79173f..19e7bbb43a5 100644 --- a/pkg/services/datasources/fakes/fake_datasource_service.go +++ b/pkg/services/datasources/fakes/fake_datasource_service.go @@ -4,6 +4,7 @@ import ( "context" "net/http" + "github.com/grafana/authlib/types" sdkhttpclient "github.com/grafana/grafana-plugin-sdk-go/backend/httpclient" "github.com/grafana/grafana/pkg/infra/httpclient" @@ -30,6 +31,19 @@ func (s *FakeDataSourceService) GetDataSource(ctx context.Context, query *dataso return nil, datasources.ErrDataSourceNotFound } +func (s *FakeDataSourceService) GetDataSourceInNamespace(ctx context.Context, namespace, name, group string) (*datasources.DataSource, error) { + ns, err := types.ParseNamespace(namespace) + if err != nil { + return nil, err + } + for _, dataSource := range s.DataSources { + if name == dataSource.UID && ns.OrgID == dataSource.OrgID && group == dataSource.Type { + return dataSource, nil + } + } + return nil, datasources.ErrDataSourceNotFound +} + func (s *FakeDataSourceService) GetDataSources(ctx context.Context, query *datasources.GetDataSourcesQuery) ([]*datasources.DataSource, error) { var dataSources []*datasources.DataSource for _, datasource := range s.DataSources { diff --git a/pkg/services/datasources/service/datasource.go b/pkg/services/datasources/service/datasource.go index f5cbe96225b..84a3e14141c 100644 --- a/pkg/services/datasources/service/datasource.go +++ b/pkg/services/datasources/service/datasource.go @@ -117,6 +117,8 @@ func (s *Service) Usage(ctx context.Context, scopeParams *quota.ScopeParameters) type DataSourceRetriever interface { // GetDataSource gets a datasource. GetDataSource(ctx context.Context, query *datasources.GetDataSourceQuery) (*datasources.DataSource, error) + // GetDataSourceInNamespace gets a datasource by namespace, name (datasource uid), and group (datasource type). + GetDataSourceInNamespace(ctx context.Context, namespace, name, group string) (*datasources.DataSource, error) } // NewNameScopeResolver provides an ScopeAttributeResolver able to @@ -176,6 +178,10 @@ func (s *Service) GetDataSource(ctx context.Context, query *datasources.GetDataS return s.SQLStore.GetDataSource(ctx, query) } +func (s *Service) GetDataSourceInNamespace(ctx context.Context, namespace, name, group string) (*datasources.DataSource, error) { + return s.SQLStore.GetDataSourceInNamespace(ctx, namespace, name, group) +} + func (s *Service) GetDataSources(ctx context.Context, query *datasources.GetDataSourcesQuery) ([]*datasources.DataSource, error) { return s.SQLStore.GetDataSources(ctx, query) } diff --git a/pkg/services/datasources/service/datasource_test.go b/pkg/services/datasources/service/datasource_test.go index 0de33c32e5f..1aeca6af087 100644 --- a/pkg/services/datasources/service/datasource_test.go +++ b/pkg/services/datasources/service/datasource_test.go @@ -17,6 +17,7 @@ import ( "github.com/stretchr/testify/require" "gopkg.in/ini.v1" + "github.com/grafana/authlib/types" "github.com/grafana/grafana-plugin-sdk-go/backend" sdkhttpclient "github.com/grafana/grafana-plugin-sdk-go/backend/httpclient" "github.com/grafana/grafana/pkg/components/simplejson" @@ -63,6 +64,19 @@ func (d *dataSourceMockRetriever) GetDataSource(ctx context.Context, query *data return nil, datasources.ErrDataSourceNotFound } +func (d *dataSourceMockRetriever) GetDataSourceInNamespace(ctx context.Context, namespace, name, group string) (*datasources.DataSource, error) { + ns, err := types.ParseNamespace(namespace) + if err != nil { + return nil, err + } + for _, dataSource := range d.res { + if name == dataSource.UID && ns.OrgID == dataSource.OrgID && group == dataSource.Type { + return dataSource, nil + } + } + return nil, datasources.ErrDataSourceNotFound +} + func TestIntegrationService_AddDataSource(t *testing.T) { testutil.SkipIntegrationTestInShortMode(t) diff --git a/pkg/services/datasources/service/store.go b/pkg/services/datasources/service/store.go index c89200ee2fc..e0ef6a88111 100644 --- a/pkg/services/datasources/service/store.go +++ b/pkg/services/datasources/service/store.go @@ -7,6 +7,7 @@ import ( "strings" "time" + "github.com/grafana/authlib/types" "github.com/grafana/grafana/pkg/util/xorm" "github.com/grafana/grafana/pkg/components/simplejson" @@ -24,6 +25,7 @@ import ( // Store is the interface for the datasource Service's storage. type Store interface { GetDataSource(context.Context, *datasources.GetDataSourceQuery) (*datasources.DataSource, error) + GetDataSourceInNamespace(context.Context, string, string, string) (*datasources.DataSource, error) GetDataSources(context.Context, *datasources.GetDataSourcesQuery) ([]*datasources.DataSource, error) GetDataSourcesByType(context.Context, *datasources.GetDataSourcesByTypeQuery) ([]*datasources.DataSource, error) DeleteDataSource(context.Context, *datasources.DeleteDataSourceCommand) error @@ -90,6 +92,41 @@ func (ss *SqlStore) getDataSource(_ context.Context, query *datasources.GetDataS return datasource, nil } +func (ss *SqlStore) GetDataSourceInNamespace(ctx context.Context, namespace, name, group string) (*datasources.DataSource, error) { + var ( + dataSource *datasources.DataSource + err error + ) + ns, err := types.ParseNamespace(namespace) + if err != nil { + return nil, err + } + + return dataSource, ss.db.WithDbSession(ctx, func(sess *db.Session) error { + dataSource, err = ss.getDataSourceInGroup(ctx, ns.OrgID, name, group, sess) + return err + }) +} + +func (ss *SqlStore) getDataSourceInGroup(_ context.Context, orgID int64, name, group string, sess *db.Session) (*datasources.DataSource, error) { + datasource := &datasources.DataSource{ + OrgID: orgID, + Type: group, + UID: name, + } + has, err := sess.Get(datasource) + + if err != nil { + ss.logger.Error("Failed getting data source", "err", err, "name", name, "orgId", orgID, "group", group) + return nil, err + } else if !has { + ss.logger.Debug("Data source not found", "name", name, "orgId", orgID, "group", group) + return nil, datasources.ErrDataSourceNotFound + } + + return datasource, nil +} + func (ss *SqlStore) GetDataSources(ctx context.Context, query *datasources.GetDataSourcesQuery) ([]*datasources.DataSource, error) { var ( sess *xorm.Session diff --git a/pkg/services/datasources/service/store_test.go b/pkg/services/datasources/service/store_test.go index eef123b138b..2de184c5c62 100644 --- a/pkg/services/datasources/service/store_test.go +++ b/pkg/services/datasources/service/store_test.go @@ -407,6 +407,43 @@ func TestIntegrationDataAccess(t *testing.T) { }) }) + t.Run("GetDataSourceInGroup", func(t *testing.T) { + t.Run("Only returns datasource of specified type", func(t *testing.T) { + db := db.InitTestDB(t) + ss := SqlStore{db: db, logger: log.NewNopLogger()} + + ds, err := ss.AddDataSource(context.Background(), &datasources.AddDataSourceCommand{ + OrgID: 10, + Name: "Elasticsearch", + Type: datasources.DS_ES, + Access: datasources.DS_ACCESS_DIRECT, + URL: "http://test", + Database: "site", + ReadOnly: true, + }) + require.NoError(t, err) + + ds2, err := ss.AddDataSource(context.Background(), &datasources.AddDataSourceCommand{ + OrgID: 10, + Name: "Graphite", + Type: datasources.DS_GRAPHITE, + Access: datasources.DS_ACCESS_DIRECT, + URL: "http://test", + Database: "site", + ReadOnly: true, + }) + require.NoError(t, err) + + dataSource, err := ss.GetDataSourceInNamespace(context.Background(), "org-10", ds.UID, datasources.DS_ES) + require.NoError(t, err) + require.Equal(t, ds.UID, dataSource.UID) + + _, err = ss.GetDataSourceInNamespace(context.Background(), "org-10", ds2.UID, datasources.DS_ES) + require.Error(t, err) + require.IsType(t, datasources.ErrDataSourceNotFound, err) + }) + }) + t.Run("GetDataSourcesByType", func(t *testing.T) { t.Run("Only returns datasources of specified type", func(t *testing.T) { db := db.InitTestDB(t) From e5cf0e2086db21628372127b92003abadc1457c8 Mon Sep 17 00:00:00 2001 From: Isabel Matwawana <76437239+imatwawana@users.noreply.github.com> Date: Tue, 28 Oct 2025 13:16:37 -0400 Subject: [PATCH 063/378] Docs: Add styling from field cell option (#113107) Co-authored-by: Paul Marbach --- .../shared/visualizations/cell-options.md | 1 + .../visualizations/table/index.md | 43 ++++++++++++++----- 2 files changed, 33 insertions(+), 11 deletions(-) diff --git a/docs/sources/shared/visualizations/cell-options.md b/docs/sources/shared/visualizations/cell-options.md index 9521ded500c..a2549edf0ca 100644 --- a/docs/sources/shared/visualizations/cell-options.md +++ b/docs/sources/shared/visualizations/cell-options.md @@ -7,4 +7,5 @@ title: Cell options | ------ | ----------- | | Cell value inspect |

Enables value inspection from table cells. When the switch is toggled on, clicking the inspect icon in a cell opens the **Inspect value** drawer which contains two tabs: **Plain text** and **Code editor**.

Grafana attempts to automatically detect the type of data in the cell and opens the drawer with the associated tab showing. However, you can switch back and forth between tabs.

| | Tooltip from field | Toggle on the **Tooltip from field** switch to use the values from another field (or column) in a tooltip. For more information, refer to [Tooltip from field](#tooltip-from-field). | +| Styling from field | Toggle on the **Styling from field** switch to apply the styling from another field (or column). The referenced field must contain CSS properties formatted in JSON object syntax (for example, `{"name":"John"}`). For more information, refer to the [Styling from field](#styling-from-field). | diff --git a/docs/sources/visualizations/panels-visualizations/visualizations/table/index.md b/docs/sources/visualizations/panels-visualizations/visualizations/table/index.md index 84015fa7357..8dea090218f 100644 --- a/docs/sources/visualizations/panels-visualizations/visualizations/table/index.md +++ b/docs/sources/visualizations/panels-visualizations/visualizations/table/index.md @@ -325,9 +325,10 @@ The colored background cell type has the following options: | Apply to entire row | Toggle the switch on to apply the background color that's configured for the cell to the whole row. | | Cell value inspect |

Enables value inspection from table cells. When the switch is toggled on, clicking the inspect icon in a cell opens the **Inspect value** drawer which contains two tabs: **Plain text** and **Code editor**.

Grafana attempts to automatically detect the type of data in the cell and opens the drawer with the associated tab showing. However, you can switch back and forth between tabs.

| | Tooltip from field | Toggle on the **Tooltip from field** switch to use the values from another field (or column) in a tooltip. For more information, refer to the [Tooltip from field](#tooltip-from-field). | +| Styling from field | Toggle on the **Styling from field** switch to apply the styling from another field (or column). The referenced field must contain CSS properties formatted in JSON object syntax (for example, `{"name":"John"}`). For more information, refer to the [Styling from field](#styling-from-field). | - + #### Data links @@ -346,6 +347,7 @@ The gauge cell type has the following options: | Gauge display mode | Controls the type of gauge used. For more information, refer to the [Gauge display mode](#gauge-display-mode). | | Value display | Controls how the value is displayed. For more information, refer to the [Value display](#value-display). | | Tooltip from field | Toggle on the **Tooltip from field** switch to use the values from another field (or column) in a tooltip. For more information, refer to [Tooltip from field](#tooltip-from-field). | +| Styling from field | Toggle on the **Styling from field** switch to apply the styling from another field (or column). The referenced field must contain CSS properties formatted in JSON object syntax (for example, `{"name":"John"}`). For more information, refer to the [Styling from field](#styling-from-field). | {{< admonition type="note" >}} @@ -402,24 +404,19 @@ For more detailed information about all of the sparkline styling options (except | Point size | Set the size of the points, from 1 to 40 pixels in diameter. | | Bar alignment | Set the position of the bar relative to a data point. | | Tooltip from field | Toggle on the **Tooltip from field** switch to use the values from another field (or column) in a tooltip. For more information, refer to [Tooltip from field](#tooltip-from-field). | +| Styling from field | Toggle on the **Styling from field** switch to apply the styling from another field (or column). The referenced field must contain CSS properties formatted in JSON object syntax (for example, `{"name":"John"}`). For more information, refer to the [Styling from field](#styling-from-field). | #### JSON View This cell type shows values formatted as code. -If a value is an object the JSON view allowing browsing the JSON object will appear on hover. +If a value is an object, the JSON object will appear on hover. {{< figure src="/static/img/docs/tables/json-view.png" max-width="350px" alt="JSON view" class="docs-image--no-shadow" >}} -For the JSON view cell type, you can set enable **Cell value inspect**. -This enables value inspection from table cells. -When the switch is toggled on, clicking the inspect icon in a cell opens the **Inspect value** drawer which contains two tabs: **Plain text** and **Code editor**. +It has the following cell options: -Toggle on the **Tooltip from field** switch to use the values from another field (or column) in a tooltip. -For more information, refer to [Tooltip from field](#tooltip-from-field). - -Grafana attempts to automatically detect the type of data in the cell and opens the drawer with the associated tab showing. -However, you can switch back and forth between tabs. +{{< docs/shared lookup="visualizations/cell-options.md" source="grafana" version="" >}} #### Pill @@ -510,7 +507,7 @@ Select one of the following options: **Auto**, **Top**, **Right**, **Bottom**, a The content of the tooltip is determined by the values of the source field and can't be directly edited. However, you can affect the display of the value using overrides like value mappings, as shown in the [Example: Tooltip from field with value mappings](#example-tooltip-from-field-with-value-mappings) section. -While you can turn on this option under **Cell options**, and have it applied to all cells in the table, it's typically used as an override on a sub-set of cells instead. +While you can turn on this option under **Cell options** and have it applied to all cells in the table, it's typically used as an override on a sub-set of cells instead. This is demonstrated in the example in the following section. ##### Example: Tooltip from field using overrides @@ -546,6 +543,30 @@ Now, when you hover the cursor over the chip in the "Short text" cell, the mappe You can use all field overrides to affect the display of the tooltip. For example, the **Table > Column width** or **Cell options > Cell type** overrides can change the cell width or visual display of the data. +#### Styling from field + +Toggle on the **Styling from field** switch to apply the styling from another field (or column). +The referenced field must contain [CSS properties](https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleProperties) formatted in JSON object syntax. For example: + +```JSON +{"marginLeft":12, "text-decoration": "underline"} +``` + +While you can turn on this option under **Cell options** and have it applied to all cells in the table, it's typically used as an override on a sub-set of cells instead. +This is demonstrated in the following example. + +The following table has six visible fields (columns) as well as a hidden field called "Style": + +{{< figure src="/media/docs/grafana/panels-visualizations/screenshot-style-from-field-config-v12.3.png" max-width="750px" alt="Configuration of a table including the styling from field option" >}} + +- The "Style" field has JSON objects with CSS properties. (Note that they are formatted for use in CSV format in this example.) +- The "Style" field is hidden using the **Table > Hide in table** override property. +- The "Info" field is using the **Cell options > Styling from field** override property with the "Style" field as the source. + +The following image shows the "Info" field with the styling from the "Style" field applied: + +{{< figure src="/media/docs/grafana/panels-visualizations/screenshot-style-from-field-v12.3.png" max-width="750px" alt="Info field with styling from Style field applied" >}} + ### Standard options {{< docs/shared lookup="visualizations/standard-options.md" source="grafana" version="" >}} From 8263803e81f26bdce676c5676b7cc4838cdf9042 Mon Sep 17 00:00:00 2001 From: Nathan Marrs Date: Tue, 28 Oct 2025 13:05:32 -0700 Subject: [PATCH 064/378] Grafana Data Source: Add random walk configuration options (#113009) * Grafana: Add random walk configuration options to Grafana datasource Add UI controls to configure random walk parameters (min, max, start value, spread, noise, drop percent) to match TestData datasource functionality. - Add RandomWalkEditor component with inline number inputs for all parameters - Update GrafanaQuery type to include random walk configuration fields - Update backend to parse and apply query parameters to RandomWalk function - Configuration options match TestData datasource UX for consistency * Grafana: Add series count support to random walk Add ability to generate multiple random walk series in a single query for complete parity with TestData datasource. - Add seriesCount field to RandomWalkEditor - Update backend to loop and generate multiple frames based on series count - Default to 1 series if not specified for backward compatibility * Grafana: Improve random walk editor UI with better organization and tooltips Enhance the random walk configuration UI for better usability: - Organize fields into two logical rows (core config vs fine-tuning) - Add helpful tooltips to all fields explaining their purpose - Increase label width to prevent text wrapping - Group related fields visually for better comprehension Row 1: Series count, Start value, Min, Max (basic shape and range) Row 2: Spread, Noise, Drop % (randomness and variation controls) This provides a cleaner, more intuitive experience compared to TestData's single-row layout, making it easier for users to configure random walks. * Grafana: Format RandomWalkEditor code Apply consistent formatting to RandomWalkEditor component. * Grafana: Add E2E tests for random walk configuration Add comprehensive Playwright E2E tests to verify random walk functionality: - Test that all configuration fields render correctly - Test min/max value constraints - Test multiple series generation - Test spread and noise parameters - Test drop percentage for simulating missing data - Test that tooltips are present and functional These tests ensure the random walk configuration works end-to-end from UI input to data rendering in panels. * Grafana: Fix E2E tests for random walk configuration Fix Playwright test selectors and assertions to work reliably: - Use specific element IDs to avoid selector conflicts - Remove flaky dropPercent check from rendering test (covered separately) - Simplify test assertions to focus on functional verification - All 7 tests now passing consistently Tests verify: field rendering, min/max constraints, series count, spread/noise configuration, drop percentage, and tooltips. * Grafana: Add advanced E2E tests for random walk Add two additional tests for better coverage: - Test configuration value persistence across interactions - Test that series count actually generates the expected number of series These tests verify deeper functionality beyond basic UI rendering, ensuring the random walk feature works correctly end-to-end. All 9 tests passing consistently (20.1s runtime). * Grafana: Remove redundant Min/Max tooltips Remove tooltips from Min and Max fields that just repeated the label text. These fields are self-explanatory and don't need tooltip icons. Keeps the UI cleaner while maintaining helpful tooltips on fields that actually benefit from explanation (Series count, Start value, Spread, Noise, Drop %). * Grafana: Add CODEOWNERS entry for random walk E2E tests Add codeowner assignment for the new grafana-datasource-random-walk.spec.ts test file to @grafana/grafana-frontend-platform, matching the ownership of the Grafana datasource code. * Add dashboardTemplates feature toggle and put new changes behind this toggle to limit impact * Grafana: Add unit tests for dashboardTemplates feature toggle Add unit tests to verify RandomWalkEditor renders correctly based on the dashboardTemplates feature toggle: - Test that random walk editor renders when FF is enabled - Test that random walk editor is hidden when FF is disabled These tests ensure the feature toggle works as expected and prevents the random walk configuration UI from appearing when the feature is disabled. * revert previous codeowners change as not necessary * Grafana: Remove redundant E2E test for feature flag disabled Remove E2E test for dashboardTemplates feature flag disabled scenario since it's already covered by unit tests and E2E environment can't reliably control server-side feature flags. Feature flag behavior is properly tested in QueryEditor.test.tsx unit tests. E2E tests focus on functional validation when the feature is enabled. * fix lint --- .github/CODEOWNERS | 1 + .../grafana-datasource-random-walk.spec.ts | 220 ++++++++++++++++++ .../src/types/featureToggles.gen.ts | 4 + pkg/services/featuremgmt/registry.go | 7 + pkg/services/featuremgmt/toggles_gen.csv | 1 + pkg/services/featuremgmt/toggles_gen.go | 4 + pkg/services/featuremgmt/toggles_gen.json | 12 + pkg/tsdb/grafanads/grafana.go | 16 +- .../grafana/components/QueryEditor.test.tsx | 78 +++++++ .../grafana/components/QueryEditor.tsx | 9 + .../grafana/components/RandomWalkEditor.tsx | 115 +++++++++ .../app/plugins/datasource/grafana/types.ts | 8 + 12 files changed, 473 insertions(+), 2 deletions(-) create mode 100644 e2e-playwright/various-suite/grafana-datasource-random-walk.spec.ts create mode 100644 public/app/plugins/datasource/grafana/components/QueryEditor.test.tsx create mode 100644 public/app/plugins/datasource/grafana/components/RandomWalkEditor.tsx diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index ce7089273ef..853f27774d4 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -505,6 +505,7 @@ i18next.config.ts @grafana/grafana-frontend-platform /e2e-playwright/various-suite/frontend-sandbox-app.spec.ts @grafana/plugins-platform-frontend /e2e-playwright/various-suite/frontend-sandbox-datasource.spec.ts @grafana/plugins-platform-frontend /e2e-playwright/various-suite/gauge.spec.ts @grafana/dataviz-squad +/e2e-playwright/various-suite/grafana-datasource-random-walk.spec.ts @grafana/grafana-frontend-platform /e2e-playwright/various-suite/graph-auto-migrate.spec.ts @grafana/dataviz-squad /e2e-playwright/various-suite/inspect-drawer.spec.ts @grafana/dashboards-squad /e2e-playwright/various-suite/keybinds.spec.ts @grafana/grafana-frontend-platform diff --git a/e2e-playwright/various-suite/grafana-datasource-random-walk.spec.ts b/e2e-playwright/various-suite/grafana-datasource-random-walk.spec.ts new file mode 100644 index 00000000000..15cb4d7bdd4 --- /dev/null +++ b/e2e-playwright/various-suite/grafana-datasource-random-walk.spec.ts @@ -0,0 +1,220 @@ +import { test as base, expect } from '@grafana/plugin-e2e'; + +// Note: Random walk configuration UI requires dashboardTemplates feature toggle to be enabled +const test = base.extend({}); +test.use({ + featureToggles: { + dashboardTemplates: true, + }, +}); + +test.describe( + 'Grafana datasource random walk', + { + tag: ['@grafana-datasource'], + }, + () => { + test('should render random walk configuration fields', async ({ gotoDashboardPage, page, selectors }) => { + // Create new dashboard + const dashboardPage = await gotoDashboardPage({}); + + // Add new panel + await dashboardPage.addPanel(); + + // Wait for the first field to be visible (ensures query editor loaded) + await expect(page.locator('#randomWalk-seriesCount-A')).toBeVisible(); + + // Verify core configuration fields (row 1) + await expect(page.locator('#randomWalk-startValue-A')).toBeVisible(); + await expect(page.locator('#randomWalk-min-A')).toBeVisible(); + await expect(page.locator('#randomWalk-max-A')).toBeVisible(); + + // Verify fine-tuning fields (row 2) + await expect(page.locator('#randomWalk-spread-A')).toBeVisible(); + await expect(page.locator('#randomWalk-noise-A')).toBeVisible(); + + // Drop percentage is tested separately in its own test + }); + + test('should configure min and max values and render constrained data', async ({ + gotoDashboardPage, + page, + selectors, + }) => { + // Create new dashboard + const dashboardPage = await gotoDashboardPage({}); + + // Add new panel + await dashboardPage.addPanel(); + + // Configure random walk with min/max constraints using specific IDs + const minInput = page.locator('#randomWalk-min-A'); + const maxInput = page.locator('#randomWalk-max-A'); + + await minInput.fill('10'); + await maxInput.fill('50'); + + // Wait for the query to execute + await page.waitForTimeout(1000); + + // Verify graph renders with a series + await expect( + dashboardPage.getByGrafanaSelector(selectors.components.VizLegend.seriesName('A-series')) + ).toBeVisible(); + }); + + test('should generate multiple series when series count is configured', async ({ + gotoDashboardPage, + page, + selectors, + }) => { + // Create new dashboard + const dashboardPage = await gotoDashboardPage({}); + + // Add new panel + await dashboardPage.addPanel(); + + // Configure series count to 3 using role selector + const seriesCountInput = page.getByRole('spinbutton', { name: 'Series count' }); + await seriesCountInput.fill('3'); + + // Wait for query to execute and check that we have series in the legend + await expect( + dashboardPage.getByGrafanaSelector(selectors.components.VizLegend.seriesName('A-series')) + ).toBeVisible(); + + // Verify the input value is set correctly + await expect(seriesCountInput).toHaveValue('3'); + }); + + test('should configure spread and noise parameters', async ({ gotoDashboardPage, page, selectors }) => { + // Create new dashboard + const dashboardPage = await gotoDashboardPage({}); + + // Add new panel + await dashboardPage.addPanel(); + + // Configure spread and noise using role selectors + const spreadInput = page.getByRole('spinbutton', { name: 'Spread' }); + const noiseInput = page.getByRole('spinbutton', { name: 'Noise' }); + const startValueInput = page.getByRole('spinbutton', { name: 'Start value' }); + + await startValueInput.fill('100'); + await spreadInput.fill('5'); + await noiseInput.fill('2'); + + // Verify graph renders + await expect( + dashboardPage.getByGrafanaSelector(selectors.components.VizLegend.seriesName('A-series')) + ).toBeVisible(); + }); + + test('should configure drop percentage for missing data', async ({ gotoDashboardPage, page, selectors }) => { + // Create new dashboard + const dashboardPage = await gotoDashboardPage({}); + + // Add new panel + await dashboardPage.addPanel(); + + // Configure drop percentage using role selector + const dropInput = page.getByRole('spinbutton', { name: 'Drop (%)' }); + await dropInput.fill('20'); + + // Verify graph still renders even with dropped points + await expect( + dashboardPage.getByGrafanaSelector(selectors.components.VizLegend.seriesName('A-series')) + ).toBeVisible(); + }); + + test('should show tooltips on configuration fields', async ({ gotoDashboardPage, page }) => { + // Create new dashboard + const dashboardPage = await gotoDashboardPage({}); + + // Add new panel + await dashboardPage.addPanel(); + + // Verify the Spread field has a tooltip by hovering near its label + const spreadInput = page.locator('#randomWalk-spread-A'); + await expect(spreadInput).toBeVisible(); + + // The tooltip is part of the InlineField component + // Just verify we can interact with the field (tooltip rendering is handled by the component) + await spreadInput.hover(); + + // Verify the field is configured correctly with tooltip text in the DOM + const spreadLabel = page.getByText('Spread').first(); + await expect(spreadLabel).toBeVisible(); + }); + + test('should maintain configuration values when switching between queries', async ({ + gotoDashboardPage, + page, + selectors, + }) => { + // Create new dashboard + const dashboardPage = await gotoDashboardPage({}); + + // Add new panel + await dashboardPage.addPanel(); + + // Configure multiple random walk parameters + await page.locator('#randomWalk-seriesCount-A').fill('2'); + await page.locator('#randomWalk-startValue-A').fill('75'); + await page.locator('#randomWalk-min-A').fill('20'); + await page.locator('#randomWalk-max-A').fill('90'); + await page.locator('#randomWalk-spread-A').fill('3'); + await page.locator('#randomWalk-noise-A').fill('1.5'); + + // Wait for query to execute + await page.waitForTimeout(500); + + // Verify all values are set correctly + await expect(page.locator('#randomWalk-seriesCount-A')).toHaveValue('2'); + await expect(page.locator('#randomWalk-startValue-A')).toHaveValue('75'); + await expect(page.locator('#randomWalk-min-A')).toHaveValue('20'); + await expect(page.locator('#randomWalk-max-A')).toHaveValue('90'); + await expect(page.locator('#randomWalk-spread-A')).toHaveValue('3'); + await expect(page.locator('#randomWalk-noise-A')).toHaveValue('1.5'); + + // Verify graph renders with the configured data + await expect( + dashboardPage.getByGrafanaSelector(selectors.components.VizLegend.seriesName('A-series')) + ).toBeVisible(); + }); + + test('should verify series count actually generates multiple series', async ({ + gotoDashboardPage, + page, + selectors, + }) => { + // Create new dashboard + const dashboardPage = await gotoDashboardPage({}); + + // Add new panel + await dashboardPage.addPanel(); + + // Set series count to 1 first and verify + await page.locator('#randomWalk-seriesCount-A').fill('1'); + await page.waitForTimeout(500); + + // Check legend - with 1 series we should see only A-series + await expect( + dashboardPage.getByGrafanaSelector(selectors.components.VizLegend.seriesName('A-series')) + ).toBeVisible(); + + // Now set series count to 3 + await page.locator('#randomWalk-seriesCount-A').fill('3'); + await page.waitForTimeout(1000); + + // With multiple series, they should all render + // The backend generates multiple frames which should show in the panel + // We can verify by checking the panel has data (legend shows A-series) + await expect( + dashboardPage.getByGrafanaSelector(selectors.components.VizLegend.seriesName('A-series')) + ).toBeVisible(); + + // Verify the configuration is set + await expect(page.locator('#randomWalk-seriesCount-A')).toHaveValue('3'); + }); + } +); diff --git a/packages/grafana-data/src/types/featureToggles.gen.ts b/packages/grafana-data/src/types/featureToggles.gen.ts index 2855555733a..1f166051adc 100644 --- a/packages/grafana-data/src/types/featureToggles.gen.ts +++ b/packages/grafana-data/src/types/featureToggles.gen.ts @@ -1232,4 +1232,8 @@ export interface FeatureToggles { * @default true */ onlyStoreActionSets?: boolean; + /** + * Enable template dashboards + */ + dashboardTemplates?: boolean; } diff --git a/pkg/services/featuremgmt/registry.go b/pkg/services/featuremgmt/registry.go index 491c1142b3b..edbc06b0029 100644 --- a/pkg/services/featuremgmt/registry.go +++ b/pkg/services/featuremgmt/registry.go @@ -2133,6 +2133,13 @@ var ( Owner: identityAccessTeam, Expression: "true", }, + { + Name: "dashboardTemplates", + Description: "Enable template dashboards", + Stage: FeatureStageExperimental, + Owner: grafanaSharingSquad, + FrontendOnly: false, + }, } ) diff --git a/pkg/services/featuremgmt/toggles_gen.csv b/pkg/services/featuremgmt/toggles_gen.csv index 4b64ee08612..9a51e087cd6 100644 --- a/pkg/services/featuremgmt/toggles_gen.csv +++ b/pkg/services/featuremgmt/toggles_gen.csv @@ -274,3 +274,4 @@ newGauge,experimental,@grafana/dataviz-squad,false,false,true preventPanelChromeOverflow,preview,@grafana/grafana-frontend-platform,false,false,true pluginStoreServiceLoading,experimental,@grafana/plugins-platform-backend,false,false,false onlyStoreActionSets,GA,@grafana/identity-access-team,false,false,false +dashboardTemplates,experimental,@grafana/sharing-squad,false,false,false diff --git a/pkg/services/featuremgmt/toggles_gen.go b/pkg/services/featuremgmt/toggles_gen.go index 8b28acc992b..13e47ce210e 100644 --- a/pkg/services/featuremgmt/toggles_gen.go +++ b/pkg/services/featuremgmt/toggles_gen.go @@ -1105,4 +1105,8 @@ const ( // FlagOnlyStoreActionSets // When storing dashboard and folder resource permissions, only store action sets and not the full list of underlying permission FlagOnlyStoreActionSets = "onlyStoreActionSets" + + // FlagDashboardTemplates + // Enable template dashboards + FlagDashboardTemplates = "dashboardTemplates" ) diff --git a/pkg/services/featuremgmt/toggles_gen.json b/pkg/services/featuremgmt/toggles_gen.json index 2019ca4b976..583c41b5d42 100644 --- a/pkg/services/featuremgmt/toggles_gen.json +++ b/pkg/services/featuremgmt/toggles_gen.json @@ -1161,6 +1161,18 @@ "codeowner": "@grafana/grafana-app-platform-squad" } }, + { + "metadata": { + "name": "dashboardTemplates", + "resourceVersion": "1761575312733", + "creationTimestamp": "2025-10-27T14:28:32Z" + }, + "spec": { + "description": "Enable template dashboards", + "stage": "experimental", + "codeowner": "@grafana/sharing-squad" + } + }, { "metadata": { "name": "dashboardUndoRedo", diff --git a/pkg/tsdb/grafanads/grafana.go b/pkg/tsdb/grafanads/grafana.go index 3953e17dc5e..06254b7f0b8 100644 --- a/pkg/tsdb/grafanads/grafana.go +++ b/pkg/tsdb/grafanads/grafana.go @@ -169,12 +169,24 @@ func (s *Service) doReadQuery(ctx context.Context, query backend.DataQuery) back func (s *Service) doRandomWalk(query backend.DataQuery) backend.DataResponse { response := backend.DataResponse{} - model, err := testdatasource.GetJSONModel(json.RawMessage{}) + model, err := testdatasource.GetJSONModel(query.JSON) if err != nil { response.Error = err return response } - response.Frames = data.Frames{testdatasource.RandomWalk(query, model, 0)} + + // Default to 1 series if not specified + seriesCount := model.SeriesCount + if seriesCount == 0 { + seriesCount = 1 + } + + // Generate the requested number of series + frames := make([]*data.Frame, 0, seriesCount) + for i := 0; i < seriesCount; i++ { + frames = append(frames, testdatasource.RandomWalk(query, model, i)) + } + response.Frames = frames return response } diff --git a/public/app/plugins/datasource/grafana/components/QueryEditor.test.tsx b/public/app/plugins/datasource/grafana/components/QueryEditor.test.tsx new file mode 100644 index 00000000000..46b1f690f04 --- /dev/null +++ b/public/app/plugins/datasource/grafana/components/QueryEditor.test.tsx @@ -0,0 +1,78 @@ +import { render, waitFor } from '@testing-library/react'; +import { act } from 'react'; + +import { config } from '@grafana/runtime'; + +import { GrafanaDatasource } from '../datasource'; +import { GrafanaQuery, GrafanaQueryType } from '../types'; + +import { QueryEditor } from './QueryEditor'; + +jest.mock('@grafana/runtime', () => ({ + ...jest.requireActual('@grafana/runtime'), + config: { + featureToggles: {}, + }, +})); + +jest.mock('app/features/live/info', () => ({ + getManagedChannelInfo: jest.fn(() => Promise.resolve({ channels: [], channelFields: {} })), +})); + +describe('QueryEditor', () => { + const mockOnChange = jest.fn(); + const mockOnRunQuery = jest.fn(); + const mockDatasource = {} as GrafanaDatasource; + + beforeEach(() => { + jest.clearAllMocks(); + }); + + describe('Random Walk configuration', () => { + it('should render random walk editor when feature toggle is enabled', async () => { + config.featureToggles.dashboardTemplates = true; + + const query: GrafanaQuery = { + refId: 'A', + queryType: GrafanaQueryType.RandomWalk, + }; + + await act(async () => { + render( + + ); + }); + + // Wait for async operations to complete + await waitFor(() => { + // Verify random walk configuration fields are rendered using IDs + expect(document.querySelector('#randomWalk-seriesCount-A')).toBeInTheDocument(); + expect(document.querySelector('#randomWalk-startValue-A')).toBeInTheDocument(); + expect(document.querySelector('#randomWalk-spread-A')).toBeInTheDocument(); + }); + }); + + it('should not render random walk editor when feature toggle is disabled', async () => { + config.featureToggles.dashboardTemplates = false; + + const query: GrafanaQuery = { + refId: 'A', + queryType: GrafanaQueryType.RandomWalk, + }; + + await act(async () => { + render( + + ); + }); + + // Wait for component to settle + await waitFor(() => { + // Verify random walk configuration fields are NOT rendered + expect(document.querySelector('#randomWalk-seriesCount-A')).not.toBeInTheDocument(); + expect(document.querySelector('#randomWalk-startValue-A')).not.toBeInTheDocument(); + expect(document.querySelector('#randomWalk-spread-A')).not.toBeInTheDocument(); + }); + }); + }); +}); diff --git a/public/app/plugins/datasource/grafana/components/QueryEditor.tsx b/public/app/plugins/datasource/grafana/components/QueryEditor.tsx index c1534f58378..8afe9701082 100644 --- a/public/app/plugins/datasource/grafana/components/QueryEditor.tsx +++ b/public/app/plugins/datasource/grafana/components/QueryEditor.tsx @@ -40,6 +40,7 @@ import { SearchQuery } from 'app/features/search/service/types'; import { GrafanaDatasource } from '../datasource'; import { defaultQuery, GrafanaQuery, GrafanaQueryType } from '../types'; +import { RandomWalkEditor } from './RandomWalkEditor'; import SearchEditor from './SearchEditor'; interface Props extends QueryEditorProps, Themeable2 {} @@ -450,6 +451,11 @@ export class UnthemedQueryEditor extends PureComponent { onRunQuery(); }; + renderRandomWalkQuery() { + const { query, onChange, onRunQuery } = this.props; + return ; + } + render() { const query = { ...defaultQuery, @@ -487,6 +493,9 @@ export class UnthemedQueryEditor extends PureComponent { /> + {queryType === GrafanaQueryType.RandomWalk && + config.featureToggles.dashboardTemplates && + this.renderRandomWalkQuery()} {queryType === GrafanaQueryType.LiveMeasurements && this.renderMeasurementsQuery()} {queryType === GrafanaQueryType.List && this.renderListPublicFiles()} {queryType === GrafanaQueryType.Snapshot && this.renderSnapshotQuery()} diff --git a/public/app/plugins/datasource/grafana/components/RandomWalkEditor.tsx b/public/app/plugins/datasource/grafana/components/RandomWalkEditor.tsx new file mode 100644 index 00000000000..db85df2cb57 --- /dev/null +++ b/public/app/plugins/datasource/grafana/components/RandomWalkEditor.tsx @@ -0,0 +1,115 @@ +import { FormEvent } from 'react'; + +import { InlineField, InlineFieldRow, Input } from '@grafana/ui'; + +import { GrafanaQuery } from '../types'; + +interface RandomWalkEditorProps { + query: GrafanaQuery; + onChange: (value: GrafanaQuery) => void; + onRunQuery: () => void; +} + +interface FieldConfig { + label: string; + id: keyof GrafanaQuery; + placeholder: string; + min?: number; + step?: number; + max?: number; + tooltip?: string; +} + +// Core configuration - controls the basic shape and range +const coreFields: FieldConfig[] = [ + { + label: 'Series count', + id: 'seriesCount', + placeholder: '1', + min: 1, + step: 1, + tooltip: 'Number of series to generate', + }, + { + label: 'Start value', + id: 'startValue', + placeholder: 'auto', + step: 1, + tooltip: 'Initial value for the random walk', + }, + { label: 'Min', id: 'min', placeholder: 'none', step: 0.1 }, + { label: 'Max', id: 'max', placeholder: 'none', step: 0.1 }, +]; + +// Fine-tuning parameters - controls randomness and variation +const advancedFields: FieldConfig[] = [ + { + label: 'Spread', + id: 'spread', + placeholder: '1', + min: 0.5, + step: 0.1, + tooltip: 'Maximum step size between values. Higher values create more dramatic changes.', + }, + { + label: 'Noise', + id: 'noise', + placeholder: '0', + min: 0, + step: 0.1, + tooltip: 'Random noise added to each value. Higher values create more variability.', + }, + { + label: 'Drop (%)', + id: 'dropPercent', + placeholder: '0', + min: 0, + max: 100, + step: 1, + tooltip: 'Percentage of points to randomly drop (simulates missing data)', + }, +]; + +const labelWidth = 16; + +export const RandomWalkEditor = ({ query, onChange, onRunQuery }: RandomWalkEditorProps) => { + const onInputChange = (e: FormEvent) => { + const { name, value } = e.currentTarget; + const numValue = value === '' ? undefined : parseFloat(value); + + onChange({ + ...query, + [name]: numValue, + }); + onRunQuery(); + }; + + const renderField = (fieldConfig: FieldConfig) => { + const { label, id, min, step, max, placeholder, tooltip } = fieldConfig; + const value = query[id]; + + return ( + + + + ); + }; + + return ( + <> + {coreFields.map(renderField)} + {advancedFields.map(renderField)} + + ); +}; diff --git a/public/app/plugins/datasource/grafana/types.ts b/public/app/plugins/datasource/grafana/types.ts index 52202904c00..d6efe49bc4f 100644 --- a/public/app/plugins/datasource/grafana/types.ts +++ b/public/app/plugins/datasource/grafana/types.ts @@ -33,6 +33,14 @@ export interface GrafanaQuery extends DataQuery { snapshot?: DataFrameJSON[]; timeRegion?: TimeRegionConfig; file?: GrafanaQueryFile; + // Random walk configuration + seriesCount?: number; + startValue?: number; + min?: number; + max?: number; + spread?: number; + noise?: number; + dropPercent?: number; } export interface GrafanaQueryFile { From 237ab6c1b40d8d0f207449e218b59e15ea76dbc2 Mon Sep 17 00:00:00 2001 From: Paul Marbach Date: Tue, 28 Oct 2025 16:37:28 -0400 Subject: [PATCH 065/378] Table: Pill and JSON Cells should allow formatting (#111951) * Table: PillCell should use formatted text inside pills * Table: JSONCell should use formatted text * remove unused imports --- .../Table/TableNG/Cells/PillCell.test.tsx | 24 +++++++++++++ .../Table/TableNG/Cells/PillCell.tsx | 6 ++-- .../src/components/Table/TableNG/TableNG.tsx | 2 +- .../components/Table/TableNG/utils.test.ts | 34 ++++++++++++++++--- .../src/components/Table/TableNG/utils.ts | 31 ++++++++--------- 5 files changed, 73 insertions(+), 24 deletions(-) diff --git a/packages/grafana-ui/src/components/Table/TableNG/Cells/PillCell.test.tsx b/packages/grafana-ui/src/components/Table/TableNG/Cells/PillCell.test.tsx index f8b20c8f312..f7a46e13add 100644 --- a/packages/grafana-ui/src/components/Table/TableNG/Cells/PillCell.test.tsx +++ b/packages/grafana-ui/src/components/Table/TableNG/Cells/PillCell.test.tsx @@ -14,6 +14,7 @@ describe('PillCell', () => { type: FieldType.string, values: values, config: {}, + display: (value: unknown) => ({ text: String(value), color: '#FF780A', numeric: NaN }), }); const ser = new XMLSerializer(); @@ -165,6 +166,29 @@ describe('PillCell', () => { ` ); }); + + it('custom display text', () => { + const mockField = fieldWithValues(['value1,value2,value3']); + const field = { + ...mockField, + display: (value: unknown) => ({ + text: `${value} lbs`, + color: '#FF780A', + numeric: 0, + }), + } satisfies Field; + + expectHTML( + render( + + ), + ` + value1 lbs + value2 lbs + value3 lbs + ` + ); + }); }); describe('Color by value mappings', () => { diff --git a/packages/grafana-ui/src/components/Table/TableNG/Cells/PillCell.tsx b/packages/grafana-ui/src/components/Table/TableNG/Cells/PillCell.tsx index d304df96da3..1aecedbd961 100644 --- a/packages/grafana-ui/src/components/Table/TableNG/Cells/PillCell.tsx +++ b/packages/grafana-ui/src/components/Table/TableNG/Cells/PillCell.tsx @@ -8,6 +8,7 @@ import { getColorByStringHash, FALLBACK_COLOR, fieldColorModeRegistry, + formattedValueToString, } from '@grafana/data'; import { FieldColorModeId } from '@grafana/schema'; @@ -20,10 +21,11 @@ export function PillCell({ rowIdx, field, theme, getTextColorForBackground }: Pi const pillValues = inferPills(value); return pillValues.length > 0 ? pillValues.map((pill, index) => { - const bgColor = getPillColor(pill, field, theme); + const renderedValue = formattedValueToString(field.display!(pill)); + const bgColor = getPillColor(renderedValue, field, theme); const textColor = getTextColorForBackground(bgColor); return { - value: String(pill), + value: renderedValue, key: `${pill}-${index}`, bgColor, color: textColor, diff --git a/packages/grafana-ui/src/components/Table/TableNG/TableNG.tsx b/packages/grafana-ui/src/components/Table/TableNG/TableNG.tsx index 17c54fde979..f5fb37b68d9 100644 --- a/packages/grafana-ui/src/components/Table/TableNG/TableNG.tsx +++ b/packages/grafana-ui/src/components/Table/TableNG/TableNG.tsx @@ -439,7 +439,7 @@ export function TableNG(props: TableNGProps) { // attach JSONCell custom display function to JSONView cell type if (cellType === TableCellDisplayMode.JSONView || field.type === FieldType.other) { - field.display = displayJsonValue; + field.display = displayJsonValue(field); } // For some cells, "aligning" the cell will mean aligning the inline contents of the cell with diff --git a/packages/grafana-ui/src/components/Table/TableNG/utils.test.ts b/packages/grafana-ui/src/components/Table/TableNG/utils.test.ts index 9109375ae17..c6060814abe 100644 --- a/packages/grafana-ui/src/components/Table/TableNG/utils.test.ts +++ b/packages/grafana-ui/src/components/Table/TableNG/utils.test.ts @@ -48,6 +48,7 @@ import { predicateByName, parseStyleJson, calculateFooterHeight, + displayJsonValue, } from './utils'; describe('TableNG utils', () => { @@ -1355,10 +1356,35 @@ describe('TableNG utils', () => { }); describe('displayJsonValue', () => { - it.todo('should parse and then stringify string values'); - it.todo('should not throw for non-serializable string values'); - it.todo('should stringify non-string values'); - it.todo('should not throw for non-serializable non-string values'); + let field: Field; + beforeEach(() => { + field = { + name: 'test', + type: FieldType.string, + config: {}, + state: { displayName: 'Test Display Name' }, + values: [], + display: (val: unknown) => ({ text: String(val), numeric: NaN }), + }; + }); + + it('should parse and then stringify string values', () => { + expect(displayJsonValue(field)('{"valid": "json"}').text).toBe('{\n "valid": "json"\n}'); + }); + + it('should not throw for non-serializable string values', () => { + expect(displayJsonValue(field)('{"invalid": "json').text).toBe('{"invalid": "json'); + }); + + it('should stringify non-string values', () => { + expect(displayJsonValue(field)(42).text).toBe('42'); + }); + + it('should use the underlying field.display method to format values and return numeric values', () => { + field.display = (val: unknown) => ({ text: `**${val}**`, numeric: Number(val), suffix: 'ms' }); + expect(displayJsonValue(field)(42).text).toBe('**42**ms'); + expect(displayJsonValue(field)(42).numeric).toBe(42); + }); }); describe('applySort', () => { diff --git a/packages/grafana-ui/src/components/Table/TableNG/utils.ts b/packages/grafana-ui/src/components/Table/TableNG/utils.ts index 848f21957b0..d2dd402217d 100644 --- a/packages/grafana-ui/src/components/Table/TableNG/utils.ts +++ b/packages/grafana-ui/src/components/Table/TableNG/utils.ts @@ -15,6 +15,7 @@ import { DisplayValueAlignmentFactors, DataFrame, DisplayProcessor, + DecimalCount, } from '@grafana/data'; import { BarGaugeDisplayMode, @@ -970,28 +971,24 @@ export function canFieldBeColorized( ); } -export const displayJsonValue: DisplayProcessor = (value: unknown): DisplayValue => { - let displayValue: string; +export const displayJsonValue: (field: Field) => DisplayProcessor = (field: Field, decimals?: DecimalCount) => { + const origDisplay = field.display!; + return (value: unknown): DisplayValue => { + let jsonText: string; - // Handle string values that might be JSON - if (typeof value === 'string') { + const displayValue = origDisplay(value, decimals); + const formattedValue = formattedValueToString(displayValue); + + // Handle string values that might be JSON try { - const parsed = JSON.parse(value); - displayValue = JSON.stringify(parsed, null, ' '); + const parsed = JSON.parse(formattedValue); + jsonText = JSON.stringify(parsed, null, ' '); } catch { - displayValue = value; // Keep original if not valid JSON + jsonText = formattedValue; // Keep original if not valid JSON } - } else { - // For non-string values, stringify them - try { - displayValue = JSON.stringify(value, null, ' '); - } catch (error) { - // Handle circular references or other stringify errors - displayValue = String(value); - } - } - return { text: displayValue, numeric: Number.NaN }; + return { ...displayValue, text: jsonText }; + }; }; export function getSummaryCellTextAlign(textAlign: TextAlign, cellType: TableCellDisplayMode): TextAlign { From 7127b2538c79dd231582b42fd73f32df905231dd Mon Sep 17 00:00:00 2001 From: Stephanie Hingtgen Date: Tue, 28 Oct 2025 15:37:51 -0600 Subject: [PATCH 066/378] Revert "unistore: replace CDK backend with KV store backend"" (#113132) Revert "unistore: replace CDK backend with KV store backend" (#112746)" This reverts commit fe9c21ebf861825fe8c753d94d26c23b32b9374c. --- pkg/storage/unified/apistore/restoptions.go | 33 +- pkg/storage/unified/apistore/watcher_test.go | 26 +- pkg/storage/unified/client.go | 17 +- pkg/storage/unified/resource/cdk_backend.go | 418 ++++++++++++++++++ pkg/storage/unified/resource/server.go | 2 +- pkg/storage/unified/resource/server_test.go | 28 +- .../unified/resource/storage_backend.go | 45 +- .../unified/resource/storage_backend_test.go | 30 -- .../unified/testing/storage_backend.go | 48 -- 9 files changed, 471 insertions(+), 176 deletions(-) create mode 100644 pkg/storage/unified/resource/cdk_backend.go diff --git a/pkg/storage/unified/apistore/restoptions.go b/pkg/storage/unified/apistore/restoptions.go index 58f702e78c1..53ce1d2bb2a 100644 --- a/pkg/storage/unified/apistore/restoptions.go +++ b/pkg/storage/unified/apistore/restoptions.go @@ -3,11 +3,13 @@ package apistore import ( + "context" "os" "path/filepath" "time" - badger "github.com/dgraph-io/badger/v4" + "gocloud.dev/blob/fileblob" + "gocloud.dev/blob/memblob" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apiserver/pkg/registry/generic" @@ -51,29 +53,18 @@ func NewRESTOptionsGetterForClient( } func NewRESTOptionsGetterMemory(originalStorageConfig storagebackend.Config, secrets secret.InlineSecureValueSupport) (*RESTOptionsGetter, error) { - // Create BadgerDB with in-memory mode - db, err := badger.Open(badger.DefaultOptions(""). - WithInMemory(true). - WithLogger(nil)) - if err != nil { - return nil, err - } - - kv := resource.NewBadgerKV(db) - backend, err := resource.NewKVStorageBackend(resource.KVBackendOptions{ - KvStore: kv, + backend, err := resource.NewCDKBackend(context.Background(), resource.CDKBackendOptions{ + Bucket: memblob.OpenBucket(&memblob.Options{}), }) if err != nil { return nil, err } - server, err := resource.NewResourceServer(resource.ResourceServerOptions{ Backend: backend, }) if err != nil { return nil, err } - return NewRESTOptionsGetterForClient( resource.NewLocalResourceClient(server), secrets, @@ -92,27 +83,25 @@ func NewRESTOptionsGetterForFileXX(path string, path = filepath.Join(os.TempDir(), "grafana-apiserver") } - db, err := badger.Open(badger.DefaultOptions(filepath.Join(path, "badger")). - WithLogger(nil)) + bucket, err := fileblob.OpenBucket(filepath.Join(path, "resource"), &fileblob.Options{ + CreateDir: true, + Metadata: fileblob.MetadataDontWrite, // skip + }) if err != nil { return nil, err } - - kv := resource.NewBadgerKV(db) - backend, err := resource.NewKVStorageBackend(resource.KVBackendOptions{ - KvStore: kv, + backend, err := resource.NewCDKBackend(context.Background(), resource.CDKBackendOptions{ + Bucket: bucket, }) if err != nil { return nil, err } - server, err := resource.NewResourceServer(resource.ResourceServerOptions{ Backend: backend, }) if err != nil { return nil, err } - return NewRESTOptionsGetterForClient( resource.NewLocalResourceClient(server), nil, // secrets diff --git a/pkg/storage/unified/apistore/watcher_test.go b/pkg/storage/unified/apistore/watcher_test.go index d23c8700c90..afd2a77b08b 100644 --- a/pkg/storage/unified/apistore/watcher_test.go +++ b/pkg/storage/unified/apistore/watcher_test.go @@ -8,13 +8,15 @@ package apistore_test import ( "context" "fmt" + "os" "strings" "testing" "time" - badger "github.com/dgraph-io/badger/v4" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "gocloud.dev/blob/fileblob" + "gocloud.dev/blob/memblob" "k8s.io/apimachinery/pkg/api/apitesting" apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/meta" @@ -103,20 +105,24 @@ func testSetup(t testing.TB, opts ...setupOption) (context.Context, storage.Inte Resource: "pods", } + bucket := memblob.OpenBucket(nil) + if true { + tmp, err := os.MkdirTemp("", "xxx-*") + require.NoError(t, err) + + bucket, err = fileblob.OpenBucket(tmp, &fileblob.Options{ + CreateDir: true, + Metadata: fileblob.MetadataDontWrite, // skip + }) + require.NoError(t, err) + } ctx := storagetesting.NewContext() var server resource.ResourceServer switch setupOpts.storageType { case StorageTypeFile: - // Create in-memory BadgerDB for testing - db, err := badger.Open(badger.DefaultOptions(""). - WithInMemory(true). - WithLogger(nil)) - require.NoError(t, err) - - kv := resource.NewBadgerKV(db) - backend, err := resource.NewKVStorageBackend(resource.KVBackendOptions{ - KvStore: kv, + backend, err := resource.NewCDKBackend(ctx, resource.CDKBackendOptions{ + Bucket: bucket, }) require.NoError(t, err) diff --git a/pkg/storage/unified/client.go b/pkg/storage/unified/client.go index 0a4d3e630ff..b0e7f6cf275 100644 --- a/pkg/storage/unified/client.go +++ b/pkg/storage/unified/client.go @@ -6,12 +6,12 @@ import ( "path/filepath" "time" - badger "github.com/dgraph-io/badger/v4" otgrpc "github.com/opentracing-contrib/go-grpc" "github.com/opentracing/opentracing-go" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc" + "gocloud.dev/blob/fileblob" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/keepalive" @@ -111,22 +111,19 @@ func newClient(opts options.StorageOptions, if opts.DataPath == "" { opts.DataPath = filepath.Join(cfg.DataPath, "grafana-apiserver") } - - // Create BadgerDB instance - db, err := badger.Open(badger.DefaultOptions(filepath.Join(opts.DataPath, "badger")). - WithLogger(nil)) + bucket, err := fileblob.OpenBucket(filepath.Join(opts.DataPath, "resource"), &fileblob.Options{ + CreateDir: true, + Metadata: fileblob.MetadataDontWrite, // skip + }) if err != nil { return nil, err } - - kv := resource.NewBadgerKV(db) - backend, err := resource.NewKVStorageBackend(resource.KVBackendOptions{ - KvStore: kv, + backend, err := resource.NewCDKBackend(ctx, resource.CDKBackendOptions{ + Bucket: bucket, }) if err != nil { return nil, err } - server, err := resource.NewResourceServer(resource.ResourceServerOptions{ Backend: backend, Blob: resource.BlobConfig{ diff --git a/pkg/storage/unified/resource/cdk_backend.go b/pkg/storage/unified/resource/cdk_backend.go new file mode 100644 index 00000000000..0cb9628758a --- /dev/null +++ b/pkg/storage/unified/resource/cdk_backend.go @@ -0,0 +1,418 @@ +package resource + +import ( + "bytes" + "context" + "errors" + "fmt" + "io" + "iter" + "net/http" + "sort" + "strconv" + "strings" + "sync" + "sync/atomic" + "time" + + "go.opentelemetry.io/otel/trace" + "go.opentelemetry.io/otel/trace/noop" + "gocloud.dev/blob" + _ "gocloud.dev/blob/fileblob" + _ "gocloud.dev/blob/memblob" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + + "github.com/grafana/grafana/pkg/apimachinery/utils" + "github.com/grafana/grafana/pkg/storage/unified/resourcepb" +) + +type CDKBackendOptions struct { + Tracer trace.Tracer + Bucket CDKBucket + RootFolder string +} + +func NewCDKBackend(ctx context.Context, opts CDKBackendOptions) (StorageBackend, error) { + if opts.Tracer == nil { + opts.Tracer = noop.NewTracerProvider().Tracer("cdk-appending-store") + } + + if opts.Bucket == nil { + return nil, fmt.Errorf("missing bucket") + } + + found, _, err := opts.Bucket.ListPage(ctx, blob.FirstPageToken, 1, &blob.ListOptions{ + Prefix: opts.RootFolder, + Delimiter: "/", + }) + if err != nil { + return nil, err + } + if found == nil { + return nil, fmt.Errorf("the root folder does not exist") + } + + backend := &cdkBackend{ + tracer: opts.Tracer, + bucket: opts.Bucket, + root: opts.RootFolder, + } + backend.rv.Swap(time.Now().UnixMilli()) + return backend, nil +} + +type cdkBackend struct { + tracer trace.Tracer + bucket CDKBucket + root string + + mutex sync.Mutex + rv atomic.Int64 + + // Simple watch stream -- NOTE, this only works for single tenant! + broadcaster Broadcaster[*WrittenEvent] + stream chan<- *WrittenEvent +} + +func (s *cdkBackend) GetResourceLastImportTimes(ctx context.Context) iter.Seq2[ResourceLastImportTime, error] { + return func(yield func(ResourceLastImportTime, error) bool) { + yield(ResourceLastImportTime{}, errors.New("not implemented")) + } +} + +func (s *cdkBackend) ListModifiedSince(ctx context.Context, key NamespacedResource, sinceRv int64) (int64, iter.Seq2[*ModifiedResource, error]) { + return 0, func(yield func(*ModifiedResource, error) bool) { + yield(nil, errors.New("not implemented")) + } +} + +func (s *cdkBackend) getPath(key *resourcepb.ResourceKey, rv int64) string { + var buffer bytes.Buffer + buffer.WriteString(s.root) + + if key.Group == "" { + return buffer.String() + } + buffer.WriteString(key.Group) + + if key.Resource == "" { + return buffer.String() + } + buffer.WriteString("/") + buffer.WriteString(key.Resource) + + if key.Namespace == "" { + if key.Name == "" { + return buffer.String() + } + buffer.WriteString("/__cluster__") + } else { + buffer.WriteString("/") + buffer.WriteString(key.Namespace) + } + + if key.Name == "" { + return buffer.String() + } + buffer.WriteString("/") + buffer.WriteString(key.Name) + + if rv > 0 { + buffer.WriteString(fmt.Sprintf("/%d.json", rv)) + } + return buffer.String() +} + +// GetResourceStats implements Backend. +func (s *cdkBackend) GetResourceStats(ctx context.Context, namespace string, minCount int) ([]ResourceStats, error) { + return nil, fmt.Errorf("not implemented") +} + +func (s *cdkBackend) WriteEvent(ctx context.Context, event WriteEvent) (rv int64, err error) { + if event.Type == resourcepb.WatchEvent_ADDED { + // ReadResource deals with deleted values (i.e. a file exists but has generation -999). + resp := s.ReadResource(ctx, &resourcepb.ReadRequest{Key: event.Key}) + if resp.Error != nil && resp.Error.Code != http.StatusNotFound { + return 0, GetError(resp.Error) + } + if resp.Value != nil { + return 0, ErrResourceAlreadyExists + } + } + + // Scope the lock + { + s.mutex.Lock() + defer s.mutex.Unlock() + + rv = s.rv.Add(1) + err = s.bucket.WriteAll(ctx, s.getPath(event.Key, rv), event.Value, &blob.WriterOptions{ + ContentType: "application/json", + }) + } + + // notify all subscribers + if s.stream != nil { + write := &WrittenEvent{ + Type: event.Type, + Key: event.Key, + PreviousRV: event.PreviousRV, + Value: event.Value, + Timestamp: time.Now().UnixMilli(), + ResourceVersion: rv, + } + s.stream <- write + } + return rv, err +} + +func (s *cdkBackend) ReadResource(ctx context.Context, req *resourcepb.ReadRequest) *BackendReadResponse { + rv := req.ResourceVersion + + path := s.getPath(req.Key, rv) + if rv < 1 { + iter := s.bucket.List(&blob.ListOptions{Prefix: path + "/", Delimiter: "/"}) + for { + obj, err := iter.Next(ctx) + if errors.Is(err, io.EOF) { + break + } + if strings.HasSuffix(obj.Key, ".json") { + idx := strings.LastIndex(obj.Key, "/") + 1 + edx := strings.LastIndex(obj.Key, ".") + if idx > 0 { + v, err := strconv.ParseInt(obj.Key[idx:edx], 10, 64) + if err == nil && v > rv { + rv = v + path = obj.Key // find the path with biggest resource version + } + } + } + } + } + + raw, err := s.bucket.ReadAll(ctx, path) + if raw == nil && req.ResourceVersion > 0 { + if req.ResourceVersion > s.rv.Load() { + return &BackendReadResponse{ + Error: &resourcepb.ErrorResult{ + Code: http.StatusGatewayTimeout, + Reason: string(metav1.StatusReasonTimeout), // match etcd behavior + Message: "ResourceVersion is larger than max", + Details: &resourcepb.ErrorDetails{ + Causes: []*resourcepb.ErrorCause{ + { + Reason: string(metav1.CauseTypeResourceVersionTooLarge), + Message: fmt.Sprintf("requested: %d, current %d", req.ResourceVersion, s.rv.Load()), + }, + }, + }, + }, + } + } + + // If the there was an explicit request, get the latest + rsp := s.ReadResource(ctx, &resourcepb.ReadRequest{Key: req.Key}) + if rsp != nil && len(rsp.Value) > 0 { + raw = rsp.Value + rv = rsp.ResourceVersion + err = nil + } + } + if err == nil && isDeletedValue(raw) { + raw = nil + } + if raw == nil { + return &BackendReadResponse{Error: NewNotFoundError(req.Key)} + } + return &BackendReadResponse{ + Key: req.Key, + Folder: "", // TODO: implement this + ResourceVersion: rv, + Value: raw, + } +} + +func isDeletedValue(raw []byte) bool { + if bytes.Contains(raw, []byte(`"generation":-999`)) { + tmp := &unstructured.Unstructured{} + err := tmp.UnmarshalJSON(raw) + if err == nil && tmp.GetGeneration() == utils.DeletedGeneration { + return true + } + } + return false +} + +func (s *cdkBackend) ListIterator(ctx context.Context, req *resourcepb.ListRequest, cb func(ListIterator) error) (int64, error) { + resources, err := buildTree(ctx, s, req.Options.Key) + if err != nil { + return 0, err + } + err = cb(resources) + return resources.listRV, err +} + +func (s *cdkBackend) ListHistory(ctx context.Context, req *resourcepb.ListRequest, cb func(ListIterator) error) (int64, error) { + return 0, fmt.Errorf("listing from history not supported in CDK backend") +} + +func (s *cdkBackend) WatchWriteEvents(ctx context.Context) (<-chan *WrittenEvent, error) { + s.mutex.Lock() + defer s.mutex.Unlock() + + if s.broadcaster == nil { + var err error + s.broadcaster, err = NewBroadcaster(context.Background(), func(c chan<- *WrittenEvent) error { + s.stream = c + return nil + }) + if err != nil { + return nil, err + } + } + return s.broadcaster.Subscribe(ctx) +} + +// group > resource > namespace > name > versions +type cdkResource struct { + prefix string + versions []cdkVersion +} +type cdkVersion struct { + rv int64 + key string +} + +type cdkListIterator struct { + bucket CDKBucket + ctx context.Context + err error + + listRV int64 + resources []cdkResource + index int + + currentRV int64 + currentKey string + currentVal []byte +} + +// Next implements ListIterator. +func (c *cdkListIterator) Next() bool { + if c.err != nil { + return false + } + for { + c.currentVal = nil + c.index += 1 + if c.index >= len(c.resources) { + return false + } + + item := c.resources[c.index] + latest := item.versions[0] + raw, err := c.bucket.ReadAll(c.ctx, latest.key) + if err != nil { + c.err = err + return false + } + if !isDeletedValue(raw) { + c.currentRV = latest.rv + c.currentKey = latest.key + c.currentVal = raw + return true + } + } +} + +// Error implements ListIterator. +func (c *cdkListIterator) Error() error { + return c.err +} + +// ResourceVersion implements ListIterator. +func (c *cdkListIterator) ResourceVersion() int64 { + return c.currentRV +} + +// Value implements ListIterator. +func (c *cdkListIterator) Value() []byte { + return c.currentVal +} + +// ContinueToken implements ListIterator. +func (c *cdkListIterator) ContinueToken() string { + return fmt.Sprintf("index:%d/key:%s", c.index, c.currentKey) +} + +// Name implements ListIterator. +func (c *cdkListIterator) Name() string { + return c.currentKey // TODO (parse name from key) +} + +// Namespace implements ListIterator. +func (c *cdkListIterator) Namespace() string { + return c.currentKey // TODO (parse namespace from key) +} + +func (c *cdkListIterator) Folder() string { + return "" // TODO: implement this +} + +var _ ListIterator = (*cdkListIterator)(nil) + +func buildTree(ctx context.Context, s *cdkBackend, key *resourcepb.ResourceKey) (*cdkListIterator, error) { + byPrefix := make(map[string]*cdkResource) + path := s.getPath(key, 0) + iter := s.bucket.List(&blob.ListOptions{Prefix: path, Delimiter: ""}) // "" is recursive + for { + obj, err := iter.Next(ctx) + if errors.Is(err, io.EOF) { + break + } + if strings.HasSuffix(obj.Key, ".json") { + idx := strings.LastIndex(obj.Key, "/") + 1 + edx := strings.LastIndex(obj.Key, ".") + if idx > 0 { + rv, err := strconv.ParseInt(obj.Key[idx:edx], 10, 64) + if err == nil { + prefix := obj.Key[:idx] + res, ok := byPrefix[prefix] + if !ok { + res = &cdkResource{prefix: prefix} + byPrefix[prefix] = res + } + + res.versions = append(res.versions, cdkVersion{ + rv: rv, + key: obj.Key, + }) + } + } + } + } + + // Now sort all versions + resources := make([]cdkResource, 0, len(byPrefix)) + for _, res := range byPrefix { + sort.Slice(res.versions, func(i, j int) bool { + return res.versions[i].rv > res.versions[j].rv + }) + resources = append(resources, *res) + } + sort.Slice(resources, func(i, j int) bool { + a := resources[i].prefix + b := resources[j].prefix + return a < b + }) + + return &cdkListIterator{ + ctx: ctx, + bucket: s.bucket, + resources: resources, + listRV: s.rv.Load(), + index: -1, // must call next first + }, nil +} diff --git a/pkg/storage/unified/resource/server.go b/pkg/storage/unified/resource/server.go index 76c3e3c2a8c..59ae4e1dc83 100644 --- a/pkg/storage/unified/resource/server.go +++ b/pkg/storage/unified/resource/server.go @@ -1072,7 +1072,7 @@ func (s *server) List(ctx context.Context, req *resourcepb.ListRequest) (*resour pageBytes += len(item.Value) rsp.Items = append(rsp.Items, item) - if (req.Limit > 0 && len(rsp.Items) >= int(req.Limit)) || pageBytes >= maxPageBytes { + if len(rsp.Items) >= int(req.Limit) || pageBytes >= maxPageBytes { t := iter.ContinueToken() if iter.Next() { rsp.NextPageToken = t diff --git a/pkg/storage/unified/resource/server_test.go b/pkg/storage/unified/resource/server_test.go index 391a931696d..66536b4d5d8 100644 --- a/pkg/storage/unified/resource/server_test.go +++ b/pkg/storage/unified/resource/server_test.go @@ -4,17 +4,20 @@ import ( "context" "encoding/json" "errors" + "fmt" "log/slog" "net/http" + "os" "strings" "sync" "testing" "time" - badger "github.com/dgraph-io/badger/v4" "github.com/prometheus/client_golang/prometheus" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "gocloud.dev/blob/fileblob" + "gocloud.dev/blob/memblob" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" authlib "github.com/grafana/authlib/types" @@ -38,19 +41,20 @@ func TestSimpleServer(t *testing.T) { } ctx := authlib.WithAuthInfo(context.Background(), testUserA) - // Create in-memory BadgerDB for testing - db, err := badger.Open(badger.DefaultOptions(""). - WithInMemory(true). - WithLogger(nil)) - require.NoError(t, err) - defer func() { - err := db.Close() + bucket := memblob.OpenBucket(nil) + if false { + tmp, err := os.MkdirTemp("", "xxx-*") require.NoError(t, err) - }() - kv := NewBadgerKV(db) - store, err := NewKVStorageBackend(KVBackendOptions{ - KvStore: kv, + bucket, err = fileblob.OpenBucket(tmp, &fileblob.Options{ + CreateDir: true, + Metadata: fileblob.MetadataDontWrite, // skip + }) + require.NoError(t, err) + fmt.Printf("ROOT: %s\n\n", tmp) + } + store, err := NewCDKBackend(ctx, CDKBackendOptions{ + Bucket: bucket, }) require.NoError(t, err) diff --git a/pkg/storage/unified/resource/storage_backend.go b/pkg/storage/unified/resource/storage_backend.go index 4de28e758d5..24bb98c1f8b 100644 --- a/pkg/storage/unified/resource/storage_backend.go +++ b/pkg/storage/unified/resource/storage_backend.go @@ -283,40 +283,6 @@ func (k *kvStorageBackend) ReadResource(ctx context.Context, req *resourcepb.Rea if req.Key == nil { return &BackendReadResponse{Error: &resourcepb.ErrorResult{Code: http.StatusBadRequest, Message: "missing key"}} } - - // If a specific resource version is requested, validate that it's not too high - if req.ResourceVersion > 0 { - // Fetch the latest RV - latestRV := k.snowflake.Generate().Int64() - if lastEventKey, err := k.eventStore.LastEventKey(ctx); err == nil { - latestRV = lastEventKey.ResourceVersion - } else if !errors.Is(err, ErrNotFound) { - return &BackendReadResponse{Error: &resourcepb.ErrorResult{ - Code: http.StatusInternalServerError, - Message: fmt.Sprintf("failed to fetch latest resource version: %v", err), - }} - } - - // Check if the requested RV is higher than the latest available RV - if req.ResourceVersion > latestRV { - return &BackendReadResponse{ - Error: &resourcepb.ErrorResult{ - Code: http.StatusGatewayTimeout, - Reason: string(metav1.StatusReasonTimeout), // match etcd behavior - Message: "ResourceVersion is larger than max", - Details: &resourcepb.ErrorDetails{ - Causes: []*resourcepb.ErrorCause{ - { - Reason: string(metav1.CauseTypeResourceVersionTooLarge), - Message: fmt.Sprintf("requested: %d, current %d", req.ResourceVersion, latestRV), - }, - }, - }, - }, - } - } - } - meta, err := k.dataStore.GetResourceKeyAtRevision(ctx, GetRequestKey{ Group: req.Key.Group, Resource: req.Key.Resource, @@ -369,15 +335,8 @@ func (k *kvStorageBackend) ListIterator(ctx context.Context, req *resourcepb.Lis resourceVersion = token.ResourceVersion } - // We set the listRV to the last event resource version. - // If no events exist yet, we generate a new snowflake. + // We set the listRV to the current time. listRV := k.snowflake.Generate().Int64() - if lastEventKey, err := k.eventStore.LastEventKey(ctx); err == nil { - listRV = lastEventKey.ResourceVersion - } else if !errors.Is(err, ErrNotFound) { - return 0, fmt.Errorf("failed to fetch last event: %w", err) - } - if resourceVersion > 0 { listRV = resourceVersion } @@ -401,7 +360,7 @@ func (k *kvStorageBackend) ListIterator(ctx context.Context, req *resourcepb.Lis } keys = append(keys, dataKey) // Only fetch the first limit items + 1 to get the next token. - if req.Limit > 0 && len(keys) >= int(req.Limit+1) { + if len(keys) >= int(req.Limit+1) { break } } diff --git a/pkg/storage/unified/resource/storage_backend_test.go b/pkg/storage/unified/resource/storage_backend_test.go index 05920a603c4..0a1c263d216 100644 --- a/pkg/storage/unified/resource/storage_backend_test.go +++ b/pkg/storage/unified/resource/storage_backend_test.go @@ -323,36 +323,6 @@ func TestKvStorageBackend_ReadResource_DeletedResource(t *testing.T) { require.Equal(t, objectToJSONBytes(t, testObj), response.Value) } -func TestKvStorageBackend_ReadResource_TooHighResourceVersion(t *testing.T) { - backend := setupTestStorageBackend(t) - ctx := context.Background() - - // First, create a resource - _, rv := createAndWriteTestObject(t, backend) - - // Try to read with a resource version that's way too high - readReq := &resourcepb.ReadRequest{ - Key: &resourcepb.ResourceKey{ - Namespace: "default", - Group: "apps", - Resource: "resources", - Name: "test-resource", - }, - ResourceVersion: rv + 1000000000000, // Way in the future - } - - response := backend.ReadResource(ctx, readReq) - require.NotNil(t, response.Error, "ReadResource should return error for too high resource version") - require.Equal(t, int32(504), response.Error.Code) // http.StatusGatewayTimeout - require.Equal(t, "Timeout", response.Error.Reason) - require.Equal(t, "ResourceVersion is larger than max", response.Error.Message) - require.NotNil(t, response.Error.Details) - require.Len(t, response.Error.Details.Causes, 1) - require.Equal(t, "ResourceVersionTooLarge", response.Error.Details.Causes[0].Reason) - require.Contains(t, response.Error.Details.Causes[0].Message, "requested:") - require.Contains(t, response.Error.Details.Causes[0].Message, "current") -} - func TestKvStorageBackend_ListIterator_Success(t *testing.T) { backend := setupTestStorageBackend(t) ctx := context.Background() diff --git a/pkg/storage/unified/testing/storage_backend.go b/pkg/storage/unified/testing/storage_backend.go index 440f2af8a26..8ce39d55e33 100644 --- a/pkg/storage/unified/testing/storage_backend.go +++ b/pkg/storage/unified/testing/storage_backend.go @@ -387,30 +387,6 @@ func runTestIntegrationBackendList(t *testing.T, backend resource.StorageBackend require.Empty(t, res.NextPageToken) }) - t.Run("fetch all with limit 0", func(t *testing.T) { - res, err := server.List(ctx, &resourcepb.ListRequest{ - Limit: 0, - Options: &resourcepb.ListOptions{ - Key: &resourcepb.ResourceKey{ - Namespace: ns, - Group: "group", - Resource: "resource", - }, - }, - }) - require.NoError(t, err) - require.Nil(t, res.Error) - require.Len(t, res.Items, 5) - // should be sorted by key ASC - require.Contains(t, string(res.Items[0].Value), "item1 ADDED") - require.Contains(t, string(res.Items[1].Value), "item2 MODIFIED") - require.Contains(t, string(res.Items[2].Value), "item4 ADDED") - require.Contains(t, string(res.Items[3].Value), "item5 ADDED") - require.Contains(t, string(res.Items[4].Value), "item6 ADDED") - - require.Empty(t, res.NextPageToken) - }) - t.Run("list latest first page ", func(t *testing.T) { res, err := server.List(ctx, &resourcepb.ListRequest{ Limit: 3, @@ -781,30 +757,6 @@ func runTestIntegrationBackendListHistory(t *testing.T, backend resource.Storage require.Contains(t, string(secondPageRes.Items[i].Value), "item1 MODIFIED") } }) - - // Test with limit=0 (should return all items) - t.Run("fetch all history with limit 0", func(t *testing.T) { - res, err := server.List(ctx, &resourcepb.ListRequest{ - Limit: 0, - Source: resourcepb.ListRequest_HISTORY, - Options: &resourcepb.ListOptions{ - Key: baseKey, - }, - }) - require.NoError(t, err) - require.Nil(t, res.Error) - require.Len(t, res.Items, 6) // Should return all 6 history items (1 ADDED + 5 MODIFIED) - - // Should be in descending order (default for history) - require.Equal(t, rvHistory5, res.Items[0].ResourceVersion) - require.Equal(t, rvHistory4, res.Items[1].ResourceVersion) - require.Equal(t, rvHistory3, res.Items[2].ResourceVersion) - require.Equal(t, rvHistory2, res.Items[3].ResourceVersion) - require.Equal(t, rvHistory1, res.Items[4].ResourceVersion) - require.Equal(t, rv1, res.Items[5].ResourceVersion) - - require.Empty(t, res.NextPageToken) - }) }) t.Run("fetch second page of history at revision", func(t *testing.T) { From 329d6a11faf985e18e51d4c2851dd3abc20c21f7 Mon Sep 17 00:00:00 2001 From: Paul Marbach Date: Tue, 28 Oct 2025 17:50:46 -0400 Subject: [PATCH 067/378] Table: Fix cell inspect for Sparkline and inferred JSON cells (#113059) * Table: Sparkline Cell inspect support * update to better support FieldType.other structures * clean up styling a bit for empty case * fix test import * add test for no x case for sparkline * fix merge mistake * fix test import --- eslint-suppressions.json | 5 - .../components/Table/TableCellInspector.tsx | 41 ++--- .../Table/TableNG/Cells/SparklineCell.tsx | 38 +---- .../src/components/Table/TableNG/TableNG.tsx | 1 - .../TableNG/__snapshots__/utils.test.ts.snap | 109 +++++++++++++ .../TableNG/components/TableCellActions.tsx | 38 +---- .../src/components/Table/TableNG/types.ts | 2 +- .../components/Table/TableNG/utils.test.ts | 151 ++++++++++++++++++ .../src/components/Table/TableNG/utils.ts | 76 ++++++++- 9 files changed, 359 insertions(+), 102 deletions(-) create mode 100644 packages/grafana-ui/src/components/Table/TableNG/__snapshots__/utils.test.ts.snap diff --git a/eslint-suppressions.json b/eslint-suppressions.json index 708c8f9fbcc..fdcf848a354 100644 --- a/eslint-suppressions.json +++ b/eslint-suppressions.json @@ -927,11 +927,6 @@ "count": 1 } }, - "packages/grafana-ui/src/components/Table/TableCellInspector.tsx": { - "@typescript-eslint/no-explicit-any": { - "count": 1 - } - }, "packages/grafana-ui/src/components/Table/TableNG/TableNG.test.tsx": { "@typescript-eslint/no-explicit-any": { "count": 2 diff --git a/packages/grafana-ui/src/components/Table/TableCellInspector.tsx b/packages/grafana-ui/src/components/Table/TableCellInspector.tsx index ed7f9111773..10169328ba4 100644 --- a/packages/grafana-ui/src/components/Table/TableCellInspector.tsx +++ b/packages/grafana-ui/src/components/Table/TableCellInspector.tsx @@ -1,8 +1,10 @@ -import { isString } from 'lodash'; +import { css } from '@emotion/css'; import { useState } from 'react'; +import { GrafanaTheme2 } from '@grafana/data'; import { t, Trans } from '@grafana/i18n'; +import { useStyles2 } from '../../themes/ThemeContext'; import { ClipboardButton } from '../ClipboardButton/ClipboardButton'; import { Drawer } from '../Drawer/Drawer'; import { Stack } from '../Layout/Stack/Stack'; @@ -17,34 +19,15 @@ export enum TableCellInspectorMode { interface TableCellInspectorProps { // eslint-disable-next-line @typescript-eslint/no-explicit-any - value: any; + value: string; onDismiss: () => void; mode: TableCellInspectorMode; } export function TableCellInspector({ value, onDismiss, mode }: TableCellInspectorProps) { - let displayValue = value; const [currentMode, setMode] = useState(mode); - - if (isString(value)) { - const trimmedValue = value.trim(); - // Exclude numeric strings like '123' from being displayed in code/JSON mode - if (trimmedValue[0] === '{' || trimmedValue[0] === '[' || mode === 'code') { - try { - value = JSON.parse(value); - displayValue = JSON.stringify(value, null, ' '); - } catch (error: any) { - // Display helpful error to help folks diagnose json errors - console.log( - 'Failed to parse JSON in Table cell inspector (this will cause JSON to not print nicely): ', - error.message - ); - } - } - } else { - displayValue = JSON.stringify(value); - } - let text = displayValue; + const text = value.trim(); + const styles = useStyles2(getStyles); const tabs = [ { @@ -81,15 +64,23 @@ export function TableCellInspector({ value, onDismiss, mode }: TableCellInspecto height={500} language="json" showLineNumbers={true} - showMiniMap={(text && text.length) > 100} + showMiniMap={(text ? text.length : 0) > 100} value={text} readOnly={true} wordWrap={true} /> ) : ( -
{text}
+
{text}
)} ); } + +// TODO: should we have different empty styles? +const getStyles = (theme: GrafanaTheme2) => ({ + textContainer: css({ + color: theme.colors.text.secondary, + minHeight: 42, + }), +}); diff --git a/packages/grafana-ui/src/components/Table/TableNG/Cells/SparklineCell.tsx b/packages/grafana-ui/src/components/Table/TableNG/Cells/SparklineCell.tsx index 08f8b8b6cd1..acedb2091a7 100644 --- a/packages/grafana-ui/src/components/Table/TableNG/Cells/SparklineCell.tsx +++ b/packages/grafana-ui/src/components/Table/TableNG/Cells/SparklineCell.tsx @@ -1,15 +1,7 @@ import { css } from '@emotion/css'; import * as React from 'react'; -import { - FieldType, - FieldConfig, - getMinMaxAndDelta, - FieldSparkline, - isDataFrame, - Field, - isDataFrameWithValue, -} from '@grafana/data'; +import { FieldConfig, getMinMaxAndDelta, Field, isDataFrameWithValue } from '@grafana/data'; import { t } from '@grafana/i18n'; import { BarAlignment, @@ -26,7 +18,7 @@ import { measureText } from '../../../../utils/measureText'; import { FormattedValueDisplay } from '../../../FormattedValueDisplay/FormattedValueDisplay'; import { Sparkline } from '../../../Sparkline/Sparkline'; import { SparklineCellProps, TableCellStyles } from '../types'; -import { getAlignmentFactor, getCellOptions } from '../utils'; +import { getAlignmentFactor, getCellOptions, prepareSparklineValue } from '../utils'; export const defaultSparklineCellConfig: TableSparklineCellOptions = { type: TableCellDisplayMode.Sparkline, @@ -43,7 +35,7 @@ export const defaultSparklineCellConfig: TableSparklineCellOptions = { export const SparklineCell = (props: SparklineCellProps) => { const { field, value, theme, timeRange, rowIdx, width } = props; - const sparkline = getSparkline(value, field); + const sparkline = prepareSparklineValue(value, field); if (!sparkline) { return <>{field.config.noValue || t('grafana-ui.table.sparkline.no-data', 'no data')}; @@ -102,30 +94,6 @@ export const SparklineCell = (props: SparklineCellProps) => { ); }; -function getSparkline(value: unknown, field: Field): FieldSparkline | undefined { - if (Array.isArray(value)) { - return { - y: { - name: `${field.name}-sparkline`, - type: FieldType.number, - values: value, - config: {}, - }, - }; - } - - if (isDataFrame(value)) { - const timeField = value.fields.find((x) => x.type === FieldType.time); - const numberField = value.fields.find((x) => x.type === FieldType.number); - - if (timeField && numberField) { - return { x: timeField, y: numberField }; - } - } - - return; -} - function getTableSparklineCellOptions(field: Field): TableSparklineCellOptions { let options = getCellOptions(field); if (options.type === TableCellDisplayMode.Auto) { diff --git a/packages/grafana-ui/src/components/Table/TableNG/TableNG.tsx b/packages/grafana-ui/src/components/Table/TableNG/TableNG.tsx index f5fb37b68d9..5f64c58773a 100644 --- a/packages/grafana-ui/src/components/Table/TableNG/TableNG.tsx +++ b/packages/grafana-ui/src/components/Table/TableNG/TableNG.tsx @@ -563,7 +563,6 @@ export function TableNG(props: TableNGProps) { ( + ({ field, value, setInspectCell, onCellFilterAdded, className, cellInspect, showFilters }: TableCellActionsProps) => ( // stopping propagation to prevent clicks within the actions menu from triggering the cell click events // for things like the data links tooltip. // eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions @@ -31,24 +17,8 @@ export const TableCellActions = memo( name="eye" aria-label={t('grafana-ui.table.cell-inspect-tooltip', 'Inspect value')} onClick={() => { - let inspectValue = value; - let mode = TableCellInspectorMode.text; - - if (field.type === FieldType.geo && value instanceof Geometry) { - inspectValue = new WKT().writeGeometry(value, { - featureProjection: 'EPSG:3857', - dataProjection: 'EPSG:4326', - }); - mode = TableCellInspectorMode.code; - } - if (cellOptions.type === TableCellDisplayMode.JSONView) { - mode = TableCellInspectorMode.code; - } - - setInspectCell({ - value: String(inspectValue ?? ''), - mode, - }); + const [inspectValue, mode] = buildInspectValue(value, field); + setInspectCell({ value: inspectValue, mode }); }} /> )} diff --git a/packages/grafana-ui/src/components/Table/TableNG/types.ts b/packages/grafana-ui/src/components/Table/TableNG/types.ts index 376fe895ba2..c4d63b2826b 100644 --- a/packages/grafana-ui/src/components/Table/TableNG/types.ts +++ b/packages/grafana-ui/src/components/Table/TableNG/types.ts @@ -167,12 +167,12 @@ export type InspectCellProps = { rowIdx?: number; value: string; mode?: TableCellInspectorMode.code | TableCellInspectorMode.text; + preformatted?: boolean; }; export interface TableCellActionsProps { field: Field; value: TableCellValue; - cellOptions: TableCellOptions; displayName: string; cellInspect: boolean; showFilters: boolean; diff --git a/packages/grafana-ui/src/components/Table/TableNG/utils.test.ts b/packages/grafana-ui/src/components/Table/TableNG/utils.test.ts index c6060814abe..d788ccdcb63 100644 --- a/packages/grafana-ui/src/components/Table/TableNG/utils.test.ts +++ b/packages/grafana-ui/src/components/Table/TableNG/utils.test.ts @@ -1,3 +1,4 @@ +import { Point } from 'ol/geom'; import { SortColumn } from 'react-data-grid'; import { @@ -49,6 +50,8 @@ import { parseStyleJson, calculateFooterHeight, displayJsonValue, + prepareSparklineValue, + buildInspectValue, } from './utils'; describe('TableNG utils', () => { @@ -1531,4 +1534,152 @@ describe('TableNG utils', () => { expect(parseStyleJson('{"notARealStyle": "someValue"}')).toEqual({ notARealStyle: 'someValue' }); }); }); + + describe('prepareSparklineValue', () => { + it('should return an array of numbers when given an array of numbers', () => { + expect( + prepareSparklineValue([1, 2, 3, 4, 5], { + name: 'test', + type: FieldType.number, + values: [1, 2, 3, 4, 5], + config: {}, + }) + ).toEqual({ + y: { + name: `test-sparkline`, + type: FieldType.number, + values: [1, 2, 3, 4, 5], + config: {}, + }, + }); + }); + + it('should parse the x and y values from a dataframe', () => { + const frame = createDataFrame({ + fields: [ + { name: 'x', type: FieldType.time, values: [0, 1000, 2000, 3000, 4000] }, + { name: 'y', type: FieldType.number, values: [10, 20, 30, 40, 50] }, + ], + }); + expect( + prepareSparklineValue(frame, { + name: 'test', + type: FieldType.frame, + values: [frame], + config: {}, + }) + ).toEqual({ + x: { + name: 'x', + type: FieldType.time, + values: [0, 1000, 2000, 3000, 4000], + config: {}, + }, + y: { + name: 'y', + type: FieldType.number, + values: [10, 20, 30, 40, 50], + config: {}, + }, + }); + }); + + it('should return undefined for non-array and non-dataframe values', () => { + expect( + prepareSparklineValue('not an array or dataframe', { + name: 'test', + type: FieldType.string, + values: ['a', 'b', 'c'], + config: {}, + }) + ).toBeUndefined(); + }); + }); + + describe('buildInspectValue', () => { + const numberFieldWithNulls: Field = { + name: 'numbers-with-nulls', + type: FieldType.number, + values: [0, 1, 2, null, NaN], + config: {}, + }; + const stringField: Field = { + name: 'string', + type: FieldType.string, + values: ['foo', 'bar', 'baz', null], + config: {}, + }; + const jsonStringField: Field = { + ...stringField, + config: { custom: { cellOptions: { type: TableCellDisplayMode.JSONView } } }, + }; + const booleanField: Field = { + name: 'boolean-field', + type: FieldType.boolean, + values: [true, false, true], + config: {}, + }; + const sparklineField: Field = { + name: 'sparkline-field', + type: FieldType.frame, + values: [ + createDataFrame({ + fields: [ + { name: 'x', type: FieldType.time, values: [0, 1000, 2000] }, + { name: 'y', type: FieldType.number, values: [10, 20, 30] }, + ], + }), + ], + config: {}, + }; + const sparklineFieldNoX: Field = { + name: 'sparkline-field-no-x', + type: FieldType.other, + values: [[2, 4, 6, 8, 10]], + config: { + custom: { cellOptions: { type: TableCellDisplayMode.Sparkline } }, + }, + }; + const arrayField: Field = { + name: 'array-field', + type: FieldType.other, + values: [ + ['foo', 'bar', 'baz'], + ['one', 'two', 'three'], + ], + config: {}, + }; + const objectField: Field = { + name: 'array-field', + type: FieldType.other, + values: [ + { foo: true, b: 'baz' }, + { foo: false, b: 'qux' }, + ], + config: {}, + }; + const geoField: Field = { + name: 'geo-field', + type: FieldType.geo, + values: [new Point([0, -74.1])], + config: {}, + }; + it.each([ + { name: 'numbers', input: { valueIdx: 0, field: numberFieldWithNulls } }, + { name: 'string', input: { valueIdx: 0, field: stringField } }, + { name: 'string w/ JSON', input: { valueIdx: 2, field: jsonStringField } }, + { name: 'boolean', input: { valueIdx: 0, field: booleanField } }, + { name: 'NaN', input: { valueIdx: 4, field: numberFieldWithNulls } }, + { name: 'null', input: { valueIdx: 3, field: numberFieldWithNulls } }, + { name: 'null w/ JSON', input: { valueIdx: 3, field: jsonStringField } }, + { name: 'undefined', input: { valueIdx: 6, field: numberFieldWithNulls } }, + { name: 'sparkline', input: { valueIdx: 0, field: sparklineField } }, + { name: 'sparkline (no x)', input: { valueIdx: 0, field: sparklineFieldNoX } }, + { name: 'array', input: { valueIdx: 0, field: arrayField } }, + { name: 'object', input: { valueIdx: 0, field: objectField } }, + { name: 'geo', input: { valueIdx: 0, field: geoField } }, + ])('should handle $name', ({ input: { field, valueIdx = 0 } }) => { + expect(buildInspectValue(field.values[valueIdx], field)).toMatchSnapshot(); + }); + }); }); diff --git a/packages/grafana-ui/src/components/Table/TableNG/utils.ts b/packages/grafana-ui/src/components/Table/TableNG/utils.ts index d2dd402217d..e3ab23b3e0e 100644 --- a/packages/grafana-ui/src/components/Table/TableNG/utils.ts +++ b/packages/grafana-ui/src/components/Table/TableNG/utils.ts @@ -1,5 +1,7 @@ import { Property } from 'csstype'; import memoize from 'micro-memoize'; +import WKT from 'ol/format/WKT'; +import Geometry from 'ol/geom/Geometry'; import { CSSProperties } from 'react'; import { SortColumn } from 'react-data-grid'; import tinycolor from 'tinycolor2'; @@ -15,6 +17,8 @@ import { DisplayValueAlignmentFactors, DataFrame, DisplayProcessor, + isDataFrame, + FieldSparkline, DecimalCount, } from '@grafana/data'; import { @@ -26,10 +30,11 @@ import { } from '@grafana/schema'; import { getTextColorForAlphaBackground } from '../../../utils/colors'; +import { TableCellInspectorMode } from '../TableCellInspector'; import { TableCellOptions } from '../types'; import { inferPills } from './Cells/PillCell'; -import { AutoCellRenderer, getCellRenderer } from './Cells/renderers'; +import { AutoCellRenderer, getAutoRendererDisplayMode, getCellRenderer } from './Cells/renderers'; import { COLUMN, TABLE } from './constants'; import { TableRow, @@ -991,6 +996,75 @@ export const displayJsonValue: (field: Field) => DisplayProcessor = (field: Fiel }; }; +export function prepareSparklineValue(value: unknown, field: Field): FieldSparkline | undefined { + if (Array.isArray(value)) { + return { + y: { + name: `${field.name}-sparkline`, + type: FieldType.number, + values: value, + config: {}, + }, + }; + } + + if (isDataFrame(value)) { + const timeField = value.fields.find((x) => x.type === FieldType.time); + const numberField = value.fields.find((x) => x.type === FieldType.number); + + if (timeField && numberField) { + return { x: timeField, y: numberField }; + } + } + + return; +} + +function isPlainObject(value: unknown): value is object { + return typeof value === 'object' && value != null && !Array.isArray(value); +} + +export function buildInspectValue(value: unknown, field: Field): [string, TableCellInspectorMode] { + const cellOptions = getCellOptions(field); + + let inspectValue: string; + let mode = TableCellInspectorMode.text; + + if (field.type === FieldType.geo && value instanceof Geometry) { + inspectValue = new WKT().writeGeometry(value, { + featureProjection: 'EPSG:3857', + dataProjection: 'EPSG:4326', + }); + mode = TableCellInspectorMode.code; + } else if ( + cellOptions.type === TableCellDisplayMode.Sparkline || + getAutoRendererDisplayMode(field) === TableCellDisplayMode.Sparkline + ) { + // rather than JSON.stringify this, manually format it to make the coordinate tuples more legible to the user. + const fieldSparkline = prepareSparklineValue(value, field); + inspectValue = '['; + if (fieldSparkline != null) { + // if an x value exists, render as a tuple [x,y], otherwise just y + const buildValString: (idx: number) => string = + fieldSparkline.x != null + ? (idx) => `[${fieldSparkline.x!.values[idx] ?? 'null'}, ${fieldSparkline.y.values[idx] ?? 'null'}]` + : (idx) => `${fieldSparkline.y.values[idx] ?? 'null'}`; + for (let i = 0; i < fieldSparkline.y.values.length; i++) { + inspectValue += `\n ${buildValString(i)}${i === fieldSparkline.y.values.length - 1 ? '\n' : ','}`; + } + } + inspectValue += ']'; + mode = TableCellInspectorMode.code; + } else if (cellOptions.type === TableCellDisplayMode.JSONView || Array.isArray(value) || isPlainObject(value)) { + inspectValue = JSON.stringify(value, null, ' '); + mode = TableCellInspectorMode.code; + } else { + inspectValue = String(value ?? ''); + } + + return [inspectValue, mode]; +} + export function getSummaryCellTextAlign(textAlign: TextAlign, cellType: TableCellDisplayMode): TextAlign { // gauge is weird. left-aligned gauge has the viz on the left and its numbers on the right, and vice-versa. // if you center-aligned your gauge... ok. From d72e048bfe8348c0a0b5d8ee3550cd46736ac718 Mon Sep 17 00:00:00 2001 From: Ryan McKinley Date: Wed, 29 Oct 2025 00:54:10 +0300 Subject: [PATCH 068/378] Chore: Use Kind().GroupVersionResource() (#113133) --- pkg/api/playlist.go | 7 +---- pkg/api/short_url.go | 7 +---- pkg/registry/apps/playlist/legacy_storage.go | 6 +--- pkg/registry/apps/playlist/register.go | 6 +--- pkg/registry/apps/plugins/register.go | 6 +--- pkg/registry/apps/shorturl/legacy_storage.go | 11 ++------ pkg/registry/apps/shorturl/register.go | 6 +--- .../builder/runner/admission_test.go | 19 ++++--------- pkg/services/cleanup/cleanup.go | 7 +---- .../alerting/notifications/common/testing.go | 28 ++++--------------- .../apis/alerting/rules/common/testing.go | 26 +++++------------ 11 files changed, 27 insertions(+), 102 deletions(-) diff --git a/pkg/api/playlist.go b/pkg/api/playlist.go index 4108bba14f9..632646c7c61 100644 --- a/pkg/api/playlist.go +++ b/pkg/api/playlist.go @@ -144,13 +144,8 @@ type playlistK8sHandler struct { //----------------------------------------------------------------------------------------- func newPlaylistK8sHandler(hs *HTTPServer) *playlistK8sHandler { - gvr := schema.GroupVersionResource{ - Group: v0alpha1.PlaylistKind().Group(), - Version: v0alpha1.PlaylistKind().Version(), - Resource: v0alpha1.PlaylistKind().Plural(), - } return &playlistK8sHandler{ - gvr: gvr, + gvr: v0alpha1.PlaylistKind().GroupVersionResource(), namespacer: request.GetNamespaceMapper(hs.Cfg), clientConfigProvider: hs.clientConfigProvider, } diff --git a/pkg/api/short_url.go b/pkg/api/short_url.go index 763c58395ad..b07e1488e05 100644 --- a/pkg/api/short_url.go +++ b/pkg/api/short_url.go @@ -119,13 +119,8 @@ type shortURLK8sHandler struct { } func newShortURLK8sHandler(hs *HTTPServer) *shortURLK8sHandler { - gvr := schema.GroupVersionResource{ - Group: v1alpha1.ShortURLKind().Group(), - Version: v1alpha1.ShortURLKind().Version(), - Resource: v1alpha1.ShortURLKind().Plural(), - } return &shortURLK8sHandler{ - gvr: gvr, + gvr: v1alpha1.ShortURLKind().GroupVersionResource(), namespacer: request.GetNamespaceMapper(hs.Cfg), clientConfigProvider: hs.clientConfigProvider, cfg: hs.Cfg, diff --git a/pkg/registry/apps/playlist/legacy_storage.go b/pkg/registry/apps/playlist/legacy_storage.go index 4f6affce640..8425035e093 100644 --- a/pkg/registry/apps/playlist/legacy_storage.go +++ b/pkg/registry/apps/playlist/legacy_storage.go @@ -10,7 +10,6 @@ import ( "k8s.io/apimachinery/pkg/apis/meta/internalversion" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apiserver/pkg/registry/rest" playlist "github.com/grafana/grafana/apps/playlist/pkg/apis/playlist/v0alpha1" @@ -87,10 +86,7 @@ func (s *legacyStorage) Get(ctx context.Context, name string, options *metav1.Ge }) if err != nil || dto == nil { if errors.Is(err, playlistsvc.ErrPlaylistNotFound) || err == nil { - err = k8serrors.NewNotFound(schema.GroupResource{ - Group: playlist.PlaylistKind().Group(), - Resource: playlist.PlaylistKind().Plural(), - }, name) + err = k8serrors.NewNotFound(playlist.PlaylistKind().GroupVersionResource().GroupResource(), name) } return nil, err } diff --git a/pkg/registry/apps/playlist/register.go b/pkg/registry/apps/playlist/register.go index 67d6476401f..52bbc0210f9 100644 --- a/pkg/registry/apps/playlist/register.go +++ b/pkg/registry/apps/playlist/register.go @@ -65,11 +65,7 @@ func RegisterAppInstaller( // GetLegacyStorage returns the legacy storage for the playlist app. func (p *PlaylistAppInstaller) GetLegacyStorage(requested schema.GroupVersionResource) grafanarest.Storage { - gvr := schema.GroupVersionResource{ - Group: playlistv0alpha1.PlaylistKind().Group(), - Version: playlistv0alpha1.PlaylistKind().Version(), - Resource: playlistv0alpha1.PlaylistKind().Plural(), - } + gvr := playlistv0alpha1.PlaylistKind().GroupVersionResource() if requested.String() != gvr.String() { return nil } diff --git a/pkg/registry/apps/plugins/register.go b/pkg/registry/apps/plugins/register.go index dc05a47f965..2929efda78f 100644 --- a/pkg/registry/apps/plugins/register.go +++ b/pkg/registry/apps/plugins/register.go @@ -55,11 +55,7 @@ func (p *PluginsAppInstaller) InstallAPIs( server appsdkapiserver.GenericAPIServer, restOptsGetter generic.RESTOptionsGetter, ) error { - pluginMetaGVR := schema.GroupVersionResource{ - Group: pluginsv0alpha1.GroupVersion.Group, - Version: pluginsv0alpha1.GroupVersion.Version, - Resource: pluginsv0alpha1.PluginMetaKind().Plural(), - } + pluginMetaGVR := pluginsv0alpha1.PluginMetaKind().GroupVersionResource() replacedStorage := map[schema.GroupVersionResource]rest.Storage{ pluginMetaGVR: pluginsapp.NewPluginMetaStorage(request.GetNamespaceMapper(p.cfg)), } diff --git a/pkg/registry/apps/shorturl/legacy_storage.go b/pkg/registry/apps/shorturl/legacy_storage.go index 8ee7a59e899..c9462359236 100644 --- a/pkg/registry/apps/shorturl/legacy_storage.go +++ b/pkg/registry/apps/shorturl/legacy_storage.go @@ -10,7 +10,6 @@ import ( "k8s.io/apimachinery/pkg/apis/meta/internalversion" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apiserver/pkg/registry/rest" shorturl "github.com/grafana/grafana/apps/shorturl/pkg/apis/shorturl/v1alpha1" @@ -97,10 +96,7 @@ func (s *legacyStorage) Get(ctx context.Context, name string, options *metav1.Ge dto, err := s.service.GetShortURLByUID(ctx, signedInUser, name) if err != nil || dto == nil { if errors.Is(err, shorturls.ErrShortURLNotFound) || err == nil { - err = k8serrors.NewNotFound(schema.GroupResource{ - Group: shorturl.ShortURLKind().Group(), - Resource: shorturl.ShortURLKind().Plural(), - }, name) + err = k8serrors.NewNotFound(shorturl.ShortURLKind().GroupVersionResource().GroupResource(), name) } return nil, err } @@ -167,10 +163,7 @@ func (s *legacyStorage) Update(ctx context.Context, shortURL, err := s.service.GetShortURLByUID(ctx, signedInUser, name) if err != nil || shortURL == nil { if errors.Is(err, shorturls.ErrShortURLNotFound) || err == nil { - err = k8serrors.NewNotFound(schema.GroupResource{ - Group: shorturl.ShortURLKind().Group(), - Resource: shorturl.ShortURLKind().Plural(), - }, name) + err = k8serrors.NewNotFound(shorturl.ShortURLKind().GroupVersionResource().GroupResource(), name) } return nil, false, err } diff --git a/pkg/registry/apps/shorturl/register.go b/pkg/registry/apps/shorturl/register.go index ecf56769e55..a44593ceabe 100644 --- a/pkg/registry/apps/shorturl/register.go +++ b/pkg/registry/apps/shorturl/register.go @@ -55,11 +55,7 @@ func RegisterAppInstaller( } func (s *ShortURLAppInstaller) GetLegacyStorage(requested schema.GroupVersionResource) grafanarest.Storage { - gvr := schema.GroupVersionResource{ - Group: shorturl.ShortURLKind().Group(), - Version: shorturl.ShortURLKind().Version(), - Resource: shorturl.ShortURLKind().Plural(), - } + gvr := shorturl.ShortURLKind().GroupVersionResource() if requested.String() != gvr.String() { return nil } diff --git a/pkg/services/apiserver/builder/runner/admission_test.go b/pkg/services/apiserver/builder/runner/admission_test.go index f9b6fec3244..11275afdea8 100644 --- a/pkg/services/apiserver/builder/runner/admission_test.go +++ b/pkg/services/apiserver/builder/runner/admission_test.go @@ -5,12 +5,11 @@ import ( "errors" "testing" - "github.com/grafana/grafana-app-sdk/app" "github.com/stretchr/testify/require" - "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apiserver/pkg/admission" "k8s.io/apiserver/pkg/authentication/user" + "github.com/grafana/grafana-app-sdk/app" examplev1 "github.com/grafana/grafana/pkg/services/apiserver/builder/runner/testdata/app/pkg/apis/example/v1" ) @@ -20,12 +19,8 @@ func TestBuilderAdmission_Validate(t *testing.T) { A: "test", }, } - gvk := schema.GroupVersionKind{ - Group: examplev1.ExampleKind().Group(), - Version: examplev1.ExampleKind().Version(), - Kind: examplev1.ExampleKind().Kind(), - } - gvr := gvk.GroupVersion().WithResource(examplev1.ExampleKind().Plural()) + gvk := examplev1.ExampleKind().GroupVersionKind() + gvr := examplev1.ExampleKind().GroupVersionResource() defaultAttributes := admission.NewAttributesRecord(exampleObj, nil, gvk, "default", "foo", gvr, "", admission.Create, nil, false, &user.DefaultInfo{}) tests := []struct { @@ -73,12 +68,8 @@ func TestBuilderAdmission_Validate(t *testing.T) { } func TestBuilderAdmission_Mutate(t *testing.T) { - gvk := schema.GroupVersionKind{ - Group: examplev1.ExampleKind().Group(), - Version: examplev1.ExampleKind().Version(), - Kind: examplev1.ExampleKind().Kind(), - } - gvr := gvk.GroupVersion().WithResource(examplev1.ExampleKind().Plural()) + gvk := examplev1.ExampleKind().GroupVersionKind() + gvr := examplev1.ExampleKind().GroupVersionResource() getAttributes := func() admission.Attributes { exampleObj := &examplev1.Example{ Spec: examplev1.ExampleSpec{ diff --git a/pkg/services/cleanup/cleanup.go b/pkg/services/cleanup/cleanup.go index cc73faa7b12..0e4fe0d319f 100644 --- a/pkg/services/cleanup/cleanup.go +++ b/pkg/services/cleanup/cleanup.go @@ -14,7 +14,6 @@ import ( k8serrors "k8s.io/apimachinery/pkg/api/errors" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/client-go/dynamic" "github.com/grafana/grafana/apps/shorturl/pkg/apis/shorturl/v1alpha1" @@ -326,11 +325,7 @@ func (srv *CleanUpService) deleteStaleKubernetesShortURLs(ctx context.Context) { } // Set up the GroupVersionResource for shortURLs - gvr := schema.GroupVersionResource{ - Group: v1alpha1.ShortURLKind().Group(), - Version: v1alpha1.ShortURLKind().Version(), - Resource: v1alpha1.ShortURLKind().Plural(), - } + gvr := v1alpha1.ShortURLKind().GroupVersionResource() // Calculate the expiration time expirationTime := time.Now().Add(-time.Duration(srv.Cfg.ShortLinkExpiration*24) * time.Hour) diff --git a/pkg/tests/apis/alerting/notifications/common/testing.go b/pkg/tests/apis/alerting/notifications/common/testing.go index bd9891402c9..2376b1368aa 100644 --- a/pkg/tests/apis/alerting/notifications/common/testing.go +++ b/pkg/tests/apis/alerting/notifications/common/testing.go @@ -3,12 +3,11 @@ package common import ( "testing" - "github.com/grafana/grafana/pkg/tests/apis" "github.com/stretchr/testify/require" - "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/client-go/dynamic" "github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/alertingnotifications/v0alpha1" + "github.com/grafana/grafana/pkg/tests/apis" ) func NewReceiverClient(t *testing.T, user apis.User) *apis.TypedClient[v0alpha1.Receiver, v0alpha1.ReceiverList] { @@ -19,11 +18,8 @@ func NewReceiverClient(t *testing.T, user apis.User) *apis.TypedClient[v0alpha1. return &apis.TypedClient[v0alpha1.Receiver, v0alpha1.ReceiverList]{ Client: client.Resource( - schema.GroupVersionResource{ - Group: v0alpha1.ReceiverKind().Group(), - Version: v0alpha1.ReceiverKind().Version(), - Resource: v0alpha1.ReceiverKind().Plural(), - }).Namespace("default"), + v0alpha1.ReceiverKind().GroupVersionResource()). + Namespace("default"), } } @@ -35,11 +31,7 @@ func NewRoutingTreeClient(t *testing.T, user apis.User) *apis.TypedClient[v0alph return &apis.TypedClient[v0alpha1.RoutingTree, v0alpha1.RoutingTreeList]{ Client: client.Resource( - schema.GroupVersionResource{ - Group: v0alpha1.RoutingTreeKind().Group(), - Version: v0alpha1.RoutingTreeKind().Version(), - Resource: v0alpha1.RoutingTreeKind().Plural(), - }).Namespace("default"), + v0alpha1.RoutingTreeKind().GroupVersionResource()).Namespace("default"), } } @@ -51,11 +43,7 @@ func NewTemplateGroupClient(t *testing.T, user apis.User) *apis.TypedClient[v0al return &apis.TypedClient[v0alpha1.TemplateGroup, v0alpha1.TemplateGroupList]{ Client: client.Resource( - schema.GroupVersionResource{ - Group: v0alpha1.TemplateGroupKind().Group(), - Version: v0alpha1.TemplateGroupKind().Version(), - Resource: v0alpha1.TemplateGroupKind().Plural(), - }).Namespace("default"), + v0alpha1.TemplateGroupKind().GroupVersionResource()).Namespace("default"), } } @@ -67,10 +55,6 @@ func NewTimeIntervalClient(t *testing.T, user apis.User) *apis.TypedClient[v0alp return &apis.TypedClient[v0alpha1.TimeInterval, v0alpha1.TimeIntervalList]{ Client: client.Resource( - schema.GroupVersionResource{ - Group: v0alpha1.TimeIntervalKind().Group(), - Version: v0alpha1.TimeIntervalKind().Version(), - Resource: v0alpha1.TimeIntervalKind().Plural(), - }).Namespace("default"), + v0alpha1.TimeIntervalKind().GroupVersionResource()).Namespace("default"), } } diff --git a/pkg/tests/apis/alerting/rules/common/testing.go b/pkg/tests/apis/alerting/rules/common/testing.go index da9dd55a694..be43be5da26 100644 --- a/pkg/tests/apis/alerting/rules/common/testing.go +++ b/pkg/tests/apis/alerting/rules/common/testing.go @@ -4,14 +4,14 @@ import ( "context" "testing" + "github.com/stretchr/testify/require" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/dynamic" + "github.com/grafana/grafana/apps/alerting/rules/pkg/apis/alerting/v0alpha1" folders "github.com/grafana/grafana/apps/folder/pkg/apis/folder/v1beta1" "github.com/grafana/grafana/pkg/tests/apis" "github.com/grafana/grafana/pkg/tests/testinfra" - "github.com/stretchr/testify/require" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/client-go/dynamic" ) func NewAlertRuleClient(t *testing.T, user apis.User) *apis.TypedClient[v0alpha1.AlertRule, v0alpha1.AlertRuleList] { @@ -22,11 +22,7 @@ func NewAlertRuleClient(t *testing.T, user apis.User) *apis.TypedClient[v0alpha1 return &apis.TypedClient[v0alpha1.AlertRule, v0alpha1.AlertRuleList]{ Client: client.Resource( - schema.GroupVersionResource{ - Group: v0alpha1.AlertRuleKind().Group(), - Version: v0alpha1.AlertRuleKind().Version(), - Resource: v0alpha1.AlertRuleKind().Plural(), - }).Namespace("default"), + v0alpha1.AlertRuleKind().GroupVersionResource()).Namespace("default"), } } @@ -38,11 +34,7 @@ func NewRecordingRuleClient(t *testing.T, user apis.User) *apis.TypedClient[v0al return &apis.TypedClient[v0alpha1.RecordingRule, v0alpha1.RecordingRuleList]{ Client: client.Resource( - schema.GroupVersionResource{ - Group: v0alpha1.RecordingRuleKind().Group(), - Version: v0alpha1.RecordingRuleKind().Version(), - Resource: v0alpha1.RecordingRuleKind().Plural(), - }).Namespace("default"), + v0alpha1.RecordingRuleKind().GroupVersionResource()).Namespace("default"), } } @@ -54,11 +46,7 @@ func NewFolderClient(t *testing.T, user apis.User) *apis.TypedClient[folders.Fol return &apis.TypedClient[folders.Folder, folders.FolderList]{ Client: client.Resource( - schema.GroupVersionResource{ - Group: folders.FolderKind().Group(), - Version: folders.FolderKind().Version(), - Resource: folders.FolderKind().Plural(), - }).Namespace("default"), + folders.FolderKind().GroupVersionResource()).Namespace("default"), } } From 9533cc4dbb2df50e9004b96cf4af59a4b39b95fa Mon Sep 17 00:00:00 2001 From: Georges Chaudy Date: Tue, 28 Oct 2025 23:18:15 +0100 Subject: [PATCH 069/378] kvstore: Fix missing Folder field in listModifiedSinceEventStore data lookup (#113131) * fix: ListModifiedSince for resources in folders * fix: ListModifiedSince for resources in folders --- .../unified/resource/storage_backend.go | 9 +- .../unified/resource/storage_backend_test.go | 105 ++++++++++++++++++ 2 files changed, 106 insertions(+), 8 deletions(-) diff --git a/pkg/storage/unified/resource/storage_backend.go b/pkg/storage/unified/resource/storage_backend.go index 24bb98c1f8b..2f11da20f48 100644 --- a/pkg/storage/unified/resource/storage_backend.go +++ b/pkg/storage/unified/resource/storage_backend.go @@ -737,14 +737,7 @@ func (k *kvStorageBackend) listModifiedSinceEventStore(ctx context.Context, key } seen[evtKey.Name] = struct{}{} - value, err := k.getValueFromDataStore(ctx, DataKey{ - Group: evtKey.Group, - Resource: evtKey.Resource, - Namespace: evtKey.Namespace, - Name: evtKey.Name, - ResourceVersion: evtKey.ResourceVersion, - Action: evtKey.Action, - }) + value, err := k.getValueFromDataStore(ctx, DataKey(evtKey)) if err != nil { yield(&ModifiedResource{}, err) return diff --git a/pkg/storage/unified/resource/storage_backend_test.go b/pkg/storage/unified/resource/storage_backend_test.go index 0a1c263d216..8b1143db6d1 100644 --- a/pkg/storage/unified/resource/storage_backend_test.go +++ b/pkg/storage/unified/resource/storage_backend_test.go @@ -785,6 +785,111 @@ func seedBackend(t *testing.T, backend *kvStorageBackend, ctx context.Context, n return expectations } +func TestKvStorageBackend_ListModifiedSince_WithFolder(t *testing.T) { + backend := setupTestStorageBackend(t) + ctx := context.Background() + + // Use a unique resource type to avoid conflicts with other tests + ns := NamespacedResource{ + Namespace: "test-folder-ns", + Group: "test.folder.app", + Resource: "test-resources", + } + + // Create test objects with folder field set + testObj1, err := createTestObjectWithName("dashboard-1", ns, "data-1") + require.NoError(t, err) + metaAccessor1, err := utils.MetaAccessor(testObj1) + require.NoError(t, err) + metaAccessor1.SetFolder("folder-abc") + + testObj2, err := createTestObjectWithName("dashboard-2", ns, "data-2") + require.NoError(t, err) + metaAccessor2, err := utils.MetaAccessor(testObj2) + require.NoError(t, err) + metaAccessor2.SetFolder("folder-xyz") + + // Write first dashboard + writeEvent1 := WriteEvent{ + Type: resourcepb.WatchEvent_ADDED, + Key: &resourcepb.ResourceKey{ + Namespace: ns.Namespace, + Group: ns.Group, + Resource: ns.Resource, + Name: "dashboard-1", + }, + Value: objectToJSONBytes(t, testObj1), + Object: metaAccessor1, + PreviousRV: 0, + } + rv1, err := backend.WriteEvent(ctx, writeEvent1) + require.NoError(t, err) + + // Write second dashboard + writeEvent2 := WriteEvent{ + Type: resourcepb.WatchEvent_ADDED, + Key: &resourcepb.ResourceKey{ + Namespace: ns.Namespace, + Group: ns.Group, + Resource: ns.Resource, + Name: "dashboard-2", + }, + Value: objectToJSONBytes(t, testObj2), + Object: metaAccessor2, + PreviousRV: 0, + } + rv2, err := backend.WriteEvent(ctx, writeEvent2) + require.NoError(t, err) + + tests := []struct { + name string + sinceRV func() int64 + codePath string + }{ + { + name: "via event store (recent RV < 1 hour)", + sinceRV: func() int64 { return rv1 - 1 }, + codePath: "listModifiedSinceEventStore", + }, + { + name: "via data store (old RV > 1 hour)", + sinceRV: func() int64 { return generateOldSnowflake(t) }, + codePath: "listModifiedSinceDataStore", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + sinceRV := tt.sinceRV() + + // List resources + rv, seq := backend.ListModifiedSince(ctx, ns, sinceRV) + + changes := make(map[string]*ModifiedResource) + for mr, err := range seq { + require.NoError(t, err, "Should not get error when Folder field is included") + require.Equal(t, ns.Group, mr.Key.Group) + require.Equal(t, ns.Namespace, mr.Key.Namespace) + require.Equal(t, ns.Resource, mr.Key.Resource) + changes[mr.Key.Name] = mr + } + + require.Greater(t, rv, sinceRV) + require.Len(t, changes, 2, "Should return 2 resources") + + // Verify dashboard-1 + require.Contains(t, changes, "dashboard-1") + require.Equal(t, rv1, changes["dashboard-1"].ResourceVersion) + require.Equal(t, objectToJSONBytes(t, testObj1), changes["dashboard-1"].Value) + + // Verify dashboard-2 + require.Contains(t, changes, "dashboard-2") + require.Equal(t, rv2, changes["dashboard-2"].ResourceVersion) + require.Equal(t, objectToJSONBytes(t, testObj2), changes["dashboard-2"].Value) + }) + } +} + func createAndSaveTestObject(t *testing.T, backend *kvStorageBackend, ctx context.Context, ns NamespacedResource, uniqueStringGen func() string, updates int, deleted bool) *ModifiedResource { name := uniqueStringGen() action := resourcepb.WatchEvent_ADDED From 1492db8eaded1515862e4abde696796c9d8c34de Mon Sep 17 00:00:00 2001 From: Nathan Marrs Date: Tue, 28 Oct 2025 16:27:37 -0700 Subject: [PATCH 070/378] Grafana: Fix main build by skipping flaky test (#113138) skip panel smokescreen test due to breaking main build (potentially flaky) --- e2e-playwright/smoke-tests-suite/panels.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e-playwright/smoke-tests-suite/panels.spec.ts b/e2e-playwright/smoke-tests-suite/panels.spec.ts index 822b0ad90b4..08a4189f735 100644 --- a/e2e-playwright/smoke-tests-suite/panels.spec.ts +++ b/e2e-playwright/smoke-tests-suite/panels.spec.ts @@ -7,7 +7,7 @@ test.describe( tag: ['@acceptance'], }, () => { - test('Tests each panel type in the panel edit view to ensure no crash', async ({ + test.skip('Tests each panel type in the panel edit view to ensure no crash', async ({ gotoDashboardPage, selectors, page, From 2c1aa65f2d9eef5e7ae14af0ab9b4917b34d183f Mon Sep 17 00:00:00 2001 From: "grafana-pr-automation[bot]" <140550294+grafana-pr-automation[bot]@users.noreply.github.com> Date: Wed, 29 Oct 2025 00:41:02 +0000 Subject: [PATCH 071/378] I18n: Download translations from Crowdin (#113140) New Crowdin translations by GitHub Action Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- public/locales/cs-CZ/grafana.json | 1 + public/locales/de-DE/grafana.json | 1 + public/locales/es-ES/grafana.json | 1 + public/locales/fr-FR/grafana.json | 1 + public/locales/hu-HU/grafana.json | 1 + public/locales/id-ID/grafana.json | 1 + public/locales/it-IT/grafana.json | 1 + public/locales/ja-JP/grafana.json | 1 + public/locales/ko-KR/grafana.json | 1 + public/locales/nl-NL/grafana.json | 1 + public/locales/pl-PL/grafana.json | 1 + public/locales/pt-BR/grafana.json | 1 + public/locales/pt-PT/grafana.json | 1 + public/locales/ru-RU/grafana.json | 1 + public/locales/sv-SE/grafana.json | 1 + public/locales/tr-TR/grafana.json | 1 + public/locales/zh-Hans/grafana.json | 1 + public/locales/zh-Hant/grafana.json | 1 + 18 files changed, 18 insertions(+) diff --git a/public/locales/cs-CZ/grafana.json b/public/locales/cs-CZ/grafana.json index 5b9e80a4404..9abd78940c1 100644 --- a/public/locales/cs-CZ/grafana.json +++ b/public/locales/cs-CZ/grafana.json @@ -4160,6 +4160,7 @@ "description": "Použít vlastní hodnotu" }, "options": { + "loading": "", "no-found": "Nebyly nalezeny žádné možnosti." } }, diff --git a/public/locales/de-DE/grafana.json b/public/locales/de-DE/grafana.json index bfeffc22032..6aa5ee76432 100644 --- a/public/locales/de-DE/grafana.json +++ b/public/locales/de-DE/grafana.json @@ -4120,6 +4120,7 @@ "description": "Benutzerdefinierten Wert verwenden" }, "options": { + "loading": "", "no-found": "Keine Optionen gefunden." } }, diff --git a/public/locales/es-ES/grafana.json b/public/locales/es-ES/grafana.json index 6e99108c6d5..6e93bc641b8 100644 --- a/public/locales/es-ES/grafana.json +++ b/public/locales/es-ES/grafana.json @@ -4120,6 +4120,7 @@ "description": "Usar valor personalizado" }, "options": { + "loading": "", "no-found": "No se han encontrado opciones." } }, diff --git a/public/locales/fr-FR/grafana.json b/public/locales/fr-FR/grafana.json index 8bdfac6e3a1..5f59f4eb023 100644 --- a/public/locales/fr-FR/grafana.json +++ b/public/locales/fr-FR/grafana.json @@ -4120,6 +4120,7 @@ "description": "Utiliser une valeur personnalisée" }, "options": { + "loading": "", "no-found": "Aucune option trouvée." } }, diff --git a/public/locales/hu-HU/grafana.json b/public/locales/hu-HU/grafana.json index 4ab9bcb1678..c18d53a7831 100644 --- a/public/locales/hu-HU/grafana.json +++ b/public/locales/hu-HU/grafana.json @@ -4120,6 +4120,7 @@ "description": "Egyéni érték használata" }, "options": { + "loading": "", "no-found": "Nem találhatók opciók." } }, diff --git a/public/locales/id-ID/grafana.json b/public/locales/id-ID/grafana.json index 17825673bbd..97627226a56 100644 --- a/public/locales/id-ID/grafana.json +++ b/public/locales/id-ID/grafana.json @@ -4100,6 +4100,7 @@ "description": "Gunakan nilai kustom" }, "options": { + "loading": "", "no-found": "Opsi tidak ditemukan." } }, diff --git a/public/locales/it-IT/grafana.json b/public/locales/it-IT/grafana.json index a7d095fffc8..4b5dc671573 100644 --- a/public/locales/it-IT/grafana.json +++ b/public/locales/it-IT/grafana.json @@ -4120,6 +4120,7 @@ "description": "Usa il valore personalizzato" }, "options": { + "loading": "", "no-found": "Nessuna opzione trovata." } }, diff --git a/public/locales/ja-JP/grafana.json b/public/locales/ja-JP/grafana.json index 6ffbd6ef018..5b24acb3434 100644 --- a/public/locales/ja-JP/grafana.json +++ b/public/locales/ja-JP/grafana.json @@ -4100,6 +4100,7 @@ "description": "カスタム値の利用" }, "options": { + "loading": "", "no-found": "オプションが見つかりません" } }, diff --git a/public/locales/ko-KR/grafana.json b/public/locales/ko-KR/grafana.json index 80dee79c3a2..469989c8707 100644 --- a/public/locales/ko-KR/grafana.json +++ b/public/locales/ko-KR/grafana.json @@ -4100,6 +4100,7 @@ "description": "사용자 지정 값 사용" }, "options": { + "loading": "", "no-found": "옵션을 찾을 수 없습니다." } }, diff --git a/public/locales/nl-NL/grafana.json b/public/locales/nl-NL/grafana.json index f23f595bff2..9e46e64fb84 100644 --- a/public/locales/nl-NL/grafana.json +++ b/public/locales/nl-NL/grafana.json @@ -4120,6 +4120,7 @@ "description": "Aangepaste waarde gebruiken" }, "options": { + "loading": "", "no-found": "Geen opties gevonden." } }, diff --git a/public/locales/pl-PL/grafana.json b/public/locales/pl-PL/grafana.json index 37540c44888..ab686289d01 100644 --- a/public/locales/pl-PL/grafana.json +++ b/public/locales/pl-PL/grafana.json @@ -4160,6 +4160,7 @@ "description": "Użyj wartości niestandardowej" }, "options": { + "loading": "", "no-found": "Brak opcji." } }, diff --git a/public/locales/pt-BR/grafana.json b/public/locales/pt-BR/grafana.json index f53b11abe29..9b2d4662786 100644 --- a/public/locales/pt-BR/grafana.json +++ b/public/locales/pt-BR/grafana.json @@ -4120,6 +4120,7 @@ "description": "Usar valor personalizado" }, "options": { + "loading": "", "no-found": "Nenhuma opção encontrada." } }, diff --git a/public/locales/pt-PT/grafana.json b/public/locales/pt-PT/grafana.json index 0f74596b448..db0d3d98b1a 100644 --- a/public/locales/pt-PT/grafana.json +++ b/public/locales/pt-PT/grafana.json @@ -4120,6 +4120,7 @@ "description": "Utilizar valor personalizado" }, "options": { + "loading": "", "no-found": "Nenhuma opção encontrada." } }, diff --git a/public/locales/ru-RU/grafana.json b/public/locales/ru-RU/grafana.json index ae8747b74fb..51037975989 100644 --- a/public/locales/ru-RU/grafana.json +++ b/public/locales/ru-RU/grafana.json @@ -4160,6 +4160,7 @@ "description": "Использовать пользовательское значение" }, "options": { + "loading": "", "no-found": "Параметры не найдены." } }, diff --git a/public/locales/sv-SE/grafana.json b/public/locales/sv-SE/grafana.json index b44428db3d0..5ede98266b1 100644 --- a/public/locales/sv-SE/grafana.json +++ b/public/locales/sv-SE/grafana.json @@ -4120,6 +4120,7 @@ "description": "Använd eget värde" }, "options": { + "loading": "", "no-found": "Inga alternativ hittades." } }, diff --git a/public/locales/tr-TR/grafana.json b/public/locales/tr-TR/grafana.json index 8f6c3f2fad8..432dfa7979f 100644 --- a/public/locales/tr-TR/grafana.json +++ b/public/locales/tr-TR/grafana.json @@ -4120,6 +4120,7 @@ "description": "Özel değer kullan" }, "options": { + "loading": "", "no-found": "Seçenek bulunamadı." } }, diff --git a/public/locales/zh-Hans/grafana.json b/public/locales/zh-Hans/grafana.json index 92102c0443d..339ae6027eb 100644 --- a/public/locales/zh-Hans/grafana.json +++ b/public/locales/zh-Hans/grafana.json @@ -4100,6 +4100,7 @@ "description": "使用自定义值" }, "options": { + "loading": "", "no-found": "未找到任何选项。" } }, diff --git a/public/locales/zh-Hant/grafana.json b/public/locales/zh-Hant/grafana.json index c1d25184ba5..176b57347ec 100644 --- a/public/locales/zh-Hant/grafana.json +++ b/public/locales/zh-Hant/grafana.json @@ -4100,6 +4100,7 @@ "description": "使用自訂值" }, "options": { + "loading": "", "no-found": "沒有找到選項。" } }, From 25dd7e927fb1e4966d8a44b138ab65bb07d13384 Mon Sep 17 00:00:00 2001 From: Costa Alexoglou Date: Wed, 29 Oct 2025 08:41:53 +0100 Subject: [PATCH 072/378] feat: add granular context timeout (#112952) * feat: add granular context timeout * test: forced thread timeout * fix: test assumption for blocks * test: new change * trigger build * remove loggers to test * test with fmt.print * fix: deadlocks --- .../apis/provisioning/jobs/progress.go | 40 ++++--- .../apis/provisioning/jobs/sync/full.go | 110 +++++++++++------- .../apis/provisioning/jobs/sync/full_test.go | 46 +++++++- 3 files changed, 131 insertions(+), 65 deletions(-) diff --git a/pkg/registry/apis/provisioning/jobs/progress.go b/pkg/registry/apis/provisioning/jobs/progress.go index f9cea399865..95b99ea704f 100644 --- a/pkg/registry/apis/provisioning/jobs/progress.go +++ b/pkg/registry/apis/provisioning/jobs/progress.go @@ -70,23 +70,31 @@ func newJobProgressRecorder(ProgressFn ProgressFn) JobProgressRecorder { } func (r *jobProgressRecorder) Record(ctx context.Context, result JobResourceResult) { + var shouldLogError bool + var logErr error + r.mu.Lock() r.resultCount++ - logger := logging.FromContext(ctx).With("path", result.Path, "group", result.Group, "kind", result.Kind, "action", result.Action, "name", result.Name) if result.Error != nil { - logger.Error("job resource operation failed", "err", result.Error) + shouldLogError = true + logErr = result.Error if len(r.errors) < 20 { r.errors = append(r.errors, result.Error.Error()) } r.errorCount++ - } else { - logger.Info("job resource operation succeeded") } r.updateSummary(result) r.mu.Unlock() + logger := logging.FromContext(ctx).With("path", result.Path, "group", result.Group, "kind", result.Kind, "action", result.Action, "name", result.Name) + if shouldLogError { + logger.Error("job resource operation failed", "err", logErr) + } else { + logger.Info("job resource operation succeeded") + } + r.maybeNotify(ctx) } @@ -145,9 +153,6 @@ func (r *jobProgressRecorder) StrictMaxErrors(maxErrors int) { } func (r *jobProgressRecorder) TooManyErrors() error { - r.mu.RLock() - defer r.mu.RUnlock() - if r.maxErrors > 0 && r.errorCount >= r.maxErrors { return fmt.Errorf("too many errors: %d", r.errorCount) } @@ -156,9 +161,6 @@ func (r *jobProgressRecorder) TooManyErrors() error { } func (r *jobProgressRecorder) summary() []*provisioning.JobResourceSummary { - r.mu.RLock() - defer r.mu.RUnlock() - if len(r.summaries) == 0 { return nil } @@ -247,13 +249,9 @@ func (r *jobProgressRecorder) maybeNotify(ctx context.Context) { func (r *jobProgressRecorder) Complete(ctx context.Context, err error) provisioning.JobStatus { r.mu.RLock() - defer r.mu.RUnlock() - // Initialize base job status jobStatus := provisioning.JobStatus{ - Started: r.started.UnixMilli(), - // FIXME: if we call this method twice, the state will be different - // This results in sync status to be different from job status + Started: r.started.UnixMilli(), Finished: time.Now().UnixMilli(), State: provisioning.JobStateSuccess, Message: "completed successfully", @@ -268,9 +266,13 @@ func (r *jobProgressRecorder) Complete(ctx context.Context, err error) provision jobStatus.Errors = r.errors jobStatus.URLs = r.refURLs - // Check for errors during execution + tooManyErrors := r.maxErrors > 0 && r.errorCount >= r.maxErrors + finalMessage := r.finalMessage + + r.mu.RUnlock() + if len(jobStatus.Errors) > 0 && jobStatus.State != provisioning.JobStateError { - if r.TooManyErrors() != nil { + if tooManyErrors { jobStatus.Message = "completed with too many errors" jobStatus.State = provisioning.JobStateError } else { @@ -280,8 +282,8 @@ func (r *jobProgressRecorder) Complete(ctx context.Context, err error) provision } // Override message if progress have a more explicit message - if r.finalMessage != "" && jobStatus.State != provisioning.JobStateError { - jobStatus.Message = r.finalMessage + if finalMessage != "" && jobStatus.State != provisioning.JobStateError { + jobStatus.Message = finalMessage } return jobStatus diff --git a/pkg/registry/apis/provisioning/jobs/sync/full.go b/pkg/registry/apis/provisioning/jobs/sync/full.go index 0c5d9c5bb2d..14d53c00afc 100644 --- a/pkg/registry/apis/provisioning/jobs/sync/full.go +++ b/pkg/registry/apis/provisioning/jobs/sync/full.go @@ -4,12 +4,14 @@ import ( "context" "fmt" "sync" + "time" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/trace" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime/schema" + "github.com/grafana/grafana-app-sdk/logging" "github.com/grafana/grafana/apps/provisioning/pkg/repository" "github.com/grafana/grafana/apps/provisioning/pkg/safepath" "github.com/grafana/grafana/pkg/infra/tracing" @@ -145,11 +147,11 @@ func applyChange(ctx context.Context, change ResourceFileChange, clients resourc Group: gvk.Group, Kind: gvk.Kind, } - if err != nil { writeSpan.RecordError(err) result.Error = fmt.Errorf("writing resource from file %s: %w", change.Path, err) } + progress.Record(writeCtx, result) writeSpan.End() } @@ -224,72 +226,75 @@ func applyChanges(ctx context.Context, changes []ResourceFileChange, clients res } func applyFoldersSerially(ctx context.Context, folders []ResourceFileChange, clients resources.ResourceClients, repositoryResources resources.RepositoryResources, progress jobs.JobProgressRecorder, tracer tracing.Tracer) error { - folderCtx, folderCancel := context.WithCancel(ctx) - defer folderCancel() + logger := logging.FromContext(ctx) for _, folder := range folders { - if folderCtx.Err() != nil { - return folderCtx.Err() + if ctx.Err() != nil { + return ctx.Err() } if err := progress.TooManyErrors(); err != nil { return err } + folderCtx, cancel := context.WithTimeout(ctx, 15*time.Second) + applyChange(folderCtx, folder, clients, repositoryResources, progress, tracer) + + if folderCtx.Err() == context.DeadlineExceeded { + logger.Error("operation timed out after 15 seconds", "path", folder.Path, "action", folder.Action) + + recordCtx, recordCancel := context.WithTimeout(context.Background(), 15*time.Second) + progress.Record(recordCtx, jobs.JobResourceResult{ + Path: folder.Path, + Action: folder.Action, + Error: fmt.Errorf("operation timed out after 15 seconds"), + }) + recordCancel() + } + + cancel() } return nil } func applyResourcesInParallel(ctx context.Context, resources []ResourceFileChange, clients resources.ResourceClients, repositoryResources resources.RepositoryResources, progress jobs.JobProgressRecorder, tracer tracing.Tracer, maxSyncWorkers int) error { + logger := logging.FromContext(ctx) + logger.Info("applying resources in parallel test changes 1") + if len(resources) == 0 { return nil } - workerCtx, cancel := context.WithCancel(ctx) - defer cancel() - - changeChan := make(chan ResourceFileChange, len(resources)) + sem := make(chan struct{}, maxSyncWorkers) var wg sync.WaitGroup - for i := 0; i < maxSyncWorkers; i++ { - wg.Add(1) - go func() { - defer wg.Done() - for { - select { - case change, ok := <-changeChan: - if !ok { - return - } - - if err := progress.TooManyErrors(); err != nil { - cancel() - return - } - if workerCtx.Err() != nil { - return - } - - applyChange(workerCtx, change, clients, repositoryResources, progress, tracer) - - case <-workerCtx.Done(): - return - } - } - }() - } - +loop: for _, change := range resources { - select { - case changeChan <- change: - case <-workerCtx.Done(): - goto done + if err := progress.TooManyErrors(); err != nil { + break } + if ctx.Err() != nil { + break + } + + // Acquire semaphore slot (blocks if max workers reached) + select { + case sem <- struct{}{}: + case <-ctx.Done(): + break loop + } + + wg.Add(1) + go func(change ResourceFileChange) { + defer wg.Done() + defer func() { <-sem }() + + applyChangeWithTimeout(ctx, change, clients, repositoryResources, progress, tracer, logger) + }(change) } -done: - close(changeChan) + wg.Wait() if err := progress.TooManyErrors(); err != nil { @@ -298,3 +303,22 @@ done: return ctx.Err() } + +func applyChangeWithTimeout(ctx context.Context, change ResourceFileChange, clients resources.ResourceClients, repositoryResources resources.RepositoryResources, progress jobs.JobProgressRecorder, tracer tracing.Tracer, logger logging.Logger) { + changeCtx, cancel := context.WithTimeout(ctx, 15*time.Second) + defer cancel() + + applyChange(changeCtx, change, clients, repositoryResources, progress, tracer) + + if changeCtx.Err() == context.DeadlineExceeded { + logger.Error("operation timed out after 15 seconds", "path", change.Path, "action", change.Action) + + recordCtx, recordCancel := context.WithTimeout(context.Background(), 15*time.Second) + progress.Record(recordCtx, jobs.JobResourceResult{ + Path: change.Path, + Action: change.Action, + Error: fmt.Errorf("operation timed out after 15 seconds"), + }) + recordCancel() + } +} diff --git a/pkg/registry/apis/provisioning/jobs/sync/full_test.go b/pkg/registry/apis/provisioning/jobs/sync/full_test.go index 76cf514f23d..904b2645256 100644 --- a/pkg/registry/apis/provisioning/jobs/sync/full_test.go +++ b/pkg/registry/apis/provisioning/jobs/sync/full_test.go @@ -4,7 +4,9 @@ import ( "context" "errors" "fmt" + "sync/atomic" "testing" + "time" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" @@ -202,10 +204,9 @@ func TestFullSync_ApplyChanges(t *testing.T) { //nolint:gocyclo }, }, setupMocks: func(repo *repository.MockRepository, repoResources *resources.MockRepositoryResources, clients *resources.MockResourceClients, progress *jobs.MockJobProgressRecorder, compareFn *MockCompareFn) { - callCount := 0 + var callCount int64 = 0 progress.On("TooManyErrors").Return(func() error { - callCount++ - if callCount > 1 { + if atomic.AddInt64(&callCount, 1) > 1 { return fmt.Errorf("too many errors") } return nil @@ -682,6 +683,45 @@ func TestFullSync_ApplyChanges(t *testing.T) { //nolint:gocyclo })).Return() }, }, + { + name: "operation timeout after 15 seconds", + description: "Should record timeout error when operation takes longer than 15 seconds", + changes: []ResourceFileChange{ + { + Action: repository.FileActionCreated, + Path: "dashboards/slow.json", + }, + }, + setupMocks: func(repo *repository.MockRepository, repoResources *resources.MockRepositoryResources, clients *resources.MockResourceClients, progress *jobs.MockJobProgressRecorder, compareFn *MockCompareFn) { + progress.On("TooManyErrors").Return(nil) + + repoResources.On("WriteResourceFromFile", mock.Anything, "dashboards/slow.json", ""). + Run(func(args mock.Arguments) { + ctx := args.Get(0).(context.Context) + select { + case <-ctx.Done(): + return + case <-time.After(20 * time.Second): + return + } + }). + Return("", schema.GroupVersionKind{}, context.DeadlineExceeded) + + progress.On("Record", mock.Anything, mock.MatchedBy(func(result jobs.JobResourceResult) bool { + return result.Action == repository.FileActionCreated && + result.Path == "dashboards/slow.json" && + result.Error != nil && + result.Error.Error() == "writing resource from file dashboards/slow.json: context deadline exceeded" + })).Return().Once() + + progress.On("Record", mock.Anything, mock.MatchedBy(func(result jobs.JobResourceResult) bool { + return result.Action == repository.FileActionCreated && + result.Path == "dashboards/slow.json" && + result.Error != nil && + result.Error.Error() == "operation timed out after 15 seconds" + })).Return().Once() + }, + }, } for _, tt := range tests { From 5a031b370f4eeb873ed305c11a0235017fd54307 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Wed, 29 Oct 2025 09:06:23 +0100 Subject: [PATCH 073/378] PanelTimeSettings: Support panel time range settings changes from dashboard in view mode (#113027) * Something is working * Progress * Update * Update * Update * Some new unit tests * Fix * time shift fix * Update * Always show hidden toggle * Update --- .../src/types/featureToggles.gen.ts | 4 + .../src/components/PanelChrome/TitleItem.tsx | 10 +- .../grafana-ui/src/options/builder/index.ts | 1 - .../src/options/builder/timeCompare.tsx | 19 -- pkg/services/featuremgmt/registry.go | 11 + pkg/services/featuremgmt/toggles_gen.csv | 1 + pkg/services/featuremgmt/toggles_gen.go | 4 + pkg/services/featuremgmt/toggles_gen.json | 12 ++ .../PanelDataQueriesTab.test.tsx | 2 +- .../PanelDataPane/PanelDataQueriesTab.tsx | 2 +- .../panel-edit/getPanelFrameOptions.tsx | 2 +- .../saving/DashboardSceneChangeTracker.ts | 2 +- .../scene/CustomTimeRangeCompare.tsx | 79 ------- .../scene/DashboardLevelTimeMacro.test.ts | 2 +- .../scene/DashboardScene.test.tsx | 2 +- .../scene/LibraryPanelBehavior.test.tsx | 2 +- .../scene/LibraryPanelBehavior.tsx | 2 +- .../scene/PanelMenuBehavior.tsx | 12 ++ .../PanelTimeRange.test.tsx | 26 ++- .../{ => panel-timerange}/PanelTimeRange.tsx | 83 +++++++- .../panel-timerange/PanelTimeRangeDrawer.tsx | 201 ++++++++++++++++++ .../scene/panel-timerange/utils.ts | 56 +++++ .../layoutSerializers/utils.test.ts | 76 +------ .../serialization/layoutSerializers/utils.ts | 7 +- .../transformSaveModelToScene.test.ts | 37 +--- .../transformSaveModelToScene.ts | 6 +- .../transformSceneToSaveModel.ts | 2 +- .../transformSceneToSaveModelSchemaV2.ts | 2 +- .../sharing/SharePanelEmbedTab.tsx | 2 +- .../features/dashboard-scene/utils/utils.ts | 4 - .../app/plugins/panel/timeseries/module.tsx | 5 - public/locales/en-US/grafana.json | 23 ++ 32 files changed, 445 insertions(+), 254 deletions(-) delete mode 100644 packages/grafana-ui/src/options/builder/timeCompare.tsx delete mode 100644 public/app/features/dashboard-scene/scene/CustomTimeRangeCompare.tsx rename public/app/features/dashboard-scene/scene/{ => panel-timerange}/PanelTimeRange.test.tsx (84%) rename public/app/features/dashboard-scene/scene/{ => panel-timerange}/PanelTimeRange.tsx (60%) create mode 100644 public/app/features/dashboard-scene/scene/panel-timerange/PanelTimeRangeDrawer.tsx create mode 100644 public/app/features/dashboard-scene/scene/panel-timerange/utils.ts diff --git a/packages/grafana-data/src/types/featureToggles.gen.ts b/packages/grafana-data/src/types/featureToggles.gen.ts index 1f166051adc..65f523fc212 100644 --- a/packages/grafana-data/src/types/featureToggles.gen.ts +++ b/packages/grafana-data/src/types/featureToggles.gen.ts @@ -1233,6 +1233,10 @@ export interface FeatureToggles { */ onlyStoreActionSets?: boolean; /** + * Enables a new panel time settings drawer + */ + panelTimeSettings?: boolean; + /** * Enable template dashboards */ dashboardTemplates?: boolean; diff --git a/packages/grafana-ui/src/components/PanelChrome/TitleItem.tsx b/packages/grafana-ui/src/components/PanelChrome/TitleItem.tsx index 6a2a8adaa2d..18fee0039ad 100644 --- a/packages/grafana-ui/src/components/PanelChrome/TitleItem.tsx +++ b/packages/grafana-ui/src/components/PanelChrome/TitleItem.tsx @@ -39,7 +39,13 @@ export const TitleItem = forwardRef( ); } else if (onClick) { return ( - ); @@ -59,7 +65,6 @@ const getStyles = (theme: GrafanaTheme2) => { const item = css({ color: `${theme.colors.text.secondary}`, label: 'panel-header-item', - cursor: 'auto', border: 'none', borderRadius: `${theme.shape.radius.default}`, padding: `${theme.spacing(0, 1)}`, @@ -84,5 +89,6 @@ const getStyles = (theme: GrafanaTheme2) => { return { item, linkItem: cx(item, css({ cursor: 'pointer' })), + buttonItem: cx(item, css({ cursor: 'pointer' })), }; }; diff --git a/packages/grafana-ui/src/options/builder/index.ts b/packages/grafana-ui/src/options/builder/index.ts index 98b376794ee..42dd18e4850 100644 --- a/packages/grafana-ui/src/options/builder/index.ts +++ b/packages/grafana-ui/src/options/builder/index.ts @@ -4,4 +4,3 @@ export * from './legend'; export { addTooltipOptions } from './tooltip'; export * from './text'; export * from './stacking'; -export { addTimeCompareOption } from './timeCompare'; diff --git a/packages/grafana-ui/src/options/builder/timeCompare.tsx b/packages/grafana-ui/src/options/builder/timeCompare.tsx deleted file mode 100644 index 222856ff9f4..00000000000 --- a/packages/grafana-ui/src/options/builder/timeCompare.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import { PanelOptionsEditorBuilder } from '@grafana/data'; -import { TimeCompareOptions } from '@grafana/schema'; - -/** - * Adds a generic time comparison option to the panel options editor. - * Can be used by any panel that supports time comparison. - */ -export function addTimeCompareOption( - builder: PanelOptionsEditorBuilder, - defaultValue = false -) { - builder.addBooleanSwitch({ - path: 'timeCompare', - name: 'Show comparison selector', - category: ['Time Comparison'], - description: 'Enables the comparison selector, so you can compare data between two time ranges', - defaultValue, - }); -} diff --git a/pkg/services/featuremgmt/registry.go b/pkg/services/featuremgmt/registry.go index edbc06b0029..43c3490359f 100644 --- a/pkg/services/featuremgmt/registry.go +++ b/pkg/services/featuremgmt/registry.go @@ -2133,6 +2133,17 @@ var ( Owner: identityAccessTeam, Expression: "true", }, + { + Name: "panelTimeSettings", + Description: "Enables a new panel time settings drawer", + FrontendOnly: false, + Stage: FeatureStageExperimental, + Owner: grafanaDashboardsSquad, + RequiresRestart: false, + AllowSelfServe: false, + HideFromDocs: false, + HideFromAdminPage: false, + }, { Name: "dashboardTemplates", Description: "Enable template dashboards", diff --git a/pkg/services/featuremgmt/toggles_gen.csv b/pkg/services/featuremgmt/toggles_gen.csv index 9a51e087cd6..35943dad6e2 100644 --- a/pkg/services/featuremgmt/toggles_gen.csv +++ b/pkg/services/featuremgmt/toggles_gen.csv @@ -274,4 +274,5 @@ newGauge,experimental,@grafana/dataviz-squad,false,false,true preventPanelChromeOverflow,preview,@grafana/grafana-frontend-platform,false,false,true pluginStoreServiceLoading,experimental,@grafana/plugins-platform-backend,false,false,false onlyStoreActionSets,GA,@grafana/identity-access-team,false,false,false +panelTimeSettings,experimental,@grafana/dashboards-squad,false,false,false dashboardTemplates,experimental,@grafana/sharing-squad,false,false,false diff --git a/pkg/services/featuremgmt/toggles_gen.go b/pkg/services/featuremgmt/toggles_gen.go index 13e47ce210e..fd328f487ac 100644 --- a/pkg/services/featuremgmt/toggles_gen.go +++ b/pkg/services/featuremgmt/toggles_gen.go @@ -1106,6 +1106,10 @@ const ( // When storing dashboard and folder resource permissions, only store action sets and not the full list of underlying permission FlagOnlyStoreActionSets = "onlyStoreActionSets" + // FlagPanelTimeSettings + // Enables a new panel time settings drawer + FlagPanelTimeSettings = "panelTimeSettings" + // FlagDashboardTemplates // Enable template dashboards FlagDashboardTemplates = "dashboardTemplates" diff --git a/pkg/services/featuremgmt/toggles_gen.json b/pkg/services/featuremgmt/toggles_gen.json index 583c41b5d42..ec67bd4bce9 100644 --- a/pkg/services/featuremgmt/toggles_gen.json +++ b/pkg/services/featuremgmt/toggles_gen.json @@ -2886,6 +2886,18 @@ "expression": "true" } }, + { + "metadata": { + "name": "panelTimeSettings", + "resourceVersion": "1761555646368", + "creationTimestamp": "2025-10-27T09:00:46Z" + }, + "spec": { + "description": "Enables a new panel time settings drawer", + "stage": "experimental", + "codeowner": "@grafana/dashboards-squad" + } + }, { "metadata": { "name": "panelTitleSearch", diff --git a/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataQueriesTab.test.tsx b/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataQueriesTab.test.tsx index aad14f4fa8b..40da4a158a8 100644 --- a/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataQueriesTab.test.tsx +++ b/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataQueriesTab.test.tsx @@ -24,7 +24,7 @@ import { SHARED_DASHBOARD_QUERY, DASHBOARD_DATASOURCE_PLUGIN_ID } from 'app/plug import { DashboardDataDTO } from 'app/types/dashboard'; import { PanelInspectDrawer } from '../../inspect/PanelInspectDrawer'; -import { PanelTimeRange, PanelTimeRangeState } from '../../scene/PanelTimeRange'; +import { PanelTimeRange, PanelTimeRangeState } from '../../scene/panel-timerange/PanelTimeRange'; import { transformSaveModelToScene } from '../../serialization/transformSaveModelToScene'; import { findVizPanelByKey } from '../../utils/utils'; import { buildPanelEditScene } from '../PanelEditor'; diff --git a/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataQueriesTab.tsx b/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataQueriesTab.tsx index 94e3d1ed2ad..490084b24ff 100644 --- a/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataQueriesTab.tsx +++ b/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataQueriesTab.tsx @@ -34,7 +34,7 @@ import { useQueryLibraryContext } from '../../../explore/QueryLibrary/QueryLibra import { ExpressionDatasourceUID } from '../../../expressions/types'; import { getDatasourceSrv } from '../../../plugins/datasource_srv'; import { PanelInspectDrawer } from '../../inspect/PanelInspectDrawer'; -import { PanelTimeRange } from '../../scene/PanelTimeRange'; +import { PanelTimeRange } from '../../scene/panel-timerange/PanelTimeRange'; import { getDashboardSceneFor, getQueryRunnerFor } from '../../utils/utils'; import { getUpdatedHoverHeader } from '../getPanelFrameOptions'; diff --git a/public/app/features/dashboard-scene/panel-edit/getPanelFrameOptions.tsx b/public/app/features/dashboard-scene/panel-edit/getPanelFrameOptions.tsx index c78b7a1a6b1..e881df09579 100644 --- a/public/app/features/dashboard-scene/panel-edit/getPanelFrameOptions.tsx +++ b/public/app/features/dashboard-scene/panel-edit/getPanelFrameOptions.tsx @@ -14,8 +14,8 @@ import { getPanelLinksVariableSuggestions } from 'app/features/panel/panellinks/ import { dashboardEditActions } from '../edit-pane/shared'; import { VizPanelLinks } from '../scene/PanelLinks'; -import { PanelTimeRange } from '../scene/PanelTimeRange'; import { useEditPaneInputAutoFocus } from '../scene/layouts-shared/utils'; +import { PanelTimeRange } from '../scene/panel-timerange/PanelTimeRange'; import { isDashboardLayoutItem } from '../scene/types/DashboardLayoutItem'; import { vizPanelToPanel, transformSceneToSaveModel } from '../serialization/transformSceneToSaveModel'; import { dashboardSceneGraph } from '../utils/dashboardSceneGraph'; diff --git a/public/app/features/dashboard-scene/saving/DashboardSceneChangeTracker.ts b/public/app/features/dashboard-scene/saving/DashboardSceneChangeTracker.ts index 658cf97fa1f..6bae04e7248 100644 --- a/public/app/features/dashboard-scene/saving/DashboardSceneChangeTracker.ts +++ b/public/app/features/dashboard-scene/saving/DashboardSceneChangeTracker.ts @@ -24,7 +24,6 @@ import { DashboardControls } from '../scene/DashboardControls'; import { DashboardScene, PERSISTED_PROPS } from '../scene/DashboardScene'; import { LibraryPanelBehavior } from '../scene/LibraryPanelBehavior'; import { VizPanelLinks } from '../scene/PanelLinks'; -import { PanelTimeRange } from '../scene/PanelTimeRange'; import { AutoGridItem } from '../scene/layout-auto-grid/AutoGridItem'; import { AutoGridLayoutManager } from '../scene/layout-auto-grid/AutoGridLayoutManager'; import { DashboardGridItem } from '../scene/layout-default/DashboardGridItem'; @@ -32,6 +31,7 @@ import { RowItem } from '../scene/layout-rows/RowItem'; import { RowsLayoutManager } from '../scene/layout-rows/RowsLayoutManager'; import { TabItem } from '../scene/layout-tabs/TabItem'; import { TabsLayoutManager } from '../scene/layout-tabs/TabsLayoutManager'; +import { PanelTimeRange } from '../scene/panel-timerange/PanelTimeRange'; import { isSceneVariableInstance } from '../settings/variables/utils'; import { DashboardChangeInfo } from './shared'; diff --git a/public/app/features/dashboard-scene/scene/CustomTimeRangeCompare.tsx b/public/app/features/dashboard-scene/scene/CustomTimeRangeCompare.tsx deleted file mode 100644 index e741ea98ba2..00000000000 --- a/public/app/features/dashboard-scene/scene/CustomTimeRangeCompare.tsx +++ /dev/null @@ -1,79 +0,0 @@ -import { reportInteraction } from '@grafana/runtime'; -import { SceneTimeRangeCompare, SceneComponentProps, VizPanel, sceneGraph } from '@grafana/scenes'; -import { TimeCompareOptions } from '@grafana/schema'; - -function hasTimeCompare(options: unknown): options is TimeCompareOptions { - return options != null && typeof options === 'object' && 'timeCompare' in options; -} - -export class CustomTimeRangeCompare extends SceneTimeRangeCompare { - private readonly parentOnCompareWithChanged: (compareWith: string) => void; - - constructor(state: Partial = {}) { - super({ - ...state, - compareWith: undefined, - compareOptions: [], - hideCheckbox: true, - }); - - this.parentOnCompareWithChanged = this.onCompareWithChanged.bind(this); - - this.onCompareWithChanged = (compareWith: string) => { - const vizPanel = sceneGraph.getAncestor(this, VizPanel); - - reportInteraction('panel_time_comparison', { - viz_type: vizPanel?.getPlugin()?.meta.id || 'unknown', - select_type: 'option_selected', - option_type: compareWith, - }); - - this.parentOnCompareWithChanged(compareWith); - }; - - this.addActivationHandler(() => this._activationHandler()); - } - - private _activationHandler() { - // Subscribe to parent panel's options changes - const vizPanel = sceneGraph.getAncestor(this, VizPanel); - - this._subs.add( - vizPanel.subscribeToState((newState, prevState) => { - const newTimeCompareEnabled = hasTimeCompare(newState.options) && newState.options.timeCompare; - const prevTimeCompareEnabled = hasTimeCompare(prevState.options) && prevState.options.timeCompare; - - // Only act when transitioning from enabled to disabled - if (prevTimeCompareEnabled && !newTimeCompareEnabled) { - this._handleDisable(); - } - }) - ); - } - - private _handleDisable() { - // Only clear state if there's actually a comparison active - if (this.state.compareWith) { - this.setState({ - compareWith: undefined, - }); - } - } - - static Component = function CustomTimeRangeCompareRenderer({ model }: SceneComponentProps) { - const vizPanel = sceneGraph.getAncestor(model, VizPanel); - const { options } = vizPanel.useState(); - - const isTimeCompareEnabled = hasTimeCompare(options) && options.timeCompare; - - if (!isTimeCompareEnabled) { - return <>; - } - - return ( -
- -
- ); - }; -} diff --git a/public/app/features/dashboard-scene/scene/DashboardLevelTimeMacro.test.ts b/public/app/features/dashboard-scene/scene/DashboardLevelTimeMacro.test.ts index d55c4940f52..9a7bc67cd22 100644 --- a/public/app/features/dashboard-scene/scene/DashboardLevelTimeMacro.test.ts +++ b/public/app/features/dashboard-scene/scene/DashboardLevelTimeMacro.test.ts @@ -6,7 +6,6 @@ import { activateFullSceneTree } from '../utils/test-utils'; import { DashboardLevelTimeMacro } from './DashboardLevelTimeMacro'; import { DashboardScene } from './DashboardScene'; -import { PanelTimeRange } from './PanelTimeRange'; import { AutoGridItem } from './layout-auto-grid/AutoGridItem'; import { AutoGridLayout } from './layout-auto-grid/AutoGridLayout'; import { @@ -14,6 +13,7 @@ import { getAutoRowsTemplate, getTemplateColumnsTemplate, } from './layout-auto-grid/AutoGridLayoutManager'; +import { PanelTimeRange } from './panel-timerange/PanelTimeRange'; jest.mock('@grafana/runtime', () => ({ ...jest.requireActual('@grafana/runtime'), diff --git a/public/app/features/dashboard-scene/scene/DashboardScene.test.tsx b/public/app/features/dashboard-scene/scene/DashboardScene.test.tsx index 7454ad46eb3..29478ca80a1 100644 --- a/public/app/features/dashboard-scene/scene/DashboardScene.test.tsx +++ b/public/app/features/dashboard-scene/scene/DashboardScene.test.tsx @@ -43,10 +43,10 @@ import { findVizPanelByKey, getLibraryPanelBehavior, isLibraryPanel } from '../u import { DashboardControls } from './DashboardControls'; import { DashboardScene, DashboardSceneState } from './DashboardScene'; import { LibraryPanelBehavior } from './LibraryPanelBehavior'; -import { PanelTimeRange } from './PanelTimeRange'; import { DashboardGridItem } from './layout-default/DashboardGridItem'; import { DefaultGridLayoutManager } from './layout-default/DefaultGridLayoutManager'; import { RowActions } from './layout-default/row-actions/RowActions'; +import { PanelTimeRange } from './panel-timerange/PanelTimeRange'; jest.mock('../settings/version-history/HistorySrv'); jest.mock('../serialization/transformSaveModelToScene'); diff --git a/public/app/features/dashboard-scene/scene/LibraryPanelBehavior.test.tsx b/public/app/features/dashboard-scene/scene/LibraryPanelBehavior.test.tsx index e8a3c3d4d8b..238e6a87b06 100644 --- a/public/app/features/dashboard-scene/scene/LibraryPanelBehavior.test.tsx +++ b/public/app/features/dashboard-scene/scene/LibraryPanelBehavior.test.tsx @@ -22,9 +22,9 @@ import { getPanelIdForVizPanel } from '../utils/utils'; import { DashboardScene } from './DashboardScene'; import { LibraryPanelBehavior } from './LibraryPanelBehavior'; import { VizPanelLinks } from './PanelLinks'; -import { PanelTimeRange } from './PanelTimeRange'; import { DashboardGridItem } from './layout-default/DashboardGridItem'; import { DefaultGridLayoutManager } from './layout-default/DefaultGridLayoutManager'; +import { PanelTimeRange } from './panel-timerange/PanelTimeRange'; setPluginImportUtils({ importPanelPlugin: (id: string) => Promise.resolve(getPanelPlugin({})), diff --git a/public/app/features/dashboard-scene/scene/LibraryPanelBehavior.tsx b/public/app/features/dashboard-scene/scene/LibraryPanelBehavior.tsx index ecccc4b21d1..74b78bbc323 100644 --- a/public/app/features/dashboard-scene/scene/LibraryPanelBehavior.tsx +++ b/public/app/features/dashboard-scene/scene/LibraryPanelBehavior.tsx @@ -13,8 +13,8 @@ import { getPanelIdForVizPanel } from '../utils/utils'; import { VizPanelLinks, VizPanelLinksMenu } from './PanelLinks'; import { panelLinksBehavior } from './PanelMenuBehavior'; import { PanelNotices } from './PanelNotices'; -import { PanelTimeRange } from './PanelTimeRange'; import { DashboardGridItem } from './layout-default/DashboardGridItem'; +import { PanelTimeRange } from './panel-timerange/PanelTimeRange'; export interface LibraryPanelBehaviorState extends SceneObjectState { uid: string; diff --git a/public/app/features/dashboard-scene/scene/PanelMenuBehavior.tsx b/public/app/features/dashboard-scene/scene/PanelMenuBehavior.tsx index b357e734bb7..8a5502115a8 100644 --- a/public/app/features/dashboard-scene/scene/PanelMenuBehavior.tsx +++ b/public/app/features/dashboard-scene/scene/PanelMenuBehavior.tsx @@ -43,6 +43,7 @@ import { getDashboardSceneFor, getPanelIdForVizPanel, getQueryRunnerFor, isLibra import { DashboardScene } from './DashboardScene'; import { VizPanelLinks, VizPanelLinksMenu } from './PanelLinks'; import { UnlinkLibraryPanelModal } from './UnlinkLibraryPanelModal'; +import { PanelTimeRangeDrawer } from './panel-timerange/PanelTimeRangeDrawer'; let getPluginExtensions: GetPluginExtensions; @@ -280,6 +281,17 @@ export function panelMenuBehavior(menu: VizPanelMenu) { items.push(getInspectMenuItem(plugin, panel, dashboard)); + if (config.featureToggles.panelTimeSettings) { + items.push({ + text: t('panel.header-menu.time-settings', 'Time settings'), + iconClassName: 'clock-nine', + onClick: (e) => { + e.preventDefault(); + dashboard.showModal(new PanelTimeRangeDrawer({ panelRef: panel.getRef() })); + }, + }); + } + setupGetPluginExtensions(); const { extensions } = getPluginExtensions({ diff --git a/public/app/features/dashboard-scene/scene/PanelTimeRange.test.tsx b/public/app/features/dashboard-scene/scene/panel-timerange/PanelTimeRange.test.tsx similarity index 84% rename from public/app/features/dashboard-scene/scene/PanelTimeRange.test.tsx rename to public/app/features/dashboard-scene/scene/panel-timerange/PanelTimeRange.test.tsx index a4b7cdd944c..7e39e1e696e 100644 --- a/public/app/features/dashboard-scene/scene/PanelTimeRange.test.tsx +++ b/public/app/features/dashboard-scene/scene/panel-timerange/PanelTimeRange.test.tsx @@ -10,7 +10,7 @@ import { TestVariable, } from '@grafana/scenes'; -import { activateFullSceneTree } from '../utils/test-utils'; +import { activateFullSceneTree } from '../../utils/test-utils'; import { PanelTimeRange } from './PanelTimeRange'; @@ -43,7 +43,7 @@ describe('PanelTimeRange', () => { expect(panelTime.state.value.from.toISOString()).toBe('2019-02-11T11:00:00.000Z'); expect(panelTime.state.value.to.toISOString()).toBe('2019-02-11T17:00:00.000Z'); - expect(panelTime.state.timeInfo).toBe(' timeshift -2h'); + expect(panelTime.state.timeInfo).toBe('Timeshift -2h'); }); it('should apply both relative time and time shift', () => { @@ -52,7 +52,23 @@ describe('PanelTimeRange', () => { buildAndActivateSceneFor(panelTime); expect(panelTime.state.value.from.toISOString()).toBe('2019-02-11T15:00:00.000Z'); - expect(panelTime.state.timeInfo).toBe('Last 2 hours timeshift -2h'); + expect(panelTime.state.timeInfo).toBe('Last 2 hours + timeshift -2h'); + }); + + it('should add time comparison to timeInfo', () => { + const panelTime = new PanelTimeRange({ compareWith: '1d' }); + + buildAndActivateSceneFor(panelTime); + + expect(panelTime.state.timeInfo).toBe('Compared to day before'); + }); + + it('should add time override and time comparison to timeInfo', () => { + const panelTime = new PanelTimeRange({ timeFrom: '1h', compareWith: '1d' }); + + buildAndActivateSceneFor(panelTime); + + expect(panelTime.state.timeInfo).toBe('Last 1 hour + compared to day before'); }); it('should update timeInfo when timeShift and timeFrom are variable expressions', async () => { @@ -75,14 +91,14 @@ describe('PanelTimeRange', () => { }); activateFullSceneTree(scene); - expect(panelTime.state.timeInfo).toBe('Last 10 seconds timeshift -20s'); + expect(panelTime.state.timeInfo).toBe('Last 10 seconds + timeshift -20s'); customTimeFrom.setState({ value: '15s' }); customTimeShift.setState({ value: '25s' }); panelTime.forceRender(); - expect(panelTime.state.timeInfo).toBe('Last 15 seconds timeshift -25s'); + expect(panelTime.state.timeInfo).toBe('Last 15 seconds + timeshift -25s'); }); it('should update panelTimeRange from/to based on scene timeRange on activate', () => { diff --git a/public/app/features/dashboard-scene/scene/PanelTimeRange.tsx b/public/app/features/dashboard-scene/scene/panel-timerange/PanelTimeRange.tsx similarity index 60% rename from public/app/features/dashboard-scene/scene/PanelTimeRange.tsx rename to public/app/features/dashboard-scene/scene/panel-timerange/PanelTimeRange.tsx index 6c5fac6d443..4449cff2ea6 100644 --- a/public/app/features/dashboard-scene/scene/PanelTimeRange.tsx +++ b/public/app/features/dashboard-scene/scene/panel-timerange/PanelTimeRange.tsx @@ -1,22 +1,35 @@ import { css } from '@emotion/css'; +import { capitalize } from 'lodash'; -import { dateMath, getDefaultTimeRange, GrafanaTheme2, rangeUtil, TimeRange } from '@grafana/data'; +import { DataQueryRequest, dateMath, getDefaultTimeRange, GrafanaTheme2, rangeUtil, TimeRange } from '@grafana/data'; +import { config } from '@grafana/runtime'; import { + ExtraQueryDescriptor, SceneComponentProps, + SceneDataQuery, sceneGraph, SceneTimeRangeLike, SceneTimeRangeState, SceneTimeRangeTransformerBase, VariableDependencyConfig, + VizPanel, } from '@grafana/scenes'; -import { Icon, PanelChrome, TimePickerTooltip, Tooltip, useStyles2 } from '@grafana/ui'; +import { Icon, PanelChrome, Stack, TimePickerTooltip, Tooltip, useStyles2 } from '@grafana/ui'; import { TimeOverrideResult } from 'app/features/dashboard/utils/panel'; +import { getDashboardSceneFor } from '../../utils/utils'; + +import { DEFAULT_COMPARE_OPTIONS, PanelTimeRangeDrawer, PanelTimeRangeZoomBehavior } from './PanelTimeRangeDrawer'; +import { getCompareTimeRange, timeShiftAlignmentProcessor } from './utils'; + export interface PanelTimeRangeState extends SceneTimeRangeState { + enabled?: boolean; timeFrom?: string; + zoomBehavior?: PanelTimeRangeZoomBehavior; timeShift?: string; hideTimeOverride?: boolean; timeInfo?: string; + compareWith?: string; } export class PanelTimeRange extends SceneTimeRangeTransformerBase implements SceneTimeRangeLike { @@ -61,13 +74,48 @@ export class PanelTimeRange extends SceneTimeRangeTransformerBase query.timeRangeCompare !== false); + if (targets.length) { + extraQueries.push({ + req: { + ...request, + targets, + range: compareRange, + }, + processor: timeShiftAlignmentProcessor, + }); + } + return extraQueries; + } + + // The query runner should rerun the comparison query if the compareWith value has changed and there are queries that haven't opted out of TWC + public shouldRerun(prev: PanelTimeRangeState, next: PanelTimeRangeState, queries: SceneDataQuery[]): boolean { + return ( + prev.compareWith !== next.compareWith && queries.find((query) => query.timeRangeCompare !== false) !== undefined + ); + } + private getTimeOverride(parentTimeRange: TimeRange): TimeOverrideResult { - const { timeFrom, timeShift } = this.state; + const { timeFrom, timeShift, compareWith } = this.state; + const infoBlocks = []; const newTimeData = { timeInfo: '', timeRange: parentTimeRange }; if (timeFrom) { @@ -82,12 +130,12 @@ export class PanelTimeRange extends SceneTimeRangeTransformerBase x.value === compareWith); + const text = option ? `compared to ${option.label.toLowerCase()}` : ''; + infoBlocks.push(text); + } + + newTimeData.timeInfo = capitalize(infoBlocks.join(' + ')); return newTimeData; } + + public onOpenSettings = () => { + const panel = this.parent; + const dashboard = getDashboardSceneFor(this); + if (panel instanceof VizPanel) { + dashboard.showModal(new PanelTimeRangeDrawer({ panelRef: panel.getRef() })); + } + }; } function PanelTimeRangeRenderer({ model }: SceneComponentProps) { @@ -125,10 +189,15 @@ function PanelTimeRangeRenderer({ model }: SceneComponentProps) return null; } + const onClick = config.featureToggles.panelTimeSettings ? model.onOpenSettings : undefined; + return ( }> - - {timeInfo} + + + +
{timeInfo}
+
); diff --git a/public/app/features/dashboard-scene/scene/panel-timerange/PanelTimeRangeDrawer.tsx b/public/app/features/dashboard-scene/scene/panel-timerange/PanelTimeRangeDrawer.tsx new file mode 100644 index 00000000000..215a5fba5d4 --- /dev/null +++ b/public/app/features/dashboard-scene/scene/panel-timerange/PanelTimeRangeDrawer.tsx @@ -0,0 +1,201 @@ +import { FeatureState } from '@grafana/data'; +import { t, Trans } from '@grafana/i18n'; +import { config } from '@grafana/runtime'; +import { SceneComponentProps, SceneObjectBase, SceneObjectRef, SceneObjectState, VizPanel } from '@grafana/scenes'; +import { Box, Button, Combobox, Drawer, FeatureBadge, Field, Label, Stack, Switch } from '@grafana/ui'; + +import { getQuickOptions } from '../../../../../../packages/grafana-ui/src/components/DateTimePickers/options'; +import { getDashboardSceneFor, getQueryRunnerFor } from '../../utils/utils'; + +import { PanelTimeRange } from './PanelTimeRange'; + +export const DEFAULT_COMPARE_OPTIONS = [ + { label: 'Disabled', value: '' }, + { label: 'Day before', value: '1d' }, + { label: 'Week before', value: '1w' }, + { label: 'Month before', value: '1M' }, +]; + +export type PanelTimeRangeZoomBehavior = 'panel_and_dashboard' | 'dashboard' | 'panel'; + +export interface PanelTimeRangeDrawerState extends SceneObjectState { + panelRef: SceneObjectRef; + timeFrom?: string; + timeShift?: string; + zoomBehavior?: PanelTimeRangeZoomBehavior; + hideTimeOverride?: boolean; + compareWith?: string; + timeFromLocked?: boolean; +} + +export class PanelTimeRangeDrawer extends SceneObjectBase { + public constructor(state: PanelTimeRangeDrawerState) { + super({ + ...state, + }); + + const panel = this.state.panelRef.resolve(); + const timeRange = panel.state.$timeRange; + + if (timeRange instanceof PanelTimeRange) { + this.setState({ + timeFrom: timeRange.state.timeFrom, + timeShift: timeRange.state.timeShift, + hideTimeOverride: timeRange.state.hideTimeOverride, + compareWith: timeRange.state.compareWith, + }); + } + } + + public onClose = () => { + getDashboardSceneFor(this).closeModal(); + }; + + public onApply = () => { + const panel = this.state.panelRef.resolve(); + let timeRange = panel.state.$timeRange; + + if (!(timeRange instanceof PanelTimeRange)) { + timeRange = new PanelTimeRange(); + } + + timeRange.setState({ + timeFrom: this.state.timeFrom, + timeShift: this.state.timeShift, + hideTimeOverride: this.state.hideTimeOverride, + compareWith: this.state.compareWith, + zoomBehavior: this.state.zoomBehavior, + }); + + if (!panel.state.$timeRange) { + panel.setState({ $timeRange: timeRange }); + const queryRunner = getQueryRunnerFor(panel); + queryRunner?.runQueries(); + } + + this.onClose(); + }; + + static Component = ({ model }: SceneComponentProps) => { + const { timeFrom, timeShift, compareWith, hideTimeOverride } = model.useState(); + + const timeOptions = getQuickOptions() + .filter((o) => { + // Filter out time options that are not relative to now as we do not have persitance support for those yet + return o.to === 'now'; + }) + .map((option, index) => ({ label: option.display, value: option.from })); + + timeOptions.unshift({ label: t('common.disabled', 'Disabled'), value: '' }); + + const timeShiftOptions = [ + { label: t('common.disabled', 'Disabled'), value: '' }, + { label: t('time-period.1_hour', '1 hour'), value: '1h' }, + { label: t('time-period.6_hours', '6 hours'), value: '6h' }, + { label: t('time-period.12_hours', '12 hours'), value: '12h' }, + { label: t('time-period.1_day', '1 day'), value: '24h' }, + { label: t('time-period.7_days', '7 days'), value: '7d' }, + { label: t('time-period.30_days', '30 days'), value: '30d' }, + ]; + + return ( + + + + + { + model.setState({ timeFrom: x.value }); + }} + /> + + + + { + model.setState({ timeShift: x.value }); + }} + /> + + + {config.featureToggles.timeComparison && ( + + + + + } + > + model.setState({ compareWith: x.value })} + /> + + )} + + + model.setState({ hideTimeOverride: x.currentTarget.checked })} + /> + + + + + + + + + + + ); + }; +} diff --git a/public/app/features/dashboard-scene/scene/panel-timerange/utils.ts b/public/app/features/dashboard-scene/scene/panel-timerange/utils.ts new file mode 100644 index 00000000000..3bbd25c869b --- /dev/null +++ b/public/app/features/dashboard-scene/scene/panel-timerange/utils.ts @@ -0,0 +1,56 @@ +// Processor function for use with time shifted comparison series. +// This aligns the secondary series with the primary and adds custom +// metadata and config to the secondary series' fields so that it is + +import { of } from 'rxjs'; + +import { dateTime, DateTime, rangeUtil, TimeRange } from '@grafana/data'; +import { ExtraQueryDataProcessor } from '@grafana/scenes'; + +// rendered appropriately. +export const timeShiftAlignmentProcessor: ExtraQueryDataProcessor = (primary, secondary) => { + const diff = secondary.timeRange.from.diff(primary.timeRange.from); + secondary.series.forEach((series) => { + series.refId = getCompareSeriesRefId(series.refId || ''); + series.meta = { + ...series.meta, + // @ts-ignore Remove when https://github.com/grafana/grafana/pull/71129 is released + timeCompare: { + diffMs: diff, + isTimeShiftQuery: true, + }, + }; + }); + return of(secondary); +}; + +export const getCompareSeriesRefId = (refId: string) => `${refId}-compare`; + +const PREVIOUS_PERIOD_VALUE = '__previousPeriod'; + +export function getCompareTimeRange(timeRange: TimeRange, compareWith: string | undefined): TimeRange | undefined { + let compareFrom: DateTime; + let compareTo: DateTime; + + if (compareWith) { + if (compareWith === PREVIOUS_PERIOD_VALUE) { + const diffMs = timeRange.to.diff(timeRange.from); + compareFrom = dateTime(timeRange.from!).subtract(diffMs); + compareTo = dateTime(timeRange.to!).subtract(diffMs); + } else { + compareFrom = dateTime(timeRange.from!).subtract(rangeUtil.intervalToMs(compareWith)); + compareTo = dateTime(timeRange.to!).subtract(rangeUtil.intervalToMs(compareWith)); + } + + return { + from: compareFrom, + to: compareTo, + raw: { + from: compareFrom, + to: compareTo, + }, + }; + } + + return undefined; +} diff --git a/public/app/features/dashboard-scene/serialization/layoutSerializers/utils.test.ts b/public/app/features/dashboard-scene/serialization/layoutSerializers/utils.test.ts index d703b6e233d..be11b4e9dcd 100644 --- a/public/app/features/dashboard-scene/serialization/layoutSerializers/utils.test.ts +++ b/public/app/features/dashboard-scene/serialization/layoutSerializers/utils.test.ts @@ -1,8 +1,6 @@ -import { defaultDataQueryKind, PanelQueryKind, PanelKind } from '@grafana/schema/dist/esm/schema/dashboard/v2'; +import { defaultDataQueryKind, PanelQueryKind } from '@grafana/schema/dist/esm/schema/dashboard/v2'; -import { CustomTimeRangeCompare } from '../../scene/CustomTimeRangeCompare'; - -import { buildVizPanel, getRuntimePanelDataSource } from './utils'; +import { getRuntimePanelDataSource } from './utils'; // Mock the config needed for the function jest.mock('@grafana/runtime', () => ({ @@ -42,76 +40,6 @@ jest.mock('@grafana/runtime', () => ({ }, })); -// Mock only what's essential for header actions tests -jest.mock('../../scene/CustomTimeRangeCompare', () => ({ - CustomTimeRangeCompare: jest.fn(), -})); - -// Helper function to create a minimal panel for testing -const createTestPanel = (): PanelKind => ({ - kind: 'Panel', - spec: { - id: 1, - title: 'Test Panel', - description: '', - vizConfig: { - kind: 'VizConfig', - group: 'timeseries', - version: '1.0.0', - spec: { - options: {}, - fieldConfig: { defaults: {}, overrides: [] }, - }, - }, - data: { - kind: 'QueryGroup', - spec: { - queries: [], - queryOptions: {}, - transformations: [], - }, - }, - links: [], - }, -}); - -describe('buildVizPanel', () => { - describe('header actions', () => { - beforeEach(() => { - jest.clearAllMocks(); - }); - - it('should include CustomTimeRangeCompare in headerActions when timeComparison feature toggle is enabled', () => { - // Mock config with timeComparison enabled - const mockConfig = require('@grafana/runtime').config; - mockConfig.featureToggles.timeComparison = true; - - const panel = createTestPanel(); - const vizPanel = buildVizPanel(panel); - - expect(vizPanel.state.headerActions).toBeDefined(); - expect(vizPanel.state.headerActions).toHaveLength(1); - expect(CustomTimeRangeCompare).toHaveBeenCalledWith({ - key: 'time-compare', - compareWith: undefined, - compareOptions: [], - }); - }); - - it('should not include headerActions when timeComparison feature toggle is disabled', () => { - // Mock config with timeComparison disabled - const mockConfig = require('@grafana/runtime').config; - mockConfig.featureToggles.timeComparison = false; - - const panel = createTestPanel(); - const vizPanel = buildVizPanel(panel); - - expect(vizPanel.state.headerActions).toBeUndefined(); - expect(CustomTimeRangeCompare).not.toHaveBeenCalled(); - }); - }); -}); - describe('getRuntimePanelDataSource', () => { it('should return the datasource when it is specified in the query', () => { const query: PanelQueryKind = { diff --git a/public/app/features/dashboard-scene/serialization/layoutSerializers/utils.ts b/public/app/features/dashboard-scene/serialization/layoutSerializers/utils.ts index 78ab49707cd..3f8c2edf01e 100644 --- a/public/app/features/dashboard-scene/serialization/layoutSerializers/utils.ts +++ b/public/app/features/dashboard-scene/serialization/layoutSerializers/utils.ts @@ -24,16 +24,15 @@ import { import { MIXED_DATASOURCE_NAME } from 'app/plugins/datasource/mixed/MixedDataSource'; import { ConditionalRenderingGroup } from '../../conditional-rendering/group/ConditionalRenderingGroup'; -import { CustomTimeRangeCompare } from '../../scene/CustomTimeRangeCompare'; import { DashboardDatasourceBehaviour } from '../../scene/DashboardDatasourceBehaviour'; import { DashboardScene } from '../../scene/DashboardScene'; import { LibraryPanelBehavior } from '../../scene/LibraryPanelBehavior'; import { VizPanelLinks, VizPanelLinksMenu } from '../../scene/PanelLinks'; import { panelLinksBehavior, panelMenuBehavior } from '../../scene/PanelMenuBehavior'; import { PanelNotices } from '../../scene/PanelNotices'; -import { PanelTimeRange } from '../../scene/PanelTimeRange'; import { AutoGridItem } from '../../scene/layout-auto-grid/AutoGridItem'; import { DashboardGridItem } from '../../scene/layout-default/DashboardGridItem'; +import { PanelTimeRange } from '../../scene/panel-timerange/PanelTimeRange'; import { setDashboardPanelContext } from '../../scene/setDashboardPanelContext'; import { DashboardLayoutManager } from '../../scene/types/DashboardLayoutManager'; import { getVizPanelKeyForPanelId } from '../../utils/utils'; @@ -72,10 +71,6 @@ export function buildVizPanel(panel: PanelKind, id?: number): VizPanel { titleItems, $behaviors: [], extendPanelContext: setDashboardPanelContext, - // _UNSAFE_customMigrationHandler: getAngularPanelMigrationHandler(panel), //FIXME: Angular Migration - headerActions: config.featureToggles.timeComparison - ? [new CustomTimeRangeCompare({ key: 'time-compare', compareWith: undefined, compareOptions: [] })] - : undefined, }; if (!config.publicDashboardAccessToken) { diff --git a/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.test.ts b/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.test.ts index 46b5324bbeb..a37dcd2fbae 100644 --- a/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.test.ts +++ b/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.test.ts @@ -29,11 +29,11 @@ import { DashboardDataDTO } from 'app/types/dashboard'; import { DashboardDataLayerSet } from '../scene/DashboardDataLayerSet'; import { LibraryPanelBehavior } from '../scene/LibraryPanelBehavior'; -import { PanelTimeRange } from '../scene/PanelTimeRange'; import { DashboardGridItem } from '../scene/layout-default/DashboardGridItem'; import { DefaultGridLayoutManager } from '../scene/layout-default/DefaultGridLayoutManager'; import { RowRepeaterBehavior } from '../scene/layout-default/RowRepeaterBehavior'; import { RowsLayoutManager } from '../scene/layout-rows/RowsLayoutManager'; +import { PanelTimeRange } from '../scene/panel-timerange/PanelTimeRange'; import { NEW_LINK } from '../settings/links/utils'; import { getQueryRunnerFor } from '../utils/utils'; @@ -810,41 +810,6 @@ describe('transformSaveModelToScene', () => { expect((libPanelBehavior as LibraryPanelBehavior).state.name).toEqual(panel.libraryPanel.name); expect(gridItem.state.body.state.title).toEqual(panel.title); }); - - describe('header actions', () => { - beforeEach(() => { - jest.clearAllMocks(); - }); - - it('should include headerActions when timeComparison feature toggle is enabled', () => { - config.featureToggles.timeComparison = true; - - const panel = { - title: 'Test Panel', - type: 'timeseries', - gridPos: { x: 0, y: 0, w: 12, h: 8 }, - }; - - const { vizPanel } = buildGridItemForTest(panel); - - expect(vizPanel.state.headerActions).toBeDefined(); - expect(vizPanel.state.headerActions).toHaveLength(1); - }); - - it('should not include headerActions when timeComparison feature toggle is disabled', () => { - config.featureToggles.timeComparison = false; - - const panel = { - title: 'Test Panel', - type: 'timeseries', - gridPos: { x: 0, y: 0, w: 12, h: 8 }, - }; - - const { vizPanel } = buildGridItemForTest(panel); - - expect(vizPanel.state.headerActions).toBeUndefined(); - }); - }); }); describe('Convert to new rows', () => { diff --git a/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.ts b/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.ts index 8c3f3559030..6ec06c96c28 100644 --- a/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.ts +++ b/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.ts @@ -33,7 +33,6 @@ import { DashboardDTO, DashboardDataDTO } from 'app/types/dashboard'; import { addPanelsOnLoadBehavior } from '../addToDashboard/addPanelsOnLoadBehavior'; import { AlertStatesDataLayer } from '../scene/AlertStatesDataLayer'; -import { CustomTimeRangeCompare } from '../scene/CustomTimeRangeCompare'; import { DashboardAnnotationsDataLayer } from '../scene/DashboardAnnotationsDataLayer'; import { DashboardControls } from '../scene/DashboardControls'; import { DashboardDataLayerSet } from '../scene/DashboardDataLayerSet'; @@ -44,7 +43,6 @@ import { LibraryPanelBehavior } from '../scene/LibraryPanelBehavior'; import { VizPanelLinks, VizPanelLinksMenu } from '../scene/PanelLinks'; import { panelLinksBehavior, panelMenuBehavior } from '../scene/PanelMenuBehavior'; import { PanelNotices } from '../scene/PanelNotices'; -import { PanelTimeRange } from '../scene/PanelTimeRange'; import { DashboardGridItem, RepeatDirection } from '../scene/layout-default/DashboardGridItem'; import { DefaultGridLayoutManager } from '../scene/layout-default/DefaultGridLayoutManager'; import { RowRepeaterBehavior } from '../scene/layout-default/RowRepeaterBehavior'; @@ -52,6 +50,7 @@ import { RowActions } from '../scene/layout-default/row-actions/RowActions'; import { RowItem } from '../scene/layout-rows/RowItem'; import { RowsLayoutManager } from '../scene/layout-rows/RowsLayoutManager'; import { getIsLazy } from '../scene/layouts-shared/utils'; +import { PanelTimeRange } from '../scene/panel-timerange/PanelTimeRange'; import { setDashboardPanelContext } from '../scene/setDashboardPanelContext'; import { DashboardLayoutManager } from '../scene/types/DashboardLayoutManager'; import { createPanelDataProvider } from '../utils/createPanelDataProvider'; @@ -428,9 +427,6 @@ export function buildGridItemForPanel(panel: PanelModel): DashboardGridItem { $behaviors: [], extendPanelContext: setDashboardPanelContext, _UNSAFE_customMigrationHandler: getAngularPanelMigrationHandler(panel), - headerActions: config.featureToggles.timeComparison - ? [new CustomTimeRangeCompare({ key: 'time-compare', compareWith: undefined, compareOptions: [] })] - : undefined, }; if (panel.libraryPanel) { diff --git a/public/app/features/dashboard-scene/serialization/transformSceneToSaveModel.ts b/public/app/features/dashboard-scene/serialization/transformSceneToSaveModel.ts index a18a5918c7e..16b3957435f 100644 --- a/public/app/features/dashboard-scene/serialization/transformSceneToSaveModel.ts +++ b/public/app/features/dashboard-scene/serialization/transformSceneToSaveModel.ts @@ -32,10 +32,10 @@ import { GrafanaQueryType } from 'app/plugins/datasource/grafana/types'; import { DashboardDataLayerSet } from '../scene/DashboardDataLayerSet'; import { DashboardScene } from '../scene/DashboardScene'; -import { PanelTimeRange } from '../scene/PanelTimeRange'; import { DashboardGridItem } from '../scene/layout-default/DashboardGridItem'; import { DefaultGridLayoutManager } from '../scene/layout-default/DefaultGridLayoutManager'; import { RowRepeaterBehavior } from '../scene/layout-default/RowRepeaterBehavior'; +import { PanelTimeRange } from '../scene/panel-timerange/PanelTimeRange'; import { dashboardSceneGraph } from '../utils/dashboardSceneGraph'; import { djb2Hash } from '../utils/djb2Hash'; import { diff --git a/public/app/features/dashboard-scene/serialization/transformSceneToSaveModelSchemaV2.ts b/public/app/features/dashboard-scene/serialization/transformSceneToSaveModelSchemaV2.ts index a1d379d9865..da7e19d3a41 100644 --- a/public/app/features/dashboard-scene/serialization/transformSceneToSaveModelSchemaV2.ts +++ b/public/app/features/dashboard-scene/serialization/transformSceneToSaveModelSchemaV2.ts @@ -48,7 +48,7 @@ import { } from '../../../../../packages/grafana-schema/src/schema/dashboard/v2'; import { DashboardDataLayerSet } from '../scene/DashboardDataLayerSet'; import { DashboardScene, DashboardSceneState } from '../scene/DashboardScene'; -import { PanelTimeRange } from '../scene/PanelTimeRange'; +import { PanelTimeRange } from '../scene/panel-timerange/PanelTimeRange'; import { dashboardSceneGraph } from '../utils/dashboardSceneGraph'; import { getLibraryPanelBehavior, getPanelIdForVizPanel, getQueryRunnerFor, isLibraryPanel } from '../utils/utils'; diff --git a/public/app/features/dashboard-scene/sharing/SharePanelEmbedTab.tsx b/public/app/features/dashboard-scene/sharing/SharePanelEmbedTab.tsx index 7652a2c6f17..2e69a0abcb6 100644 --- a/public/app/features/dashboard-scene/sharing/SharePanelEmbedTab.tsx +++ b/public/app/features/dashboard-scene/sharing/SharePanelEmbedTab.tsx @@ -5,7 +5,7 @@ import { ShareEmbed } from 'app/features/dashboard/components/ShareModal/ShareEm import { buildParams, shareDashboardType } from 'app/features/dashboard/components/ShareModal/utils'; import { DashboardScene } from '../scene/DashboardScene'; -import { PanelTimeRange } from '../scene/PanelTimeRange'; +import { PanelTimeRange } from '../scene/panel-timerange/PanelTimeRange'; import { getDashboardUrl } from '../utils/getDashboardUrl'; import { getDashboardSceneFor } from '../utils/utils'; diff --git a/public/app/features/dashboard-scene/utils/utils.ts b/public/app/features/dashboard-scene/utils/utils.ts index 780275bc239..12dba08eda4 100644 --- a/public/app/features/dashboard-scene/utils/utils.ts +++ b/public/app/features/dashboard-scene/utils/utils.ts @@ -17,7 +17,6 @@ import { Dashboard, Panel, RowPanel } from '@grafana/schema'; import { createLogger } from '@grafana/ui'; import { initialIntervalVariableModelState } from 'app/features/variables/interval/reducer'; -import { CustomTimeRangeCompare } from '../scene/CustomTimeRangeCompare'; import { DashboardDatasourceBehaviour } from '../scene/DashboardDatasourceBehaviour'; import { DashboardLayoutOrchestrator } from '../scene/DashboardLayoutOrchestrator'; import { DashboardScene, DashboardSceneState } from '../scene/DashboardScene'; @@ -256,9 +255,6 @@ export function getDefaultVizPanel(): VizPanel { menu: new VizPanelMenu({ $behaviors: [panelMenuBehavior], }), - headerActions: config.featureToggles.timeComparison - ? [new CustomTimeRangeCompare({ key: 'time-compare', compareWith: undefined, compareOptions: [] })] - : undefined, $data: new SceneDataTransformer({ $data: new SceneQueryRunner({ queries: [{ refId: 'A' }], diff --git a/public/app/plugins/panel/timeseries/module.tsx b/public/app/plugins/panel/timeseries/module.tsx index 967cba918b5..beccdf480d6 100644 --- a/public/app/plugins/panel/timeseries/module.tsx +++ b/public/app/plugins/panel/timeseries/module.tsx @@ -1,6 +1,5 @@ import { PanelPlugin } from '@grafana/data'; import { t } from '@grafana/i18n'; -import { config } from '@grafana/runtime'; import { commonOptionsBuilder } from '@grafana/ui'; import { optsWithHideZeros } from '@grafana/ui/internal'; @@ -18,10 +17,6 @@ export const plugin = new PanelPlugin(TimeSeriesPanel) commonOptionsBuilder.addTooltipOptions(builder, false, true, optsWithHideZeros); commonOptionsBuilder.addLegendOptions(builder); - if (config.featureToggles.timeComparison && config.featureToggles.dashboardScene) { - commonOptionsBuilder.addTimeCompareOption(builder); - } - builder.addCustomEditor({ id: 'timezone', name: t('timeseries.name-time-zone', 'Time zone'), diff --git a/public/locales/en-US/grafana.json b/public/locales/en-US/grafana.json index b0d349ab26b..1beea7c487a 100644 --- a/public/locales/en-US/grafana.json +++ b/public/locales/en-US/grafana.json @@ -4157,6 +4157,7 @@ "cancel": "Cancel", "clear": "Clear", "collapse": "Collapse", + "disabled": "Disabled", "edit": "Edit", "help": "Help", "loading": "Loading...", @@ -5133,6 +5134,19 @@ "aria-label-remove-override": "Remove override", "tooltip-remove-override": "Remove override" }, + "panel": { + "time-range-settings": { + "hide-time-info": "Hidden time info", + "hide-time-info-description": "Do not show the custom time range in the panel header", + "time-from": "Custom panel time range", + "time-from-description": "Overrides the dashboard time range. To specify a value not found in the list just type in a custom value, for example 5m or 2h", + "time-shift": "Time shift", + "time-shift-description": "Adds a time shift relative to the dashboard or panel time range. To specify a value not found in the list just type in a custom value, for example 5m or 2h", + "time-window-compare": "Time window comparison", + "time-window-compare-description": "Query and overlay data from a different time period", + "title": "Panel time range settings" + } + }, "panel-edit": { "alerting-tab": { "dashboard-not-saved": "Dashboard must be saved before alerts can be added.", @@ -10872,6 +10886,7 @@ "replace-library-panel": "Replace library panel", "share": "Share", "show-legend": "Show legend", + "time-settings": "Time settings", "unlink-library-panel": "Unlink library panel", "view": "View" }, @@ -13135,6 +13150,14 @@ "title": "Panel" } }, + "time-period": { + "1_day": "1 day", + "1_hour": "1 hour", + "12_hours": "12 hours", + "30_days": "30 days", + "6_hours": "6 hours", + "7_days": "7 days" + }, "time-picker": { "absolute": { "recent-title": "Recently used absolute ranges", From c7d77c6c64fc6ab1be4dce119d1dd1377d33a2d7 Mon Sep 17 00:00:00 2001 From: Javier Ruiz Date: Wed, 29 Oct 2025 09:25:09 +0100 Subject: [PATCH 074/378] Nav: Update Observability section nav to phase 2 (#112806) * Move up a level the knowledge graph children * Remove unused frontend id * Add special id to plugin pages --- pkg/services/navtree/models.go | 2 -- pkg/services/navtree/navtreeimpl/applinks.go | 35 +++++++++++--------- 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/pkg/services/navtree/models.go b/pkg/services/navtree/models.go index 15418e04b59..50ccfcb4cdd 100644 --- a/pkg/services/navtree/models.go +++ b/pkg/services/navtree/models.go @@ -26,7 +26,6 @@ const ( WeightCloudServiceProviders WeightInfrastructure WeightApplication - WeightFrontend WeightAsserts WeightDataConnections WeightApps @@ -48,7 +47,6 @@ const ( NavIDAlerting = "alerting" NavIDObservability = "observability" NavIDInfrastructure = "infrastructure" - NavIDFrontend = "frontend" NavIDReporting = "reports" NavIDApps = "apps" NavIDCfgGeneral = "cfg/general" diff --git a/pkg/services/navtree/navtreeimpl/applinks.go b/pkg/services/navtree/navtreeimpl/applinks.go index 8c92bad85af..7a2f15206dc 100644 --- a/pkg/services/navtree/navtreeimpl/applinks.go +++ b/pkg/services/navtree/navtreeimpl/applinks.go @@ -4,6 +4,7 @@ import ( "path" "sort" "strconv" + "strings" "github.com/grafana/grafana/pkg/plugins" ac "github.com/grafana/grafana/pkg/services/accesscontrol" @@ -260,10 +261,22 @@ func (s *ServiceImpl) addPluginToSection(c *contextmodel.ReqContext, treeRoot *n } } + sectionChildren := []*navtree.NavLink{appLink} + // asserts pages expand to root Observability section instead of it's own node + if plugin.ID == "grafana-asserts-app" { + sectionChildren = appLink.Children + + // keep current sorting if the pages, but above all the other apps + for _, child := range sectionChildren { + child.SortWeight = -100 + child.SortWeight + child.Id = "standalone-plugin-page-" + strings.ReplaceAll(strings.ToLower(child.Text), " ", "-") + } + } + if sectionID == navtree.NavIDRoot { treeRoot.AddSection(appLink) } else if navNode := treeRoot.FindById(sectionID); navNode != nil { - navNode.Children = append(navNode.Children, appLink) + navNode.Children = append(navNode.Children, sectionChildren...) } else { switch sectionID { case navtree.NavIDApps: @@ -272,7 +285,7 @@ func (s *ServiceImpl) addPluginToSection(c *contextmodel.ReqContext, treeRoot *n Icon: "layer-group", SubTitle: "App plugins that extend the Grafana experience", Id: navtree.NavIDApps, - Children: []*navtree.NavLink{appLink}, + Children: sectionChildren, SortWeight: navtree.WeightApps, Url: s.cfg.AppSubURL + "/apps", }) @@ -283,7 +296,7 @@ func (s *ServiceImpl) addPluginToSection(c *contextmodel.ReqContext, treeRoot *n SubTitle: "Monitor infrastructure and applications in real time with Grafana Cloud's fully managed observability suite", Icon: "heart-rate", SortWeight: navtree.WeightObservability, - Children: []*navtree.NavLink{appLink}, + Children: sectionChildren, Url: s.cfg.AppSubURL + "/observability", }) case navtree.NavIDInfrastructure: @@ -293,19 +306,9 @@ func (s *ServiceImpl) addPluginToSection(c *contextmodel.ReqContext, treeRoot *n SubTitle: "Understand your infrastructure's health", Icon: "heart-rate", SortWeight: navtree.WeightInfrastructure, - Children: []*navtree.NavLink{appLink}, + Children: sectionChildren, Url: s.cfg.AppSubURL + "/infrastructure", }) - case navtree.NavIDFrontend: - treeRoot.AddSection(&navtree.NavLink{ - Text: "Frontend", - Id: navtree.NavIDFrontend, - SubTitle: "Gain real user monitoring insights", - Icon: "frontend-observability", - SortWeight: navtree.WeightFrontend, - Children: []*navtree.NavLink{appLink}, - Url: s.cfg.AppSubURL + "/frontend", - }) case navtree.NavIDAlertsAndIncidents: alertsAndIncidentsChildren := []*navtree.NavLink{} for _, alertingNode := range alertingNodes { @@ -332,7 +335,7 @@ func (s *ServiceImpl) addPluginToSection(c *contextmodel.ReqContext, treeRoot *n SubTitle: "Optimize performance with k6 and Synthetic Monitoring insights", Icon: "k6", SortWeight: navtree.WeightTestingAndSynthetics, - Children: []*navtree.NavLink{appLink}, + Children: sectionChildren, Url: s.cfg.AppSubURL + "/testing-and-synthetics", }) case navtree.NavIDAdaptiveTelemetry: @@ -342,7 +345,7 @@ func (s *ServiceImpl) addPluginToSection(c *contextmodel.ReqContext, treeRoot *n SubTitle: "Reduce noise, cut costs, and accelerate troubleshooting by intelligently ingesting only the telemetry data that matters most.", Icon: "adaptive-telemetry", SortWeight: navtree.WeightAIAndML + 1, // Place under "AI & Machine Learning" - Children: []*navtree.NavLink{appLink}, + Children: sectionChildren, Url: "adaptive-telemetry", // Use the icon URL from the first "Adaptive Telemetry" plugin in the list (they will all be the same) Img: s.cfg.AppSubURL + plugin.Info.Logos.Large, From 3176821ddc300941020e71ae8c2843ad34379527 Mon Sep 17 00:00:00 2001 From: Stephanie Hingtgen Date: Wed, 29 Oct 2025 03:13:26 -0600 Subject: [PATCH 075/378] Docs: Update search default information (#113146) --- docs/sources/developers/http_api/folder_dashboard_search.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sources/developers/http_api/folder_dashboard_search.md b/docs/sources/developers/http_api/folder_dashboard_search.md index eda90559d99..819a1fcac6c 100644 --- a/docs/sources/developers/http_api/folder_dashboard_search.md +++ b/docs/sources/developers/http_api/folder_dashboard_search.md @@ -36,7 +36,7 @@ Query parameters: - **dashboardUIDs** – List of dashboard uid's to search for - **folderUIDs** – List of folder UIDs to search in - **starred** – Flag indicating if only starred Dashboards should be returned -- **limit** – Limit the number of returned results (max is 5000; default is 1000) +- **limit** – Limit the number of returned results (max is 5000; default is 1000). If an invalid value is provided (for example, strings or special characters), the parameter defaults to 1000. - **page** – Use this parameter to access hits beyond limit. Numbering starts at 1. limit param acts as page size. **Example request for retrieving folders and dashboards at the root level**: From 2d5713e3309224b5574f68427bd9fc2b92213afc Mon Sep 17 00:00:00 2001 From: Stephanie Hingtgen Date: Wed, 29 Oct 2025 03:26:42 -0600 Subject: [PATCH 076/378] Docs: Add information on continue tokens (#113144) --- docs/sources/developers/http_api/dashboard.md | 58 ++++++++++++++++++- docs/sources/developers/http_api/folder.md | 52 ++++++++++++++++- 2 files changed, 108 insertions(+), 2 deletions(-) diff --git a/docs/sources/developers/http_api/dashboard.md b/docs/sources/developers/http_api/dashboard.md index f5456a22e77..0c886a83b48 100644 --- a/docs/sources/developers/http_api/dashboard.md +++ b/docs/sources/developers/http_api/dashboard.md @@ -634,6 +634,11 @@ Lists all dashboards in the given organization. You can control the maximum numb - namespace: to read more about the namespace to use, see the [API overview](https://grafana.com/docs/grafana//developers/http_api/apis/). +**Query parameters**: + +- **`limit`** (optional): Maximum number of dashboards to return +- **`continue`** (optional): Continue token from a previous response to fetch the next page + **Required permissions** See note in the [introduction]({{< ref "#dashboard-api" >}}) for an explanation. @@ -666,7 +671,7 @@ Content-Length: 644 "apiVersion": "dashboard.grafana.app/v1alpha1", "metadata": { "resourceVersion": "1741315830000", - "continue": "org:1/start:1158/folder:" + "continue": "eyJvIjoxNTIsInYiOjE3NjE3MDQyMjQyMDcxODksInMiOmZhbHNlfQ==" }, "items": [ { @@ -697,6 +702,57 @@ Content-Length: 644 } ``` +The `metadata.continue` field contains a token to fetch the next page. + +**Example subsequent request using continue token**: + +```http +GET /apis/dashboard.grafana.app/v1beta1/namespaces/default/dashboards?limit=1&continue=eyJvIjoxNTIsInYiOjE3NjE3MDQyMjQyMDcxODksInMiOmZhbHNlfQ== HTTP/1.1 +Accept: application/json +Content-Type: application/json +Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk +``` + +**Example subsequent response**: + +```http +HTTP/1.1 200 OK +Content-Type: application/json; charset=UTF-8 + +{ + "kind": "DashboardList", + "apiVersion": "dashboard.grafana.app/v1alpha1", + "items": [ + { + "kind": "Dashboard", + "apiVersion": "dashboard.grafana.app/v1alpha1", + "metadata": { + "name": "hpqcmg", + "namespace": "default", + "uid": "WQyL7pNTpfGPNlPM6HRJSePrBg5dXmxr4iPQL7txLtwY", + "resourceVersion": "1", + "generation": 1, + "creationTimestamp": "2025-03-06T19:51:31Z", + "annotations": { + "grafana.app/createdBy": "service-account:cef2t2rfm73lsb", + "grafana.app/updatedBy": "service-account:cef2t2rfm73lsb", + "grafana.app/updatedTimestamp": "2025-03-06T19:51:31Z" + } + }, + "spec": { + "schemaVersion": 41, + "title": "Another dashboard", + "uid": "hpqcmg", + "version": 1, + ... + } + } + ] +} +``` + +Continue making requests with the updated `continue` token until you receive a response without a `continue` field in the metadata, indicating you've reached the last page. + Status Codes: - **200** – OK diff --git a/docs/sources/developers/http_api/folder.md b/docs/sources/developers/http_api/folder.md index cd66653e0e6..bc3b6605db0 100644 --- a/docs/sources/developers/http_api/folder.md +++ b/docs/sources/developers/http_api/folder.md @@ -41,6 +41,11 @@ Returns all folders that the authenticated user has permission to view within th - namespace: to read more about the namespace to use, see the [API overview](ref:apis). +**Query parameters**: + +- **`limit`** (optional): Maximum number of folders to return +- **`continue`** (optional): Continue token from a previous response to fetch the next page + **Required permissions** See note in the [introduction]({{< ref "#folder-api" >}}) for an explanation. @@ -67,7 +72,7 @@ Content-Type: application/json "kind": "FolderList", "apiVersion": "folder.grafana.app/v1beta1", "metadata": { - "continue": "org:1/start:1158/folder:" + "continue": "eyJvIjoxNTIsInYiOjE3NjE3MDQyMjQyMDcxODksInMiOmZhbHNlfQ==" }, "items": [ { @@ -93,6 +98,51 @@ Content-Type: application/json } ``` +The `metadata.continue` field contains a token to fetch the next page. + +**Example subsequent request using continue token**: + +```http +GET /apis/folder.grafana.app/v1beta1/namespaces/default/folders?limit=1&continue=eyJvIjoxNTIsInYiOjE3NjE3MDQyMjQyMDcxODksInMiOmZhbHNlfQ== HTTP/1.1 +Accept: application/json +Content-Type: application/json +Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk +``` + +**Example subsequent response**: + +```http +HTTP/1.1 200 +Content-Type: application/json +{ + "kind": "FolderList", + "apiVersion": "folder.grafana.app/v1beta1", + "items": [ + { + "kind": "Folder", + "apiVersion": "folder.grafana.app/v1beta1", + "metadata": { + "name": "bef30vrzxs3y8e", + "namespace": "default", + "uid": "YCtv1FXDsJmTYQoTgcPnfuwZhDZge3uMpXOefaOHjb5Y", + "resourceVersion": "1741343687000", + "creationTimestamp": "2025-03-07T10:35:47Z", + "annotations": { + "grafana.app/createdBy": "service-account:cef2t2rfm73lsb", + "grafana.app/updatedBy": "service-account:cef2t2rfm73lsb", + "grafana.app/updatedTimestamp": "2025-03-07T10:35:47Z" + } + }, + "spec": { + "title": "another folder" + } + } + ] +} +``` + +Continue making requests with the updated `continue` token until you receive a response without a `continue` field in the metadata, indicating you've reached the last page. + Status Codes: - **200** – OK From c0ae0f437f36b7c915af377b98d8acc44c8c873a Mon Sep 17 00:00:00 2001 From: Tobias Skarhed <1438972+tskarhed@users.noreply.github.com> Date: Wed, 29 Oct 2025 10:52:18 +0100 Subject: [PATCH 077/378] Scopes: Display subtitle and enable direct scopes apply (#112876) * Display subtitle and enable direct scopes apply * Extract each type into its own component * Fix unit integration test * Fix fe linting * Fix imports * Import order * Update generated type * Update type generation * Format go * Add test case for radio button container selection * Remove infra mock * Remove non-existant imports * Remove unused assertions * Refactor tree item for a11y * Add proper keyboard support for directly applying scope * Update i18n * Fix button selector * Remove test code * Fix race condition for seletion vs blur update --- apps/scope/pkg/apis/scope/v0alpha1/types.go | 7 +- .../scope/v0alpha1/zz_generated.openapi.go | 7 + .../dashboard-cujs/scope-cujs.spec.ts | 1 - e2e-playwright/utils/scope-helpers.ts | 11 +- packages/grafana-data/src/types/scopes.ts | 2 +- .../scopes/selector/ScopesTreeItem.tsx | 290 ++++++++++++++---- .../scopes/selector/ScopesTreeSearch.tsx | 7 +- .../scopes/selector/useScopesHighlighting.tsx | 14 + public/app/features/scopes/tests/tree.test.ts | 42 ++- .../features/scopes/tests/utils/actions.ts | 15 +- .../features/scopes/tests/utils/assertions.ts | 17 +- .../app/features/scopes/tests/utils/mocks.ts | 46 +++ .../features/scopes/tests/utils/selectors.ts | 13 +- public/locales/en-US/grafana.json | 2 - 14 files changed, 377 insertions(+), 97 deletions(-) diff --git a/apps/scope/pkg/apis/scope/v0alpha1/types.go b/apps/scope/pkg/apis/scope/v0alpha1/types.go index 799195b2832..b0f58fdfd44 100644 --- a/apps/scope/pkg/apis/scope/v0alpha1/types.go +++ b/apps/scope/pkg/apis/scope/v0alpha1/types.go @@ -146,7 +146,12 @@ type ScopeNodeSpec struct { NodeType NodeType `json:"nodeType"` // container | leaf - Title string `json:"title"` + Title string `json:"title"` + //+optional + // Displays next to the title to provide more context. + SubTitle string `json:"subTitle,omitempty"` + + //+optional Description string `json:"description,omitempty"` DisableMultiSelect bool `json:"disableMultiSelect"` diff --git a/apps/scope/pkg/apis/scope/v0alpha1/zz_generated.openapi.go b/apps/scope/pkg/apis/scope/v0alpha1/zz_generated.openapi.go index 243b0ff2c2e..a0b0e90b557 100644 --- a/apps/scope/pkg/apis/scope/v0alpha1/zz_generated.openapi.go +++ b/apps/scope/pkg/apis/scope/v0alpha1/zz_generated.openapi.go @@ -838,6 +838,13 @@ func schema_pkg_apis_scope_v0alpha1_ScopeNodeSpec(ref common.ReferenceCallback) Format: "", }, }, + "subTitle": { + SchemaProps: spec.SchemaProps{ + Description: "Displays next to the title to provide more context.", + Type: []string{"string"}, + Format: "", + }, + }, "description": { SchemaProps: spec.SchemaProps{ Type: []string{"string"}, diff --git a/e2e-playwright/dashboard-cujs/scope-cujs.spec.ts b/e2e-playwright/dashboard-cujs/scope-cujs.spec.ts index 919930027b8..7d8d202cf41 100644 --- a/e2e-playwright/dashboard-cujs/scope-cujs.spec.ts +++ b/e2e-playwright/dashboard-cujs/scope-cujs.spec.ts @@ -9,7 +9,6 @@ import { openScopesSelector, searchScopes, selectScope, - TestScope, } from '../utils/scope-helpers'; import { testScopes } from '../utils/scopes'; diff --git a/e2e-playwright/utils/scope-helpers.ts b/e2e-playwright/utils/scope-helpers.ts index 4fb12cc41da..749577ecb05 100644 --- a/e2e-playwright/utils/scope-helpers.ts +++ b/e2e-playwright/utils/scope-helpers.ts @@ -128,7 +128,7 @@ export async function scopeSelectRequest(page: Page, selectedScope: TestScope): export async function selectScope(page: Page, scopeName: string, selectedScope?: TestScope) { const click = async () => { const element = page.locator( - `[data-testid="scopes-tree-${scopeName}-checkbox"], [data-testid="scopes-tree-${scopeName}-radio"]` + `[data-testid="scopes-tree-${scopeName}-checkbox"], [data-testid="scopes-tree-${scopeName}-radio"], [data-testid="scopes-tree-${scopeName}-link"]` ); await element.scrollIntoViewIfNeeded(); await element.click({ force: true }); @@ -254,9 +254,9 @@ export async function getScopeTreeName(page: Page, nth: number): Promise } export async function getScopeLeafName(page: Page, nth: number): Promise { - const locator = page.getByTestId(/^scopes-tree-.*-(checkbox|radio)/).nth(nth); + const locator = page.getByTestId(/^scopes-tree-.*-(checkbox|radio|link)/).nth(nth); const fullTestId = await locator.getAttribute('data-testid'); - const scopeName = fullTestId?.replace(/^scopes-tree-/, '').replace(/-(checkbox|radio)/, ''); + const scopeName = fullTestId?.replace(/^scopes-tree-/, '').replace(/-(checkbox|radio|link)/, ''); if (!scopeName) { throw new Error('There are no scopes in the selector'); @@ -266,10 +266,11 @@ export async function getScopeLeafName(page: Page, nth: number): Promise } export async function getScopeLeafTitle(page: Page, nth: number): Promise { - const leafLocator = page.getByTestId(/^scopes-tree-.*-(checkbox|radio)/).nth(nth); + // Get the nth selectable tree item (checkbox, radio, or link) + const leafLocator = page.getByTestId(/^scopes-tree-.*-(checkbox|radio|link)/).nth(nth); // Find the closest ancestor element that has the main tree item test id const titleLocator = leafLocator.locator( - 'xpath=ancestor::*[@data-testid][starts-with(@data-testid, "scopes-tree-") and not(contains(@data-testid, "-checkbox")) and not(contains(@data-testid, "-radio")) and not(contains(@data-testid, "-expand"))]' + 'xpath=ancestor::*[@data-testid][starts-with(@data-testid, "scopes-tree-") and not(contains(@data-testid, "-checkbox")) and not(contains(@data-testid, "-radio")) and not(contains(@data-testid, "-link")) and not(contains(@data-testid, "-expand"))]' ); const scopeTitle = await titleLocator.textContent(); if (!scopeTitle) { diff --git a/packages/grafana-data/src/types/scopes.ts b/packages/grafana-data/src/types/scopes.ts index 98b32dfa0c7..e5897c137da 100644 --- a/packages/grafana-data/src/types/scopes.ts +++ b/packages/grafana-data/src/types/scopes.ts @@ -70,7 +70,7 @@ export type ScopeNodeLinkType = 'scope'; export interface ScopeNodeSpec { nodeType: ScopeNodeNodeType; title: string; - + subTitle?: string; description?: string; // If true for a scope category/type, it means only single child can be selected at a time. diff --git a/public/app/features/scopes/selector/ScopesTreeItem.tsx b/public/app/features/scopes/selector/ScopesTreeItem.tsx index 3dfe68e4209..235a65fb19e 100644 --- a/public/app/features/scopes/selector/ScopesTreeItem.tsx +++ b/public/app/features/scopes/selector/ScopesTreeItem.tsx @@ -2,13 +2,177 @@ import { css, cx } from '@emotion/css'; import Highlighter from 'react-highlight-words'; import { GrafanaTheme2 } from '@grafana/data'; -import { t } from '@grafana/i18n'; -import { Checkbox, Icon, RadioButtonDot, useStyles2 } from '@grafana/ui'; +import { Checkbox, Icon, RadioButtonDot, useStyles2, Text } from '@grafana/ui'; + +import { useScopesServices } from '../ScopesContextProvider'; import { ScopesTree } from './ScopesTree'; import { isNodeExpandable, isNodeSelectable } from './scopesTreeUtils'; import { NodesMap, SelectedScope, TreeNode } from './types'; +// Helper components for rendering different selectable content types +interface RadioButtonDotProps { + scopeNodeId: string; + selected: boolean; + onChange: () => void; + children?: React.ReactNode; + 'aria-labelledby'?: string; +} + +function ScopeRadioButtonDot({ + scopeNodeId, + selected, + onChange, + children, + 'aria-labelledby': ariaLabelledby, +}: RadioButtonDotProps) { + return ( + + ); +} + +interface LinkLikeButtonProps { + scopeNodeId: string; + onClick: () => void; + children: React.ReactNode; +} + +function ScopeLinkLikeButton({ scopeNodeId, onClick, children }: LinkLikeButtonProps) { + const styles = useStyles2(getStyles); + return ( + + ); +} + +interface CheckboxWithLabelProps { + scopeNodeId: string; + selected: boolean; + showLabel: boolean; + onChange: () => void; + children?: React.ReactNode; + 'aria-labelledby'?: string; +} + +function ScopeCheckboxWithLabel({ + scopeNodeId, + selected, + showLabel, + onChange, + children, + 'aria-labelledby': ariaLabelledby, +}: CheckboxWithLabelProps) { + const styles = useStyles2(getStyles); + return ( +
+ + {showLabel && ( + + )} +
+ ); +} + +interface TitleContentProps { + shouldHighlight: boolean; + titleText: string; + searchWords: string[]; +} + +function TitleContent({ shouldHighlight, titleText, searchWords }: TitleContentProps) { + if (shouldHighlight) { + return ; + } + return <>{titleText}; +} + +interface ExpandButtonProps { + scopeNodeId: string; + expanded: boolean; + onClick: () => void; + children: React.ReactNode; + controlsId: string; + isSelectable: boolean; + disableMultiSelect: boolean; + selected: boolean; + onSelect: () => void; +} + +function ScopeExpandButton({ + scopeNodeId, + expanded, + onClick, + children, + controlsId, + isSelectable, + disableMultiSelect, + selected, + onSelect, +}: ExpandButtonProps) { + const styles = useStyles2(getStyles); + + const buttonId = getTreeItemElementId(scopeNodeId) + '-button'; + + const SelectComponent = () => { + if (!isSelectable || expanded) { + return null; + } + if (disableMultiSelect) { + return ( + + ); + } + return ( + + ); + }; + return ( + <> + + + + ); +} + export interface ScopesTreeItemProps { anyChildExpanded: boolean; loadingNodeName: string | undefined; @@ -38,7 +202,8 @@ export function ScopesTreeItem({ toggleExpandedNode, }: ScopesTreeItemProps) { const styles = useStyles2(getStyles); - + const services = useScopesServices(); + const { closeAndApply } = services?.scopesSelectorService || {}; if (anyChildExpanded && !treeNode.expanded) { return null; } @@ -48,6 +213,7 @@ export function ScopesTreeItem({ // Should not happen as only way we show a tree is if we also load the nodes. return null; } + const parentNode = scopeNode.spec.parentName ? scopeNodes[scopeNode.spec.parentName] : undefined; const disableMultiSelect = parentNode?.spec.disableMultiSelect ?? false; @@ -57,9 +223,11 @@ export function ScopesTreeItem({ // Create search words for highlighting if there's a query // Only highlight if we have a query AND this node is not expanded (not a parent showing children) const titleText = scopeNode.spec.title; - const shouldHighlight = treeNode.query && !treeNode.expanded; + const shouldHighlight = Boolean(treeNode.query && !treeNode.expanded); const searchWords = shouldHighlight ? getSearchWordsFromQuery(treeNode.query) : []; + const childrenId = getTreeItemElementId(treeNode.scopeNodeId) + '-children'; + return (
- {isSelectable && !treeNode.expanded ? ( - disableMultiSelect ? ( - - ) : ( - titleText - ) - } - data-testid={`scopes-tree-${treeNode.scopeNodeId}-radio`} - onClick={() => { - selected ? deselectScope(treeNode.scopeNodeId) : selectScope(treeNode.scopeNodeId); - }} - /> - ) : ( -
- + {disableMultiSelect && ( + { + selectScope(treeNode.scopeNodeId); + closeAndApply?.(); + }} + > + + + )} + {!disableMultiSelect && ( + { selected ? deselectScope(treeNode.scopeNodeId) : selectScope(treeNode.scopeNodeId); }} - /> - {!isExpandable && ( - - )} -
- ) - ) : null} + > + + + )} + + )} {isExpandable && ( - + {scopeNode.spec.subTitle && ( + + {scopeNode.spec.subTitle} + )}
-
+
{treeNode.expanded && ( { margin: 0, padding: 0, }), + linkLikeItem: css({ + alignItems: 'center', + background: 'none', + border: 0, + display: 'flex', + gap: theme.spacing(1), + margin: 0, + padding: 0, + textDecoration: 'none', + + '&:hover': { + textDecoration: 'underline', + }, + }), children: css({ display: 'flex', flexDirection: 'column', diff --git a/public/app/features/scopes/selector/ScopesTreeSearch.tsx b/public/app/features/scopes/selector/ScopesTreeSearch.tsx index 780165f6074..22e8129ce66 100644 --- a/public/app/features/scopes/selector/ScopesTreeSearch.tsx +++ b/public/app/features/scopes/selector/ScopesTreeSearch.tsx @@ -79,7 +79,12 @@ export function ScopesTreeSearch({ setInputState({ value, dirty: true }); }} onFocus={onFocus} - onBlur={onBlur} + onBlur={() => { + // TODO:Handle weird race condition where the blur event interupts selection of a radio button. This is because disableHighlighting is called, which forces a re-render of the tree. This re-render causes the radio button to lose focus, and the selection to be interrupted. + setTimeout(() => { + onBlur(); + }, 0); + }} /> ); } diff --git a/public/app/features/scopes/selector/useScopesHighlighting.tsx b/public/app/features/scopes/selector/useScopesHighlighting.tsx index 75f573a3422..c0b8aef8002 100644 --- a/public/app/features/scopes/selector/useScopesHighlighting.tsx +++ b/public/app/features/scopes/selector/useScopesHighlighting.tsx @@ -1,5 +1,7 @@ import { useState } from 'react'; +import { useScopesServices } from '../ScopesContextProvider'; + import { getTreeItemElementId } from './ScopesTreeItem'; import { isNodeExpandable, isNodeSelectable } from './scopesTreeUtils'; import { NodesMap, SelectedScope, TreeNode } from './types'; @@ -28,6 +30,8 @@ export function useScopesHighlighting({ }: UseScopesHighlightingParams) { // Enable keyboard highlighting when the search field is focused const [highlightEnabled, setHighlightEnabled] = useState(false); + const services = useScopesServices(); + const { changeScopes } = services?.scopesSelectorService || {}; const items = [...selectedNodes, ...resultNodes]; @@ -52,6 +56,16 @@ export function useScopesHighlighting({ return; } + // If parent has disableMultiSelect, apply scope directly + const parentNode = scopeNodes[nodeId]?.spec.parentName + ? scopeNodes[scopeNodes[nodeId]?.spec.parentName] + : undefined; + + if (parentNode?.spec.disableMultiSelect && changeScopes && scopeNodes[nodeId]?.spec.linkId) { + changeScopes([scopeNodes[nodeId].spec.linkId], parentNode.metadata.name); + return; + } + // Toggle selection if (selectedScopes.some((s) => s.scopeNodeId === nodeId)) { deselectScope(nodeId); diff --git a/public/app/features/scopes/tests/tree.test.ts b/public/app/features/scopes/tests/tree.test.ts index eefacb4ee9c..f0f46e2dd9c 100644 --- a/public/app/features/scopes/tests/tree.test.ts +++ b/public/app/features/scopes/tests/tree.test.ts @@ -21,6 +21,9 @@ import { selectResultCloud, selectResultCloudDev, selectResultCloudOps, + expandResultEnvironments, + selectResultEnvironmentsDev, + selectResultEnvironmentsProd, updateScopes, } from './utils/actions'; import { @@ -33,10 +36,10 @@ import { expectResultApplicationsMimirNotPresent, expectResultApplicationsMimirPresent, expectResultApplicationsMimirSelected, - expectResultCloudDevNotSelected, - expectResultCloudDevSelected, - expectResultCloudOpsNotSelected, - expectResultCloudOpsSelected, + expectResultEnvironmentsDevNotSelected, + expectResultEnvironmentsDevSelected, + expectResultEnvironmentsProdNotSelected, + expectResultEnvironmentsProdSelected, expectScopesHeadline, expectScopesSelectorValue, } from './utils/assertions'; @@ -133,12 +136,33 @@ describe('Tree', () => { await openSelector(); await expandResultCloud(); await selectResultCloudDev(); - expectResultCloudDevSelected(); - expectResultCloudOpsNotSelected(); + // Verify the content of the scopes selector input + expectScopesSelectorValue('Dev'); + + // Single leaf node links always apply the scope, hence we need to open the selector again + await openSelector(); await selectResultCloudOps(); - expectResultCloudDevNotSelected(); - expectResultCloudOpsSelected(); + expectScopesSelectorValue('Ops'); + }); + + it('Can only select one selectable container at a time', async () => { + await openSelector(); + await expandResultEnvironments(); + + // Select the Development environment container + await selectResultEnvironmentsDev(); + expectResultEnvironmentsDevSelected(); // Check selection state before applying + expectResultEnvironmentsProdNotSelected(); // Production should not be selected + + // Select the Production environment container - should replace Development + await selectResultEnvironmentsProd(); + expectResultEnvironmentsProdSelected(); // Check selection state before applying + expectResultEnvironmentsDevNotSelected(); // Development should no longer be selected + + // Apply scopes and verify final state + await applyScopes(); + expectScopesSelectorValue('Production'); }); it('Search works', async () => { @@ -276,7 +300,7 @@ describe('Tree', () => { await openSelector(); // Verify that Cloud is expanded - expect(screen.getByRole('button', { name: 'Collapse Cloud' })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: 'Cloud' })).toBeInTheDocument(); }); describe('Keyboard Navigation', () => { diff --git a/public/app/features/scopes/tests/utils/actions.ts b/public/app/features/scopes/tests/utils/actions.ts index e5b7eb44a20..b018ab674be 100644 --- a/public/app/features/scopes/tests/utils/actions.ts +++ b/public/app/features/scopes/tests/utils/actions.ts @@ -22,16 +22,19 @@ import { getResultApplicationsCloudSelect, getResultApplicationsGrafanaSelect, getResultApplicationsMimirSelect, - getResultCloudDevRadio, getResultCloudExpand, - getResultCloudOpsRadio, getResultCloudSelect, + getResultEnvironmentsExpand, + getResultEnvironmentsDevSelect, + getResultEnvironmentsProdSelect, getSelectorApply, getSelectorCancel, getSelectorClear, getSelectorInput, getTreeSearch, findResultApplicationsExpand, + getResultCloudDevLink, + getResultCloudOpsLink, } from './selectors'; const click = async (selector: () => HTMLElement) => act(() => userEvent.click(selector())); @@ -68,8 +71,12 @@ export const selectResultApplicationsMimir = async () => click(getResultApplicat export const selectResultApplicationsCloud = async () => click(getResultApplicationsCloudSelect); export const selectResultApplicationsCloudDev = async () => click(getResultApplicationsCloudDevSelect); export const selectResultCloud = async () => click(getResultCloudSelect); -export const selectResultCloudDev = async () => click(getResultCloudDevRadio); -export const selectResultCloudOps = async () => click(getResultCloudOpsRadio); +export const selectResultCloudDev = async () => click(getResultCloudDevLink); +export const selectResultCloudOps = async () => click(getResultCloudOpsLink); + +export const expandResultEnvironments = async () => click(getResultEnvironmentsExpand); +export const selectResultEnvironmentsDev = async () => click(getResultEnvironmentsDevSelect); +export const selectResultEnvironmentsProd = async () => click(getResultEnvironmentsProdSelect); export const toggleDashboards = async () => click(getDashboardsExpand); export const searchDashboards = async (value: string) => type(getDashboardsSearch, value); diff --git a/public/app/features/scopes/tests/utils/assertions.ts b/public/app/features/scopes/tests/utils/assertions.ts index cab6c527c06..92e98715231 100644 --- a/public/app/features/scopes/tests/utils/assertions.ts +++ b/public/app/features/scopes/tests/utils/assertions.ts @@ -12,8 +12,6 @@ import { getResultApplicationsCloudSelect, getResultApplicationsGrafanaSelect, getResultApplicationsMimirSelect, - getResultCloudDevRadio, - getResultCloudOpsRadio, getSelectorInput, getTreeHeadline, queryAllDashboard, @@ -28,14 +26,16 @@ import { queryResultApplicationsCloudSelect, queryResultApplicationsGrafanaSelect, queryResultApplicationsMimirSelect, + getResultEnvironmentsDevSelect, + getResultEnvironmentsProdSelect, querySelectorApply, } from './selectors'; const expectInDocument = (selector: () => HTMLElement) => expect(selector()).toBeInTheDocument(); const expectNotInDocument = (selector: () => HTMLElement | null) => expect(selector()).not.toBeInTheDocument(); const expectChecked = (selector: () => HTMLInputElement) => expect(selector()).toBeChecked(); -const expectRadioChecked = (selector: () => HTMLInputElement) => expect(selector().checked).toBe(true); -const expectRadioNotChecked = (selector: () => HTMLInputElement) => expect(selector().checked).toBe(false); +const expectNotChecked = (selector: () => HTMLInputElement) => expect(selector()).not.toBeChecked(); + const expectValue = (selector: () => HTMLInputElement, value: string) => expect(selector().value).toBe(value); const expectTextContent = (selector: () => HTMLElement, text: string) => expect(selector()).toHaveTextContent(text); const expectDisabled = (selector: () => HTMLElement) => expect(selector()).toBeDisabled(); @@ -62,10 +62,11 @@ export const expectResultApplicationsMimirPresent = () => expectInDocument(getRe export const expectResultApplicationsMimirNotPresent = () => expectNotInDocument(queryResultApplicationsMimirSelect); export const expectResultApplicationsCloudPresent = () => expectInDocument(getResultApplicationsCloudSelect); export const expectResultApplicationsCloudNotPresent = () => expectNotInDocument(queryResultApplicationsCloudSelect); -export const expectResultCloudDevSelected = () => expectRadioChecked(getResultCloudDevRadio); -export const expectResultCloudDevNotSelected = () => expectRadioNotChecked(getResultCloudDevRadio); -export const expectResultCloudOpsSelected = () => expectRadioChecked(getResultCloudOpsRadio); -export const expectResultCloudOpsNotSelected = () => expectRadioNotChecked(getResultCloudOpsRadio); + +export const expectResultEnvironmentsDevSelected = () => expectChecked(getResultEnvironmentsDevSelect); +export const expectResultEnvironmentsDevNotSelected = () => expectNotChecked(getResultEnvironmentsDevSelect); +export const expectResultEnvironmentsProdSelected = () => expectChecked(getResultEnvironmentsProdSelect); +export const expectResultEnvironmentsProdNotSelected = () => expectNotChecked(getResultEnvironmentsProdSelect); export const expectDashboardsDisabled = () => expectDisabled(getDashboardsExpand); export const expectDashboardsClosed = () => expectNotInDocument(queryDashboardsContainer); diff --git a/public/app/features/scopes/tests/utils/mocks.ts b/public/app/features/scopes/tests/utils/mocks.ts index a94093747c9..7b306350eb5 100644 --- a/public/app/features/scopes/tests/utils/mocks.ts +++ b/public/app/features/scopes/tests/utils/mocks.ts @@ -59,6 +59,20 @@ export const mocksScopes: Scope[] = [ filters: [{ key: 'app', value: 'tempo', operator: 'equals' }], }, }, + { + metadata: { name: 'dev-env' }, + spec: { + title: 'Development', + filters: [{ key: 'environment', value: 'dev', operator: 'equals' }], + }, + }, + { + metadata: { name: 'prod-env' }, + spec: { + title: 'Production', + filters: [{ key: 'environment', value: 'prod', operator: 'equals' }], + }, + }, ] as const; const dashboardBindingsGenerator = ( @@ -341,6 +355,38 @@ export const mocksNodes: ScopeNode[] = [ parentName: 'cloud-applications', }, }, + { + metadata: { name: 'environments' }, + spec: { + nodeType: 'container', + title: 'Environments', + description: 'Environment Scopes', + disableMultiSelect: true, + parentName: '', + }, + }, + { + metadata: { name: 'environments-dev' }, + spec: { + nodeType: 'container', + title: 'Development', + description: 'Development Environment', + linkType: 'scope', + linkId: 'dev-env', + parentName: 'environments', + }, + }, + { + metadata: { name: 'environments-prod' }, + spec: { + nodeType: 'container', + title: 'Production', + description: 'Production Environment', + linkType: 'scope', + linkId: 'prod-env', + parentName: 'environments', + }, + }, ] as const; export const dashboardReloadSpy = jest.spyOn(getDashboardScenePageStateManager(), 'reloadDashboard'); diff --git a/public/app/features/scopes/tests/utils/selectors.ts b/public/app/features/scopes/tests/utils/selectors.ts index 0f49a10c133..4e3b7ed109a 100644 --- a/public/app/features/scopes/tests/utils/selectors.ts +++ b/public/app/features/scopes/tests/utils/selectors.ts @@ -9,6 +9,7 @@ const selectors = { headline: 'scopes-tree-headline', select: (nodeId: string) => `scopes-tree-${nodeId}-checkbox`, radio: (nodeId: string) => `scopes-tree-${nodeId}-radio`, + link: (nodeId: string) => `scopes-tree-${nodeId}-link`, expand: (nodeId: string) => `scopes-tree-${nodeId}-expand`, title: (nodeId: string) => `scopes-tree-${nodeId}-title`, }, @@ -93,7 +94,15 @@ export const getResultApplicationsCloudDevSelect = () => export const getResultCloudSelect = () => screen.getByTestId(selectors.tree.select('cloud')); export const getResultCloudExpand = () => screen.getByTestId(selectors.tree.expand('cloud')); -export const getResultCloudDevRadio = () => screen.getByTestId(selectors.tree.radio('cloud-dev')); -export const getResultCloudOpsRadio = () => screen.getByTestId(selectors.tree.radio('cloud-ops')); +export const getResultCloudDevLink = () => screen.getByTestId(selectors.tree.link('cloud-dev')); +export const getResultCloudOpsLink = () => screen.getByTestId(selectors.tree.link('cloud-ops')); + +export const getResultEnvironmentsExpand = () => screen.getByTestId(selectors.tree.expand('environments')); +export const getResultEnvironmentsDevSelect = () => + screen.getByTestId(selectors.tree.radio('environments-dev')); +export const getResultEnvironmentsProdSelect = () => + screen.getByTestId(selectors.tree.radio('environments-prod')); +export const queryResultEnvironmentsDevSelect = () => screen.queryByTestId(selectors.tree.radio('environments-dev')); +export const queryResultEnvironmentsProdSelect = () => screen.queryByTestId(selectors.tree.radio('environments-prod')); export const getListOfScopes = (service: ScopesService) => service.state.value; diff --git a/public/locales/en-US/grafana.json b/public/locales/en-US/grafana.json index 1beea7c487a..c458e08fe59 100644 --- a/public/locales/en-US/grafana.json +++ b/public/locales/en-US/grafana.json @@ -12305,8 +12305,6 @@ "title": "Select scopes" }, "tree": { - "collapse": "Collapse {{title}}", - "expand": "Expand {{title}}", "headline": { "noResults": "No results found for your query", "recommended": "Recommended", From e75610ed0368d07e63470a2cb0008ba3ba06f833 Mon Sep 17 00:00:00 2001 From: Ashley Harrison Date: Wed, 29 Oct 2025 10:09:06 +0000 Subject: [PATCH 078/378] Frontend service: Ensure we set `Cache-Control` header in the response (#113152) ensure we set Cache-Control header in the response from frontend-service --- pkg/services/frontend/index.go | 1 + pkg/services/frontend/index_test.go | 1 + 2 files changed, 2 insertions(+) diff --git a/pkg/services/frontend/index.go b/pkg/services/frontend/index.go index 89f7fcaf066..ec70d83468a 100644 --- a/pkg/services/frontend/index.go +++ b/pkg/services/frontend/index.go @@ -153,6 +153,7 @@ func (p *IndexProvider) HandleRequest(writer http.ResponseWriter, request *http. p.runIndexDataHooks(reqCtx, &data) writer.Header().Set("Content-Type", "text/html; charset=UTF-8") + writer.Header().Set("Cache-Control", "no-store") writer.WriteHeader(200) if err := p.index.Execute(writer, &data); err != nil { if errors.Is(err, syscall.EPIPE) { // Client has stopped listening. diff --git a/pkg/services/frontend/index_test.go b/pkg/services/frontend/index_test.go index 3f0b76ac4f4..46fdeba4410 100644 --- a/pkg/services/frontend/index_test.go +++ b/pkg/services/frontend/index_test.go @@ -92,6 +92,7 @@ func TestFrontendService_WebAssets(t *testing.T) { assert.Equal(t, 200, recorder.Code) assert.Contains(t, recorder.Header().Get("Content-Type"), "text/html") + assert.Contains(t, recorder.Header().Get("Cache-Control"), "no-store") // The response should contain references to the assets body := recorder.Body.String() From 86cb5d8af739745a1173496ba76a545efd45dfd8 Mon Sep 17 00:00:00 2001 From: Chris Chang <51393127+chriscerie@users.noreply.github.com> Date: Wed, 29 Oct 2025 19:58:58 +0900 Subject: [PATCH 079/378] Cloudwatch: Add missing AWS regions (#113010) Add missing cw regions --- pkg/tsdb/cloudwatch/constants/metrics.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pkg/tsdb/cloudwatch/constants/metrics.go b/pkg/tsdb/cloudwatch/constants/metrics.go index f52207001ec..02da8f26a7a 100644 --- a/pkg/tsdb/cloudwatch/constants/metrics.go +++ b/pkg/tsdb/cloudwatch/constants/metrics.go @@ -17,6 +17,7 @@ func Regions() RegionsSet { "ap-southeast-3": {}, "ap-southeast-4": {}, "ap-southeast-5": {}, + "ap-southeast-6": {}, "ap-southeast-7": {}, "ca-central-1": {}, "ca-west-1": {}, @@ -24,6 +25,7 @@ func Regions() RegionsSet { "cn-northwest-1": {}, "eu-central-1": {}, "eu-central-2": {}, + "eu-isoe-west-1": {}, "eu-north-1": {}, "eu-south-1": {}, "eu-south-2": {}, @@ -40,7 +42,11 @@ func Regions() RegionsSet { "us-gov-east-1": {}, "us-gov-west-1": {}, "us-iso-east-1": {}, + "us-iso-west-1": {}, "us-isob-east-1": {}, + "us-isob-west-1": {}, + "us-isof-east-1": {}, + "us-northeast-1": {}, "us-west-1": {}, "us-west-2": {}, } From c0b8fc6e6c35b59e9fcb15cd94d70940ae1907e9 Mon Sep 17 00:00:00 2001 From: Ryan McKinley Date: Wed, 29 Oct 2025 14:06:35 +0300 Subject: [PATCH 080/378] Chore: update storybook/test-runner (#113154) --- package.json | 2 +- yarn.lock | 38 +++++++++++++++++++++++++++++++------- 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index 37df4fb1c32..503049f3ed2 100644 --- a/package.json +++ b/package.json @@ -96,7 +96,7 @@ "@grafana/test-utils": "workspace:*", "@manypkg/get-packages": "^3.0.0", "@npmcli/package-json": "^6.0.0", - "@playwright/test": "1.54.1", + "@playwright/test": "1.55.1", "@pmmmwh/react-refresh-webpack-plugin": "0.6.1", "@react-types/button": "3.13.0", "@react-types/menu": "3.10.3", diff --git a/yarn.lock b/yarn.lock index b281216a8e8..9c9e587d570 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6469,14 +6469,14 @@ __metadata: languageName: node linkType: hard -"@playwright/test@npm:1.54.1": - version: 1.54.1 - resolution: "@playwright/test@npm:1.54.1" +"@playwright/test@npm:1.55.1": + version: 1.55.1 + resolution: "@playwright/test@npm:1.55.1" dependencies: - playwright: "npm:1.54.1" + playwright: "npm:1.55.1" bin: playwright: cli.js - checksum: 10/75ea34818f57f11bd8a1e6e3ac202c752c520c98467607be67c0eccfe41ea8ff6ae6824e91cb5ecacbee403aef4e1e6210500ee3cc82dd9317a8ee7136af18d3 + checksum: 10/c67a46353c58aaeac551bce2654cdef0e9a0ad76b1667514832d34acd4b26ec72f35ea7595cd3fad4c4e1e039d5bb876b8d62c89af4525d455285f6fff9f0642 languageName: node linkType: hard @@ -18835,7 +18835,7 @@ __metadata: "@opentelemetry/api": "npm:1.9.0" "@opentelemetry/exporter-collector": "npm:0.25.0" "@opentelemetry/semantic-conventions": "npm:1.37.0" - "@playwright/test": "npm:1.54.1" + "@playwright/test": "npm:1.55.1" "@pmmmwh/react-refresh-webpack-plugin": "npm:0.6.1" "@popperjs/core": "npm:2.11.8" "@react-aria/dialog": "npm:3.5.31" @@ -26313,7 +26313,31 @@ __metadata: languageName: node linkType: hard -"playwright@npm:1.54.1, playwright@npm:^1.14.0": +"playwright-core@npm:1.55.1": + version: 1.55.1 + resolution: "playwright-core@npm:1.55.1" + bin: + playwright-core: cli.js + checksum: 10/953a43039dbcca04513bd3138a9dee249a136d5377da00d49402ffcd24d33ca84dc1dc04636d1b76e9f8c9fd28a302b89cda1ae544d72b5d829c28e623bfcb0b + languageName: node + linkType: hard + +"playwright@npm:1.55.1": + version: 1.55.1 + resolution: "playwright@npm:1.55.1" + dependencies: + fsevents: "npm:2.3.2" + playwright-core: "npm:1.55.1" + dependenciesMeta: + fsevents: + optional: true + bin: + playwright: cli.js + checksum: 10/5dcf9ce564cacf6c06ebc864bb2b1f709c641792560d49889ed4c98e230be54a963ec8aaafff11269735d8d22da4900bd2d4ef9f1748d132326ffda8fb1f3f20 + languageName: node + linkType: hard + +"playwright@npm:^1.14.0": version: 1.54.1 resolution: "playwright@npm:1.54.1" dependencies: From 6093afddd4991a390030000f8c43eaf222849cf4 Mon Sep 17 00:00:00 2001 From: Tom Ratcliffe Date: Wed, 29 Oct 2025 11:21:58 +0000 Subject: [PATCH 081/378] Folders: Migrate FolderFilter component to ComboBox (#113047) --- .github/CODEOWNERS | 2 +- .../src/handlers/api/search/handlers.ts | 7 +- .../FolderFilter/FolderFilter.test.tsx | 46 +++++++ .../components/FolderFilter/FolderFilter.tsx | 44 ++---- .../LibraryPanelsSearch.test.tsx | 129 +++++++----------- .../LibraryPanelsSearch.tsx | 3 +- public/locales/en-US/grafana.json | 1 - 7 files changed, 122 insertions(+), 110 deletions(-) create mode 100644 public/app/core/components/FolderFilter/FolderFilter.test.tsx diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 853f27774d4..ea0e83e3baa 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -798,7 +798,7 @@ playwright.storybook.config.ts @grafana/grafana-frontend-platform /public/app/core/components/ColorScale/ @grafana/dataviz-squad /public/app/core/components/DynamicImports/ @grafana/grafana-search-navigate-organise /public/app/core/components/EmptyListCTA/ @grafana/grafana-frontend-platform -/public/app/core/components/FolderFilter/ @grafana/sharing-squad +/public/app/core/components/FolderFilter/ @grafana/grafana-search-navigate-organise /public/app/core/components/Footer/ @grafana/grafana-search-navigate-organise /public/app/core/components/ForgottenPassword/ @grafana/grafana-search-navigate-organise /public/app/core/components/Form/ @grafana/grafana-frontend-platform diff --git a/packages/grafana-test-utils/src/handlers/api/search/handlers.ts b/packages/grafana-test-utils/src/handlers/api/search/handlers.ts index 2aebd03b174..d9fa090fbf1 100644 --- a/packages/grafana-test-utils/src/handlers/api/search/handlers.ts +++ b/packages/grafana-test-utils/src/handlers/api/search/handlers.ts @@ -17,12 +17,17 @@ const slugify = (str: string) => { .replace(/ +/g, '-'); }; +const typeFilterMap: Record = { + 'dash-db': 'dashboard', + 'dash-folder': 'folder', +}; + const getLegacySearchHandler = () => http.get('/api/search', ({ request }) => { const folderFilter = new URL(request.url).searchParams.get('folderUIDs') || null; const typeFilter = new URL(request.url).searchParams.get('type') || null; // Workaround for the fixture kind being 'dashboard' instead of 'dash-db' - const mappedTypeFilter = typeFilter === 'dash-db' ? 'dashboard' : typeFilter; + const mappedTypeFilter = typeFilter ? typeFilterMap[typeFilter] || typeFilter : null; const starredFilter = new URL(request.url).searchParams.get('starred') || null; const tagFilter = new URL(request.url).searchParams.getAll('tag') || null; diff --git a/public/app/core/components/FolderFilter/FolderFilter.test.tsx b/public/app/core/components/FolderFilter/FolderFilter.test.tsx new file mode 100644 index 00000000000..06f0cf62a2a --- /dev/null +++ b/public/app/core/components/FolderFilter/FolderFilter.test.tsx @@ -0,0 +1,46 @@ +import { comboboxTestSetup } from 'test/helpers/comboboxTestSetup'; +import { render, screen, testWithFeatureToggles } from 'test/test-utils'; + +import { setBackendSrv } from '@grafana/runtime'; +import { setupMockServer } from '@grafana/test-utils/server'; +import { getFolderFixtures } from '@grafana/test-utils/unstable'; +import { backendSrv } from 'app/core/services/backend_srv'; +import { resetGrafanaSearcher } from 'app/features/search/service/searcher'; + +import { FolderFilter } from './FolderFilter'; +const [_, { folderA, folderB }] = getFolderFixtures(); + +setBackendSrv(backendSrv); +setupMockServer(); +comboboxTestSetup(); + +const fixtures: Array< + [ + // Test title + string, + // Feature toggle setup + Parameters[0], + ] +> = [ + ['app platform APIs enabled', { enable: ['unifiedStorageSearchUI'] }], + ['app platform APIs disabled', {}], +]; + +describe.each(fixtures)('FolderFilter - %s', (_title, featureToggleSetup) => { + beforeEach(() => { + resetGrafanaSearcher(); + }); + + testWithFeatureToggles(featureToggleSetup); + + it('allows selecting folders', async () => { + const onChange = jest.fn(); + const { user } = render(); + + await user.click(screen.getByPlaceholderText('Filter by folder')); + + await user.click(await screen.findByText(folderA.item.title)); + await user.click(await screen.findByText(folderB.item.title)); + expect(onChange).toHaveBeenCalledWith([folderA.item.uid, folderB.item.uid]); + }); +}); diff --git a/public/app/core/components/FolderFilter/FolderFilter.tsx b/public/app/core/components/FolderFilter/FolderFilter.tsx index c98490ea0c7..1f8f3e5557d 100644 --- a/public/app/core/components/FolderFilter/FolderFilter.tsx +++ b/public/app/core/components/FolderFilter/FolderFilter.tsx @@ -1,25 +1,17 @@ -import debounce from 'debounce-promise'; -import { useCallback, useMemo, useState } from 'react'; +import { useCallback, useState } from 'react'; -import { SelectableValue } from '@grafana/data'; import { t } from '@grafana/i18n'; -import { AsyncMultiSelect, Icon } from '@grafana/ui'; +import { ComboboxOption, MultiCombobox } from '@grafana/ui'; import { getGrafanaSearcher } from 'app/features/search/service/searcher'; -import { FolderInfo } from 'app/types/folders'; export interface FolderFilterProps { - onChange: (folder: FolderInfo[]) => void; - maxMenuHeight?: number; + onChange: (folder: string[]) => void; } -export function FolderFilter({ onChange, maxMenuHeight }: FolderFilterProps): JSX.Element { - const [loading, setLoading] = useState(false); - const getOptions = useCallback((searchString: string) => getFoldersAsOptions(searchString, setLoading), []); - const debouncedLoadOptions = useMemo(() => debounce(getOptions, 300), [getOptions]); - - const [value, setValue] = useState>>([]); +export function FolderFilter({ onChange }: FolderFilterProps): JSX.Element { + const [value, setValue] = useState([]); const onSelectOptionChange = useCallback( - (folders: Array>) => { + (folders: ComboboxOption[]) => { const changedFolderIds = folders.filter((f) => Boolean(f.value)).map((f) => f.value!); onChange(changedFolderIds); setValue(folders); @@ -28,26 +20,21 @@ export function FolderFilter({ onChange, maxMenuHeight }: FolderFilterProps): JS ); return ( - } aria-label={t('folder-filter.select-aria-label', 'Folder filter')} - defaultOptions /> ); } -async function getFoldersAsOptions( - searchString: string, - setLoading: (loading: boolean) => void -): Promise>> { - setLoading(true); +async function getFoldersAsOptions(searchString: string) { // Use searcher as it will handle the logic for using the appropriate API const searcher = getGrafanaSearcher(); const queryResponse = await searcher.search({ @@ -59,13 +46,12 @@ async function getFoldersAsOptions( const options = queryResponse.view.map((item) => ({ label: item.name, - value: { uid: item.uid, title: item.name }, + value: item.uid, })); if (!searchString || 'dashboards'.includes(searchString.toLowerCase())) { - options.unshift({ label: 'Dashboards', value: { uid: 'general', title: 'Dashboards' } }); + options.unshift({ label: 'Dashboards', value: 'general' }); } - setLoading(false); return options; } diff --git a/public/app/features/library-panels/components/LibraryPanelsSearch/LibraryPanelsSearch.test.tsx b/public/app/features/library-panels/components/LibraryPanelsSearch/LibraryPanelsSearch.test.tsx index bb938595b72..7cb1a99a864 100644 --- a/public/app/features/library-panels/components/LibraryPanelsSearch/LibraryPanelsSearch.test.tsx +++ b/public/app/features/library-panels/components/LibraryPanelsSearch/LibraryPanelsSearch.test.tsx @@ -1,10 +1,9 @@ -import { render, screen, waitFor, within } from '@testing-library/react'; -import userEvent from '@testing-library/user-event'; +import { render, screen, waitFor, within } from 'test/test-utils'; import { PanelPluginMeta, PluginMetaInfo, PluginType } from '@grafana/data'; -import { config } from '@grafana/runtime'; +import { setBackendSrv } from '@grafana/runtime'; import { Panel } from '@grafana/schema'; -import { getGrafanaSearcher } from 'app/features/search/service/searcher'; +import { setupMockServer } from '@grafana/test-utils/server'; import { backendSrv } from '../../../../core/services/backend_srv'; import * as panelUtils from '../../../panel/state/util'; @@ -13,6 +12,29 @@ import { LibraryElementsSearchResult } from '../../types'; import { LibraryPanelsSearch, LibraryPanelsSearchProps } from './LibraryPanelsSearch'; +setBackendSrv(backendSrv); +setupMockServer(); + +const pluginInfo = { logos: { small: '', large: '' } } as PluginMetaInfo; +const graph: PanelPluginMeta = { + name: 'Graph', + id: 'graph', + info: pluginInfo, + baseUrl: '', + type: PluginType.panel, + module: '', + sort: 0, +}; +const timeseries: PanelPluginMeta = { + name: 'Time Series', + id: 'timeseries', + info: pluginInfo, + baseUrl: '', + type: PluginType.panel, + module: '', + sort: 1, +}; + jest.mock('@grafana/runtime', () => ({ ...jest.requireActual('@grafana/runtime'), config: { @@ -26,79 +48,35 @@ jest.mock('@grafana/runtime', () => ({ }, })); -jest.mock('debounce-promise', () => { - const debounce = () => { - const debounced = () => - Promise.resolve([ - { label: 'Dashboards', value: { uid: '', title: 'Dashboards' } }, - { label: 'Folder1', value: { id: 'xMsQdBfWz', title: 'Folder1' } }, - { label: 'Folder2', value: { id: 'wfTJJL5Wz', title: 'Folder2' } }, - ]); - return debounced; - }; - - return debounce; -}); - +const getLibraryPanelsSpy = jest.spyOn(api, 'getLibraryPanels'); jest.spyOn(api, 'getConnectedDashboards').mockResolvedValue([]); jest.spyOn(api, 'deleteLibraryPanel').mockResolvedValue({ message: 'success' }); +jest.spyOn(panelUtils, 'getAllPanelPluginMeta').mockReturnValue([graph, timeseries]); + async function getTestContext( propOverrides: Partial = {}, searchResult: LibraryElementsSearchResult = { elements: [], perPage: 40, page: 1, totalCount: 0 } ) { - jest.clearAllMocks(); - const pluginInfo = { logos: { small: '', large: '' } } as PluginMetaInfo; - const graph: PanelPluginMeta = { - name: 'Graph', - id: 'graph', - info: pluginInfo, - baseUrl: '', - type: PluginType.panel, - module: '', - sort: 0, - }; - const timeseries: PanelPluginMeta = { - name: 'Time Series', - id: 'timeseries', - info: pluginInfo, - baseUrl: '', - type: PluginType.panel, - module: '', - sort: 1, - }; - - config.featureToggles = { panelTitleSearch: false }; - const getSpy = jest.spyOn(backendSrv, 'get'); - - jest.spyOn(getGrafanaSearcher(), 'getSortOptions').mockResolvedValue([ - { - label: 'Alphabetically (A–Z)', - value: 'alpha-asc', - }, - { - label: 'Alphabetically (Z–A)', - value: 'alpha-desc', - }, - ]); - - const getLibraryPanelsSpy = jest.spyOn(api, 'getLibraryPanels').mockResolvedValue(searchResult); - const getAllPanelPluginMetaSpy = jest.spyOn(panelUtils, 'getAllPanelPluginMeta').mockReturnValue([graph, timeseries]); + getLibraryPanelsSpy.mockResolvedValue(searchResult); const props: LibraryPanelsSearchProps = { onClick: jest.fn(), }; Object.assign(props, propOverrides); - const { rerender } = render(); + const view = render(); await waitFor(() => expect(getLibraryPanelsSpy).toHaveBeenCalled()); expect(getLibraryPanelsSpy).toHaveBeenCalledTimes(1); - jest.clearAllMocks(); - return { rerender, getLibraryPanelsSpy, getSpy, getAllPanelPluginMetaSpy }; + return view; } describe('LibraryPanelsSearch', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + describe('when mounted with default options', () => { it('should show input filter and library panels view', async () => { await getTestContext(); @@ -109,9 +87,9 @@ describe('LibraryPanelsSearch', () => { describe('and user searches for library panel by name or description', () => { it('should call api with correct params', async () => { - const { getLibraryPanelsSpy } = await getTestContext(); + const { user } = await getTestContext(); - await userEvent.type(screen.getByPlaceholderText(/search by name/i), 'a'); + await user.type(screen.getByPlaceholderText(/search by name/i), 'a'); await waitFor(() => expect(getLibraryPanelsSpy).toHaveBeenCalled()); await waitFor(() => expect(getLibraryPanelsSpy).toHaveBeenCalledWith({ @@ -138,9 +116,9 @@ describe('LibraryPanelsSearch', () => { describe('and user changes sorting', () => { it('should call api with correct params', async () => { - const { getLibraryPanelsSpy } = await getTestContext({ showSort: true }); + const { user } = await getTestContext({ showSort: true }); - await userEvent.type(screen.getByText(/sort \(default a–z\)/i), 'Desc{enter}'); + await user.type(screen.getByText(/sort \(default a–z\)/i), 'Desc{enter}'); await waitFor(() => expect(getLibraryPanelsSpy).toHaveBeenCalledWith({ searchString: '', @@ -167,10 +145,10 @@ describe('LibraryPanelsSearch', () => { describe('and user changes panel filter', () => { it('should call api with correct params', async () => { - const { getLibraryPanelsSpy } = await getTestContext({ showPanelFilter: true }); + const { user } = await getTestContext({ showPanelFilter: true }); - await userEvent.type(screen.getByRole('combobox', { name: /panel type filter/i }), 'Graph{enter}'); - await userEvent.type(screen.getByRole('combobox', { name: /panel type filter/i }), 'Time Series{enter}'); + await user.type(screen.getByRole('combobox', { name: /panel type filter/i }), 'Graph{enter}'); + await user.type(screen.getByRole('combobox', { name: /panel type filter/i }), 'Time Series{enter}'); await waitFor(() => expect(getLibraryPanelsSpy).toHaveBeenCalledWith({ searchString: '', @@ -191,12 +169,12 @@ describe('LibraryPanelsSearch', () => { expect(screen.getByPlaceholderText(/search by name/i)).toBeInTheDocument(); expect(screen.getByText(/you haven\'t created any library panels yet/i)).toBeInTheDocument(); - expect(screen.getByRole('combobox', { name: /folder filter/i })).toBeInTheDocument(); + expect(screen.getByPlaceholderText('Filter by folder')).toBeInTheDocument(); }); describe('and user changes folder filter', () => { it('should call api with correct params', async () => { - const { getLibraryPanelsSpy } = await getTestContext( + const { user } = await getTestContext( { showFolderFilter: true, currentFolderUID: 'wXyZ1234' }, { elements: [ @@ -225,8 +203,7 @@ describe('LibraryPanelsSearch', () => { } ); - await userEvent.click(screen.getByRole('combobox', { name: /folder filter/i })); - await userEvent.type(screen.getByRole('combobox', { name: /folder filter/i }), 'library', { + await user.type(screen.getByPlaceholderText('Filter by folder'), 'library', { skipClick: true, }); @@ -329,7 +306,7 @@ describe('LibraryPanelsSearch', () => { describe('when mounted with showSecondaryActions and a specific folder', () => { describe('and user deletes a panel', () => { it('should call api with correct params', async () => { - const { getLibraryPanelsSpy } = await getTestContext( + const { user } = await getTestContext( { showSecondaryActions: true, currentFolderUID: 'wfTJJL5Wz' }, { elements: [ @@ -358,11 +335,11 @@ describe('LibraryPanelsSearch', () => { } ); - await userEvent.click(screen.getByLabelText('Delete')); - await waitFor(() => expect(screen.getByText('Do you want to delete this panel?')).toBeInTheDocument()); - await userEvent.click(screen.getAllByRole('button', { name: 'Delete' })[1]); + await user.click(screen.getByLabelText('Delete')); + await screen.findByText('Do you want to delete this panel?'); + await user.click(screen.getAllByRole('button', { name: 'Delete' })[1]); - await waitFor(() => { + await waitFor(() => expect(getLibraryPanelsSpy).toHaveBeenCalledWith({ searchString: '', folderFilterUIDs: ['wfTJJL5Wz'], @@ -370,8 +347,8 @@ describe('LibraryPanelsSearch', () => { typeFilter: [], sortDirection: undefined, perPage: 40, - }); - }); + }) + ); }); }); }); diff --git a/public/app/features/library-panels/components/LibraryPanelsSearch/LibraryPanelsSearch.tsx b/public/app/features/library-panels/components/LibraryPanelsSearch/LibraryPanelsSearch.tsx index 151752b2ede..27a6635fd3f 100644 --- a/public/app/features/library-panels/components/LibraryPanelsSearch/LibraryPanelsSearch.tsx +++ b/public/app/features/library-panels/components/LibraryPanelsSearch/LibraryPanelsSearch.tsx @@ -5,7 +5,6 @@ import { useDebounce } from 'react-use'; import { GrafanaTheme2, PanelPluginMeta, SelectableValue } from '@grafana/data'; import { t } from '@grafana/i18n'; import { useStyles2, Stack, FilterInput } from '@grafana/ui'; -import { FolderInfo } from 'app/types/folders'; import { FolderFilter } from '../../../../core/components/FolderFilter/FolderFilter'; import { PanelTypeFilter } from '../../../../core/components/PanelTypeFilter/PanelTypeFilter'; @@ -162,7 +161,7 @@ const SearchControls = memo( [onPanelFilterChange] ); const folderFilterChanged = useCallback( - (folders: FolderInfo[]) => onFolderFilterChange(folders.map((f) => f.uid ?? '')), + (folders: string[]) => onFolderFilterChange(folders), [onFolderFilterChange] ); diff --git a/public/locales/en-US/grafana.json b/public/locales/en-US/grafana.json index c458e08fe59..e8c29e9ffe7 100644 --- a/public/locales/en-US/grafana.json +++ b/public/locales/en-US/grafana.json @@ -7658,7 +7658,6 @@ } }, "folder-filter": { - "noOptionsMessage-no-folders-found": "No folders found", "select-aria-label": "Folder filter", "select-placeholder": "Filter by folder" }, From 1d0ab617e8ffe9591d2098cf9aa3490d6f6712d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Irene=20Rodr=C3=ADguez?= Date: Wed, 29 Oct 2025 13:38:49 +0100 Subject: [PATCH 082/378] Update Git Sync and File provisioning status to private preview (#113158) --- docs/sources/observability-as-code/_index.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/sources/observability-as-code/_index.md b/docs/sources/observability-as-code/_index.md index 42303dd62f9..33a2c6aeb4d 100644 --- a/docs/sources/observability-as-code/_index.md +++ b/docs/sources/observability-as-code/_index.md @@ -12,6 +12,7 @@ labels: products: - enterprise - oss + - cloud title: Observability as Code weight: 100 cards: @@ -32,11 +33,11 @@ cards: height: 24 href: ./foundation-sdk/ description: The Grafana Foundation SDK is a set of tools, types, and libraries that let you define Grafana dashboards and resources using strongly typed code. - - title: Git Sync (experimental) + - title: Git Sync (private preview) height: 24 href: ./provision-resources/intro-git-sync/ description: Git Sync is an experimental feature that lets you store your dashboard files in a GitHub repository and synchronize those changes with your Grafana instance. - - title: File provisioning (experimental) + - title: File provisioning (private preview) height: 24 href: ./provision-resources/ description: File provisioning in Grafana lets you include resources, including folders and dashboard JSON files, that are stored in a local file system. From 86bf99aaaa7ef49fff41ad76ca79ea0321e613ed Mon Sep 17 00:00:00 2001 From: Pepe Cano <825430+ppcano@users.noreply.github.com> Date: Wed, 29 Oct 2025 13:58:13 +0100 Subject: [PATCH 083/378] docs(alerting): add additional migration details (#112383) --- docs/sources/alerting/alerting-rules/alerting-migration.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/sources/alerting/alerting-rules/alerting-migration.md b/docs/sources/alerting/alerting-rules/alerting-migration.md index 2e63db00136..3afa3aec453 100644 --- a/docs/sources/alerting/alerting-rules/alerting-migration.md +++ b/docs/sources/alerting/alerting-rules/alerting-migration.md @@ -65,6 +65,10 @@ The copied rules are converted to Grafana-managed rules, preserving their behavi The rule query offset is taken from the `query_offset` value in the rule group configuration. If empty, it defaults to the [`rule_query_offset` configuration setting](ref:configure-grafana-rule_query_offset), which is `1m` by default. +- **Rule query conversion** + + For alert rules, adds `prometheus_math` and `threshold` expressions to preserve Prometheus no data behavior, ensuring the alert stays in **Normal** state when `query` returns no data. + - **Missing series evaluations to resolve** The [Missing series evaluations to resolve](ref:missing_series_evaluations_to_resolve) setting is set to `1` to replicate Prometheus’s alert eviction behavior. From 8bff09b88bf9363571e8a4e450d3137e4f9ca888 Mon Sep 17 00:00:00 2001 From: Luminessa Starlight Date: Wed, 29 Oct 2025 09:11:23 -0400 Subject: [PATCH 084/378] Docs: Add storybook links to components (#113102) * for every storybook component, a storybook link * typo fix * text improvements --- .../grafana-ui/src/components/Alert/Alert.tsx | 5 +++ .../AutoSaveField/AutoSaveField.tsx | 6 ++++ .../grafana-ui/src/components/Badge/Badge.tsx | 5 +++ .../src/components/BarGauge/BarGauge.tsx | 3 ++ .../src/components/BigValue/BigValue.tsx | 5 +++ .../src/components/Button/Button.tsx | 3 ++ .../ButtonCascader/ButtonCascader.tsx | 3 ++ .../CallToActionCard/CallToActionCard.tsx | 6 +++- .../grafana-ui/src/components/Card/Card.tsx | 1 + .../src/components/Carousel/Carousel.tsx | 5 +++ .../src/components/Cascader/Cascader.tsx | 5 +++ .../ClickOutsideWrapper.tsx | 5 +++ .../ClipboardButton/ClipboardButton.tsx | 5 +++ .../Collapse/CollapsableSection.tsx | 5 +++ .../src/components/Collapse/Collapse.tsx | 5 +++ .../components/ColorPicker/ColorPicker.tsx | 3 ++ .../ColorPicker/ColorPickerInput.tsx | 3 ++ .../ColorPicker/SeriesColorPickerPopover.tsx | 3 ++ .../src/components/Combobox/Combobox.tsx | 4 ++- .../src/components/Combobox/MultiCombobox.tsx | 5 +++ .../ConfirmButton/ConfirmButton.tsx | 5 +++ .../components/ConfirmModal/ConfirmModal.tsx | 5 +++ .../components/ContextMenu/ContextMenu.tsx | 5 +++ .../DataSourceHttpSettings.mdx | 2 ++ .../DataSourceHttpSettings.tsx | 2 ++ .../DateTimePickers/DatePicker/DatePicker.tsx | 7 +++- .../DatePickerWithInput.tsx | 7 +++- .../DateTimePicker/DateTimePicker.tsx | 5 +++ .../RelativeTimeRangePicker.tsx | 1 + .../DateTimePickers/TimeRangeInput.tsx | 5 +++ .../DateTimePickers/TimeRangePicker.tsx | 3 ++ .../DateTimePickers/TimeZonePicker.tsx | 3 ++ .../DateTimePickers/WeekStartPicker.tsx | 3 ++ .../src/components/Divider/Divider.tsx | 3 ++ .../src/components/Drawer/Drawer.tsx | 5 +++ .../src/components/Dropdown/ButtonSelect.tsx | 2 ++ .../src/components/Dropdown/Dropdown.tsx | 5 +++ .../EmptySearchResult/EmptySearchResult.tsx | 6 +++- .../src/components/EmptyState/EmptyState.tsx | 5 +++ .../ErrorBoundary/ErrorBoundary.tsx | 5 +++ .../components/FeatureBadge/FeatureBadge.tsx | 5 +++ .../components/FileDropzone/FileDropzone.tsx | 5 +++ .../components/FileDropzone/FileListItem.tsx | 5 +++ .../src/components/FileUpload/FileUpload.tsx | 5 +++ .../src/components/FilterPill/FilterPill.tsx | 5 +++ .../src/components/FormField/FormField.tsx | 2 ++ .../FormattedValueDisplay.tsx | 5 +++ .../src/components/Forms/Checkbox.tsx | 3 ++ .../grafana-ui/src/components/Forms/Field.tsx | 5 +++ .../src/components/Forms/FieldArray.tsx | 2 ++ .../src/components/Forms/FieldSet.tsx | 5 +++ .../Forms/FieldValidationMessage.tsx | 5 +++ .../grafana-ui/src/components/Forms/Form.tsx | 2 ++ .../src/components/Forms/InlineField.mdx | 2 +- .../src/components/Forms/InlineField.tsx | 5 +++ .../src/components/Forms/InlineFieldRow.tsx | 5 +++ .../src/components/Forms/InlineLabel.mdx | 2 +- .../src/components/Forms/InlineLabel.tsx | 5 +++ .../grafana-ui/src/components/Forms/Label.tsx | 5 +++ .../src/components/Forms/Legend.tsx | 5 +++ .../RadioButtonGroup/RadioButtonGroup.tsx | 5 +++ .../Forms/RadioButtonList/RadioButtonList.tsx | 5 +++ .../grafana-ui/src/components/Icon/Icon.tsx | 5 +++ .../src/components/IconButton/IconButton.tsx | 5 +++ .../src/components/InfoBox/InfoBox.tsx | 6 +++- .../components/InfoTooltip/InfoTooltip.tsx | 6 +++- .../components/InlineToast/InlineToast.tsx | 5 +++ .../src/components/Input/AutoSizeInput.tsx | 5 +++ .../grafana-ui/src/components/Input/Input.tsx | 5 +++ .../InteractiveTable/InteractiveTable.tsx | 8 ++++- .../src/components/Layout/Box/Box.tsx | 5 +++ .../src/components/Layout/Grid/Grid.tsx | 5 +++ .../src/components/Layout/Layout.tsx | 2 ++ .../src/components/Layout/Space.mdx | 2 +- .../src/components/Layout/Space.tsx | 5 +++ .../src/components/Layout/Stack/Stack.tsx | 3 +- .../src/components/Link/TextLink.tsx | 5 +++ .../grafana-ui/src/components/List/List.tsx | 6 +++- .../src/components/LoadingBar/LoadingBar.tsx | 5 +++ .../LoadingPlaceholder/LoadingPlaceholder.tsx | 3 ++ .../grafana-ui/src/components/Menu/Menu.tsx | 3 ++ .../grafana-ui/src/components/Modal/Modal.tsx | 3 ++ .../src/components/Monaco/CodeEditor.tsx | 5 +++ .../src/components/PageLayout/PageToolbar.tsx | 6 +++- .../src/components/Pagination/Pagination.tsx | 5 +++ .../components/PanelChrome/PanelChrome.tsx | 4 +++ .../PanelContainer/PanelContainer.tsx | 6 +++- .../PluginSignatureBadge.tsx | 2 ++ .../src/components/QueryField/QueryField.tsx | 16 +++++---- .../components/RadialGauge/RadialGauge.tsx | 3 ++ .../RefreshPicker/RefreshPicker.tsx | 5 +++ .../RenderUserContentAsHTML.tsx | 5 +++ .../ScrollContainer/ScrollContainer.tsx | 5 +++ .../SecretFormField/SecretFormField.tsx | 2 ++ .../components/SecretInput/SecretInput.tsx | 5 +++ .../SecretTextArea/SecretTextArea.tsx | 2 ++ .../src/components/Segment/Segment.tsx | 3 ++ .../src/components/Segment/SegmentAsync.tsx | 3 ++ .../src/components/Segment/SegmentInput.tsx | 3 ++ .../src/components/Select/Select.tsx | 34 ++++++++++++++++--- .../src/components/Slider/RangeSlider.tsx | 2 ++ .../src/components/Slider/Slider.tsx | 2 ++ .../src/components/Spinner/Spinner.tsx | 4 +++ .../src/components/Splitter/useSplitter.ts | 5 +++ .../src/components/Switch/Switch.tsx | 5 +++ .../src/components/Table/TableRT/Table.tsx | 5 +++ .../TableInputCSV/TableInputCSV.tsx | 6 +++- .../grafana-ui/src/components/Tabs/Tab.tsx | 3 ++ .../src/components/Tabs/TabContent.tsx | 3 ++ .../src/components/Tabs/TabsBar.tsx | 5 +++ .../grafana-ui/src/components/Tags/Tag.tsx | 5 +++ .../src/components/Tags/TagList.tsx | 5 +++ .../src/components/TagsInput/TagsInput.tsx | 5 +++ .../grafana-ui/src/components/Text/Text.tsx | 5 +++ .../src/components/TextArea/TextArea.tsx | 5 +++ .../src/components/Toggletip/Toggletip.tsx | 5 +++ .../ToolbarButton/ToolbarButton.tsx | 5 +++ .../ToolbarButton/ToolbarButtonRow.tsx | 5 +++ .../src/components/Tooltip/Tooltip.tsx | 3 ++ .../src/components/UnitPicker/UnitPicker.tsx | 3 ++ .../components/UsersIndicator/UserIcon.tsx | 5 +++ .../UsersIndicator/UsersIndicator.tsx | 6 ++++ .../components/ValuePicker/ValuePicker.tsx | 5 +++ .../src/components/VizLayout/VizLayout.tsx | 2 ++ .../src/components/VizLegend/VizLegend.tsx | 2 ++ 125 files changed, 548 insertions(+), 26 deletions(-) diff --git a/packages/grafana-ui/src/components/Alert/Alert.tsx b/packages/grafana-ui/src/components/Alert/Alert.tsx index 56b81d14351..8b3b55a41cc 100644 --- a/packages/grafana-ui/src/components/Alert/Alert.tsx +++ b/packages/grafana-ui/src/components/Alert/Alert.tsx @@ -26,6 +26,11 @@ export interface Props extends HTMLAttributes { topSpacing?: number; } +/** + * An alert displays an important message in a way that attracts the user's attention without interrupting the user's task. + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/information-alert--docs + */ export const Alert = React.forwardRef( ( { diff --git a/packages/grafana-ui/src/components/AutoSaveField/AutoSaveField.tsx b/packages/grafana-ui/src/components/AutoSaveField/AutoSaveField.tsx index f53670b73a6..f78262d0548 100644 --- a/packages/grafana-ui/src/components/AutoSaveField/AutoSaveField.tsx +++ b/packages/grafana-ui/src/components/AutoSaveField/AutoSaveField.tsx @@ -21,6 +21,12 @@ export interface Props extends Omit { /** Input that will save its value on change */ children: (onChange: (newValue: T) => void) => React.ReactElement; } + +/** + * Used for form inputs that should save its content automatically. + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/inputs-autosavefield--docs + */ export function AutoSaveField(props: Props) { const { invalid, diff --git a/packages/grafana-ui/src/components/Badge/Badge.tsx b/packages/grafana-ui/src/components/Badge/Badge.tsx index 201957ab534..53bcabc646d 100644 --- a/packages/grafana-ui/src/components/Badge/Badge.tsx +++ b/packages/grafana-ui/src/components/Badge/Badge.tsx @@ -47,6 +47,11 @@ const BadgeSkeleton: SkeletonComponent = ({ rootProps }) => { return ; }; +/** + * The badge component adds meta information to other content, for example about release status or new elements. You can add any `Icon` component or use the badge without an icon. + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/information-badge--docs + */ export const Badge = attachSkeleton(BadgeComponent, BadgeSkeleton); const getSkeletonStyles = () => ({ diff --git a/packages/grafana-ui/src/components/BarGauge/BarGauge.tsx b/packages/grafana-ui/src/components/BarGauge/BarGauge.tsx index 3392f059662..639bf41ca13 100644 --- a/packages/grafana-ui/src/components/BarGauge/BarGauge.tsx +++ b/packages/grafana-ui/src/components/BarGauge/BarGauge.tsx @@ -56,6 +56,9 @@ export interface Props extends Themeable2 { isOverflow: boolean; } +/** + * https://developers.grafana.com/ui/latest/index.html?path=/docs/plugins-bargauge--docs + */ export class BarGauge extends PureComponent { static defaultProps: Partial = { lcdCellWidth: 12, diff --git a/packages/grafana-ui/src/components/BigValue/BigValue.tsx b/packages/grafana-ui/src/components/BigValue/BigValue.tsx index 08bacf3e2af..870d350ba95 100644 --- a/packages/grafana-ui/src/components/BigValue/BigValue.tsx +++ b/packages/grafana-ui/src/components/BigValue/BigValue.tsx @@ -82,6 +82,11 @@ export interface Props extends Themeable2 { disableWideLayout?: boolean; } +/** + * Component for showing a value based on a [DisplayValue](https://github.com/grafana/grafana/blob/main/packages/grafana-data/src/types/displayValue.ts#L5). + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/plugins-bigvalue--docs + */ export const BigValue = memo((props) => { const { onClick, className, hasLinks, theme, justifyMode = BigValueJustifyMode.Auto } = props; diff --git a/packages/grafana-ui/src/components/Button/Button.tsx b/packages/grafana-ui/src/components/Button/Button.tsx index c596904a39b..9e1d1c4a1a9 100644 --- a/packages/grafana-ui/src/components/Button/Button.tsx +++ b/packages/grafana-ui/src/components/Button/Button.tsx @@ -51,6 +51,9 @@ type CommonProps = BasePropsWithChildren | NoChildrenTooltip | NoChildrenAriaLab export type ButtonProps = CommonProps & ButtonHTMLAttributes; +/** + * https://developers.grafana.com/ui/latest/index.html?path=/docs/inputs-button--docs + */ export const Button = React.forwardRef( ( { diff --git a/packages/grafana-ui/src/components/ButtonCascader/ButtonCascader.tsx b/packages/grafana-ui/src/components/ButtonCascader/ButtonCascader.tsx index 43aaff2bee2..e52b368f759 100644 --- a/packages/grafana-ui/src/components/ButtonCascader/ButtonCascader.tsx +++ b/packages/grafana-ui/src/components/ButtonCascader/ButtonCascader.tsx @@ -28,6 +28,9 @@ export interface ButtonCascaderProps { hideDownIcon?: boolean; } +/** + * https://developers.grafana.com/ui/latest/index.html?path=/docs/inputs-buttoncascader--docs + */ export const ButtonCascader = (props: ButtonCascaderProps) => { const { onChange, className, loadData, icon, buttonProps, hideDownIcon, variant, disabled, ...rest } = props; const styles = useStyles2(getStyles); diff --git a/packages/grafana-ui/src/components/CallToActionCard/CallToActionCard.tsx b/packages/grafana-ui/src/components/CallToActionCard/CallToActionCard.tsx index ca3348c2b54..cd859f77256 100644 --- a/packages/grafana-ui/src/components/CallToActionCard/CallToActionCard.tsx +++ b/packages/grafana-ui/src/components/CallToActionCard/CallToActionCard.tsx @@ -11,7 +11,11 @@ export interface CallToActionCardProps { className?: string; } -/** @deprecated Use instead */ +/** + * @deprecated Use `` instead. + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/information-deprecated-calltoactioncard--docs + */ export const CallToActionCard = ({ message, callToActionElement, footer, className }: CallToActionCardProps) => { const css = useStyles2(getStyles); diff --git a/packages/grafana-ui/src/components/Card/Card.tsx b/packages/grafana-ui/src/components/Card/Card.tsx index 80194b56136..f1514f6f60e 100644 --- a/packages/grafana-ui/src/components/Card/Card.tsx +++ b/packages/grafana-ui/src/components/Card/Card.tsx @@ -51,6 +51,7 @@ const CardContext = React.createContext<{ /** * Generic card component * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/layout-card--docs * @public */ export const Card: CardInterface = ({ diff --git a/packages/grafana-ui/src/components/Carousel/Carousel.tsx b/packages/grafana-ui/src/components/Carousel/Carousel.tsx index f3cc7892293..57f4ed59005 100644 --- a/packages/grafana-ui/src/components/Carousel/Carousel.tsx +++ b/packages/grafana-ui/src/components/Carousel/Carousel.tsx @@ -22,6 +22,11 @@ export interface CarouselProps { images: CarouselImage[]; } +/** + * The Carousel component displays a grid of image thumbnails that can be clicked to view full-sized images in a modal with navigation controls. It provides an elegant way to present collections of images or screenshots with fullscreen preview capabilities. + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/overlays-carousel--docs + */ export const Carousel: React.FC = ({ images }) => { const [selectedIndex, setSelectedIndex] = useState(null); const [imageErrors, setImageErrors] = useState>({}); diff --git a/packages/grafana-ui/src/components/Cascader/Cascader.tsx b/packages/grafana-ui/src/components/Cascader/Cascader.tsx index ed8c1af953d..8f80b3b6093 100644 --- a/packages/grafana-ui/src/components/Cascader/Cascader.tsx +++ b/packages/grafana-ui/src/components/Cascader/Cascader.tsx @@ -321,4 +321,9 @@ class UnthemedCascader extends PureComponent { } } +/** + * The cascader component is a Select with a cascading flyout menu. When you have lots of options in your select, they can be hard to navigate from a regular dropdown list. In that case you can use the cascader to organize your options into groups hierarchically. Just like in the Select component, the cascader input doubles as a search field to quickly jump to a selection without navigating the list. + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/inputs-cascader--docs + */ export const Cascader = withTheme2(UnthemedCascader); diff --git a/packages/grafana-ui/src/components/ClickOutsideWrapper/ClickOutsideWrapper.tsx b/packages/grafana-ui/src/components/ClickOutsideWrapper/ClickOutsideWrapper.tsx index 4a3b9e9b88a..1e9ab3e6de1 100644 --- a/packages/grafana-ui/src/components/ClickOutsideWrapper/ClickOutsideWrapper.tsx +++ b/packages/grafana-ui/src/components/ClickOutsideWrapper/ClickOutsideWrapper.tsx @@ -13,6 +13,11 @@ export interface Props { children: React.ReactNode; } +/** + * A wrapper component that detects clicks outside of the elements by attaching event listener to `window` or `document` objects. Useful for components that require an action being triggered when a click outside has occurred, for example closing an overlay or popup. + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/utilities-clickoutsidewrapper--docs + */ export function ClickOutsideWrapper({ includeButtonPress = true, parent = window, diff --git a/packages/grafana-ui/src/components/ClipboardButton/ClipboardButton.tsx b/packages/grafana-ui/src/components/ClipboardButton/ClipboardButton.tsx index a42871dcde0..f1f00cdb25e 100644 --- a/packages/grafana-ui/src/components/ClipboardButton/ClipboardButton.tsx +++ b/packages/grafana-ui/src/components/ClipboardButton/ClipboardButton.tsx @@ -21,6 +21,11 @@ export type Props = ButtonProps & { const SHOW_SUCCESS_DURATION = 2 * 1000; +/** + * A control for allowing the user to copy text to their clipboard. Uses native APIs on modern browsers, falling back to the old `document.execCommand('copy')` API on other browsers. The text to be copied should be provided via `getText` prop. + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/inputs-clipboardbutton--docs + */ export function ClipboardButton({ onClipboardCopy, onClipboardError, diff --git a/packages/grafana-ui/src/components/Collapse/CollapsableSection.tsx b/packages/grafana-ui/src/components/Collapse/CollapsableSection.tsx index 12c00333dfd..936d9837813 100644 --- a/packages/grafana-ui/src/components/Collapse/CollapsableSection.tsx +++ b/packages/grafana-ui/src/components/Collapse/CollapsableSection.tsx @@ -25,6 +25,11 @@ export interface Props { unmountContentWhenClosed?: boolean; } +/** + * A simple container for enabling collapsing/expanding of content. + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/layout-collapsablesection--docs + */ export const CollapsableSection = ({ label, isOpen, diff --git a/packages/grafana-ui/src/components/Collapse/Collapse.tsx b/packages/grafana-ui/src/components/Collapse/Collapse.tsx index 57aec7a3ed4..d0f8757e1ca 100644 --- a/packages/grafana-ui/src/components/Collapse/Collapse.tsx +++ b/packages/grafana-ui/src/components/Collapse/Collapse.tsx @@ -128,6 +128,11 @@ export const ControlledCollapse = ({ isOpen, onToggle, ...otherProps }: React.Pr ); }; +/** + * A content area, which can be horizontally collapsed and expanded. Can be used to hide extra information on the page. + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/layout-collapse--docs + */ export const Collapse = ({ isOpen, label, diff --git a/packages/grafana-ui/src/components/ColorPicker/ColorPicker.tsx b/packages/grafana-ui/src/components/ColorPicker/ColorPicker.tsx index 819d60746db..f44b3f00fa4 100644 --- a/packages/grafana-ui/src/components/ColorPicker/ColorPicker.tsx +++ b/packages/grafana-ui/src/components/ColorPicker/ColorPicker.tsx @@ -84,6 +84,9 @@ export const colorPickerFactory = ( }; }; +/** + * https://developers.grafana.com/ui/latest/index.html?path=/docs/pickers-colorpicker--docs + */ export const ColorPicker = withTheme2(colorPickerFactory(ColorPickerPopover, 'ColorPicker')); export const SeriesColorPicker = withTheme2(colorPickerFactory(SeriesColorPickerPopover, 'SeriesColorPicker')); diff --git a/packages/grafana-ui/src/components/ColorPicker/ColorPickerInput.tsx b/packages/grafana-ui/src/components/ColorPicker/ColorPickerInput.tsx index 27f807051a8..5dd4e2acb25 100644 --- a/packages/grafana-ui/src/components/ColorPicker/ColorPickerInput.tsx +++ b/packages/grafana-ui/src/components/ColorPicker/ColorPickerInput.tsx @@ -19,6 +19,9 @@ export interface ColorPickerInputProps extends Omit( ({ value = '', onChange, returnColorAs = 'rgb', ...inputProps }, ref) => { const [currentColor, setColor] = useState(value); diff --git a/packages/grafana-ui/src/components/ColorPicker/SeriesColorPickerPopover.tsx b/packages/grafana-ui/src/components/ColorPicker/SeriesColorPickerPopover.tsx index 2c0350d9329..6e38fa3148e 100644 --- a/packages/grafana-ui/src/components/ColorPicker/SeriesColorPickerPopover.tsx +++ b/packages/grafana-ui/src/components/ColorPicker/SeriesColorPickerPopover.tsx @@ -12,6 +12,9 @@ export interface SeriesColorPickerPopoverProps extends ColorPickerProps, Popover onToggleAxis?: () => void; } +/** + * https://developers.grafana.com/ui/latest/index.html?path=/docs/pickers-seriescolorpicker--docs + */ export const SeriesColorPickerPopover = (props: SeriesColorPickerPopoverProps) => { const { yaxis, onToggleAxis, color, ...colorPickerProps } = props; const yAxisLabel = t('grafana-ui.series-color-picker-popover.y-axis-usage', 'Use right y-axis'); diff --git a/packages/grafana-ui/src/components/Combobox/Combobox.tsx b/packages/grafana-ui/src/components/Combobox/Combobox.tsx index 9c4de9c2d8b..a4664c62441 100644 --- a/packages/grafana-ui/src/components/Combobox/Combobox.tsx +++ b/packages/grafana-ui/src/components/Combobox/Combobox.tsx @@ -119,8 +119,10 @@ const noop = () => {}; export const VIRTUAL_OVERSCAN_ITEMS = 4; /** - * A performant Select replacement. + * A performant and accessible combobox component that supports both synchronous and asynchronous options loading. It provides type-ahead filtering, keyboard navigation, and virtual scrolling for handling large datasets efficiently. + * Replaces the Select component, and has better performance. * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/inputs-combobox--docs * @alpha */ export const Combobox = (props: ComboboxProps) => { diff --git a/packages/grafana-ui/src/components/Combobox/MultiCombobox.tsx b/packages/grafana-ui/src/components/Combobox/MultiCombobox.tsx index 989bf3d0e2e..3a1e2856a68 100644 --- a/packages/grafana-ui/src/components/Combobox/MultiCombobox.tsx +++ b/packages/grafana-ui/src/components/Combobox/MultiCombobox.tsx @@ -35,6 +35,11 @@ interface MultiComboboxBaseProps export type MultiComboboxProps = MultiComboboxBaseProps & AutoSizeConditionals; +/** + * The behavior of the MultiCombobox is similar to that of the Combobox, but it allows you to select multiple options. For all non-multi behaviors, see the Combobox documentation. + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/inputs-multicombobox--docs + */ export const MultiCombobox = (props: MultiComboboxProps) => { const { placeholder, diff --git a/packages/grafana-ui/src/components/ConfirmButton/ConfirmButton.tsx b/packages/grafana-ui/src/components/ConfirmButton/ConfirmButton.tsx index 5ddfd473700..0a5e3db8688 100644 --- a/packages/grafana-ui/src/components/ConfirmButton/ConfirmButton.tsx +++ b/packages/grafana-ui/src/components/ConfirmButton/ConfirmButton.tsx @@ -31,6 +31,11 @@ export interface Props { onCancel?(): void; } +/** + * The ConfirmButton is an interactive component that adds a double-confirm option to a clickable action. When clicked, the action is replaced by an inline confirmation with the option to cancel. In Grafana, this is used, for example, for editing values in settings tables. + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/inputs-confirmbutton--docs + */ export const ConfirmButton = ({ children, className, diff --git a/packages/grafana-ui/src/components/ConfirmModal/ConfirmModal.tsx b/packages/grafana-ui/src/components/ConfirmModal/ConfirmModal.tsx index ffcffa96f58..b57f9d8557b 100644 --- a/packages/grafana-ui/src/components/ConfirmModal/ConfirmModal.tsx +++ b/packages/grafana-ui/src/components/ConfirmModal/ConfirmModal.tsx @@ -48,6 +48,11 @@ export interface ConfirmModalProps { disabled?: boolean; } +/** + * Used to request user for action confirmation, e.g. deleting items. Triggers provided `onConfirm` callback. + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/overlays-confirmmodal--docs + */ export const ConfirmModal = ({ isOpen, title, diff --git a/packages/grafana-ui/src/components/ContextMenu/ContextMenu.tsx b/packages/grafana-ui/src/components/ContextMenu/ContextMenu.tsx index 86802d58743..5a96497cdef 100644 --- a/packages/grafana-ui/src/components/ContextMenu/ContextMenu.tsx +++ b/packages/grafana-ui/src/components/ContextMenu/ContextMenu.tsx @@ -22,6 +22,11 @@ export interface ContextMenuProps { renderHeader?: () => React.ReactNode; } +/** + * A menu displaying additional options when it's not possible to show them at all times due to a space constraint. + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/overlays-contextmenu--docs + */ export const ContextMenu = React.memo( ({ x, y, onClose, focusOnOpen = true, renderMenuItems, renderHeader }: ContextMenuProps) => { const menuRef = useRef(null); diff --git a/packages/grafana-ui/src/components/DataSourceSettings/DataSourceHttpSettings.mdx b/packages/grafana-ui/src/components/DataSourceSettings/DataSourceHttpSettings.mdx index 08671fcb108..f241ced1384 100644 --- a/packages/grafana-ui/src/components/DataSourceSettings/DataSourceHttpSettings.mdx +++ b/packages/grafana-ui/src/components/DataSourceSettings/DataSourceHttpSettings.mdx @@ -5,6 +5,8 @@ import { DataSourceHttpSettings } from './DataSourceHttpSettings'; # DataSourceHttpSettings +> **Deprecated!** Use components from `@grafana/plugin-ui` instead, according to the [migration guide](https://github.com/grafana/plugin-ui/blob/main/src/components/ConfigEditor/migrating-from-datasource-http-settings.md) + Component for displaying the configuration options for a data source plugin. ### When to use diff --git a/packages/grafana-ui/src/components/DataSourceSettings/DataSourceHttpSettings.tsx b/packages/grafana-ui/src/components/DataSourceSettings/DataSourceHttpSettings.tsx index e57f7747494..65f6ff77259 100644 --- a/packages/grafana-ui/src/components/DataSourceSettings/DataSourceHttpSettings.tsx +++ b/packages/grafana-ui/src/components/DataSourceSettings/DataSourceHttpSettings.tsx @@ -72,6 +72,8 @@ const LABEL_WIDTH = 26; /** * @deprecated Use components from `@grafana/plugin-ui` instead, according to the [migration guide](https://github.com/grafana/plugin-ui/blob/main/src/components/ConfigEditor/migrating-from-datasource-http-settings.md). + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/plugins-datasourcehttpsettings--docs */ export const DataSourceHttpSettings = (props: HttpSettingsProps) => { const { diff --git a/packages/grafana-ui/src/components/DateTimePickers/DatePicker/DatePicker.tsx b/packages/grafana-ui/src/components/DateTimePickers/DatePicker/DatePicker.tsx index 28c88547023..a69a6d9fb18 100644 --- a/packages/grafana-ui/src/components/DateTimePickers/DatePicker/DatePicker.tsx +++ b/packages/grafana-ui/src/components/DateTimePickers/DatePicker/DatePicker.tsx @@ -19,7 +19,12 @@ export interface DatePickerProps { maxDate?: Date; } -/** @public */ +/** + * A component with a calendar view for selecting a date. + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/date-time-pickers-datepicker--docs + * @public + * */ export const DatePicker = memo((props) => { const styles = useStyles2(getStyles); const { isOpen, onClose } = props; diff --git a/packages/grafana-ui/src/components/DateTimePickers/DatePickerWithInput/DatePickerWithInput.tsx b/packages/grafana-ui/src/components/DateTimePickers/DatePickerWithInput/DatePickerWithInput.tsx index 4d2d6533a31..0103a1d21a5 100644 --- a/packages/grafana-ui/src/components/DateTimePickers/DatePickerWithInput/DatePickerWithInput.tsx +++ b/packages/grafana-ui/src/components/DateTimePickers/DatePickerWithInput/DatePickerWithInput.tsx @@ -27,7 +27,12 @@ export interface DatePickerWithInputProps extends Omit( ({ value, minDate, maxDate, onChange, closeOnSelect, placeholder = 'Date', ...rest }, ref) => { const [open, setOpen] = useState(false); diff --git a/packages/grafana-ui/src/components/DateTimePickers/DateTimePicker/DateTimePicker.tsx b/packages/grafana-ui/src/components/DateTimePickers/DateTimePicker/DateTimePicker.tsx index 1f4eb4da47d..a7024681d42 100644 --- a/packages/grafana-ui/src/components/DateTimePickers/DateTimePicker/DateTimePicker.tsx +++ b/packages/grafana-ui/src/components/DateTimePickers/DateTimePicker/DateTimePicker.tsx @@ -60,6 +60,11 @@ export interface Props { timeZone?: TimeZone; } +/** + * A component for selecting a date *and* time. + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/date-time-pickers-datetimepicker--docs + */ export const DateTimePicker = ({ date, maxDate, diff --git a/packages/grafana-ui/src/components/DateTimePickers/RelativeTimeRangePicker/RelativeTimeRangePicker.tsx b/packages/grafana-ui/src/components/DateTimePickers/RelativeTimeRangePicker/RelativeTimeRangePicker.tsx index 74a19dd6efd..e07345bf111 100644 --- a/packages/grafana-ui/src/components/DateTimePickers/RelativeTimeRangePicker/RelativeTimeRangePicker.tsx +++ b/packages/grafana-ui/src/components/DateTimePickers/RelativeTimeRangePicker/RelativeTimeRangePicker.tsx @@ -41,6 +41,7 @@ type InputState = { }; /** + * https://developers.grafana.com/ui/latest/index.html?path=/docs/date-time-pickers-relativetimerangepicker--docs * @internal */ export function RelativeTimeRangePicker(props: RelativeTimeRangePickerProps) { diff --git a/packages/grafana-ui/src/components/DateTimePickers/TimeRangeInput.tsx b/packages/grafana-ui/src/components/DateTimePickers/TimeRangeInput.tsx index 67d3af9496a..90666dad8b3 100644 --- a/packages/grafana-ui/src/components/DateTimePickers/TimeRangeInput.tsx +++ b/packages/grafana-ui/src/components/DateTimePickers/TimeRangeInput.tsx @@ -36,6 +36,11 @@ export interface TimeRangeInputProps { const noop = () => {}; +/** + * A variant of TimeRangePicker for use in forms. + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/date-time-pickers-timerangeinput--docs + */ export const TimeRangeInput = ({ value, onChange, diff --git a/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker.tsx b/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker.tsx index 3157b6ca837..b26a6e4c36d 100644 --- a/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker.tsx +++ b/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker.tsx @@ -73,6 +73,9 @@ export interface State { isOpen: boolean; } +/** + * https://developers.grafana.com/ui/latest/index.html?path=/docs/date-time-pickers-timerangepicker--docs + */ export function TimeRangePicker(props: TimeRangePickerProps) { const [isOpen, setOpen] = useState(false); diff --git a/packages/grafana-ui/src/components/DateTimePickers/TimeZonePicker.tsx b/packages/grafana-ui/src/components/DateTimePickers/TimeZonePicker.tsx index f41279cb983..464dcc9fb24 100644 --- a/packages/grafana-ui/src/components/DateTimePickers/TimeZonePicker.tsx +++ b/packages/grafana-ui/src/components/DateTimePickers/TimeZonePicker.tsx @@ -31,6 +31,9 @@ export interface Props { openMenuOnFocus?: boolean; } +/** + * https://developers.grafana.com/ui/latest/index.html?path=/docs/date-time-pickers-timezonepicker--docs + */ export const TimeZonePicker = (props: Props) => { const { onChange, diff --git a/packages/grafana-ui/src/components/DateTimePickers/WeekStartPicker.tsx b/packages/grafana-ui/src/components/DateTimePickers/WeekStartPicker.tsx index 0207dcb67a8..2fe37d06d3f 100644 --- a/packages/grafana-ui/src/components/DateTimePickers/WeekStartPicker.tsx +++ b/packages/grafana-ui/src/components/DateTimePickers/WeekStartPicker.tsx @@ -39,6 +39,9 @@ export function getWeekStart(override?: string): WeekStart { return 'monday'; } +/** + * https://developers.grafana.com/ui/latest/index.html?path=/docs/date-time-pickers-weekstartpicker--docs + */ export const WeekStartPicker = (props: Props) => { const { onChange, width, autoFocus = false, onBlur, value, disabled = false, inputId } = props; const weekStarts: ComboboxOption[] = useMemo( diff --git a/packages/grafana-ui/src/components/Divider/Divider.tsx b/packages/grafana-ui/src/components/Divider/Divider.tsx index b9f5f580183..721ea8b58dc 100644 --- a/packages/grafana-ui/src/components/Divider/Divider.tsx +++ b/packages/grafana-ui/src/components/Divider/Divider.tsx @@ -9,6 +9,9 @@ interface DividerProps { spacing?: ThemeSpacingTokens; } +/** + * https://developers.grafana.com/ui/latest/index.html?path=/docs/layout-divider--docs + */ export const Divider = ({ direction = 'horizontal', spacing = 2 }: DividerProps) => { const styles = useStyles2(getStyles, spacing); diff --git a/packages/grafana-ui/src/components/Drawer/Drawer.tsx b/packages/grafana-ui/src/components/Drawer/Drawer.tsx index b81a3784b72..b7ee0252bfc 100644 --- a/packages/grafana-ui/src/components/Drawer/Drawer.tsx +++ b/packages/grafana-ui/src/components/Drawer/Drawer.tsx @@ -62,6 +62,11 @@ const drawerSizes = { lg: { width: '75vw', minWidth: 744 }, }; +/** + * Drawer is a slide in overlay that can be used to display additional information without hiding the main page content. It can be anchored to the left or right edge of the screen. + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/overlays-drawer--docs + */ export function Drawer({ children, onClose, diff --git a/packages/grafana-ui/src/components/Dropdown/ButtonSelect.tsx b/packages/grafana-ui/src/components/Dropdown/ButtonSelect.tsx index a2e23e78575..99f4db3b56b 100644 --- a/packages/grafana-ui/src/components/Dropdown/ButtonSelect.tsx +++ b/packages/grafana-ui/src/components/Dropdown/ButtonSelect.tsx @@ -25,6 +25,8 @@ export interface Props extends HTMLAttributes { /** * @deprecated Use Combobox or Dropdown instead + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/inputs-deprecated-buttonselect--docs */ const ButtonSelectComponent = (props: Props) => { const { className, options, value, onChange, narrow, variant, root, ...restProps } = props; diff --git a/packages/grafana-ui/src/components/Dropdown/Dropdown.tsx b/packages/grafana-ui/src/components/Dropdown/Dropdown.tsx index 77cdcc92519..b098665db7b 100644 --- a/packages/grafana-ui/src/components/Dropdown/Dropdown.tsx +++ b/packages/grafana-ui/src/components/Dropdown/Dropdown.tsx @@ -31,6 +31,11 @@ export interface Props { onVisibleChange?: (state: boolean) => void; } +/** + * Hook up a menu or other overlay to any trigger. + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/overlays-dropdown--docs + */ export const Dropdown = React.memo(({ children, overlay, placement, offset, root, onVisibleChange }: Props) => { const [show, setShow] = useState(false); const transitionRef = useRef(null); diff --git a/packages/grafana-ui/src/components/EmptySearchResult/EmptySearchResult.tsx b/packages/grafana-ui/src/components/EmptySearchResult/EmptySearchResult.tsx index 2ddafbf865b..72f353b4ed7 100644 --- a/packages/grafana-ui/src/components/EmptySearchResult/EmptySearchResult.tsx +++ b/packages/grafana-ui/src/components/EmptySearchResult/EmptySearchResult.tsx @@ -8,7 +8,11 @@ export interface Props { children: JSX.Element | string; } -/** @deprecated Use instead */ +/** + * @deprecated Use `` instead. + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/information-deprecated-emptysearchresult--docs + */ const EmptySearchResult = ({ children }: Props) => { const styles = useStyles2(getStyles); return
{children}
; diff --git a/packages/grafana-ui/src/components/EmptyState/EmptyState.tsx b/packages/grafana-ui/src/components/EmptyState/EmptyState.tsx index a7ee3774666..7e9c73fb0f1 100644 --- a/packages/grafana-ui/src/components/EmptyState/EmptyState.tsx +++ b/packages/grafana-ui/src/components/EmptyState/EmptyState.tsx @@ -38,6 +38,11 @@ interface Props { role?: AriaRole; } +/** + * The EmptyState component consists of a message and optionally an image, button, and additional information. + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/information-emptystate--docs + */ export const EmptyState = ({ button, children, diff --git a/packages/grafana-ui/src/components/ErrorBoundary/ErrorBoundary.tsx b/packages/grafana-ui/src/components/ErrorBoundary/ErrorBoundary.tsx index 63044d76d2f..dd49f34b985 100644 --- a/packages/grafana-ui/src/components/ErrorBoundary/ErrorBoundary.tsx +++ b/packages/grafana-ui/src/components/ErrorBoundary/ErrorBoundary.tsx @@ -33,6 +33,11 @@ interface State { errorInfo: ErrorInfo | null; } +/** + * A React component that catches errors in child components. Useful for logging or displaying a fallback UI in case of errors. More information about error boundaries is available at [React documentation website](https://reactjs.org/docs/error-boundaries.html). + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/utilities-errorboundary--docs + */ export class ErrorBoundary extends PureComponent { readonly state: State = { error: null, diff --git a/packages/grafana-ui/src/components/FeatureBadge/FeatureBadge.tsx b/packages/grafana-ui/src/components/FeatureBadge/FeatureBadge.tsx index 6a67913e453..f1af47396f3 100644 --- a/packages/grafana-ui/src/components/FeatureBadge/FeatureBadge.tsx +++ b/packages/grafana-ui/src/components/FeatureBadge/FeatureBadge.tsx @@ -8,6 +8,11 @@ export interface FeatureBadgeProps { tooltip?: string; } +/** + * A component for displaying information about different release stages of features, in accordance with the guidelines provided at [Grafana's Release Life Cycle](https://grafana.com/docs/release-life-cycle). + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/information-featurebadge--docs + */ export const FeatureBadge = ({ featureState, tooltip }: FeatureBadgeProps) => { const display = getPanelStateBadgeDisplayModel(featureState); return ; diff --git a/packages/grafana-ui/src/components/FileDropzone/FileDropzone.tsx b/packages/grafana-ui/src/components/FileDropzone/FileDropzone.tsx index 120c7e08a09..ad1fa0b8b49 100644 --- a/packages/grafana-ui/src/components/FileDropzone/FileDropzone.tsx +++ b/packages/grafana-ui/src/components/FileDropzone/FileDropzone.tsx @@ -63,6 +63,11 @@ export interface DropzoneFile { retryUpload?: () => void; } +/** + * A dropzone component to use for file uploads. + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/inputs-filedropzone--docs + */ export function FileDropzone({ options, children, diff --git a/packages/grafana-ui/src/components/FileDropzone/FileListItem.tsx b/packages/grafana-ui/src/components/FileDropzone/FileListItem.tsx index b13066621c6..e54d66b34b5 100644 --- a/packages/grafana-ui/src/components/FileDropzone/FileListItem.tsx +++ b/packages/grafana-ui/src/components/FileDropzone/FileListItem.tsx @@ -17,6 +17,11 @@ export interface FileListItemProps { removeFile?: (file: DropzoneFile) => void; } +/** + * A FileListItem component used for the FileDropzone component to show uploaded files. + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/inputs-filelistitem--docs + */ export function FileListItem({ file: customFile, removeFile }: FileListItemProps) { const styles = useStyles2(getStyles); const { file, progress, error, abortUpload, retryUpload } = customFile; diff --git a/packages/grafana-ui/src/components/FileUpload/FileUpload.tsx b/packages/grafana-ui/src/components/FileUpload/FileUpload.tsx index 528d4a7e193..5ad7662ff56 100644 --- a/packages/grafana-ui/src/components/FileUpload/FileUpload.tsx +++ b/packages/grafana-ui/src/components/FileUpload/FileUpload.tsx @@ -27,6 +27,11 @@ export interface Props { showFileName?: boolean; } +/** + * A button-styled input that triggers file upload popup. Button text and accepted file extensions can be customized via `label` and `accepted` props respectively. + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/inputs-fileupload--docs + */ export const FileUpload = ({ onFileUpload, className, diff --git a/packages/grafana-ui/src/components/FilterPill/FilterPill.tsx b/packages/grafana-ui/src/components/FilterPill/FilterPill.tsx index 48140e3940d..6fdbaa2e76d 100644 --- a/packages/grafana-ui/src/components/FilterPill/FilterPill.tsx +++ b/packages/grafana-ui/src/components/FilterPill/FilterPill.tsx @@ -15,6 +15,11 @@ export interface FilterPillProps { icon?: IconName; } +/** + * A component used for quick toggling on/off filters. Mostly used in inline form components and transformation/query editors. + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/inputs-filterpill--docs + */ export const FilterPill = ({ label, selected, onClick, icon = 'check' }: FilterPillProps) => { const styles = useStyles2(getStyles); const clearButton = useStyles2(clearButtonStyles); diff --git a/packages/grafana-ui/src/components/FormField/FormField.tsx b/packages/grafana-ui/src/components/FormField/FormField.tsx index 4d9bca9ded8..c4663db842e 100644 --- a/packages/grafana-ui/src/components/FormField/FormField.tsx +++ b/packages/grafana-ui/src/components/FormField/FormField.tsx @@ -24,6 +24,8 @@ export interface Props extends InputHTMLAttributes { * * For inline fields, use {@link InlineField}, {@link https://developers.grafana.com/ui/latest/index.html?path=/story/forms-inlinefield--basic See Storybook}. * @deprecated Please use the {@link Field} component, {@link https://developers.grafana.com/ui/latest/index.html?path=/story/forms-field--simple See Storybook}. + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/forms-deprecated-formfield--docs */ export const FormField = ({ label, diff --git a/packages/grafana-ui/src/components/FormattedValueDisplay/FormattedValueDisplay.tsx b/packages/grafana-ui/src/components/FormattedValueDisplay/FormattedValueDisplay.tsx index 6c9d6dd5334..f2e0527939a 100644 --- a/packages/grafana-ui/src/components/FormattedValueDisplay/FormattedValueDisplay.tsx +++ b/packages/grafana-ui/src/components/FormattedValueDisplay/FormattedValueDisplay.tsx @@ -18,6 +18,11 @@ function fontSizeReductionFactor(fontSize: number) { return 0.6; } +/** + * Used to display a value, which also supports prefix and suffix. + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/plugins-formattedvaluedisplay--docs + */ export const FormattedValueDisplay = ({ value, className, style, ...htmlProps }: Props) => { const hasPrefix = (value.prefix ?? '').length > 0; const hasSuffix = (value.suffix ?? '').length > 0; diff --git a/packages/grafana-ui/src/components/Forms/Checkbox.tsx b/packages/grafana-ui/src/components/Forms/Checkbox.tsx index 173f821e287..c20b0892e21 100644 --- a/packages/grafana-ui/src/components/Forms/Checkbox.tsx +++ b/packages/grafana-ui/src/components/Forms/Checkbox.tsx @@ -24,6 +24,9 @@ export interface CheckboxProps extends Omit, 'value' invalid?: boolean; } +/** + * https://developers.grafana.com/ui/latest/index.html?path=/docs/inputs-checkbox--docs + */ export const Checkbox = React.forwardRef( ( { label, description, value, htmlValue, onChange, disabled, className, indeterminate, invalid, ...inputProps }, diff --git a/packages/grafana-ui/src/components/Forms/Field.tsx b/packages/grafana-ui/src/components/Forms/Field.tsx index 1c80a2caf81..6c5884e04c9 100644 --- a/packages/grafana-ui/src/components/Forms/Field.tsx +++ b/packages/grafana-ui/src/components/Forms/Field.tsx @@ -43,6 +43,11 @@ export interface FieldProps extends HTMLAttributes { noMargin?: boolean; } +/** + * Field is the basic component for rendering form elements together with labels and description. + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/forms-field--docs + */ export const Field = React.forwardRef( ( { diff --git a/packages/grafana-ui/src/components/Forms/FieldArray.tsx b/packages/grafana-ui/src/components/Forms/FieldArray.tsx index fc0cda3b7ff..5c21767ab84 100644 --- a/packages/grafana-ui/src/components/Forms/FieldArray.tsx +++ b/packages/grafana-ui/src/components/Forms/FieldArray.tsx @@ -9,6 +9,8 @@ export interface FieldArrayProps extends UseFieldArrayProps { /** * @deprecated use the `useFieldArray` hook from react-hook-form instead + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/forms-fieldarray--docs */ export const FieldArray: FC = ({ name, control, children, ...rest }) => { const { fields, append, prepend, remove, swap, move, insert } = useFieldArray({ diff --git a/packages/grafana-ui/src/components/Forms/FieldSet.tsx b/packages/grafana-ui/src/components/Forms/FieldSet.tsx index 421ba3a5ad3..4f42cb96f8e 100644 --- a/packages/grafana-ui/src/components/Forms/FieldSet.tsx +++ b/packages/grafana-ui/src/components/Forms/FieldSet.tsx @@ -14,6 +14,11 @@ export interface Props extends Omit, 'label'> { label?: React.ReactNode; } +/** + * Component used to group form elements inside a form, equivalent to HTML's [fieldset](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/fieldset) tag. Accepts optional label, which, if provided, is used as a text for the set's legend. + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/forms-fieldset--docs + */ export const FieldSet = ({ label, children, className, ...rest }: Props) => { const styles = useStyles2(getStyles); diff --git a/packages/grafana-ui/src/components/Forms/FieldValidationMessage.tsx b/packages/grafana-ui/src/components/Forms/FieldValidationMessage.tsx index 78f1aeab79e..3a3fd5b078b 100644 --- a/packages/grafana-ui/src/components/Forms/FieldValidationMessage.tsx +++ b/packages/grafana-ui/src/components/Forms/FieldValidationMessage.tsx @@ -12,6 +12,11 @@ export interface FieldValidationMessageProps { horizontal?: boolean; } +/** + * Component for displaying a validation error message under an element. + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/forms-fieldvalidationmessage--docs + */ export const FieldValidationMessage = ({ children, horizontal, diff --git a/packages/grafana-ui/src/components/Forms/Form.tsx b/packages/grafana-ui/src/components/Forms/Form.tsx index 2eb45c69a0e..c251780be96 100644 --- a/packages/grafana-ui/src/components/Forms/Form.tsx +++ b/packages/grafana-ui/src/components/Forms/Form.tsx @@ -18,6 +18,8 @@ interface FormProps extends Omit({ defaultValues, diff --git a/packages/grafana-ui/src/components/Forms/InlineField.mdx b/packages/grafana-ui/src/components/Forms/InlineField.mdx index 1b13b8d3811..b08be513645 100644 --- a/packages/grafana-ui/src/components/Forms/InlineField.mdx +++ b/packages/grafana-ui/src/components/Forms/InlineField.mdx @@ -3,7 +3,7 @@ import { InlineField } from './InlineField'; # InlineField -A basic component for rendering form elements, like `Input`, `Select`, `Checkbox`, etc, inline together with `InlineLabel`. If the child element has `id` specified, the label's `htmlFor` attribute, pointing to the id, will be added. +A basic component for rendering form elements, like `Input`, `Checkbox`, `Combobox`, etc, inline together with `InlineLabel`. If the child element has `id` specified, the label's `htmlFor` attribute, pointing to the id, will be added. The width of the `InlineLabel` can be modified via `labelWidth` prop, which is a multiple of 8px. For example, an `InlineField` with `labelWidth={20}` will have a label 160px wide. diff --git a/packages/grafana-ui/src/components/Forms/InlineField.tsx b/packages/grafana-ui/src/components/Forms/InlineField.tsx index c63d87b585b..a2e7bd4f9e7 100644 --- a/packages/grafana-ui/src/components/Forms/InlineField.tsx +++ b/packages/grafana-ui/src/components/Forms/InlineField.tsx @@ -29,6 +29,11 @@ export interface Props extends Omit, 'css'> { children: ReactNode | ReactNode[]; } +/** + * Used to align multiple InlineField components in one row. The row will wrap if the width of the children exceeds its own. Equivalent to the div with gf-form-inline class name. Multiple InlineFieldRows vertically stack on each other. + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/forms-inlinefieldrow--docs + */ export const InlineFieldRow = ({ children, className, ...htmlProps }: Props) => { const styles = useStyles2(getStyles); return ( diff --git a/packages/grafana-ui/src/components/Forms/InlineLabel.mdx b/packages/grafana-ui/src/components/Forms/InlineLabel.mdx index 9a451f07922..be5b5766a9d 100644 --- a/packages/grafana-ui/src/components/Forms/InlineLabel.mdx +++ b/packages/grafana-ui/src/components/Forms/InlineLabel.mdx @@ -3,7 +3,7 @@ import { InlineLabel } from './InlineLabel'; # InlineLabel -A horizontal variant of `Label`, primarily used in query editors. Can be combined with form components that expect a label, eg. `Input`, `Select`, `Checkbox`. +A horizontal variant of `Label`, primarily used in query editors. Can be combined with form components that expect a label, eg. `Input`, `Checkbox`, `Combobox`. If you need to add additional explanation, use the tooltip prop, which will render an info icon with tooltip inside the label. For query editor readability, the label text should be as short as possible (4 words or fewer). diff --git a/packages/grafana-ui/src/components/Forms/InlineLabel.tsx b/packages/grafana-ui/src/components/Forms/InlineLabel.tsx index fef27352c7f..63b7b7ccb46 100644 --- a/packages/grafana-ui/src/components/Forms/InlineLabel.tsx +++ b/packages/grafana-ui/src/components/Forms/InlineLabel.tsx @@ -25,6 +25,11 @@ export interface Props extends Omit category?: React.ReactNode[]; } +/** + * The label component can be used to label form inputs with a heading/"Option name" and a description. To automatically have the right arrangement of this component with a form input, use the `Field` component. + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/forms-label--docs + */ export const Label = ({ children, description, className, category, ...labelProps }: LabelProps) => { const styles = useStyles2(getLabelStyles); const categories = category?.map((c, i) => { diff --git a/packages/grafana-ui/src/components/Forms/Legend.tsx b/packages/grafana-ui/src/components/Forms/Legend.tsx index 7b48c149b7b..90af8e1229e 100644 --- a/packages/grafana-ui/src/components/Forms/Legend.tsx +++ b/packages/grafana-ui/src/components/Forms/Legend.tsx @@ -21,6 +21,11 @@ export const getLegendStyles = (theme: GrafanaTheme2) => { }; }; +/** + * Legend should be used to add a caption to a group of related form elements that have been grouped toegheter into a `FieldSet`. + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/forms-legend--docs + */ export const Legend = ({ children, className, ...legendProps }: LabelProps) => { const styles = useStyles2(getLegendStyles); diff --git a/packages/grafana-ui/src/components/Forms/RadioButtonGroup/RadioButtonGroup.tsx b/packages/grafana-ui/src/components/Forms/RadioButtonGroup/RadioButtonGroup.tsx index b47ff9913d3..ebef41cbed8 100644 --- a/packages/grafana-ui/src/components/Forms/RadioButtonGroup/RadioButtonGroup.tsx +++ b/packages/grafana-ui/src/components/Forms/RadioButtonGroup/RadioButtonGroup.tsx @@ -24,6 +24,11 @@ export interface RadioButtonGroupProps { invalid?: boolean; } +/** + * RadioButtonGroup is used to select a single value from multiple mutually exclusive options. + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/inputs-radiobuttongroup--docs + */ export function RadioButtonGroup({ options, value, diff --git a/packages/grafana-ui/src/components/Forms/RadioButtonList/RadioButtonList.tsx b/packages/grafana-ui/src/components/Forms/RadioButtonList/RadioButtonList.tsx index a6366c64756..6127d143438 100644 --- a/packages/grafana-ui/src/components/Forms/RadioButtonList/RadioButtonList.tsx +++ b/packages/grafana-ui/src/components/Forms/RadioButtonList/RadioButtonList.tsx @@ -22,6 +22,11 @@ export interface RadioButtonListProps { className?: string; } +/** + * RadioButtonList is used to select a single value from multiple mutually exclusive options usually in a vertical manner. + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/inputs-radiobuttonlist--docs + */ export function RadioButtonList({ name, id, diff --git a/packages/grafana-ui/src/components/Icon/Icon.tsx b/packages/grafana-ui/src/components/Icon/Icon.tsx index ed987489f14..fa4e1fac6d3 100644 --- a/packages/grafana-ui/src/components/Icon/Icon.tsx +++ b/packages/grafana-ui/src/components/Icon/Icon.tsx @@ -42,6 +42,11 @@ const getIconStyles = (theme: GrafanaTheme2) => { }; }; +/** + * Grafana's icon wrapper component. + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/iconography-icon--docs + */ export const Icon = React.memo( React.forwardRef( ({ size = 'md', type = 'default', name, className, style, title = '', ...rest }, ref) => { diff --git a/packages/grafana-ui/src/components/IconButton/IconButton.tsx b/packages/grafana-ui/src/components/IconButton/IconButton.tsx index bbc4519f71f..d4d77c33fab 100644 --- a/packages/grafana-ui/src/components/IconButton/IconButton.tsx +++ b/packages/grafana-ui/src/components/IconButton/IconButton.tsx @@ -43,6 +43,11 @@ interface BasePropsWithAriaLabel extends BaseProps { export type Props = BasePropsWithTooltip | BasePropsWithAriaLabel; +/** + * This component looks just like an icon but behaves like a button. + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/inputs-iconbutton--docs + */ export const IconButton = React.forwardRef((props, ref) => { const { size = 'md', variant = 'secondary' } = props; let limitedIconSize: LimitedIconSize; diff --git a/packages/grafana-ui/src/components/InfoBox/InfoBox.tsx b/packages/grafana-ui/src/components/InfoBox/InfoBox.tsx index cb445321333..bf3e0e7f69c 100644 --- a/packages/grafana-ui/src/components/InfoBox/InfoBox.tsx +++ b/packages/grafana-ui/src/components/InfoBox/InfoBox.tsx @@ -23,7 +23,11 @@ export interface InfoBoxProps extends Omit, onDismiss?: () => void; } -/** @deprecated use Alert with severity info */ +/** + * @deprecated use Alert with severity info. + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/information-deprecated-infobox--docs + * */ export const InfoBox = React.memo( React.forwardRef( ({ title, className, children, branded, url, urlTitle, onDismiss, severity = 'info', ...otherProps }, ref) => { diff --git a/packages/grafana-ui/src/components/InfoTooltip/InfoTooltip.tsx b/packages/grafana-ui/src/components/InfoTooltip/InfoTooltip.tsx index 6f189837c43..9af5cadaa74 100644 --- a/packages/grafana-ui/src/components/InfoTooltip/InfoTooltip.tsx +++ b/packages/grafana-ui/src/components/InfoTooltip/InfoTooltip.tsx @@ -6,7 +6,11 @@ interface InfoTooltipProps extends Omit { children: PopoverContent; } -/** @deprecated Use instead */ +/** + * @deprecated Use instead. + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/overlays-deprecated-infotooltip--docs + */ export const InfoTooltip = ({ children, ...restProps }: InfoTooltipProps) => { return ; }; diff --git a/packages/grafana-ui/src/components/InlineToast/InlineToast.tsx b/packages/grafana-ui/src/components/InlineToast/InlineToast.tsx index 178b0032b1e..de79c028d9f 100644 --- a/packages/grafana-ui/src/components/InlineToast/InlineToast.tsx +++ b/packages/grafana-ui/src/components/InlineToast/InlineToast.tsx @@ -24,6 +24,11 @@ export interface InlineToastProps { alternativePlacement?: Side; } +/** + * Used to indicate temporal status near fields/components, such as a *Saved* indicator next to a field, or a little *Copied!* indicator above a button. + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/information-inlinetoast--docs + */ export function InlineToast({ referenceElement, children, suffixIcon, placement }: InlineToastProps) { const styles = useStyles2(getStyles); const theme = useTheme2(); diff --git a/packages/grafana-ui/src/components/Input/AutoSizeInput.tsx b/packages/grafana-ui/src/components/Input/AutoSizeInput.tsx index 2cf17612d99..2e533cf065f 100644 --- a/packages/grafana-ui/src/components/Input/AutoSizeInput.tsx +++ b/packages/grafana-ui/src/components/Input/AutoSizeInput.tsx @@ -20,6 +20,11 @@ export interface Props extends InputProps { defaultValue?: string | number | readonly string[]; } +/** + * You can use it or regular text input. When used, AutoSizeInput resizes itself to the current content. For an array of data or tree-structured data, consider using `Combobox` or `Cascader` respectively. + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/inputs-autosizeinput--docs + */ export const AutoSizeInput = React.forwardRef((props, ref) => { const { defaultValue = '', diff --git a/packages/grafana-ui/src/components/Input/Input.tsx b/packages/grafana-ui/src/components/Input/Input.tsx index 62aca888d03..4da6c9c22c7 100644 --- a/packages/grafana-ui/src/components/Input/Input.tsx +++ b/packages/grafana-ui/src/components/Input/Input.tsx @@ -34,6 +34,11 @@ interface StyleDeps { width?: number; } +/** + * Used for regular text input. For an array of data or tree-structured data, consider using `Combobox` or `Cascader` respectively. + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/inputs-input--docs + */ export const Input = forwardRef((props, ref) => { const { className, diff --git a/packages/grafana-ui/src/components/InteractiveTable/InteractiveTable.tsx b/packages/grafana-ui/src/components/InteractiveTable/InteractiveTable.tsx index 4c0faebccf5..a046f24b89c 100644 --- a/packages/grafana-ui/src/components/InteractiveTable/InteractiveTable.tsx +++ b/packages/grafana-ui/src/components/InteractiveTable/InteractiveTable.tsx @@ -172,7 +172,13 @@ interface WithoutExpandableRow extends BaseProps = WithExpandableRow | WithoutExpandableRow; -/** @alpha */ +/** + * The InteractiveTable is used to display and select data efficiently. It allows for the display and modification of detailed information. + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/layout-interactivetable--docs + * + * @alpha + */ export function InteractiveTable({ className, columns, diff --git a/packages/grafana-ui/src/components/Layout/Box/Box.tsx b/packages/grafana-ui/src/components/Layout/Box/Box.tsx index c012eb9d5f3..a7d10e4c746 100644 --- a/packages/grafana-ui/src/components/Layout/Box/Box.tsx +++ b/packages/grafana-ui/src/components/Layout/Box/Box.tsx @@ -70,6 +70,11 @@ export interface BoxProps extends FlexProps, SizeProps, Omit; } +/** + * The Box Component is the most basic layout component. It can be used to build more complex components and layouts with properties that use our design tokens instead of using CSS. + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/layout-box--docs + */ export const Box = forwardRef>((props, ref) => { const { children, diff --git a/packages/grafana-ui/src/components/Layout/Grid/Grid.tsx b/packages/grafana-ui/src/components/Layout/Grid/Grid.tsx index 1573f881a04..ffba1eb88de 100644 --- a/packages/grafana-ui/src/components/Layout/Grid/Grid.tsx +++ b/packages/grafana-ui/src/components/Layout/Grid/Grid.tsx @@ -34,6 +34,11 @@ interface PropsWithMinColumnWidth extends GridPropsBase { /** 'columns' and 'minColumnWidth' are mutually exclusive */ type GridProps = PropsWithColumns | PropsWithMinColumnWidth; +/** + * The Grid component is a layout component that allows you to create a grid of columns and rows to organize content and elements. It is a wrapper around the [CSS Grid](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout) specification. + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/layout-grid--docs + */ export const Grid = forwardRef((props, ref) => { const { alignItems, children, gap, rowGap, columnGap, columns, minColumnWidth, ...rest } = props; const styles = useStyles2(getGridStyles, gap, rowGap, columnGap, columns, minColumnWidth, alignItems); diff --git a/packages/grafana-ui/src/components/Layout/Layout.tsx b/packages/grafana-ui/src/components/Layout/Layout.tsx index a2f34d44d06..71fe0803b83 100644 --- a/packages/grafana-ui/src/components/Layout/Layout.tsx +++ b/packages/grafana-ui/src/components/Layout/Layout.tsx @@ -33,6 +33,8 @@ export interface ContainerProps { /** * @deprecated use Stack component instead + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/layout-deprecated-groups--docs */ export const Layout = ({ children, diff --git a/packages/grafana-ui/src/components/Layout/Space.mdx b/packages/grafana-ui/src/components/Layout/Space.mdx index 47bc0cb8e54..dd5182a8cea 100644 --- a/packages/grafana-ui/src/components/Layout/Space.mdx +++ b/packages/grafana-ui/src/components/Layout/Space.mdx @@ -5,7 +5,7 @@ import { Space } from './Space'; # Space -The `Space` component is a component used to add space between elements. Horizontal space is added using the `h` prop, while vertical space is added using the `v` prop. When adding horizontal space between inline or inline-block elements, the `layout` props should be set to `inline`, otherwise the `block` value of the prop can be used. +The `Space` component is a component used to add space between elements. Horizontal space is added using the `h` prop, while vertical space is added using the `v` prop. When adding horizontal space between inline or inline-block elements, the `layout` prop should be set to `inline`, otherwise the `block` value of the prop can be used. ### Usage diff --git a/packages/grafana-ui/src/components/Layout/Space.tsx b/packages/grafana-ui/src/components/Layout/Space.tsx index 2df48501ea4..8a81bcb1eed 100644 --- a/packages/grafana-ui/src/components/Layout/Space.tsx +++ b/packages/grafana-ui/src/components/Layout/Space.tsx @@ -19,6 +19,11 @@ export interface SpaceProps { layout?: 'block' | 'inline'; } +/** + * The Space component is a component used to add space between elements. Horizontal space is added using the `h` prop, while vertical space is added using the `v` prop. When adding horizontal space between inline or inline-block elements, the `layout` prop should be set to `"inline"`, otherwise the `"block"` value of the prop can be used. + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/layout-space--docs + */ export const Space = ({ v = 0, h = 0, layout }: SpaceProps) => { return ; }; diff --git a/packages/grafana-ui/src/components/Layout/Stack/Stack.tsx b/packages/grafana-ui/src/components/Layout/Stack/Stack.tsx index e54cc724f2d..b3a4984b110 100644 --- a/packages/grafana-ui/src/components/Layout/Stack/Stack.tsx +++ b/packages/grafana-ui/src/components/Layout/Stack/Stack.tsx @@ -21,7 +21,8 @@ interface StackProps extends FlexProps, SizeProps, Omit((props, ref) => { const { diff --git a/packages/grafana-ui/src/components/Link/TextLink.tsx b/packages/grafana-ui/src/components/Link/TextLink.tsx index d46a1ba3bc3..1f7ec1e16de 100644 --- a/packages/grafana-ui/src/components/Link/TextLink.tsx +++ b/packages/grafana-ui/src/components/Link/TextLink.tsx @@ -43,6 +43,11 @@ const svgSizes: { bodySmall: 'xs', }; +/** + * The TextLink component renders an anchor tag `` that takes users to another page, external or internal to Grafana. + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/foundations-textlink--docs + */ export const TextLink = forwardRef( ( { href, color = 'link', external = false, inline = true, variant = 'body', weight, icon, children, ...rest }, diff --git a/packages/grafana-ui/src/components/List/List.tsx b/packages/grafana-ui/src/components/List/List.tsx index a58bb3c5d4e..d4b86807a7b 100644 --- a/packages/grafana-ui/src/components/List/List.tsx +++ b/packages/grafana-ui/src/components/List/List.tsx @@ -2,7 +2,11 @@ import { PureComponent } from 'react'; import { ListProps, AbstractList } from './AbstractList'; -/** @deprecated Use ul/li/arr.map directly instead */ +/** + * @deprecated Use ul/li/arr.map directly instead + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/layout-deprecated-list--docs + */ // no point converting, this is deprecated // eslint-disable-next-line react-prefer-function-component/react-prefer-function-component export class List extends PureComponent> { diff --git a/packages/grafana-ui/src/components/LoadingBar/LoadingBar.tsx b/packages/grafana-ui/src/components/LoadingBar/LoadingBar.tsx index 213f39b4243..1ac038fe75f 100644 --- a/packages/grafana-ui/src/components/LoadingBar/LoadingBar.tsx +++ b/packages/grafana-ui/src/components/LoadingBar/LoadingBar.tsx @@ -18,6 +18,11 @@ const MAX_DURATION_MS = 4000; const DEFAULT_ANIMATION_DELAY = 300; const MAX_TRANSLATE_X = (100 / BAR_WIDTH) * 100; +/** + * The LoadingBar is used as a simple loading slider animation in the top of its container. + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/information-loadingbar--docs + */ export function LoadingBar({ width, delay = DEFAULT_ANIMATION_DELAY, ariaLabel = 'Loading bar' }: LoadingBarProps) { const durationMs = Math.min(Math.max(Math.round(width * MILLISECONDS_PER_PIXEL), MIN_DURATION_MS), MAX_DURATION_MS); const styles = useStyles2(getStyles, delay, durationMs); diff --git a/packages/grafana-ui/src/components/LoadingPlaceholder/LoadingPlaceholder.tsx b/packages/grafana-ui/src/components/LoadingPlaceholder/LoadingPlaceholder.tsx index fb3ec626437..9f50ed9d072 100644 --- a/packages/grafana-ui/src/components/LoadingPlaceholder/LoadingPlaceholder.tsx +++ b/packages/grafana-ui/src/components/LoadingPlaceholder/LoadingPlaceholder.tsx @@ -15,6 +15,9 @@ export interface LoadingPlaceholderProps extends HTMLAttributes } /** + * Loading indicator with a text. Used to alert a user to wait for an activity to complete. + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/information-loadingplaceholder--docs * @public */ export const LoadingPlaceholder = ({ text, className, ...rest }: LoadingPlaceholderProps) => { diff --git a/packages/grafana-ui/src/components/Menu/Menu.tsx b/packages/grafana-ui/src/components/Menu/Menu.tsx index f77a26bb0e7..a1439aa5356 100644 --- a/packages/grafana-ui/src/components/Menu/Menu.tsx +++ b/packages/grafana-ui/src/components/Menu/Menu.tsx @@ -22,6 +22,9 @@ export interface MenuProps extends React.HTMLAttributes { onKeyDown?: React.KeyboardEventHandler; } +/** + * https://developers.grafana.com/ui/latest/index.html?path=/docs/overlays-menu--docs + */ const MenuComp = React.forwardRef( ({ header, children, ariaLabel, onOpen, onClose, onKeyDown, ...otherProps }, forwardedRef) => { const styles = useStyles2(getStyles); diff --git a/packages/grafana-ui/src/components/Modal/Modal.tsx b/packages/grafana-ui/src/components/Modal/Modal.tsx index 9937fe93f9f..fc00bc9e562 100644 --- a/packages/grafana-ui/src/components/Modal/Modal.tsx +++ b/packages/grafana-ui/src/components/Modal/Modal.tsx @@ -48,6 +48,9 @@ interface WithCustomTitleProps extends BaseProps { export type Props = WithStringTitleProps | WithCustomTitleProps; +/** + * https://developers.grafana.com/ui/latest/index.html?path=/docs/overlays-modal--docs + */ export function Modal(props: PropsWithChildren) { const { title, diff --git a/packages/grafana-ui/src/components/Monaco/CodeEditor.tsx b/packages/grafana-ui/src/components/Monaco/CodeEditor.tsx index 276520b873d..a0e17c92b1d 100644 --- a/packages/grafana-ui/src/components/Monaco/CodeEditor.tsx +++ b/packages/grafana-ui/src/components/Monaco/CodeEditor.tsx @@ -196,6 +196,11 @@ class UnthemedCodeEditor extends PureComponent { } } +/** + * Monaco Code editor. + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/inputs-codeeditor--docs + */ export const CodeEditor = withTheme2(UnthemedCodeEditor); const getStyles = (theme: GrafanaTheme2) => { diff --git a/packages/grafana-ui/src/components/PageLayout/PageToolbar.tsx b/packages/grafana-ui/src/components/PageLayout/PageToolbar.tsx index 296d79212f6..93e59296166 100644 --- a/packages/grafana-ui/src/components/PageLayout/PageToolbar.tsx +++ b/packages/grafana-ui/src/components/PageLayout/PageToolbar.tsx @@ -34,7 +34,11 @@ export interface Props { forceShowLeftItems?: boolean; } -/** @deprecated Use Page instead */ +/** + * @deprecated Use Page instead + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/navigation-deprecated-pagetoolbar--docs + */ export const PageToolbar = memo( ({ title, diff --git a/packages/grafana-ui/src/components/Pagination/Pagination.tsx b/packages/grafana-ui/src/components/Pagination/Pagination.tsx index 70c447e059c..c0c25d4186b 100644 --- a/packages/grafana-ui/src/components/Pagination/Pagination.tsx +++ b/packages/grafana-ui/src/components/Pagination/Pagination.tsx @@ -21,6 +21,11 @@ export interface Props { className?: string; } +/** + * Component used for rendering a page selector below paginated content. + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/navigation-pagination--docs + */ export const Pagination = ({ currentPage, numberOfPages, diff --git a/packages/grafana-ui/src/components/PanelChrome/PanelChrome.tsx b/packages/grafana-ui/src/components/PanelChrome/PanelChrome.tsx index 16d67ea51db..05d3ae406e5 100644 --- a/packages/grafana-ui/src/components/PanelChrome/PanelChrome.tsx +++ b/packages/grafana-ui/src/components/PanelChrome/PanelChrome.tsx @@ -116,6 +116,10 @@ interface HoverHeader { export type PanelPadding = 'none' | 'md'; /** + * Component used for rendering content wrapped in the same style as grafana panels. + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/plugins-panelchrome--docs + * * @internal */ export function PanelChrome({ diff --git a/packages/grafana-ui/src/components/PanelContainer/PanelContainer.tsx b/packages/grafana-ui/src/components/PanelContainer/PanelContainer.tsx index 5279c363675..fd68335b2a7 100644 --- a/packages/grafana-ui/src/components/PanelContainer/PanelContainer.tsx +++ b/packages/grafana-ui/src/components/PanelContainer/PanelContainer.tsx @@ -8,7 +8,11 @@ import { useStyles2 } from '../../themes/ThemeContext'; type Props = DetailedHTMLProps, HTMLDivElement>; // TODO: Reimplement this with Box -/** @deprecated Use Box instead */ +/** + * @deprecated Use Box instead + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/layout-deprecated-panelcontainer--docs + */ export const PanelContainer = ({ children, className, ...props }: Props) => { const styles = useStyles2(getStyles); return ( diff --git a/packages/grafana-ui/src/components/PluginSignatureBadge/PluginSignatureBadge.tsx b/packages/grafana-ui/src/components/PluginSignatureBadge/PluginSignatureBadge.tsx index 698e61c466b..9935f2323d1 100644 --- a/packages/grafana-ui/src/components/PluginSignatureBadge/PluginSignatureBadge.tsx +++ b/packages/grafana-ui/src/components/PluginSignatureBadge/PluginSignatureBadge.tsx @@ -22,6 +22,8 @@ export interface PluginSignatureBadgeProps extends HTMLAttributes { plugins: Array>; runOnChangeDebounced: Function; @@ -238,6 +232,16 @@ export class UnThemedQueryField extends PureComponent { diff --git a/packages/grafana-ui/src/components/RadialGauge/RadialGauge.tsx b/packages/grafana-ui/src/components/RadialGauge/RadialGauge.tsx index 128c56b1cb6..3dcc25e8875 100644 --- a/packages/grafana-ui/src/components/RadialGauge/RadialGauge.tsx +++ b/packages/grafana-ui/src/components/RadialGauge/RadialGauge.tsx @@ -72,6 +72,9 @@ export type RadialGradientMode = 'none' | 'auto'; export type RadialTextMode = 'auto' | 'value_and_name' | 'value' | 'name' | 'none'; export type RadialShape = 'circle' | 'gauge'; +/** + * https://developers.grafana.com/ui/latest/index.html?path=/docs/plugins-radialgauge--docs + */ export function RadialGauge(props: RadialGaugeProps) { const { width = 256, diff --git a/packages/grafana-ui/src/components/RefreshPicker/RefreshPicker.tsx b/packages/grafana-ui/src/components/RefreshPicker/RefreshPicker.tsx index d99958e88d1..363222fcad6 100644 --- a/packages/grafana-ui/src/components/RefreshPicker/RefreshPicker.tsx +++ b/packages/grafana-ui/src/components/RefreshPicker/RefreshPicker.tsx @@ -29,6 +29,11 @@ export interface Props { isOnCanvas?: boolean; } +/** + * This component is used on dashboards to refresh visualizations. + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/pickers-refreshpicker--docs + */ export class RefreshPicker extends PureComponent { static offOption = { label: 'Off', diff --git a/packages/grafana-ui/src/components/RenderUserContentAsHTML/RenderUserContentAsHTML.tsx b/packages/grafana-ui/src/components/RenderUserContentAsHTML/RenderUserContentAsHTML.tsx index d5ec22c2440..3fb806bc162 100644 --- a/packages/grafana-ui/src/components/RenderUserContentAsHTML/RenderUserContentAsHTML.tsx +++ b/packages/grafana-ui/src/components/RenderUserContentAsHTML/RenderUserContentAsHTML.tsx @@ -9,6 +9,11 @@ export interface RenderUserContentAsHTMLProps content: string; } +/** + * Abstraction layer component for sanitizing and rendering an html content. + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/utilities-renderusercontentashtml--docs + */ export function RenderUserContentAsHTML({ component, content, diff --git a/packages/grafana-ui/src/components/ScrollContainer/ScrollContainer.tsx b/packages/grafana-ui/src/components/ScrollContainer/ScrollContainer.tsx index af7907b9562..60da6f97a8d 100644 --- a/packages/grafana-ui/src/components/ScrollContainer/ScrollContainer.tsx +++ b/packages/grafana-ui/src/components/ScrollContainer/ScrollContainer.tsx @@ -17,6 +17,11 @@ interface Props extends Omit>( ( { diff --git a/packages/grafana-ui/src/components/SecretFormField/SecretFormField.tsx b/packages/grafana-ui/src/components/SecretFormField/SecretFormField.tsx index 4bfaac7c603..238d3adf3ea 100644 --- a/packages/grafana-ui/src/components/SecretFormField/SecretFormField.tsx +++ b/packages/grafana-ui/src/components/SecretFormField/SecretFormField.tsx @@ -32,6 +32,8 @@ export interface Props extends Omit, 'onRe * to the user (like datasource passwords). * * @deprecated Please use the {@link SecretInput} component with a {@link Field} instead, {@link https://developers.grafana.com/ui/latest/index.html?path=/story/forms-secretinput--basic as seen in Storybook} + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/forms-deprecated-secretformfield--docs */ export const SecretFormField = ({ label = 'Password', diff --git a/packages/grafana-ui/src/components/SecretInput/SecretInput.tsx b/packages/grafana-ui/src/components/SecretInput/SecretInput.tsx index b7cc7b41a72..23286c5a393 100644 --- a/packages/grafana-ui/src/components/SecretInput/SecretInput.tsx +++ b/packages/grafana-ui/src/components/SecretInput/SecretInput.tsx @@ -14,6 +14,11 @@ export type Props = React.ComponentProps & { export const CONFIGURED_TEXT = 'configured'; export const RESET_BUTTON_TEXT = 'Reset'; +/** + * Used for secret/password input. + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/inputs-secretinput--docs + */ export const SecretInput = ({ isConfigured, onReset, ...props }: Props) => ( {!isConfigured && } diff --git a/packages/grafana-ui/src/components/SecretTextArea/SecretTextArea.tsx b/packages/grafana-ui/src/components/SecretTextArea/SecretTextArea.tsx index b7196732660..a10ad157120 100644 --- a/packages/grafana-ui/src/components/SecretTextArea/SecretTextArea.tsx +++ b/packages/grafana-ui/src/components/SecretTextArea/SecretTextArea.tsx @@ -32,6 +32,8 @@ const getStyles = (theme: GrafanaTheme2) => { /** * Text area that does not disclose an already configured value but lets the user reset the current value and enter a new one. * Typically useful for asymmetric cryptography keys. + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/inputs-secrettextarea--docs */ export const SecretTextArea = ({ isConfigured, onReset, ...props }: Props) => { const styles = useStyles2(getStyles); diff --git a/packages/grafana-ui/src/components/Segment/Segment.tsx b/packages/grafana-ui/src/components/Segment/Segment.tsx index 3abec60b774..b39399965c4 100644 --- a/packages/grafana-ui/src/components/Segment/Segment.tsx +++ b/packages/grafana-ui/src/components/Segment/Segment.tsx @@ -20,6 +20,9 @@ export interface SegmentSyncProps extends SegmentProps, Omit({ options, value, diff --git a/packages/grafana-ui/src/components/Segment/SegmentAsync.tsx b/packages/grafana-ui/src/components/Segment/SegmentAsync.tsx index 804b1bbe92f..8a3caf6e73e 100644 --- a/packages/grafana-ui/src/components/Segment/SegmentAsync.tsx +++ b/packages/grafana-ui/src/components/Segment/SegmentAsync.tsx @@ -29,6 +29,9 @@ export interface SegmentAsyncProps extends SegmentProps, Omit({ value, onChange, diff --git a/packages/grafana-ui/src/components/Segment/SegmentInput.tsx b/packages/grafana-ui/src/components/Segment/SegmentInput.tsx index 22e9411297e..bcb46c93f04 100644 --- a/packages/grafana-ui/src/components/Segment/SegmentInput.tsx +++ b/packages/grafana-ui/src/components/Segment/SegmentInput.tsx @@ -20,6 +20,9 @@ export interface SegmentInputProps const FONT_SIZE = 14; +/** + * https://developers.grafana.com/ui/latest/index.html?path=/docs/inputs-segmentinput--docs + */ export function SegmentInput({ value: initialValue, onChange, diff --git a/packages/grafana-ui/src/components/Select/Select.tsx b/packages/grafana-ui/src/components/Select/Select.tsx index f543fa5dab5..7aaa338ae1c 100644 --- a/packages/grafana-ui/src/components/Select/Select.tsx +++ b/packages/grafana-ui/src/components/Select/Select.tsx @@ -10,11 +10,20 @@ import { VirtualizedSelectAsyncProps, } from './types'; -/** @deprecated Use Combobox component instead */ +/** + * @deprecated Use Combobox component instead + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/inputs-deprecated-select--docs + */ export function Select(props: SelectCommonProps & Rest) { return ; } +/** + * @deprecated Use Combobox component instead + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/inputs-deprecated-select--docs + */ export function MultiSelect(props: MultiSelectCommonProps & Rest) { // @ts-ignore return ; @@ -25,17 +34,29 @@ export interface AsyncSelectProps extends Omit, 'options value?: T | SelectableValue | null; } -/** @deprecated Use Combobox component instead */ +/** + * @deprecated Use Combobox component instead + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/inputs-deprecated-select--docs + */ export function AsyncSelect(props: AsyncSelectProps & Rest) { return ; } -/** @deprecated Use Combobox component instead - it's virtualised by default! */ +/** + * @deprecated Use Combobox component instead - it's virtualised by default! + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/inputs-deprecated-select--docs + */ export function VirtualizedSelect(props: VirtualizedSelectProps & Rest) { return ; } -/** @deprecated Use Combobox component instead - it's virtualised by default! */ +/** + * @deprecated Use Combobox component instead - it's virtualised by default! + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/inputs-deprecated-select--docs + */ export function AsyncVirtualizedSelect(props: VirtualizedSelectAsyncProps & Rest) { return ; } @@ -45,6 +66,11 @@ interface AsyncMultiSelectProps extends Omit, 'opti value?: Array>; } +/** + * @deprecated Use Combobox component instead + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/inputs-deprecated-select--docs + */ export function AsyncMultiSelect(props: AsyncMultiSelectProps & Rest) { // @ts-ignore return ; diff --git a/packages/grafana-ui/src/components/Slider/RangeSlider.tsx b/packages/grafana-ui/src/components/Slider/RangeSlider.tsx index 794ea5b795f..6b791fd7211 100644 --- a/packages/grafana-ui/src/components/Slider/RangeSlider.tsx +++ b/packages/grafana-ui/src/components/Slider/RangeSlider.tsx @@ -15,6 +15,8 @@ import { RangeSliderProps } from './types'; * @public * * RichHistoryQueriesTab uses this Range Component + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/inputs-rangeslider--docs */ export const RangeSlider = ({ min, diff --git a/packages/grafana-ui/src/components/Slider/Slider.tsx b/packages/grafana-ui/src/components/Slider/Slider.tsx index e8c377070bf..b41f41d0af7 100644 --- a/packages/grafana-ui/src/components/Slider/Slider.tsx +++ b/packages/grafana-ui/src/components/Slider/Slider.tsx @@ -13,6 +13,8 @@ import { SliderProps } from './types'; /** * @public + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/inputs-slider--docs */ export const Slider = ({ min, diff --git a/packages/grafana-ui/src/components/Spinner/Spinner.tsx b/packages/grafana-ui/src/components/Spinner/Spinner.tsx index 78905e29eec..af1c3b60aca 100644 --- a/packages/grafana-ui/src/components/Spinner/Spinner.tsx +++ b/packages/grafana-ui/src/components/Spinner/Spinner.tsx @@ -29,6 +29,10 @@ interface PropsWithDeprecatedSize extends Omit { /** * @public + * + * Spinner is `fa-spinner` icon animated. It is used to alert a user to wait for an activity to complete. + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/information-spinner--docs */ export const Spinner = ({ className, diff --git a/packages/grafana-ui/src/components/Splitter/useSplitter.ts b/packages/grafana-ui/src/components/Splitter/useSplitter.ts index b5343ae80aa..18fb95a532e 100644 --- a/packages/grafana-ui/src/components/Splitter/useSplitter.ts +++ b/packages/grafana-ui/src/components/Splitter/useSplitter.ts @@ -49,6 +49,11 @@ const propsForDirection = { }, } as const; +/** + * The splitter creates two resizable panes, either horizontally or vertically. + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/utilities-usesplitter--docs + */ export function useSplitter(options: UseSplitterOptions) { const { direction, diff --git a/packages/grafana-ui/src/components/Switch/Switch.tsx b/packages/grafana-ui/src/components/Switch/Switch.tsx index 0a8654b1425..d2b63a2d76a 100644 --- a/packages/grafana-ui/src/components/Switch/Switch.tsx +++ b/packages/grafana-ui/src/components/Switch/Switch.tsx @@ -14,6 +14,11 @@ export interface Props extends Omit, 'value'> { invalid?: boolean; } +/** + * Switch is a representation of an on-off state – like a light switch. So you can use Switch to toggle binary states. + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/inputs-switch--docs + */ export const Switch = forwardRef( ({ value, checked, onChange, id, label, disabled, invalid = false, ...inputProps }, ref) => { if (checked) { diff --git a/packages/grafana-ui/src/components/Table/TableRT/Table.tsx b/packages/grafana-ui/src/components/Table/TableRT/Table.tsx index 4df81505431..ea909d4642f 100644 --- a/packages/grafana-ui/src/components/Table/TableRT/Table.tsx +++ b/packages/grafana-ui/src/components/Table/TableRT/Table.tsx @@ -40,6 +40,11 @@ const COLUMN_MIN_WIDTH = 150; const FOOTER_ROW_HEIGHT = 36; const NO_DATA_TEXT = 'No data'; +/** + * Used for displaying tabular data + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/plugins-table--docs + */ export const Table = memo((props: Props) => { const { ariaLabel, diff --git a/packages/grafana-ui/src/components/TableInputCSV/TableInputCSV.tsx b/packages/grafana-ui/src/components/TableInputCSV/TableInputCSV.tsx index 57c3b9943e4..dfd967e04e3 100644 --- a/packages/grafana-ui/src/components/TableInputCSV/TableInputCSV.tsx +++ b/packages/grafana-ui/src/components/TableInputCSV/TableInputCSV.tsx @@ -102,7 +102,11 @@ export class UnThemedTableInputCSV extends PureComponent { } } -/** @deprecated */ +/** + * @deprecated + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/inputs-deprecated-tableinputcsv--docs + */ export const TableInputCSV = withTheme2(UnThemedTableInputCSV); TableInputCSV.displayName = 'TableInputCSV'; diff --git a/packages/grafana-ui/src/components/Tabs/Tab.tsx b/packages/grafana-ui/src/components/Tabs/Tab.tsx index 6eb695df437..ae58e136aeb 100644 --- a/packages/grafana-ui/src/components/Tabs/Tab.tsx +++ b/packages/grafana-ui/src/components/Tabs/Tab.tsx @@ -31,6 +31,9 @@ export interface TabProps extends HTMLProps { disabled?: boolean; } +/** + * https://developers.grafana.com/ui/latest/index.html?path=/docs/navigation-tabs--docs + */ export const Tab = React.forwardRef( ( { diff --git a/packages/grafana-ui/src/components/Tabs/TabContent.tsx b/packages/grafana-ui/src/components/Tabs/TabContent.tsx index a22f6102dba..9bceb46f3c8 100644 --- a/packages/grafana-ui/src/components/Tabs/TabContent.tsx +++ b/packages/grafana-ui/src/components/Tabs/TabContent.tsx @@ -9,6 +9,9 @@ interface Props extends HTMLAttributes { children: ReactNode; } +/** + * https://developers.grafana.com/ui/latest/index.html?path=/docs/navigation-tabs--docs + */ export const TabContent = ({ children, className, ...restProps }: Props) => { const styles = useStyles2(getTabContentStyle); diff --git a/packages/grafana-ui/src/components/Tabs/TabsBar.tsx b/packages/grafana-ui/src/components/Tabs/TabsBar.tsx index 8ba4405dcfa..c33734f7ea9 100644 --- a/packages/grafana-ui/src/components/Tabs/TabsBar.tsx +++ b/packages/grafana-ui/src/components/Tabs/TabsBar.tsx @@ -13,6 +13,11 @@ export interface Props { hideBorder?: boolean; } +/** + * A composition component for rendering a TabBar with Tabs for navigation. + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/navigation-tabs--docs + */ export const TabsBar = forwardRef(({ children, className, hideBorder = false }, ref) => { const styles = useStyles2(getStyles); diff --git a/packages/grafana-ui/src/components/Tags/Tag.tsx b/packages/grafana-ui/src/components/Tags/Tag.tsx index e1dde995bad..1d529dfcc24 100644 --- a/packages/grafana-ui/src/components/Tags/Tag.tsx +++ b/packages/grafana-ui/src/components/Tags/Tag.tsx @@ -57,6 +57,11 @@ const TagSkeleton: SkeletonComponent = ({ rootProps }) => { return ; }; +/** + * Used for displaying metadata, for example to add more details to search results. Background and border colors are generated from the tag name. + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/information-tag--docs + */ export const Tag = attachSkeleton(TagComponent, TagSkeleton); const getSkeletonStyles = () => ({ diff --git a/packages/grafana-ui/src/components/Tags/TagList.tsx b/packages/grafana-ui/src/components/Tags/TagList.tsx index d128c64610b..729fc920f28 100644 --- a/packages/grafana-ui/src/components/Tags/TagList.tsx +++ b/packages/grafana-ui/src/components/Tags/TagList.tsx @@ -73,6 +73,11 @@ const TagListSkeleton: SkeletonComponent = ({ rootProps }) => { ); }; +/** + * List of tags with predefined margins and positioning. + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/information-taglist--docs + */ export const TagList = attachSkeleton(TagListComponent, TagListSkeleton); const getSkeletonStyles = (theme: GrafanaTheme2) => ({ diff --git a/packages/grafana-ui/src/components/TagsInput/TagsInput.tsx b/packages/grafana-ui/src/components/TagsInput/TagsInput.tsx index 7bcdbb6852a..1b6e78213da 100644 --- a/packages/grafana-ui/src/components/TagsInput/TagsInput.tsx +++ b/packages/grafana-ui/src/components/TagsInput/TagsInput.tsx @@ -29,6 +29,11 @@ export interface Props { autoColors?: boolean; } +/** + * A set of an input field and a button next to it that allows the user to add new tags. The added tags are previewed next to the input and can be removed by clicking the "X" icon. You can customize the width of the input. + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/inputs-tagsinput--docs + */ export const TagsInput = forwardRef( ( { diff --git a/packages/grafana-ui/src/components/Text/Text.tsx b/packages/grafana-ui/src/components/Text/Text.tsx index 55b88ee4011..56cb2b529bb 100644 --- a/packages/grafana-ui/src/components/Text/Text.tsx +++ b/packages/grafana-ui/src/components/Text/Text.tsx @@ -29,6 +29,11 @@ export interface TextProps extends Omit, 'clas children: NonNullable; } +/** + * The Text component can be used to apply typography styles in a simple way, without the need of extra css. + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/foundations-text--docs + */ export const Text = React.forwardRef( ( { element = 'span', variant, weight, color, truncate, italic, textAlignment, children, tabular, ...restProps }, diff --git a/packages/grafana-ui/src/components/TextArea/TextArea.tsx b/packages/grafana-ui/src/components/TextArea/TextArea.tsx index 1c84344348f..6c80d370dc6 100644 --- a/packages/grafana-ui/src/components/TextArea/TextArea.tsx +++ b/packages/grafana-ui/src/components/TextArea/TextArea.tsx @@ -11,6 +11,11 @@ export interface Props extends Omit, 'size'> { invalid?: boolean; } +/** + * Use for multi line inputs like descriptions. + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/inputs-textarea--docs + */ export const TextArea = forwardRef(({ invalid, className, ...props }, ref) => { const styles = useStyles2(getTextAreaStyle, invalid); diff --git a/packages/grafana-ui/src/components/Toggletip/Toggletip.tsx b/packages/grafana-ui/src/components/Toggletip/Toggletip.tsx index 991490e36aa..84f13eaf112 100644 --- a/packages/grafana-ui/src/components/Toggletip/Toggletip.tsx +++ b/packages/grafana-ui/src/components/Toggletip/Toggletip.tsx @@ -48,6 +48,11 @@ export interface ToggletipProps { onOpen?: () => void; } +/** + * Toggletips, similar to Tooltips, provide contextual support for users when needed. They are hidden by default, a UI trigger or text link are clicked to set them to their visible state. Toggletips, unlike tooltips, are persistent until a user takes action to dismiss them by clicking on the required “X” (close) trigger. Toggletips are capable of containing varying types of complex content including interactive components, buttons, and dropdowns. + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/overlays-toggletip--docs + */ export const Toggletip = memo( ({ children, diff --git a/packages/grafana-ui/src/components/ToolbarButton/ToolbarButton.tsx b/packages/grafana-ui/src/components/ToolbarButton/ToolbarButton.tsx index 376b1b3fc38..40b468d73fb 100644 --- a/packages/grafana-ui/src/components/ToolbarButton/ToolbarButton.tsx +++ b/packages/grafana-ui/src/components/ToolbarButton/ToolbarButton.tsx @@ -41,6 +41,11 @@ export type ToolbarButtonProps = CommonProps & ButtonHTMLAttributes( ( { diff --git a/packages/grafana-ui/src/components/ToolbarButton/ToolbarButtonRow.tsx b/packages/grafana-ui/src/components/ToolbarButton/ToolbarButtonRow.tsx index 000713c57c4..54608a3acbd 100644 --- a/packages/grafana-ui/src/components/ToolbarButton/ToolbarButtonRow.tsx +++ b/packages/grafana-ui/src/components/ToolbarButton/ToolbarButtonRow.tsx @@ -17,6 +17,11 @@ export interface Props extends HTMLAttributes { alignment?: 'left' | 'right'; } +/** + * A container for multiple ToolbarButtons. Provides automatic overflow behaviour when the buttons no longer fit in the container. + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/navigation-toolbarbuttonrow--docs + */ export const ToolbarButtonRow = forwardRef( ({ alignment = 'left', className, children, ...rest }, ref) => { // null/undefined are valid react children so we need to filter them out to prevent unnecessary padding diff --git a/packages/grafana-ui/src/components/Tooltip/Tooltip.tsx b/packages/grafana-ui/src/components/Tooltip/Tooltip.tsx index b44d48ddf38..665e2d7bf6c 100644 --- a/packages/grafana-ui/src/components/Tooltip/Tooltip.tsx +++ b/packages/grafana-ui/src/components/Tooltip/Tooltip.tsx @@ -34,6 +34,9 @@ export interface TooltipProps { interactive?: boolean; } +/** + * https://developers.grafana.com/ui/latest/index.html?path=/docs/overlays-tooltip--docs + */ export const Tooltip = forwardRef( ({ children, theme, interactive, show, placement, content }, forwardedRef) => { const arrowRef = useRef(null); diff --git a/packages/grafana-ui/src/components/UnitPicker/UnitPicker.tsx b/packages/grafana-ui/src/components/UnitPicker/UnitPicker.tsx index dff45cb2a18..ac53b424bdb 100644 --- a/packages/grafana-ui/src/components/UnitPicker/UnitPicker.tsx +++ b/packages/grafana-ui/src/components/UnitPicker/UnitPicker.tsx @@ -16,6 +16,9 @@ function formatCreateLabel(input: string) { return `Custom unit: ${input}`; } +/** + * https://developers.grafana.com/ui/latest/index.html?path=/docs/pickers-unitpicker--docs + */ export class UnitPicker extends PureComponent { onChange = (value: SelectableValue) => { this.props.onChange(value.value); diff --git a/packages/grafana-ui/src/components/UsersIndicator/UserIcon.tsx b/packages/grafana-ui/src/components/UsersIndicator/UserIcon.tsx index 3d8dd97f962..ca5ff1f665c 100644 --- a/packages/grafana-ui/src/components/UsersIndicator/UserIcon.tsx +++ b/packages/grafana-ui/src/components/UsersIndicator/UserIcon.tsx @@ -51,6 +51,11 @@ const getUserInitials = (name?: string) => { return `${first?.[0] ?? ''}${last?.[0] ?? ''}`.toUpperCase(); }; +/** + * UserIcon renders a user icon and displays the user's name or initials along with the user's active status or last viewed date. + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/iconography-usericon--docs + */ export const UserIcon = ({ userView, className, diff --git a/packages/grafana-ui/src/components/UsersIndicator/UsersIndicator.tsx b/packages/grafana-ui/src/components/UsersIndicator/UsersIndicator.tsx index 44518ce25c7..66c9a0bddca 100644 --- a/packages/grafana-ui/src/components/UsersIndicator/UsersIndicator.tsx +++ b/packages/grafana-ui/src/components/UsersIndicator/UsersIndicator.tsx @@ -16,6 +16,12 @@ export interface UsersIndicatorProps { /** onClick handler for the user number indicator */ onClick?: () => void; } + +/** + * A component that displays a set of user icons indicating which users are currently active. If there are too many users to display all the icons, it will collapse the icons into a single icon with a number indicating the number of additional users. + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/iconography-usersindicator--docs + */ export const UsersIndicator = ({ users, onClick, limit = 4 }: UsersIndicatorProps) => { const styles = useStyles2(getStyles); if (!users.length) { diff --git a/packages/grafana-ui/src/components/ValuePicker/ValuePicker.tsx b/packages/grafana-ui/src/components/ValuePicker/ValuePicker.tsx index 128a038ea8d..8647140c615 100644 --- a/packages/grafana-ui/src/components/ValuePicker/ValuePicker.tsx +++ b/packages/grafana-ui/src/components/ValuePicker/ValuePicker.tsx @@ -37,6 +37,11 @@ export interface ValuePickerProps { buttonCss?: string; } +/** + * A component that looks like a button but transforms into a select when clicked. + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/pickers-valuepicker--docs + */ export function ValuePicker({ 'aria-label': ariaLabel, label, diff --git a/packages/grafana-ui/src/components/VizLayout/VizLayout.tsx b/packages/grafana-ui/src/components/VizLayout/VizLayout.tsx index 6194b3ac6b2..11b5ed6dc00 100644 --- a/packages/grafana-ui/src/components/VizLayout/VizLayout.tsx +++ b/packages/grafana-ui/src/components/VizLayout/VizLayout.tsx @@ -29,6 +29,8 @@ export interface VizLayoutComponentType extends FC { /** * @beta + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/plugins-vizlayout--docs */ export const VizLayout: VizLayoutComponentType = ({ width, height, legend, children }) => { const theme = useTheme2(); diff --git a/packages/grafana-ui/src/components/VizLegend/VizLegend.tsx b/packages/grafana-ui/src/components/VizLegend/VizLegend.tsx index f07c3abff22..0a8dc48d3a9 100644 --- a/packages/grafana-ui/src/components/VizLegend/VizLegend.tsx +++ b/packages/grafana-ui/src/components/VizLegend/VizLegend.tsx @@ -13,6 +13,8 @@ import { mapMouseEventToMode } from './utils'; /** * @public + * + * https://developers.grafana.com/ui/latest/index.html?path=/docs/plugins-vizlegend--docs */ export function VizLegend({ items, From ec0c14ac1aa2e2a1f422417905b50f6882be4aab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Farkas?= Date: Wed, 29 Oct 2025 14:19:24 +0100 Subject: [PATCH 085/378] log: added debug-log (#113156) * log: added debug-log * fixed unit test * fixed another unit test --- pkg/api/ds_query.go | 2 ++ pkg/api/ds_query_test.go | 3 +++ 2 files changed, 5 insertions(+) diff --git a/pkg/api/ds_query.go b/pkg/api/ds_query.go index dd33ba97817..6d27fbfc404 100644 --- a/pkg/api/ds_query.go +++ b/pkg/api/ds_query.go @@ -76,6 +76,8 @@ func (hs *HTTPServer) QueryMetricsV2(c *contextmodel.ReqContext) response.Respon var resp *backend.QueryDataResponse var err error + + hs.log.Debug("QueryMetricsV2: request received", "time_in_query", handleTimeInQuery) if handleTimeInQuery { resp, err = hs.queryDataService.QueryDataNew(c.Req.Context(), c.SignedInUser, c.SkipDSCache, reqDTO) } else { diff --git a/pkg/api/ds_query_test.go b/pkg/api/ds_query_test.go index e330f8f4438..11e12800056 100644 --- a/pkg/api/ds_query_test.go +++ b/pkg/api/ds_query_test.go @@ -16,6 +16,7 @@ import ( "github.com/grafana/grafana/pkg/apimachinery/errutil" "github.com/grafana/grafana/pkg/infra/db/dbtest" "github.com/grafana/grafana/pkg/infra/localcache" + "github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/plugins" "github.com/grafana/grafana/pkg/plugins/backendplugin" pluginClient "github.com/grafana/grafana/pkg/plugins/manager/client" @@ -86,6 +87,7 @@ func TestAPIEndpoint_Metrics_QueryMetricsV2(t *testing.T) { server := SetupAPITestServer(t, func(hs *HTTPServer) { hs.queryDataService = qds hs.QuotaService = quotatest.New(false, nil) + hs.log = log.New("test-logger") }) t.Run("Status code is 400 when data source response has an error", func(t *testing.T) { @@ -252,6 +254,7 @@ func TestDataSourceQueryError(t *testing.T) { err := r.Add(context.Background(), p) require.NoError(t, err) ds := &fakeDatasources.FakeDataSourceService{} + hs.log = log.New("test-logger") hs.queryDataService = query.ProvideService( cfg, &fakeDatasources.FakeCacheService{}, From f533a5a6e541539851ced957bd3dd04de7d8af7d Mon Sep 17 00:00:00 2001 From: Tom Ratcliffe Date: Wed, 29 Oct 2025 13:20:19 +0000 Subject: [PATCH 086/378] API clients: Update API clients to include all endpoints & add hooks (#113061) --- packages/grafana-api-clients/package.json | 4 + .../rtkq/advisor/v0alpha1/endpoints.gen.ts | 494 +- .../correlations/v0alpha1/endpoints.gen.ts | 10 + .../rtkq/dashboard/v0alpha1/endpoints.gen.ts | 976 ++- .../rtkq/folder/v1beta1/endpoints.gen.ts | 14 + .../rtkq/iam/v0alpha1/endpoints.gen.ts | 1711 ++++- .../src/clients/rtkq/legacy/baseAPI.ts | 9 + .../src/clients/rtkq/legacy/endpoints.gen.ts | 6820 +++++++++++++++++ .../src/clients/rtkq/legacy/index.ts | 5 + .../rtkq/playlist/v0alpha1/endpoints.gen.ts | 234 +- .../provisioning/v0alpha1/endpoints.gen.ts | 138 +- .../rtkq/shorturl/v1alpha1/endpoints.gen.ts | 14 + .../src/scripts/generate-rtk-apis.ts | 43 +- public/app/api/clients/legacy/index.ts | 6 + public/app/core/reducers/root.ts | 2 + public/app/store/configureStore.ts | 2 + 16 files changed, 10451 insertions(+), 31 deletions(-) create mode 100644 packages/grafana-api-clients/src/clients/rtkq/legacy/baseAPI.ts create mode 100644 packages/grafana-api-clients/src/clients/rtkq/legacy/endpoints.gen.ts create mode 100644 packages/grafana-api-clients/src/clients/rtkq/legacy/index.ts create mode 100644 public/app/api/clients/legacy/index.ts diff --git a/packages/grafana-api-clients/package.json b/packages/grafana-api-clients/package.json index 3aa5bd4dc6c..9741c97303b 100644 --- a/packages/grafana-api-clients/package.json +++ b/packages/grafana-api-clients/package.json @@ -48,6 +48,10 @@ "import": "./src/clients/rtkq/iam/v0alpha1/index.ts", "require": "./src/clients/rtkq/iam/v0alpha1/index.ts" }, + "./rtkq/legacy": { + "import": "./src/clients/rtkq/legacy/index.ts", + "require": "./src/clients/rtkq/legacy/index.ts" + }, "./rtkq/legacy/migrate-to-cloud": { "import": "./src/clients/rtkq/migrate-to-cloud/index.ts", "require": "./src/clients/rtkq/migrate-to-cloud/index.ts" diff --git a/packages/grafana-api-clients/src/clients/rtkq/advisor/v0alpha1/endpoints.gen.ts b/packages/grafana-api-clients/src/clients/rtkq/advisor/v0alpha1/endpoints.gen.ts index d054b90a9f4..8cf2fec2b60 100644 --- a/packages/grafana-api-clients/src/clients/rtkq/advisor/v0alpha1/endpoints.gen.ts +++ b/packages/grafana-api-clients/src/clients/rtkq/advisor/v0alpha1/endpoints.gen.ts @@ -1,11 +1,15 @@ import { api } from './baseAPI'; -export const addTagTypes = ['Check', 'CheckType'] as const; +export const addTagTypes = ['API Discovery', 'Check', 'CheckType'] as const; const injectedRtkApi = api .enhanceEndpoints({ addTagTypes, }) .injectEndpoints({ endpoints: (build) => ({ + getApiResources: build.query({ + query: () => ({ url: `/apis/advisor.grafana.app/v0alpha1/` }), + providesTags: ['API Discovery'], + }), listCheck: build.query({ query: (queryArg) => ({ url: `/checks`, @@ -39,6 +43,29 @@ const injectedRtkApi = api }), invalidatesTags: ['Check'], }), + deletecollectionCheck: build.mutation({ + query: (queryArg) => ({ + url: `/checks`, + method: 'DELETE', + params: { + pretty: queryArg.pretty, + continue: queryArg['continue'], + dryRun: queryArg.dryRun, + fieldSelector: queryArg.fieldSelector, + gracePeriodSeconds: queryArg.gracePeriodSeconds, + ignoreStoreReadErrorWithClusterBreakingPotential: queryArg.ignoreStoreReadErrorWithClusterBreakingPotential, + labelSelector: queryArg.labelSelector, + limit: queryArg.limit, + orphanDependents: queryArg.orphanDependents, + propagationPolicy: queryArg.propagationPolicy, + resourceVersion: queryArg.resourceVersion, + resourceVersionMatch: queryArg.resourceVersionMatch, + sendInitialEvents: queryArg.sendInitialEvents, + timeoutSeconds: queryArg.timeoutSeconds, + }, + }), + invalidatesTags: ['Check'], + }), getCheck: build.query({ query: (queryArg) => ({ url: `/checks/${queryArg.name}`, @@ -48,6 +75,20 @@ const injectedRtkApi = api }), providesTags: ['Check'], }), + replaceCheck: build.mutation({ + query: (queryArg) => ({ + url: `/checks/${queryArg.name}`, + method: 'PUT', + body: queryArg.check, + params: { + pretty: queryArg.pretty, + dryRun: queryArg.dryRun, + fieldManager: queryArg.fieldManager, + fieldValidation: queryArg.fieldValidation, + }, + }), + invalidatesTags: ['Check'], + }), deleteCheck: build.mutation({ query: (queryArg) => ({ url: `/checks/${queryArg.name}`, @@ -78,6 +119,44 @@ const injectedRtkApi = api }), invalidatesTags: ['Check'], }), + getCheckStatus: build.query({ + query: (queryArg) => ({ + url: `/checks/${queryArg.name}/status`, + params: { + pretty: queryArg.pretty, + }, + }), + providesTags: ['Check'], + }), + replaceCheckStatus: build.mutation({ + query: (queryArg) => ({ + url: `/checks/${queryArg.name}/status`, + method: 'PUT', + body: queryArg.check, + params: { + pretty: queryArg.pretty, + dryRun: queryArg.dryRun, + fieldManager: queryArg.fieldManager, + fieldValidation: queryArg.fieldValidation, + }, + }), + invalidatesTags: ['Check'], + }), + updateCheckStatus: build.mutation({ + query: (queryArg) => ({ + url: `/checks/${queryArg.name}/status`, + method: 'PATCH', + body: queryArg.patch, + params: { + pretty: queryArg.pretty, + dryRun: queryArg.dryRun, + fieldManager: queryArg.fieldManager, + fieldValidation: queryArg.fieldValidation, + force: queryArg.force, + }, + }), + invalidatesTags: ['Check'], + }), listCheckType: build.query({ query: (queryArg) => ({ url: `/checktypes`, @@ -97,6 +176,81 @@ const injectedRtkApi = api }), providesTags: ['CheckType'], }), + createCheckType: build.mutation({ + query: (queryArg) => ({ + url: `/checktypes`, + method: 'POST', + body: queryArg.checkType, + params: { + pretty: queryArg.pretty, + dryRun: queryArg.dryRun, + fieldManager: queryArg.fieldManager, + fieldValidation: queryArg.fieldValidation, + }, + }), + invalidatesTags: ['CheckType'], + }), + deletecollectionCheckType: build.mutation({ + query: (queryArg) => ({ + url: `/checktypes`, + method: 'DELETE', + params: { + pretty: queryArg.pretty, + continue: queryArg['continue'], + dryRun: queryArg.dryRun, + fieldSelector: queryArg.fieldSelector, + gracePeriodSeconds: queryArg.gracePeriodSeconds, + ignoreStoreReadErrorWithClusterBreakingPotential: queryArg.ignoreStoreReadErrorWithClusterBreakingPotential, + labelSelector: queryArg.labelSelector, + limit: queryArg.limit, + orphanDependents: queryArg.orphanDependents, + propagationPolicy: queryArg.propagationPolicy, + resourceVersion: queryArg.resourceVersion, + resourceVersionMatch: queryArg.resourceVersionMatch, + sendInitialEvents: queryArg.sendInitialEvents, + timeoutSeconds: queryArg.timeoutSeconds, + }, + }), + invalidatesTags: ['CheckType'], + }), + getCheckType: build.query({ + query: (queryArg) => ({ + url: `/checktypes/${queryArg.name}`, + params: { + pretty: queryArg.pretty, + }, + }), + providesTags: ['CheckType'], + }), + replaceCheckType: build.mutation({ + query: (queryArg) => ({ + url: `/checktypes/${queryArg.name}`, + method: 'PUT', + body: queryArg.checkType, + params: { + pretty: queryArg.pretty, + dryRun: queryArg.dryRun, + fieldManager: queryArg.fieldManager, + fieldValidation: queryArg.fieldValidation, + }, + }), + invalidatesTags: ['CheckType'], + }), + deleteCheckType: build.mutation({ + query: (queryArg) => ({ + url: `/checktypes/${queryArg.name}`, + method: 'DELETE', + params: { + pretty: queryArg.pretty, + dryRun: queryArg.dryRun, + gracePeriodSeconds: queryArg.gracePeriodSeconds, + ignoreStoreReadErrorWithClusterBreakingPotential: queryArg.ignoreStoreReadErrorWithClusterBreakingPotential, + orphanDependents: queryArg.orphanDependents, + propagationPolicy: queryArg.propagationPolicy, + }, + }), + invalidatesTags: ['CheckType'], + }), updateCheckType: build.mutation({ query: (queryArg) => ({ url: `/checktypes/${queryArg.name}`, @@ -112,10 +266,50 @@ const injectedRtkApi = api }), invalidatesTags: ['CheckType'], }), + getCheckTypeStatus: build.query({ + query: (queryArg) => ({ + url: `/checktypes/${queryArg.name}/status`, + params: { + pretty: queryArg.pretty, + }, + }), + providesTags: ['CheckType'], + }), + replaceCheckTypeStatus: build.mutation({ + query: (queryArg) => ({ + url: `/checktypes/${queryArg.name}/status`, + method: 'PUT', + body: queryArg.checkType, + params: { + pretty: queryArg.pretty, + dryRun: queryArg.dryRun, + fieldManager: queryArg.fieldManager, + fieldValidation: queryArg.fieldValidation, + }, + }), + invalidatesTags: ['CheckType'], + }), + updateCheckTypeStatus: build.mutation({ + query: (queryArg) => ({ + url: `/checktypes/${queryArg.name}/status`, + method: 'PATCH', + body: queryArg.patch, + params: { + pretty: queryArg.pretty, + dryRun: queryArg.dryRun, + fieldManager: queryArg.fieldManager, + fieldValidation: queryArg.fieldValidation, + force: queryArg.force, + }, + }), + invalidatesTags: ['CheckType'], + }), }), overrideExisting: false, }); export { injectedRtkApi as generatedAPI }; +export type GetApiResourcesApiResponse = /** status 200 OK */ ApiResourceList; +export type GetApiResourcesApiArg = void; export type ListCheckApiResponse = /** status 200 OK */ CheckList; export type ListCheckApiArg = { /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ @@ -176,6 +370,57 @@ export type CreateCheckApiArg = { fieldValidation?: string; check: Check; }; +export type DeletecollectionCheckApiResponse = /** status 200 OK */ Status; +export type DeletecollectionCheckApiArg = { + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; + /** The continue option should be set when retrieving more results from the server. Since this value is server defined, clients may only use the continue value from a previous query result with identical query parameters (except for the value of continue) and the server may reject a continue value it does not recognize. If the specified continue value is no longer valid whether due to expiration (generally five to fifteen minutes) or a configuration change on the server, the server will respond with a 410 ResourceExpired error together with a continue token. If the client needs a consistent list, it must restart their list without the continue field. Otherwise, the client may send another list request with the token received with the 410 error, the server will respond with a list starting from the next key, but from the latest snapshot, which is inconsistent from the previous list results - objects that are created, modified, or deleted after the first list request will be included in the response, as long as their keys are after the "next key". + + This field is not supported when watch is true. Clients may start a watch from the last resourceVersion value returned by the server and not miss any modifications. */ + continue?: string; + /** When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed */ + dryRun?: string; + /** A selector to restrict the list of returned objects by their fields. Defaults to everything. */ + fieldSelector?: string; + /** The duration in seconds before the object should be deleted. Value must be non-negative integer. The value zero indicates delete immediately. If this value is nil, the default grace period for the specified type will be used. Defaults to a per object value if not specified. zero means delete immediately. */ + gracePeriodSeconds?: number; + /** if set to true, it will trigger an unsafe deletion of the resource in case the normal deletion flow fails with a corrupt object error. A resource is considered corrupt if it can not be retrieved from the underlying storage successfully because of a) its data can not be transformed e.g. decryption failure, or b) it fails to decode into an object. NOTE: unsafe deletion ignores finalizer constraints, skips precondition checks, and removes the object from the storage. WARNING: This may potentially break the cluster if the workload associated with the resource being unsafe-deleted relies on normal deletion flow. Use only if you REALLY know what you are doing. The default value is false, and the user must opt in to enable it */ + ignoreStoreReadErrorWithClusterBreakingPotential?: boolean; + /** A selector to restrict the list of returned objects by their labels. Defaults to everything. */ + labelSelector?: string; + /** limit is a maximum number of responses to return for a list call. If more items exist, the server will set the `continue` field on the list metadata to a value that can be used with the same initial query to retrieve the next set of results. Setting a limit may return fewer than the requested amount of items (up to zero items) in the event all requested objects are filtered out and clients should only use the presence of the continue field to determine whether more results are available. Servers may choose not to support the limit argument and will return all of the available results. If limit is specified and the continue field is empty, clients may assume that no more results are available. This field is not supported if watch is true. + + The server guarantees that the objects returned when using continue will be identical to issuing a single list call without a limit - that is, no objects created, modified, or deleted after the first request is issued will be included in any subsequent continued requests. This is sometimes referred to as a consistent snapshot, and ensures that a client that is using limit to receive smaller chunks of a very large result can ensure they see all possible objects. If objects are updated during a chunked list the version of the object that was present at the time the first list result was calculated is returned. */ + limit?: number; + /** Deprecated: please use the PropagationPolicy, this field will be deprecated in 1.7. Should the dependent objects be orphaned. If true/false, the "orphan" finalizer will be added to/removed from the object's finalizers list. Either this field or PropagationPolicy may be set, but not both. */ + orphanDependents?: boolean; + /** Whether and how garbage collection will be performed. Either this field or OrphanDependents may be set, but not both. The default policy is decided by the existing finalizer set in the metadata.finalizers and the resource-specific default policy. Acceptable values are: 'Orphan' - orphan the dependents; 'Background' - allow the garbage collector to delete the dependents in the background; 'Foreground' - a cascading policy that deletes all dependents in the foreground. */ + propagationPolicy?: string; + /** resourceVersion sets a constraint on what resource versions a request may be served from. See https://kubernetes.io/docs/reference/using-api/api-concepts/#resource-versions for details. + + Defaults to unset */ + resourceVersion?: string; + /** resourceVersionMatch determines how resourceVersion is applied to list calls. It is highly recommended that resourceVersionMatch be set for list calls where resourceVersion is set See https://kubernetes.io/docs/reference/using-api/api-concepts/#resource-versions for details. + + Defaults to unset */ + resourceVersionMatch?: string; + /** `sendInitialEvents=true` may be set together with `watch=true`. In that case, the watch stream will begin with synthetic events to produce the current state of objects in the collection. Once all such events have been sent, a synthetic "Bookmark" event will be sent. The bookmark will report the ResourceVersion (RV) corresponding to the set of objects, and be marked with `"k8s.io/initial-events-end": "true"` annotation. Afterwards, the watch stream will proceed as usual, sending watch events corresponding to changes (subsequent to the RV) to objects watched. + + When `sendInitialEvents` option is set, we require `resourceVersionMatch` option to also be set. The semantic of the watch request is as following: - `resourceVersionMatch` = NotOlderThan + is interpreted as "data at least as new as the provided `resourceVersion`" + and the bookmark event is send when the state is synced + to a `resourceVersion` at least as fresh as the one provided by the ListOptions. + If `resourceVersion` is unset, this is interpreted as "consistent read" and the + bookmark event is send when the state is synced at least to the moment + when request started being processed. + - `resourceVersionMatch` set to any other value or unset + Invalid error is returned. + + Defaults to true if `resourceVersion=""` or `resourceVersion="0"` (for backward compatibility reasons) and to false otherwise. */ + sendInitialEvents?: boolean; + /** Timeout for the list/watch call. This limits the duration of the call, regardless of any activity or inactivity. */ + timeoutSeconds?: number; +}; export type GetCheckApiResponse = /** status 200 OK */ Check; export type GetCheckApiArg = { /** name of the Check */ @@ -183,6 +428,20 @@ export type GetCheckApiArg = { /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ pretty?: string; }; +export type ReplaceCheckApiResponse = /** status 200 OK */ Check | /** status 201 Created */ Check; +export type ReplaceCheckApiArg = { + /** name of the Check */ + name: string; + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; + /** When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed */ + dryRun?: string; + /** fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint. */ + fieldManager?: string; + /** fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields. Valid values are: - Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23. - Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default in v1.23+ - Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered. */ + fieldValidation?: string; + check: Check; +}; export type DeleteCheckApiResponse = /** status 200 OK */ Status | /** status 202 Accepted */ Status; export type DeleteCheckApiArg = { /** name of the Check */ @@ -216,6 +475,43 @@ export type UpdateCheckApiArg = { force?: boolean; patch: Patch; }; +export type GetCheckStatusApiResponse = /** status 200 OK */ Check; +export type GetCheckStatusApiArg = { + /** name of the Check */ + name: string; + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; +}; +export type ReplaceCheckStatusApiResponse = /** status 200 OK */ Check | /** status 201 Created */ Check; +export type ReplaceCheckStatusApiArg = { + /** name of the Check */ + name: string; + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; + /** When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed */ + dryRun?: string; + /** fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint. */ + fieldManager?: string; + /** fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields. Valid values are: - Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23. - Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default in v1.23+ - Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered. */ + fieldValidation?: string; + check: Check; +}; +export type UpdateCheckStatusApiResponse = /** status 200 OK */ Check | /** status 201 Created */ Check; +export type UpdateCheckStatusApiArg = { + /** name of the Check */ + name: string; + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; + /** When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed */ + dryRun?: string; + /** fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint. This field is required for apply requests (application/apply-patch) but optional for non-apply patch types (JsonPatch, MergePatch, StrategicMergePatch). */ + fieldManager?: string; + /** fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields. Valid values are: - Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23. - Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default in v1.23+ - Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered. */ + fieldValidation?: string; + /** Force is going to "force" Apply requests. It means user will re-acquire conflicting fields owned by other people. Force flag must be unset for non-apply patch requests. */ + force?: boolean; + patch: Patch; +}; export type ListCheckTypeApiResponse = /** status 200 OK */ CheckTypeList; export type ListCheckTypeApiArg = { /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ @@ -261,6 +557,110 @@ export type ListCheckTypeApiArg = { /** Watch for changes to the described resources and return them as a stream of add, update, and remove notifications. Specify resourceVersion. */ watch?: boolean; }; +export type CreateCheckTypeApiResponse = /** status 200 OK */ + | CheckType + | /** status 201 Created */ CheckType + | /** status 202 Accepted */ CheckType; +export type CreateCheckTypeApiArg = { + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; + /** When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed */ + dryRun?: string; + /** fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint. */ + fieldManager?: string; + /** fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields. Valid values are: - Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23. - Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default in v1.23+ - Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered. */ + fieldValidation?: string; + checkType: CheckType; +}; +export type DeletecollectionCheckTypeApiResponse = /** status 200 OK */ Status; +export type DeletecollectionCheckTypeApiArg = { + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; + /** The continue option should be set when retrieving more results from the server. Since this value is server defined, clients may only use the continue value from a previous query result with identical query parameters (except for the value of continue) and the server may reject a continue value it does not recognize. If the specified continue value is no longer valid whether due to expiration (generally five to fifteen minutes) or a configuration change on the server, the server will respond with a 410 ResourceExpired error together with a continue token. If the client needs a consistent list, it must restart their list without the continue field. Otherwise, the client may send another list request with the token received with the 410 error, the server will respond with a list starting from the next key, but from the latest snapshot, which is inconsistent from the previous list results - objects that are created, modified, or deleted after the first list request will be included in the response, as long as their keys are after the "next key". + + This field is not supported when watch is true. Clients may start a watch from the last resourceVersion value returned by the server and not miss any modifications. */ + continue?: string; + /** When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed */ + dryRun?: string; + /** A selector to restrict the list of returned objects by their fields. Defaults to everything. */ + fieldSelector?: string; + /** The duration in seconds before the object should be deleted. Value must be non-negative integer. The value zero indicates delete immediately. If this value is nil, the default grace period for the specified type will be used. Defaults to a per object value if not specified. zero means delete immediately. */ + gracePeriodSeconds?: number; + /** if set to true, it will trigger an unsafe deletion of the resource in case the normal deletion flow fails with a corrupt object error. A resource is considered corrupt if it can not be retrieved from the underlying storage successfully because of a) its data can not be transformed e.g. decryption failure, or b) it fails to decode into an object. NOTE: unsafe deletion ignores finalizer constraints, skips precondition checks, and removes the object from the storage. WARNING: This may potentially break the cluster if the workload associated with the resource being unsafe-deleted relies on normal deletion flow. Use only if you REALLY know what you are doing. The default value is false, and the user must opt in to enable it */ + ignoreStoreReadErrorWithClusterBreakingPotential?: boolean; + /** A selector to restrict the list of returned objects by their labels. Defaults to everything. */ + labelSelector?: string; + /** limit is a maximum number of responses to return for a list call. If more items exist, the server will set the `continue` field on the list metadata to a value that can be used with the same initial query to retrieve the next set of results. Setting a limit may return fewer than the requested amount of items (up to zero items) in the event all requested objects are filtered out and clients should only use the presence of the continue field to determine whether more results are available. Servers may choose not to support the limit argument and will return all of the available results. If limit is specified and the continue field is empty, clients may assume that no more results are available. This field is not supported if watch is true. + + The server guarantees that the objects returned when using continue will be identical to issuing a single list call without a limit - that is, no objects created, modified, or deleted after the first request is issued will be included in any subsequent continued requests. This is sometimes referred to as a consistent snapshot, and ensures that a client that is using limit to receive smaller chunks of a very large result can ensure they see all possible objects. If objects are updated during a chunked list the version of the object that was present at the time the first list result was calculated is returned. */ + limit?: number; + /** Deprecated: please use the PropagationPolicy, this field will be deprecated in 1.7. Should the dependent objects be orphaned. If true/false, the "orphan" finalizer will be added to/removed from the object's finalizers list. Either this field or PropagationPolicy may be set, but not both. */ + orphanDependents?: boolean; + /** Whether and how garbage collection will be performed. Either this field or OrphanDependents may be set, but not both. The default policy is decided by the existing finalizer set in the metadata.finalizers and the resource-specific default policy. Acceptable values are: 'Orphan' - orphan the dependents; 'Background' - allow the garbage collector to delete the dependents in the background; 'Foreground' - a cascading policy that deletes all dependents in the foreground. */ + propagationPolicy?: string; + /** resourceVersion sets a constraint on what resource versions a request may be served from. See https://kubernetes.io/docs/reference/using-api/api-concepts/#resource-versions for details. + + Defaults to unset */ + resourceVersion?: string; + /** resourceVersionMatch determines how resourceVersion is applied to list calls. It is highly recommended that resourceVersionMatch be set for list calls where resourceVersion is set See https://kubernetes.io/docs/reference/using-api/api-concepts/#resource-versions for details. + + Defaults to unset */ + resourceVersionMatch?: string; + /** `sendInitialEvents=true` may be set together with `watch=true`. In that case, the watch stream will begin with synthetic events to produce the current state of objects in the collection. Once all such events have been sent, a synthetic "Bookmark" event will be sent. The bookmark will report the ResourceVersion (RV) corresponding to the set of objects, and be marked with `"k8s.io/initial-events-end": "true"` annotation. Afterwards, the watch stream will proceed as usual, sending watch events corresponding to changes (subsequent to the RV) to objects watched. + + When `sendInitialEvents` option is set, we require `resourceVersionMatch` option to also be set. The semantic of the watch request is as following: - `resourceVersionMatch` = NotOlderThan + is interpreted as "data at least as new as the provided `resourceVersion`" + and the bookmark event is send when the state is synced + to a `resourceVersion` at least as fresh as the one provided by the ListOptions. + If `resourceVersion` is unset, this is interpreted as "consistent read" and the + bookmark event is send when the state is synced at least to the moment + when request started being processed. + - `resourceVersionMatch` set to any other value or unset + Invalid error is returned. + + Defaults to true if `resourceVersion=""` or `resourceVersion="0"` (for backward compatibility reasons) and to false otherwise. */ + sendInitialEvents?: boolean; + /** Timeout for the list/watch call. This limits the duration of the call, regardless of any activity or inactivity. */ + timeoutSeconds?: number; +}; +export type GetCheckTypeApiResponse = /** status 200 OK */ CheckType; +export type GetCheckTypeApiArg = { + /** name of the CheckType */ + name: string; + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; +}; +export type ReplaceCheckTypeApiResponse = /** status 200 OK */ CheckType | /** status 201 Created */ CheckType; +export type ReplaceCheckTypeApiArg = { + /** name of the CheckType */ + name: string; + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; + /** When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed */ + dryRun?: string; + /** fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint. */ + fieldManager?: string; + /** fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields. Valid values are: - Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23. - Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default in v1.23+ - Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered. */ + fieldValidation?: string; + checkType: CheckType; +}; +export type DeleteCheckTypeApiResponse = /** status 200 OK */ Status | /** status 202 Accepted */ Status; +export type DeleteCheckTypeApiArg = { + /** name of the CheckType */ + name: string; + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; + /** When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed */ + dryRun?: string; + /** The duration in seconds before the object should be deleted. Value must be non-negative integer. The value zero indicates delete immediately. If this value is nil, the default grace period for the specified type will be used. Defaults to a per object value if not specified. zero means delete immediately. */ + gracePeriodSeconds?: number; + /** if set to true, it will trigger an unsafe deletion of the resource in case the normal deletion flow fails with a corrupt object error. A resource is considered corrupt if it can not be retrieved from the underlying storage successfully because of a) its data can not be transformed e.g. decryption failure, or b) it fails to decode into an object. NOTE: unsafe deletion ignores finalizer constraints, skips precondition checks, and removes the object from the storage. WARNING: This may potentially break the cluster if the workload associated with the resource being unsafe-deleted relies on normal deletion flow. Use only if you REALLY know what you are doing. The default value is false, and the user must opt in to enable it */ + ignoreStoreReadErrorWithClusterBreakingPotential?: boolean; + /** Deprecated: please use the PropagationPolicy, this field will be deprecated in 1.7. Should the dependent objects be orphaned. If true/false, the "orphan" finalizer will be added to/removed from the object's finalizers list. Either this field or PropagationPolicy may be set, but not both. */ + orphanDependents?: boolean; + /** Whether and how garbage collection will be performed. Either this field or OrphanDependents may be set, but not both. The default policy is decided by the existing finalizer set in the metadata.finalizers and the resource-specific default policy. Acceptable values are: 'Orphan' - orphan the dependents; 'Background' - allow the garbage collector to delete the dependents in the background; 'Foreground' - a cascading policy that deletes all dependents in the foreground. */ + propagationPolicy?: string; +}; export type UpdateCheckTypeApiResponse = /** status 200 OK */ CheckType | /** status 201 Created */ CheckType; export type UpdateCheckTypeApiArg = { /** name of the CheckType */ @@ -277,6 +677,75 @@ export type UpdateCheckTypeApiArg = { force?: boolean; patch: Patch; }; +export type GetCheckTypeStatusApiResponse = /** status 200 OK */ CheckType; +export type GetCheckTypeStatusApiArg = { + /** name of the CheckType */ + name: string; + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; +}; +export type ReplaceCheckTypeStatusApiResponse = /** status 200 OK */ CheckType | /** status 201 Created */ CheckType; +export type ReplaceCheckTypeStatusApiArg = { + /** name of the CheckType */ + name: string; + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; + /** When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed */ + dryRun?: string; + /** fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint. */ + fieldManager?: string; + /** fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields. Valid values are: - Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23. - Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default in v1.23+ - Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered. */ + fieldValidation?: string; + checkType: CheckType; +}; +export type UpdateCheckTypeStatusApiResponse = /** status 200 OK */ CheckType | /** status 201 Created */ CheckType; +export type UpdateCheckTypeStatusApiArg = { + /** name of the CheckType */ + name: string; + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; + /** When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed */ + dryRun?: string; + /** fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint. This field is required for apply requests (application/apply-patch) but optional for non-apply patch types (JsonPatch, MergePatch, StrategicMergePatch). */ + fieldManager?: string; + /** fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields. Valid values are: - Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23. - Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default in v1.23+ - Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered. */ + fieldValidation?: string; + /** Force is going to "force" Apply requests. It means user will re-acquire conflicting fields owned by other people. Force flag must be unset for non-apply patch requests. */ + force?: boolean; + patch: Patch; +}; +export type ApiResource = { + /** categories is a list of the grouped resources this resource belongs to (e.g. 'all') */ + categories?: string[]; + /** group is the preferred group of the resource. Empty implies the group of the containing resource list. For subresources, this may have a different value, for example: Scale". */ + group?: string; + /** kind is the kind for the resource (e.g. 'Foo' is the kind for a resource 'foo') */ + kind: string; + /** name is the plural name of the resource. */ + name: string; + /** namespaced indicates if a resource is namespaced or not. */ + namespaced: boolean; + /** shortNames is a list of suggested short names of the resource. */ + shortNames?: string[]; + /** singularName is the singular name of the resource. This allows clients to handle plural and singular opaquely. The singularName is more correct for reporting status on a single item and both singular and plural are allowed from the kubectl CLI interface. */ + singularName: string; + /** The hash value of the storage version, the version this resource is converted to when written to the data store. Value must be treated as opaque by clients. Only equality comparison on the value is valid. This is an alpha feature and may change or be removed in the future. The field is populated by the apiserver only if the StorageVersionHash feature gate is enabled. This field will remain optional even if it graduates. */ + storageVersionHash?: string; + /** verbs is a list of supported kube verbs (this includes get, list, watch, create, update, patch, delete, deletecollection, and proxy) */ + verbs: string[]; + /** version is the preferred version of the resource. Empty implies the version of the containing resource list For subresources, this may have a different value, for example: v1 (while inside a v1beta1 version of the core resource's group)". */ + version?: string; +}; +export type ApiResourceList = { + /** APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources */ + apiVersion?: string; + /** groupVersion is the group and version this APIResourceList is for. */ + groupVersion: string; + /** Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds */ + kind?: string; + /** resources contains the name of the resources and if they are namespaced. */ + resources: ApiResource[]; +}; export type Time = string; export type FieldsV1 = object; export type ManagedFieldsEntry = { @@ -537,3 +1006,26 @@ export type CheckTypeList = { kind?: string; metadata: ListMeta; }; +export const { + useGetApiResourcesQuery, + useListCheckQuery, + useCreateCheckMutation, + useDeletecollectionCheckMutation, + useGetCheckQuery, + useReplaceCheckMutation, + useDeleteCheckMutation, + useUpdateCheckMutation, + useGetCheckStatusQuery, + useReplaceCheckStatusMutation, + useUpdateCheckStatusMutation, + useListCheckTypeQuery, + useCreateCheckTypeMutation, + useDeletecollectionCheckTypeMutation, + useGetCheckTypeQuery, + useReplaceCheckTypeMutation, + useDeleteCheckTypeMutation, + useUpdateCheckTypeMutation, + useGetCheckTypeStatusQuery, + useReplaceCheckTypeStatusMutation, + useUpdateCheckTypeStatusMutation, +} = injectedRtkApi; diff --git a/packages/grafana-api-clients/src/clients/rtkq/correlations/v0alpha1/endpoints.gen.ts b/packages/grafana-api-clients/src/clients/rtkq/correlations/v0alpha1/endpoints.gen.ts index ef81f37a246..9f40ec322a5 100644 --- a/packages/grafana-api-clients/src/clients/rtkq/correlations/v0alpha1/endpoints.gen.ts +++ b/packages/grafana-api-clients/src/clients/rtkq/correlations/v0alpha1/endpoints.gen.ts @@ -509,3 +509,13 @@ export type Status = { status?: string; }; export type Patch = object; +export const { + useGetApiResourcesQuery, + useListCorrelationQuery, + useCreateCorrelationMutation, + useDeletecollectionCorrelationMutation, + useGetCorrelationQuery, + useReplaceCorrelationMutation, + useDeleteCorrelationMutation, + useUpdateCorrelationMutation, +} = injectedRtkApi; diff --git a/packages/grafana-api-clients/src/clients/rtkq/dashboard/v0alpha1/endpoints.gen.ts b/packages/grafana-api-clients/src/clients/rtkq/dashboard/v0alpha1/endpoints.gen.ts index 5abfbe269e8..9e4aee6b516 100644 --- a/packages/grafana-api-clients/src/clients/rtkq/dashboard/v0alpha1/endpoints.gen.ts +++ b/packages/grafana-api-clients/src/clients/rtkq/dashboard/v0alpha1/endpoints.gen.ts @@ -1,11 +1,240 @@ import { api } from './baseAPI'; -export const addTagTypes = ['Search'] as const; +export const addTagTypes = ['API Discovery', 'Dashboard', 'LibraryPanel', 'Search'] as const; const injectedRtkApi = api .enhanceEndpoints({ addTagTypes, }) .injectEndpoints({ endpoints: (build) => ({ + getApiResources: build.query({ + query: () => ({ url: `/apis/dashboard.grafana.app/v0alpha1/` }), + providesTags: ['API Discovery'], + }), + listDashboard: build.query({ + query: (queryArg) => ({ + url: `/dashboards`, + params: { + pretty: queryArg.pretty, + allowWatchBookmarks: queryArg.allowWatchBookmarks, + continue: queryArg['continue'], + fieldSelector: queryArg.fieldSelector, + labelSelector: queryArg.labelSelector, + limit: queryArg.limit, + resourceVersion: queryArg.resourceVersion, + resourceVersionMatch: queryArg.resourceVersionMatch, + sendInitialEvents: queryArg.sendInitialEvents, + timeoutSeconds: queryArg.timeoutSeconds, + watch: queryArg.watch, + }, + }), + providesTags: ['Dashboard'], + }), + createDashboard: build.mutation({ + query: (queryArg) => ({ + url: `/dashboards`, + method: 'POST', + body: queryArg.dashboard, + params: { + pretty: queryArg.pretty, + dryRun: queryArg.dryRun, + fieldManager: queryArg.fieldManager, + fieldValidation: queryArg.fieldValidation, + }, + }), + invalidatesTags: ['Dashboard'], + }), + deletecollectionDashboard: build.mutation({ + query: (queryArg) => ({ + url: `/dashboards`, + method: 'DELETE', + params: { + pretty: queryArg.pretty, + continue: queryArg['continue'], + dryRun: queryArg.dryRun, + fieldSelector: queryArg.fieldSelector, + gracePeriodSeconds: queryArg.gracePeriodSeconds, + ignoreStoreReadErrorWithClusterBreakingPotential: queryArg.ignoreStoreReadErrorWithClusterBreakingPotential, + labelSelector: queryArg.labelSelector, + limit: queryArg.limit, + orphanDependents: queryArg.orphanDependents, + propagationPolicy: queryArg.propagationPolicy, + resourceVersion: queryArg.resourceVersion, + resourceVersionMatch: queryArg.resourceVersionMatch, + sendInitialEvents: queryArg.sendInitialEvents, + timeoutSeconds: queryArg.timeoutSeconds, + }, + }), + invalidatesTags: ['Dashboard'], + }), + getDashboard: build.query({ + query: (queryArg) => ({ + url: `/dashboards/${queryArg.name}`, + params: { + pretty: queryArg.pretty, + }, + }), + providesTags: ['Dashboard'], + }), + replaceDashboard: build.mutation({ + query: (queryArg) => ({ + url: `/dashboards/${queryArg.name}`, + method: 'PUT', + body: queryArg.dashboard, + params: { + pretty: queryArg.pretty, + dryRun: queryArg.dryRun, + fieldManager: queryArg.fieldManager, + fieldValidation: queryArg.fieldValidation, + }, + }), + invalidatesTags: ['Dashboard'], + }), + deleteDashboard: build.mutation({ + query: (queryArg) => ({ + url: `/dashboards/${queryArg.name}`, + method: 'DELETE', + params: { + pretty: queryArg.pretty, + dryRun: queryArg.dryRun, + gracePeriodSeconds: queryArg.gracePeriodSeconds, + ignoreStoreReadErrorWithClusterBreakingPotential: queryArg.ignoreStoreReadErrorWithClusterBreakingPotential, + orphanDependents: queryArg.orphanDependents, + propagationPolicy: queryArg.propagationPolicy, + }, + }), + invalidatesTags: ['Dashboard'], + }), + updateDashboard: build.mutation({ + query: (queryArg) => ({ + url: `/dashboards/${queryArg.name}`, + method: 'PATCH', + body: queryArg.patch, + params: { + pretty: queryArg.pretty, + dryRun: queryArg.dryRun, + fieldManager: queryArg.fieldManager, + fieldValidation: queryArg.fieldValidation, + force: queryArg.force, + }, + }), + invalidatesTags: ['Dashboard'], + }), + getDashboardDto: build.query({ + query: (queryArg) => ({ url: `/dashboards/${queryArg.name}/dto` }), + providesTags: ['Dashboard'], + }), + listLibraryPanel: build.query({ + query: (queryArg) => ({ + url: `/librarypanels`, + params: { + pretty: queryArg.pretty, + allowWatchBookmarks: queryArg.allowWatchBookmarks, + continue: queryArg['continue'], + fieldSelector: queryArg.fieldSelector, + labelSelector: queryArg.labelSelector, + limit: queryArg.limit, + resourceVersion: queryArg.resourceVersion, + resourceVersionMatch: queryArg.resourceVersionMatch, + sendInitialEvents: queryArg.sendInitialEvents, + timeoutSeconds: queryArg.timeoutSeconds, + watch: queryArg.watch, + }, + }), + providesTags: ['LibraryPanel'], + }), + createLibraryPanel: build.mutation({ + query: (queryArg) => ({ + url: `/librarypanels`, + method: 'POST', + body: queryArg.libraryPanel, + params: { + pretty: queryArg.pretty, + dryRun: queryArg.dryRun, + fieldManager: queryArg.fieldManager, + fieldValidation: queryArg.fieldValidation, + }, + }), + invalidatesTags: ['LibraryPanel'], + }), + deletecollectionLibraryPanel: build.mutation< + DeletecollectionLibraryPanelApiResponse, + DeletecollectionLibraryPanelApiArg + >({ + query: (queryArg) => ({ + url: `/librarypanels`, + method: 'DELETE', + params: { + pretty: queryArg.pretty, + continue: queryArg['continue'], + dryRun: queryArg.dryRun, + fieldSelector: queryArg.fieldSelector, + gracePeriodSeconds: queryArg.gracePeriodSeconds, + ignoreStoreReadErrorWithClusterBreakingPotential: queryArg.ignoreStoreReadErrorWithClusterBreakingPotential, + labelSelector: queryArg.labelSelector, + limit: queryArg.limit, + orphanDependents: queryArg.orphanDependents, + propagationPolicy: queryArg.propagationPolicy, + resourceVersion: queryArg.resourceVersion, + resourceVersionMatch: queryArg.resourceVersionMatch, + sendInitialEvents: queryArg.sendInitialEvents, + timeoutSeconds: queryArg.timeoutSeconds, + }, + }), + invalidatesTags: ['LibraryPanel'], + }), + getLibraryPanel: build.query({ + query: (queryArg) => ({ + url: `/librarypanels/${queryArg.name}`, + params: { + pretty: queryArg.pretty, + }, + }), + providesTags: ['LibraryPanel'], + }), + replaceLibraryPanel: build.mutation({ + query: (queryArg) => ({ + url: `/librarypanels/${queryArg.name}`, + method: 'PUT', + body: queryArg.libraryPanel, + params: { + pretty: queryArg.pretty, + dryRun: queryArg.dryRun, + fieldManager: queryArg.fieldManager, + fieldValidation: queryArg.fieldValidation, + }, + }), + invalidatesTags: ['LibraryPanel'], + }), + deleteLibraryPanel: build.mutation({ + query: (queryArg) => ({ + url: `/librarypanels/${queryArg.name}`, + method: 'DELETE', + params: { + pretty: queryArg.pretty, + dryRun: queryArg.dryRun, + gracePeriodSeconds: queryArg.gracePeriodSeconds, + ignoreStoreReadErrorWithClusterBreakingPotential: queryArg.ignoreStoreReadErrorWithClusterBreakingPotential, + orphanDependents: queryArg.orphanDependents, + propagationPolicy: queryArg.propagationPolicy, + }, + }), + invalidatesTags: ['LibraryPanel'], + }), + updateLibraryPanel: build.mutation({ + query: (queryArg) => ({ + url: `/librarypanels/${queryArg.name}`, + method: 'PATCH', + body: queryArg.patch, + params: { + pretty: queryArg.pretty, + dryRun: queryArg.dryRun, + fieldManager: queryArg.fieldManager, + fieldValidation: queryArg.fieldValidation, + force: queryArg.force, + }, + }), + invalidatesTags: ['LibraryPanel'], + }), getSearch: build.query({ query: (queryArg) => ({ url: `/search`, @@ -22,10 +251,351 @@ const injectedRtkApi = api }), providesTags: ['Search'], }), + getSearchSortable: build.query({ + query: () => ({ url: `/search/sortable` }), + providesTags: ['Search'], + }), }), overrideExisting: false, }); export { injectedRtkApi as generatedAPI }; +export type GetApiResourcesApiResponse = /** status 200 OK */ ApiResourceList; +export type GetApiResourcesApiArg = void; +export type ListDashboardApiResponse = /** status 200 OK */ DashboardList; +export type ListDashboardApiArg = { + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; + /** allowWatchBookmarks requests watch events with type "BOOKMARK". Servers that do not implement bookmarks may ignore this flag and bookmarks are sent at the server's discretion. Clients should not assume bookmarks are returned at any specific interval, nor may they assume the server will send any BOOKMARK event during a session. If this is not a watch, this field is ignored. */ + allowWatchBookmarks?: boolean; + /** The continue option should be set when retrieving more results from the server. Since this value is server defined, clients may only use the continue value from a previous query result with identical query parameters (except for the value of continue) and the server may reject a continue value it does not recognize. If the specified continue value is no longer valid whether due to expiration (generally five to fifteen minutes) or a configuration change on the server, the server will respond with a 410 ResourceExpired error together with a continue token. If the client needs a consistent list, it must restart their list without the continue field. Otherwise, the client may send another list request with the token received with the 410 error, the server will respond with a list starting from the next key, but from the latest snapshot, which is inconsistent from the previous list results - objects that are created, modified, or deleted after the first list request will be included in the response, as long as their keys are after the "next key". + + This field is not supported when watch is true. Clients may start a watch from the last resourceVersion value returned by the server and not miss any modifications. */ + continue?: string; + /** A selector to restrict the list of returned objects by their fields. Defaults to everything. */ + fieldSelector?: string; + /** A selector to restrict the list of returned objects by their labels. Defaults to everything. */ + labelSelector?: string; + /** limit is a maximum number of responses to return for a list call. If more items exist, the server will set the `continue` field on the list metadata to a value that can be used with the same initial query to retrieve the next set of results. Setting a limit may return fewer than the requested amount of items (up to zero items) in the event all requested objects are filtered out and clients should only use the presence of the continue field to determine whether more results are available. Servers may choose not to support the limit argument and will return all of the available results. If limit is specified and the continue field is empty, clients may assume that no more results are available. This field is not supported if watch is true. + + The server guarantees that the objects returned when using continue will be identical to issuing a single list call without a limit - that is, no objects created, modified, or deleted after the first request is issued will be included in any subsequent continued requests. This is sometimes referred to as a consistent snapshot, and ensures that a client that is using limit to receive smaller chunks of a very large result can ensure they see all possible objects. If objects are updated during a chunked list the version of the object that was present at the time the first list result was calculated is returned. */ + limit?: number; + /** resourceVersion sets a constraint on what resource versions a request may be served from. See https://kubernetes.io/docs/reference/using-api/api-concepts/#resource-versions for details. + + Defaults to unset */ + resourceVersion?: string; + /** resourceVersionMatch determines how resourceVersion is applied to list calls. It is highly recommended that resourceVersionMatch be set for list calls where resourceVersion is set See https://kubernetes.io/docs/reference/using-api/api-concepts/#resource-versions for details. + + Defaults to unset */ + resourceVersionMatch?: string; + /** `sendInitialEvents=true` may be set together with `watch=true`. In that case, the watch stream will begin with synthetic events to produce the current state of objects in the collection. Once all such events have been sent, a synthetic "Bookmark" event will be sent. The bookmark will report the ResourceVersion (RV) corresponding to the set of objects, and be marked with `"k8s.io/initial-events-end": "true"` annotation. Afterwards, the watch stream will proceed as usual, sending watch events corresponding to changes (subsequent to the RV) to objects watched. + + When `sendInitialEvents` option is set, we require `resourceVersionMatch` option to also be set. The semantic of the watch request is as following: - `resourceVersionMatch` = NotOlderThan + is interpreted as "data at least as new as the provided `resourceVersion`" + and the bookmark event is send when the state is synced + to a `resourceVersion` at least as fresh as the one provided by the ListOptions. + If `resourceVersion` is unset, this is interpreted as "consistent read" and the + bookmark event is send when the state is synced at least to the moment + when request started being processed. + - `resourceVersionMatch` set to any other value or unset + Invalid error is returned. + + Defaults to true if `resourceVersion=""` or `resourceVersion="0"` (for backward compatibility reasons) and to false otherwise. */ + sendInitialEvents?: boolean; + /** Timeout for the list/watch call. This limits the duration of the call, regardless of any activity or inactivity. */ + timeoutSeconds?: number; + /** Watch for changes to the described resources and return them as a stream of add, update, and remove notifications. Specify resourceVersion. */ + watch?: boolean; +}; +export type CreateDashboardApiResponse = /** status 200 OK */ + | Dashboard + | /** status 201 Created */ Dashboard + | /** status 202 Accepted */ Dashboard; +export type CreateDashboardApiArg = { + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; + /** When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed */ + dryRun?: string; + /** fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint. */ + fieldManager?: string; + /** fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields. Valid values are: - Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23. - Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default in v1.23+ - Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered. */ + fieldValidation?: string; + dashboard: Dashboard; +}; +export type DeletecollectionDashboardApiResponse = /** status 200 OK */ Status; +export type DeletecollectionDashboardApiArg = { + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; + /** The continue option should be set when retrieving more results from the server. Since this value is server defined, clients may only use the continue value from a previous query result with identical query parameters (except for the value of continue) and the server may reject a continue value it does not recognize. If the specified continue value is no longer valid whether due to expiration (generally five to fifteen minutes) or a configuration change on the server, the server will respond with a 410 ResourceExpired error together with a continue token. If the client needs a consistent list, it must restart their list without the continue field. Otherwise, the client may send another list request with the token received with the 410 error, the server will respond with a list starting from the next key, but from the latest snapshot, which is inconsistent from the previous list results - objects that are created, modified, or deleted after the first list request will be included in the response, as long as their keys are after the "next key". + + This field is not supported when watch is true. Clients may start a watch from the last resourceVersion value returned by the server and not miss any modifications. */ + continue?: string; + /** When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed */ + dryRun?: string; + /** A selector to restrict the list of returned objects by their fields. Defaults to everything. */ + fieldSelector?: string; + /** The duration in seconds before the object should be deleted. Value must be non-negative integer. The value zero indicates delete immediately. If this value is nil, the default grace period for the specified type will be used. Defaults to a per object value if not specified. zero means delete immediately. */ + gracePeriodSeconds?: number; + /** if set to true, it will trigger an unsafe deletion of the resource in case the normal deletion flow fails with a corrupt object error. A resource is considered corrupt if it can not be retrieved from the underlying storage successfully because of a) its data can not be transformed e.g. decryption failure, or b) it fails to decode into an object. NOTE: unsafe deletion ignores finalizer constraints, skips precondition checks, and removes the object from the storage. WARNING: This may potentially break the cluster if the workload associated with the resource being unsafe-deleted relies on normal deletion flow. Use only if you REALLY know what you are doing. The default value is false, and the user must opt in to enable it */ + ignoreStoreReadErrorWithClusterBreakingPotential?: boolean; + /** A selector to restrict the list of returned objects by their labels. Defaults to everything. */ + labelSelector?: string; + /** limit is a maximum number of responses to return for a list call. If more items exist, the server will set the `continue` field on the list metadata to a value that can be used with the same initial query to retrieve the next set of results. Setting a limit may return fewer than the requested amount of items (up to zero items) in the event all requested objects are filtered out and clients should only use the presence of the continue field to determine whether more results are available. Servers may choose not to support the limit argument and will return all of the available results. If limit is specified and the continue field is empty, clients may assume that no more results are available. This field is not supported if watch is true. + + The server guarantees that the objects returned when using continue will be identical to issuing a single list call without a limit - that is, no objects created, modified, or deleted after the first request is issued will be included in any subsequent continued requests. This is sometimes referred to as a consistent snapshot, and ensures that a client that is using limit to receive smaller chunks of a very large result can ensure they see all possible objects. If objects are updated during a chunked list the version of the object that was present at the time the first list result was calculated is returned. */ + limit?: number; + /** Deprecated: please use the PropagationPolicy, this field will be deprecated in 1.7. Should the dependent objects be orphaned. If true/false, the "orphan" finalizer will be added to/removed from the object's finalizers list. Either this field or PropagationPolicy may be set, but not both. */ + orphanDependents?: boolean; + /** Whether and how garbage collection will be performed. Either this field or OrphanDependents may be set, but not both. The default policy is decided by the existing finalizer set in the metadata.finalizers and the resource-specific default policy. Acceptable values are: 'Orphan' - orphan the dependents; 'Background' - allow the garbage collector to delete the dependents in the background; 'Foreground' - a cascading policy that deletes all dependents in the foreground. */ + propagationPolicy?: string; + /** resourceVersion sets a constraint on what resource versions a request may be served from. See https://kubernetes.io/docs/reference/using-api/api-concepts/#resource-versions for details. + + Defaults to unset */ + resourceVersion?: string; + /** resourceVersionMatch determines how resourceVersion is applied to list calls. It is highly recommended that resourceVersionMatch be set for list calls where resourceVersion is set See https://kubernetes.io/docs/reference/using-api/api-concepts/#resource-versions for details. + + Defaults to unset */ + resourceVersionMatch?: string; + /** `sendInitialEvents=true` may be set together with `watch=true`. In that case, the watch stream will begin with synthetic events to produce the current state of objects in the collection. Once all such events have been sent, a synthetic "Bookmark" event will be sent. The bookmark will report the ResourceVersion (RV) corresponding to the set of objects, and be marked with `"k8s.io/initial-events-end": "true"` annotation. Afterwards, the watch stream will proceed as usual, sending watch events corresponding to changes (subsequent to the RV) to objects watched. + + When `sendInitialEvents` option is set, we require `resourceVersionMatch` option to also be set. The semantic of the watch request is as following: - `resourceVersionMatch` = NotOlderThan + is interpreted as "data at least as new as the provided `resourceVersion`" + and the bookmark event is send when the state is synced + to a `resourceVersion` at least as fresh as the one provided by the ListOptions. + If `resourceVersion` is unset, this is interpreted as "consistent read" and the + bookmark event is send when the state is synced at least to the moment + when request started being processed. + - `resourceVersionMatch` set to any other value or unset + Invalid error is returned. + + Defaults to true if `resourceVersion=""` or `resourceVersion="0"` (for backward compatibility reasons) and to false otherwise. */ + sendInitialEvents?: boolean; + /** Timeout for the list/watch call. This limits the duration of the call, regardless of any activity or inactivity. */ + timeoutSeconds?: number; +}; +export type GetDashboardApiResponse = /** status 200 OK */ Dashboard; +export type GetDashboardApiArg = { + /** name of the Dashboard */ + name: string; + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; +}; +export type ReplaceDashboardApiResponse = /** status 200 OK */ Dashboard | /** status 201 Created */ Dashboard; +export type ReplaceDashboardApiArg = { + /** name of the Dashboard */ + name: string; + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; + /** When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed */ + dryRun?: string; + /** fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint. */ + fieldManager?: string; + /** fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields. Valid values are: - Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23. - Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default in v1.23+ - Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered. */ + fieldValidation?: string; + dashboard: Dashboard; +}; +export type DeleteDashboardApiResponse = /** status 200 OK */ Status | /** status 202 Accepted */ Status; +export type DeleteDashboardApiArg = { + /** name of the Dashboard */ + name: string; + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; + /** When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed */ + dryRun?: string; + /** The duration in seconds before the object should be deleted. Value must be non-negative integer. The value zero indicates delete immediately. If this value is nil, the default grace period for the specified type will be used. Defaults to a per object value if not specified. zero means delete immediately. */ + gracePeriodSeconds?: number; + /** if set to true, it will trigger an unsafe deletion of the resource in case the normal deletion flow fails with a corrupt object error. A resource is considered corrupt if it can not be retrieved from the underlying storage successfully because of a) its data can not be transformed e.g. decryption failure, or b) it fails to decode into an object. NOTE: unsafe deletion ignores finalizer constraints, skips precondition checks, and removes the object from the storage. WARNING: This may potentially break the cluster if the workload associated with the resource being unsafe-deleted relies on normal deletion flow. Use only if you REALLY know what you are doing. The default value is false, and the user must opt in to enable it */ + ignoreStoreReadErrorWithClusterBreakingPotential?: boolean; + /** Deprecated: please use the PropagationPolicy, this field will be deprecated in 1.7. Should the dependent objects be orphaned. If true/false, the "orphan" finalizer will be added to/removed from the object's finalizers list. Either this field or PropagationPolicy may be set, but not both. */ + orphanDependents?: boolean; + /** Whether and how garbage collection will be performed. Either this field or OrphanDependents may be set, but not both. The default policy is decided by the existing finalizer set in the metadata.finalizers and the resource-specific default policy. Acceptable values are: 'Orphan' - orphan the dependents; 'Background' - allow the garbage collector to delete the dependents in the background; 'Foreground' - a cascading policy that deletes all dependents in the foreground. */ + propagationPolicy?: string; +}; +export type UpdateDashboardApiResponse = /** status 200 OK */ Dashboard | /** status 201 Created */ Dashboard; +export type UpdateDashboardApiArg = { + /** name of the Dashboard */ + name: string; + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; + /** When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed */ + dryRun?: string; + /** fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint. This field is required for apply requests (application/apply-patch) but optional for non-apply patch types (JsonPatch, MergePatch, StrategicMergePatch). */ + fieldManager?: string; + /** fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields. Valid values are: - Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23. - Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default in v1.23+ - Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered. */ + fieldValidation?: string; + /** Force is going to "force" Apply requests. It means user will re-acquire conflicting fields owned by other people. Force flag must be unset for non-apply patch requests. */ + force?: boolean; + patch: Patch; +}; +export type GetDashboardDtoApiResponse = /** status 200 OK */ DashboardWithAccessInfo; +export type GetDashboardDtoApiArg = { + /** name of the DashboardWithAccessInfo */ + name: string; +}; +export type ListLibraryPanelApiResponse = /** status 200 OK */ LibraryPanelList; +export type ListLibraryPanelApiArg = { + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; + /** allowWatchBookmarks requests watch events with type "BOOKMARK". Servers that do not implement bookmarks may ignore this flag and bookmarks are sent at the server's discretion. Clients should not assume bookmarks are returned at any specific interval, nor may they assume the server will send any BOOKMARK event during a session. If this is not a watch, this field is ignored. */ + allowWatchBookmarks?: boolean; + /** The continue option should be set when retrieving more results from the server. Since this value is server defined, clients may only use the continue value from a previous query result with identical query parameters (except for the value of continue) and the server may reject a continue value it does not recognize. If the specified continue value is no longer valid whether due to expiration (generally five to fifteen minutes) or a configuration change on the server, the server will respond with a 410 ResourceExpired error together with a continue token. If the client needs a consistent list, it must restart their list without the continue field. Otherwise, the client may send another list request with the token received with the 410 error, the server will respond with a list starting from the next key, but from the latest snapshot, which is inconsistent from the previous list results - objects that are created, modified, or deleted after the first list request will be included in the response, as long as their keys are after the "next key". + + This field is not supported when watch is true. Clients may start a watch from the last resourceVersion value returned by the server and not miss any modifications. */ + continue?: string; + /** A selector to restrict the list of returned objects by their fields. Defaults to everything. */ + fieldSelector?: string; + /** A selector to restrict the list of returned objects by their labels. Defaults to everything. */ + labelSelector?: string; + /** limit is a maximum number of responses to return for a list call. If more items exist, the server will set the `continue` field on the list metadata to a value that can be used with the same initial query to retrieve the next set of results. Setting a limit may return fewer than the requested amount of items (up to zero items) in the event all requested objects are filtered out and clients should only use the presence of the continue field to determine whether more results are available. Servers may choose not to support the limit argument and will return all of the available results. If limit is specified and the continue field is empty, clients may assume that no more results are available. This field is not supported if watch is true. + + The server guarantees that the objects returned when using continue will be identical to issuing a single list call without a limit - that is, no objects created, modified, or deleted after the first request is issued will be included in any subsequent continued requests. This is sometimes referred to as a consistent snapshot, and ensures that a client that is using limit to receive smaller chunks of a very large result can ensure they see all possible objects. If objects are updated during a chunked list the version of the object that was present at the time the first list result was calculated is returned. */ + limit?: number; + /** resourceVersion sets a constraint on what resource versions a request may be served from. See https://kubernetes.io/docs/reference/using-api/api-concepts/#resource-versions for details. + + Defaults to unset */ + resourceVersion?: string; + /** resourceVersionMatch determines how resourceVersion is applied to list calls. It is highly recommended that resourceVersionMatch be set for list calls where resourceVersion is set See https://kubernetes.io/docs/reference/using-api/api-concepts/#resource-versions for details. + + Defaults to unset */ + resourceVersionMatch?: string; + /** `sendInitialEvents=true` may be set together with `watch=true`. In that case, the watch stream will begin with synthetic events to produce the current state of objects in the collection. Once all such events have been sent, a synthetic "Bookmark" event will be sent. The bookmark will report the ResourceVersion (RV) corresponding to the set of objects, and be marked with `"k8s.io/initial-events-end": "true"` annotation. Afterwards, the watch stream will proceed as usual, sending watch events corresponding to changes (subsequent to the RV) to objects watched. + + When `sendInitialEvents` option is set, we require `resourceVersionMatch` option to also be set. The semantic of the watch request is as following: - `resourceVersionMatch` = NotOlderThan + is interpreted as "data at least as new as the provided `resourceVersion`" + and the bookmark event is send when the state is synced + to a `resourceVersion` at least as fresh as the one provided by the ListOptions. + If `resourceVersion` is unset, this is interpreted as "consistent read" and the + bookmark event is send when the state is synced at least to the moment + when request started being processed. + - `resourceVersionMatch` set to any other value or unset + Invalid error is returned. + + Defaults to true if `resourceVersion=""` or `resourceVersion="0"` (for backward compatibility reasons) and to false otherwise. */ + sendInitialEvents?: boolean; + /** Timeout for the list/watch call. This limits the duration of the call, regardless of any activity or inactivity. */ + timeoutSeconds?: number; + /** Watch for changes to the described resources and return them as a stream of add, update, and remove notifications. Specify resourceVersion. */ + watch?: boolean; +}; +export type CreateLibraryPanelApiResponse = /** status 200 OK */ + | LibraryPanel + | /** status 201 Created */ LibraryPanel + | /** status 202 Accepted */ LibraryPanel; +export type CreateLibraryPanelApiArg = { + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; + /** When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed */ + dryRun?: string; + /** fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint. */ + fieldManager?: string; + /** fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields. Valid values are: - Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23. - Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default in v1.23+ - Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered. */ + fieldValidation?: string; + libraryPanel: LibraryPanel; +}; +export type DeletecollectionLibraryPanelApiResponse = /** status 200 OK */ Status; +export type DeletecollectionLibraryPanelApiArg = { + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; + /** The continue option should be set when retrieving more results from the server. Since this value is server defined, clients may only use the continue value from a previous query result with identical query parameters (except for the value of continue) and the server may reject a continue value it does not recognize. If the specified continue value is no longer valid whether due to expiration (generally five to fifteen minutes) or a configuration change on the server, the server will respond with a 410 ResourceExpired error together with a continue token. If the client needs a consistent list, it must restart their list without the continue field. Otherwise, the client may send another list request with the token received with the 410 error, the server will respond with a list starting from the next key, but from the latest snapshot, which is inconsistent from the previous list results - objects that are created, modified, or deleted after the first list request will be included in the response, as long as their keys are after the "next key". + + This field is not supported when watch is true. Clients may start a watch from the last resourceVersion value returned by the server and not miss any modifications. */ + continue?: string; + /** When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed */ + dryRun?: string; + /** A selector to restrict the list of returned objects by their fields. Defaults to everything. */ + fieldSelector?: string; + /** The duration in seconds before the object should be deleted. Value must be non-negative integer. The value zero indicates delete immediately. If this value is nil, the default grace period for the specified type will be used. Defaults to a per object value if not specified. zero means delete immediately. */ + gracePeriodSeconds?: number; + /** if set to true, it will trigger an unsafe deletion of the resource in case the normal deletion flow fails with a corrupt object error. A resource is considered corrupt if it can not be retrieved from the underlying storage successfully because of a) its data can not be transformed e.g. decryption failure, or b) it fails to decode into an object. NOTE: unsafe deletion ignores finalizer constraints, skips precondition checks, and removes the object from the storage. WARNING: This may potentially break the cluster if the workload associated with the resource being unsafe-deleted relies on normal deletion flow. Use only if you REALLY know what you are doing. The default value is false, and the user must opt in to enable it */ + ignoreStoreReadErrorWithClusterBreakingPotential?: boolean; + /** A selector to restrict the list of returned objects by their labels. Defaults to everything. */ + labelSelector?: string; + /** limit is a maximum number of responses to return for a list call. If more items exist, the server will set the `continue` field on the list metadata to a value that can be used with the same initial query to retrieve the next set of results. Setting a limit may return fewer than the requested amount of items (up to zero items) in the event all requested objects are filtered out and clients should only use the presence of the continue field to determine whether more results are available. Servers may choose not to support the limit argument and will return all of the available results. If limit is specified and the continue field is empty, clients may assume that no more results are available. This field is not supported if watch is true. + + The server guarantees that the objects returned when using continue will be identical to issuing a single list call without a limit - that is, no objects created, modified, or deleted after the first request is issued will be included in any subsequent continued requests. This is sometimes referred to as a consistent snapshot, and ensures that a client that is using limit to receive smaller chunks of a very large result can ensure they see all possible objects. If objects are updated during a chunked list the version of the object that was present at the time the first list result was calculated is returned. */ + limit?: number; + /** Deprecated: please use the PropagationPolicy, this field will be deprecated in 1.7. Should the dependent objects be orphaned. If true/false, the "orphan" finalizer will be added to/removed from the object's finalizers list. Either this field or PropagationPolicy may be set, but not both. */ + orphanDependents?: boolean; + /** Whether and how garbage collection will be performed. Either this field or OrphanDependents may be set, but not both. The default policy is decided by the existing finalizer set in the metadata.finalizers and the resource-specific default policy. Acceptable values are: 'Orphan' - orphan the dependents; 'Background' - allow the garbage collector to delete the dependents in the background; 'Foreground' - a cascading policy that deletes all dependents in the foreground. */ + propagationPolicy?: string; + /** resourceVersion sets a constraint on what resource versions a request may be served from. See https://kubernetes.io/docs/reference/using-api/api-concepts/#resource-versions for details. + + Defaults to unset */ + resourceVersion?: string; + /** resourceVersionMatch determines how resourceVersion is applied to list calls. It is highly recommended that resourceVersionMatch be set for list calls where resourceVersion is set See https://kubernetes.io/docs/reference/using-api/api-concepts/#resource-versions for details. + + Defaults to unset */ + resourceVersionMatch?: string; + /** `sendInitialEvents=true` may be set together with `watch=true`. In that case, the watch stream will begin with synthetic events to produce the current state of objects in the collection. Once all such events have been sent, a synthetic "Bookmark" event will be sent. The bookmark will report the ResourceVersion (RV) corresponding to the set of objects, and be marked with `"k8s.io/initial-events-end": "true"` annotation. Afterwards, the watch stream will proceed as usual, sending watch events corresponding to changes (subsequent to the RV) to objects watched. + + When `sendInitialEvents` option is set, we require `resourceVersionMatch` option to also be set. The semantic of the watch request is as following: - `resourceVersionMatch` = NotOlderThan + is interpreted as "data at least as new as the provided `resourceVersion`" + and the bookmark event is send when the state is synced + to a `resourceVersion` at least as fresh as the one provided by the ListOptions. + If `resourceVersion` is unset, this is interpreted as "consistent read" and the + bookmark event is send when the state is synced at least to the moment + when request started being processed. + - `resourceVersionMatch` set to any other value or unset + Invalid error is returned. + + Defaults to true if `resourceVersion=""` or `resourceVersion="0"` (for backward compatibility reasons) and to false otherwise. */ + sendInitialEvents?: boolean; + /** Timeout for the list/watch call. This limits the duration of the call, regardless of any activity or inactivity. */ + timeoutSeconds?: number; +}; +export type GetLibraryPanelApiResponse = /** status 200 OK */ LibraryPanel; +export type GetLibraryPanelApiArg = { + /** name of the LibraryPanel */ + name: string; + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; +}; +export type ReplaceLibraryPanelApiResponse = /** status 200 OK */ LibraryPanel | /** status 201 Created */ LibraryPanel; +export type ReplaceLibraryPanelApiArg = { + /** name of the LibraryPanel */ + name: string; + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; + /** When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed */ + dryRun?: string; + /** fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint. */ + fieldManager?: string; + /** fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields. Valid values are: - Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23. - Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default in v1.23+ - Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered. */ + fieldValidation?: string; + libraryPanel: LibraryPanel; +}; +export type DeleteLibraryPanelApiResponse = /** status 200 OK */ Status | /** status 202 Accepted */ Status; +export type DeleteLibraryPanelApiArg = { + /** name of the LibraryPanel */ + name: string; + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; + /** When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed */ + dryRun?: string; + /** The duration in seconds before the object should be deleted. Value must be non-negative integer. The value zero indicates delete immediately. If this value is nil, the default grace period for the specified type will be used. Defaults to a per object value if not specified. zero means delete immediately. */ + gracePeriodSeconds?: number; + /** if set to true, it will trigger an unsafe deletion of the resource in case the normal deletion flow fails with a corrupt object error. A resource is considered corrupt if it can not be retrieved from the underlying storage successfully because of a) its data can not be transformed e.g. decryption failure, or b) it fails to decode into an object. NOTE: unsafe deletion ignores finalizer constraints, skips precondition checks, and removes the object from the storage. WARNING: This may potentially break the cluster if the workload associated with the resource being unsafe-deleted relies on normal deletion flow. Use only if you REALLY know what you are doing. The default value is false, and the user must opt in to enable it */ + ignoreStoreReadErrorWithClusterBreakingPotential?: boolean; + /** Deprecated: please use the PropagationPolicy, this field will be deprecated in 1.7. Should the dependent objects be orphaned. If true/false, the "orphan" finalizer will be added to/removed from the object's finalizers list. Either this field or PropagationPolicy may be set, but not both. */ + orphanDependents?: boolean; + /** Whether and how garbage collection will be performed. Either this field or OrphanDependents may be set, but not both. The default policy is decided by the existing finalizer set in the metadata.finalizers and the resource-specific default policy. Acceptable values are: 'Orphan' - orphan the dependents; 'Background' - allow the garbage collector to delete the dependents in the background; 'Foreground' - a cascading policy that deletes all dependents in the foreground. */ + propagationPolicy?: string; +}; +export type UpdateLibraryPanelApiResponse = /** status 200 OK */ LibraryPanel | /** status 201 Created */ LibraryPanel; +export type UpdateLibraryPanelApiArg = { + /** name of the LibraryPanel */ + name: string; + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; + /** When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed */ + dryRun?: string; + /** fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint. This field is required for apply requests (application/apply-patch) but optional for non-apply patch types (JsonPatch, MergePatch, StrategicMergePatch). */ + fieldManager?: string; + /** fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields. Valid values are: - Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23. - Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default in v1.23+ - Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered. */ + fieldValidation?: string; + /** Force is going to "force" Apply requests. It means user will re-acquire conflicting fields owned by other people. Force flag must be unset for non-apply patch requests. */ + force?: boolean; + patch: Patch; +}; export type GetSearchApiResponse = /** status 200 undefined */ SearchResults; export type GetSearchApiArg = { /** user query string */ @@ -45,6 +615,390 @@ export type GetSearchApiArg = { /** add debugging info that may help explain why the result matched */ explain?: boolean; }; +export type GetSearchSortableApiResponse = /** status 200 undefined */ { + /** APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources */ + apiVersion?: string; + /** Sortable fields (depends on backend support) */ + fields: any[]; + /** Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds */ + kind?: string; +}; +export type GetSearchSortableApiArg = void; +export type ApiResource = { + /** categories is a list of the grouped resources this resource belongs to (e.g. 'all') */ + categories?: string[]; + /** group is the preferred group of the resource. Empty implies the group of the containing resource list. For subresources, this may have a different value, for example: Scale". */ + group?: string; + /** kind is the kind for the resource (e.g. 'Foo' is the kind for a resource 'foo') */ + kind: string; + /** name is the plural name of the resource. */ + name: string; + /** namespaced indicates if a resource is namespaced or not. */ + namespaced: boolean; + /** shortNames is a list of suggested short names of the resource. */ + shortNames?: string[]; + /** singularName is the singular name of the resource. This allows clients to handle plural and singular opaquely. The singularName is more correct for reporting status on a single item and both singular and plural are allowed from the kubectl CLI interface. */ + singularName: string; + /** The hash value of the storage version, the version this resource is converted to when written to the data store. Value must be treated as opaque by clients. Only equality comparison on the value is valid. This is an alpha feature and may change or be removed in the future. The field is populated by the apiserver only if the StorageVersionHash feature gate is enabled. This field will remain optional even if it graduates. */ + storageVersionHash?: string; + /** verbs is a list of supported kube verbs (this includes get, list, watch, create, update, patch, delete, deletecollection, and proxy) */ + verbs: string[]; + /** version is the preferred version of the resource. Empty implies the version of the containing resource list For subresources, this may have a different value, for example: v1 (while inside a v1beta1 version of the core resource's group)". */ + version?: string; +}; +export type ApiResourceList = { + /** APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources */ + apiVersion?: string; + /** groupVersion is the group and version this APIResourceList is for. */ + groupVersion: string; + /** Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds */ + kind?: string; + /** resources contains the name of the resources and if they are namespaced. */ + resources: ApiResource[]; +}; +export type Time = string; +export type FieldsV1 = object; +export type ManagedFieldsEntry = { + /** APIVersion defines the version of this resource that this field set applies to. The format is "group/version" just like the top-level APIVersion field. It is necessary to track the version of a field set because it cannot be automatically converted. */ + apiVersion?: string; + /** FieldsType is the discriminator for the different fields format and version. There is currently only one possible value: "FieldsV1" */ + fieldsType?: string; + /** FieldsV1 holds the first JSON version format as described in the "FieldsV1" type. */ + fieldsV1?: FieldsV1; + /** Manager is an identifier of the workflow managing these fields. */ + manager?: string; + /** Operation is the type of operation which lead to this ManagedFieldsEntry being created. The only valid values for this field are 'Apply' and 'Update'. */ + operation?: string; + /** Subresource is the name of the subresource used to update that object, or empty string if the object was updated through the main resource. The value of this field is used to distinguish between managers, even if they share the same name. For example, a status update will be distinct from a regular update using the same manager name. Note that the APIVersion field is not related to the Subresource field and it always corresponds to the version of the main resource. */ + subresource?: string; + /** Time is the timestamp of when the ManagedFields entry was added. The timestamp will also be updated if a field is added, the manager changes any of the owned fields value or removes a field. The timestamp does not update when a field is removed from the entry because another manager took it over. */ + time?: Time; +}; +export type OwnerReference = { + /** API version of the referent. */ + apiVersion: string; + /** If true, AND if the owner has the "foregroundDeletion" finalizer, then the owner cannot be deleted from the key-value store until this reference is removed. See https://kubernetes.io/docs/concepts/architecture/garbage-collection/#foreground-deletion for how the garbage collector interacts with this field and enforces the foreground deletion. Defaults to false. To set this field, a user needs "delete" permission of the owner, otherwise 422 (Unprocessable Entity) will be returned. */ + blockOwnerDeletion?: boolean; + /** If true, this reference points to the managing controller. */ + controller?: boolean; + /** Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds */ + kind: string; + /** Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names */ + name: string; + /** UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#uids */ + uid: string; +}; +export type ObjectMeta = { + /** Annotations is an unstructured key value map stored with a resource that may be set by external tools to store and retrieve arbitrary metadata. They are not queryable and should be preserved when modifying objects. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations */ + annotations?: { + [key: string]: string; + }; + /** CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. + + Populated by the system. Read-only. Null for lists. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata */ + creationTimestamp?: Time; + /** Number of seconds allowed for this object to gracefully terminate before it will be removed from the system. Only set when deletionTimestamp is also set. May only be shortened. Read-only. */ + deletionGracePeriodSeconds?: number; + /** DeletionTimestamp is RFC 3339 date and time at which this resource will be deleted. This field is set by the server when a graceful deletion is requested by the user, and is not directly settable by a client. The resource is expected to be deleted (no longer visible from resource lists, and not reachable by name) after the time in this field, once the finalizers list is empty. As long as the finalizers list contains items, deletion is blocked. Once the deletionTimestamp is set, this value may not be unset or be set further into the future, although it may be shortened or the resource may be deleted prior to this time. For example, a user may request that a pod is deleted in 30 seconds. The Kubelet will react by sending a graceful termination signal to the containers in the pod. After that 30 seconds, the Kubelet will send a hard termination signal (SIGKILL) to the container and after cleanup, remove the pod from the API. In the presence of network partitions, this object may still exist after this timestamp, until an administrator or automated process can determine the resource is fully terminated. If not set, graceful deletion of the object has not been requested. + + Populated by the system when a graceful deletion is requested. Read-only. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata */ + deletionTimestamp?: Time; + /** Must be empty before the object is deleted from the registry. Each entry is an identifier for the responsible component that will remove the entry from the list. If the deletionTimestamp of the object is non-nil, entries in this list can only be removed. Finalizers may be processed and removed in any order. Order is NOT enforced because it introduces significant risk of stuck finalizers. finalizers is a shared field, any actor with permission can reorder it. If the finalizer list is processed in order, then this can lead to a situation in which the component responsible for the first finalizer in the list is waiting for a signal (field value, external system, or other) produced by a component responsible for a finalizer later in the list, resulting in a deadlock. Without enforced ordering finalizers are free to order amongst themselves and are not vulnerable to ordering changes in the list. */ + finalizers?: string[]; + /** GenerateName is an optional prefix, used by the server, to generate a unique name ONLY IF the Name field has not been provided. If this field is used, the name returned to the client will be different than the name passed. This value will also be combined with a unique suffix. The provided value has the same validation rules as the Name field, and may be truncated by the length of the suffix required to make the value unique on the server. + + If this field is specified and the generated name exists, the server will return a 409. + + Applied only if Name is not specified. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#idempotency */ + generateName?: string; + /** A sequence number representing a specific generation of the desired state. Populated by the system. Read-only. */ + generation?: number; + /** Map of string keys and values that can be used to organize and categorize (scope and select) objects. May match selectors of replication controllers and services. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels */ + labels?: { + [key: string]: string; + }; + /** ManagedFields maps workflow-id and version to the set of fields that are managed by that workflow. This is mostly for internal housekeeping, and users typically shouldn't need to set or understand this field. A workflow can be the user's name, a controller's name, or the name of a specific apply path like "ci-cd". The set of fields is always in the version that the workflow used when modifying the object. */ + managedFields?: ManagedFieldsEntry[]; + /** Name must be unique within a namespace. Is required when creating resources, although some resources may allow a client to request the generation of an appropriate name automatically. Name is primarily intended for creation idempotence and configuration definition. Cannot be updated. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names */ + name?: string; + /** Namespace defines the space within which each name must be unique. An empty namespace is equivalent to the "default" namespace, but "default" is the canonical representation. Not all objects are required to be scoped to a namespace - the value of this field for those objects will be empty. + + Must be a DNS_LABEL. Cannot be updated. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces */ + namespace?: string; + /** List of objects depended by this object. If ALL objects in the list have been deleted, this object will be garbage collected. If this object is managed by a controller, then an entry in this list will point to this controller, with the controller field set to true. There cannot be more than one managing controller. */ + ownerReferences?: OwnerReference[]; + /** An opaque value that represents the internal version of this object that can be used by clients to determine when objects have changed. May be used for optimistic concurrency, change detection, and the watch operation on a resource or set of resources. Clients must treat these values as opaque and passed unmodified back to the server. They may only be valid for a particular resource or set of resources. + + Populated by the system. Read-only. Value must be treated as opaque by clients and . More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency */ + resourceVersion?: string; + /** Deprecated: selfLink is a legacy read-only field that is no longer populated by the system. */ + selfLink?: string; + /** UID is the unique in time and space value for this object. It is typically generated by the server on successful creation of a resource and is not allowed to change on PUT operations. + + Populated by the system. Read-only. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#uids */ + uid?: string; +}; +export type Unstructured = { + [key: string]: any; +}; +export type DashboardConversionStatus = { + /** The error message from the conversion. Empty if the conversion has not failed. */ + error?: string; + /** Whether from another version has failed. If true, means that the dashboard is not valid, and the caller should instead fetch the stored version. */ + failed: boolean; + /** The original value map[string]any */ + source?: object; + /** The version which was stored when the dashboard was created / updated. Fetching this version should always succeed. */ + storedVersion?: string; +}; +export type DashboardStatus = { + /** Optional conversion status. */ + conversion?: DashboardConversionStatus; +}; +export type Dashboard = { + /** APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources */ + apiVersion?: string; + /** Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds */ + kind?: string; + metadata: ObjectMeta; + /** Spec is the spec of the Dashboard */ + spec: Unstructured; + status: DashboardStatus; +}; +export type ListMeta = { + /** continue may be set if the user set a limit on the number of items returned, and indicates that the server has more data available. The value is opaque and may be used to issue another request to the endpoint that served this list to retrieve the next set of available objects. Continuing a consistent list may not be possible if the server configuration has changed or more than a few minutes have passed. The resourceVersion field returned when using this continue value will be identical to the value in the first response, unless you have received this token from an error message. */ + continue?: string; + /** remainingItemCount is the number of subsequent items in the list which are not included in this list response. If the list request contained label or field selectors, then the number of remaining items is unknown and the field will be left unset and omitted during serialization. If the list is complete (either because it is not chunking or because this is the last chunk), then there are no more remaining items and this field will be left unset and omitted during serialization. Servers older than v1.15 do not set this field. The intended use of the remainingItemCount is *estimating* the size of a collection. Clients should not rely on the remainingItemCount to be set or to be exact. */ + remainingItemCount?: number; + /** String that identifies the server's internal version of this object that can be used by clients to determine when objects have changed. Value must be treated as opaque by clients and passed unmodified back to the server. Populated by the system. Read-only. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency */ + resourceVersion?: string; + /** Deprecated: selfLink is a legacy read-only field that is no longer populated by the system. */ + selfLink?: string; +}; +export type DashboardList = { + /** APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources */ + apiVersion?: string; + items: Dashboard[]; + /** Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds */ + kind?: string; + metadata: ListMeta; +}; +export type StatusCause = { + /** The field of the resource that has caused this error, as named by its JSON serialization. May include dot and postfix notation for nested attributes. Arrays are zero-indexed. Fields may appear more than once in an array of causes due to fields having multiple errors. Optional. + + Examples: + "name" - the field "name" on the current resource + "items[0].name" - the field "name" on the first array entry in "items" */ + field?: string; + /** A human-readable description of the cause of the error. This field may be presented as-is to a reader. */ + message?: string; + /** A machine-readable description of the cause of the error. If this value is empty there is no information available. */ + reason?: string; +}; +export type StatusDetails = { + /** The Causes array includes more details associated with the StatusReason failure. Not all StatusReasons may provide detailed causes. */ + causes?: StatusCause[]; + /** The group attribute of the resource associated with the status StatusReason. */ + group?: string; + /** The kind attribute of the resource associated with the status StatusReason. On some operations may differ from the requested resource Kind. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds */ + kind?: string; + /** The name attribute of the resource associated with the status StatusReason (when there is a single name which can be described). */ + name?: string; + /** If specified, the time in seconds before the operation should be retried. Some errors may indicate the client must take an alternate action - for those errors this field may indicate how long to wait before taking the alternate action. */ + retryAfterSeconds?: number; + /** UID of the resource. (when there is a single resource which can be described). More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#uids */ + uid?: string; +}; +export type Status = { + /** APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources */ + apiVersion?: string; + /** Suggested HTTP return code for this status, 0 if not set. */ + code?: number; + /** Extended data associated with the reason. Each reason may define its own extended details. This field is optional and the data returned is not guaranteed to conform to any schema except that defined by the reason type. */ + details?: StatusDetails; + /** Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds */ + kind?: string; + /** A human-readable description of the status of this operation. */ + message?: string; + /** Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds */ + metadata?: ListMeta; + /** A machine-readable description of why this operation is in the "Failure" status. If this value is empty there is no information available. A Reason clarifies an HTTP status code but does not override it. */ + reason?: string; + /** Status of the operation. One of: "Success" or "Failure". More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status */ + status?: string; +}; +export type Patch = object; +export type AnnotationActions = { + canAdd: boolean; + canDelete: boolean; + canEdit: boolean; +}; +export type AnnotationPermission = { + dashboard: AnnotationActions; + organization: AnnotationActions; +}; +export type DashboardAccess = { + annotationsPermissions: AnnotationPermission; + canAdmin: boolean; + canDelete: boolean; + canEdit: boolean; + /** The permissions part */ + canSave: boolean; + canStar: boolean; + /** Metadata fields */ + slug?: string; + url?: string; +}; +export type DashboardWithAccessInfo = { + access: DashboardAccess; + /** APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources */ + apiVersion?: string; + /** Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds */ + kind?: string; + metadata: ObjectMeta; + /** Spec is the spec of the Dashboard */ + spec: Unstructured; + status: DashboardStatus; +}; +export type DataSourceRef = { + /** The apiserver version */ + apiVersion?: string; + /** The datasource plugin type */ + type: string; + /** Datasource UID (NOTE: name in k8s) */ + uid?: string; +}; +export type GridPos = { + h: number; + w: number; + x: number; + y: number; +}; +export type DataQuery = { + /** The datasource */ + datasource?: { + /** The apiserver version */ + apiVersion?: string; + /** The datasource plugin type */ + type: string; + /** Datasource UID (NOTE: name in k8s) */ + uid?: string; + }; + /** true if query is disabled (ie should not be returned to the dashboard) + NOTE: this does not always imply that the query should not be executed since + the results from a hidden query may be used as the input to other queries (SSE etc) */ + hide?: boolean; + /** Interval is the suggested duration between time points in a time series query. + NOTE: the values for intervalMs is not saved in the query model. It is typically calculated + from the interval required to fill a pixels in the visualization */ + intervalMs?: number; + /** MaxDataPoints is the maximum number of data points that should be returned from a time series query. + NOTE: the values for maxDataPoints is not saved in the query model. It is typically calculated + from the number of pixels visible in a visualization */ + maxDataPoints?: number; + /** QueryType is an optional identifier for the type of query. + It can be used to distinguish different types of queries. */ + queryType?: string; + /** RefID is the unique identifier of the query, set by the frontend call. */ + refId?: string; + /** Optionally define expected query result behavior */ + resultAssertions?: { + /** Maximum frame count */ + maxFrames?: number; + /** Type asserts that the frame matches a known type structure. + + + Possible enum values: + - `""` + - `"timeseries-wide"` + - `"timeseries-long"` + - `"timeseries-many"` + - `"timeseries-multi"` + - `"directory-listing"` + - `"table"` + - `"numeric-wide"` + - `"numeric-multi"` + - `"numeric-long"` + - `"log-lines"` */ + type?: + | '' + | 'timeseries-wide' + | 'timeseries-long' + | 'timeseries-many' + | 'timeseries-multi' + | 'directory-listing' + | 'table' + | 'numeric-wide' + | 'numeric-multi' + | 'numeric-long' + | 'log-lines'; + /** TypeVersion is the version of the Type property. Versions greater than 0.0 correspond to the dataplane + contract documentation https://grafana.github.io/dataplane/contract/. */ + typeVersion: number[]; + }; + /** TimeRange represents the query range + NOTE: unlike generic /ds/query, we can now send explicit time values in each query + NOTE: the values for timeRange are not saved in a dashboard, they are constructed on the fly */ + timeRange?: { + /** From is the start time of the query. */ + from: string; + /** To is the end time of the query. */ + to: string; + }; + [key: string]: any; +}; +export type LibraryPanelSpec = { + /** The default datasource type */ + datasource?: DataSourceRef; + /** Library panel description */ + description?: string; + /** The fieldConfig schema depends on the panel type */ + fieldConfig: Unstructured; + /** The grid position */ + gridPos?: GridPos; + /** The links for the panel */ + links?: Unstructured[]; + /** The options schema depends on the panel type */ + options: Unstructured; + /** The title of the panel when displayed in the dashboard */ + panelTitle?: string; + /** The panel type */ + pluginVersion?: string; + /** The datasource queries */ + targets?: DataQuery[]; + /** The title of the library panel */ + title?: string; + /** Whether the panel is transparent */ + transparent?: boolean; + /** The panel type */ + type: string; +}; +export type LibraryPanelStatus = { + /** The properties previously stored in SQL that are not included in this model */ + missing?: Unstructured; + /** Translation warnings (mostly things that were in SQL columns but not found in the saved body) */ + warnings?: string[]; +}; +export type LibraryPanel = { + /** APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources */ + apiVersion?: string; + /** Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds */ + kind?: string; + /** Standard object's metadata More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata */ + metadata?: ObjectMeta; + /** Panel properties */ + spec: LibraryPanelSpec; + /** Status will show errors */ + status?: LibraryPanelStatus; +}; +export type LibraryPanelList = { + /** APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources */ + apiVersion?: string; + items: LibraryPanel[]; + /** Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds */ + kind?: string; + metadata?: ListMeta; +}; export type TermFacet = { count?: number; term?: string; @@ -105,3 +1059,23 @@ export type SearchResults = { /** The number of matching results */ totalHits: number; }; +export const { + useGetApiResourcesQuery, + useListDashboardQuery, + useCreateDashboardMutation, + useDeletecollectionDashboardMutation, + useGetDashboardQuery, + useReplaceDashboardMutation, + useDeleteDashboardMutation, + useUpdateDashboardMutation, + useGetDashboardDtoQuery, + useListLibraryPanelQuery, + useCreateLibraryPanelMutation, + useDeletecollectionLibraryPanelMutation, + useGetLibraryPanelQuery, + useReplaceLibraryPanelMutation, + useDeleteLibraryPanelMutation, + useUpdateLibraryPanelMutation, + useGetSearchQuery, + useGetSearchSortableQuery, +} = injectedRtkApi; diff --git a/packages/grafana-api-clients/src/clients/rtkq/folder/v1beta1/endpoints.gen.ts b/packages/grafana-api-clients/src/clients/rtkq/folder/v1beta1/endpoints.gen.ts index ae8bba67c4b..b618f8b335a 100644 --- a/packages/grafana-api-clients/src/clients/rtkq/folder/v1beta1/endpoints.gen.ts +++ b/packages/grafana-api-clients/src/clients/rtkq/folder/v1beta1/endpoints.gen.ts @@ -560,3 +560,17 @@ export type FolderInfoList = { kind?: string; metadata?: ListMeta; }; +export const { + useGetApiResourcesQuery, + useListFolderQuery, + useCreateFolderMutation, + useDeletecollectionFolderMutation, + useGetFolderQuery, + useReplaceFolderMutation, + useDeleteFolderMutation, + useUpdateFolderMutation, + useGetFolderAccessQuery, + useGetFolderChildrenQuery, + useGetFolderCountsQuery, + useGetFolderParentsQuery, +} = injectedRtkApi; diff --git a/packages/grafana-api-clients/src/clients/rtkq/iam/v0alpha1/endpoints.gen.ts b/packages/grafana-api-clients/src/clients/rtkq/iam/v0alpha1/endpoints.gen.ts index d59b1d4cd52..bd1585fc928 100644 --- a/packages/grafana-api-clients/src/clients/rtkq/iam/v0alpha1/endpoints.gen.ts +++ b/packages/grafana-api-clients/src/clients/rtkq/iam/v0alpha1/endpoints.gen.ts @@ -1,11 +1,23 @@ import { api } from './baseAPI'; -export const addTagTypes = ['Display'] as const; +export const addTagTypes = [ + 'API Discovery', + 'Display', + 'ServiceAccount', + 'SSOSetting', + 'TeamBinding', + 'Team', + 'User', +] as const; const injectedRtkApi = api .enhanceEndpoints({ addTagTypes, }) .injectEndpoints({ endpoints: (build) => ({ + getApiResources: build.query({ + query: () => ({ url: `/apis/iam.grafana.app/v0alpha1/` }), + providesTags: ['API Discovery'], + }), getDisplayMapping: build.query({ query: (queryArg) => ({ url: `/display`, @@ -15,15 +27,1353 @@ const injectedRtkApi = api }), providesTags: ['Display'], }), + listServiceAccount: build.query({ + query: (queryArg) => ({ + url: `/serviceaccounts`, + params: { + pretty: queryArg.pretty, + allowWatchBookmarks: queryArg.allowWatchBookmarks, + continue: queryArg['continue'], + fieldSelector: queryArg.fieldSelector, + labelSelector: queryArg.labelSelector, + limit: queryArg.limit, + resourceVersion: queryArg.resourceVersion, + resourceVersionMatch: queryArg.resourceVersionMatch, + sendInitialEvents: queryArg.sendInitialEvents, + timeoutSeconds: queryArg.timeoutSeconds, + watch: queryArg.watch, + }, + }), + providesTags: ['ServiceAccount'], + }), + createServiceAccount: build.mutation({ + query: (queryArg) => ({ + url: `/serviceaccounts`, + method: 'POST', + body: queryArg.serviceAccount, + params: { + pretty: queryArg.pretty, + dryRun: queryArg.dryRun, + fieldManager: queryArg.fieldManager, + fieldValidation: queryArg.fieldValidation, + }, + }), + invalidatesTags: ['ServiceAccount'], + }), + deletecollectionServiceAccount: build.mutation< + DeletecollectionServiceAccountApiResponse, + DeletecollectionServiceAccountApiArg + >({ + query: (queryArg) => ({ + url: `/serviceaccounts`, + method: 'DELETE', + params: { + pretty: queryArg.pretty, + continue: queryArg['continue'], + dryRun: queryArg.dryRun, + fieldSelector: queryArg.fieldSelector, + gracePeriodSeconds: queryArg.gracePeriodSeconds, + ignoreStoreReadErrorWithClusterBreakingPotential: queryArg.ignoreStoreReadErrorWithClusterBreakingPotential, + labelSelector: queryArg.labelSelector, + limit: queryArg.limit, + orphanDependents: queryArg.orphanDependents, + propagationPolicy: queryArg.propagationPolicy, + resourceVersion: queryArg.resourceVersion, + resourceVersionMatch: queryArg.resourceVersionMatch, + sendInitialEvents: queryArg.sendInitialEvents, + timeoutSeconds: queryArg.timeoutSeconds, + }, + }), + invalidatesTags: ['ServiceAccount'], + }), + getServiceAccount: build.query({ + query: (queryArg) => ({ + url: `/serviceaccounts/${queryArg.name}`, + params: { + pretty: queryArg.pretty, + }, + }), + providesTags: ['ServiceAccount'], + }), + replaceServiceAccount: build.mutation({ + query: (queryArg) => ({ + url: `/serviceaccounts/${queryArg.name}`, + method: 'PUT', + body: queryArg.serviceAccount, + params: { + pretty: queryArg.pretty, + dryRun: queryArg.dryRun, + fieldManager: queryArg.fieldManager, + fieldValidation: queryArg.fieldValidation, + }, + }), + invalidatesTags: ['ServiceAccount'], + }), + deleteServiceAccount: build.mutation({ + query: (queryArg) => ({ + url: `/serviceaccounts/${queryArg.name}`, + method: 'DELETE', + params: { + pretty: queryArg.pretty, + dryRun: queryArg.dryRun, + gracePeriodSeconds: queryArg.gracePeriodSeconds, + ignoreStoreReadErrorWithClusterBreakingPotential: queryArg.ignoreStoreReadErrorWithClusterBreakingPotential, + orphanDependents: queryArg.orphanDependents, + propagationPolicy: queryArg.propagationPolicy, + }, + }), + invalidatesTags: ['ServiceAccount'], + }), + updateServiceAccount: build.mutation({ + query: (queryArg) => ({ + url: `/serviceaccounts/${queryArg.name}`, + method: 'PATCH', + body: queryArg.patch, + params: { + pretty: queryArg.pretty, + dryRun: queryArg.dryRun, + fieldManager: queryArg.fieldManager, + fieldValidation: queryArg.fieldValidation, + force: queryArg.force, + }, + }), + invalidatesTags: ['ServiceAccount'], + }), + getServiceAccountTokens: build.query({ + query: (queryArg) => ({ url: `/serviceaccounts/${queryArg.name}/tokens` }), + providesTags: ['ServiceAccount'], + }), + listSsoSetting: build.query({ + query: (queryArg) => ({ + url: `/ssosettings`, + params: { + allowWatchBookmarks: queryArg.allowWatchBookmarks, + continue: queryArg['continue'], + fieldSelector: queryArg.fieldSelector, + labelSelector: queryArg.labelSelector, + limit: queryArg.limit, + pretty: queryArg.pretty, + resourceVersion: queryArg.resourceVersion, + resourceVersionMatch: queryArg.resourceVersionMatch, + sendInitialEvents: queryArg.sendInitialEvents, + timeoutSeconds: queryArg.timeoutSeconds, + watch: queryArg.watch, + }, + }), + providesTags: ['SSOSetting'], + }), + getSsoSetting: build.query({ + query: (queryArg) => ({ + url: `/ssosettings/${queryArg.name}`, + params: { + pretty: queryArg.pretty, + }, + }), + providesTags: ['SSOSetting'], + }), + replaceSsoSetting: build.mutation({ + query: (queryArg) => ({ + url: `/ssosettings/${queryArg.name}`, + method: 'PUT', + body: queryArg.ssoSetting, + params: { + pretty: queryArg.pretty, + dryRun: queryArg.dryRun, + fieldManager: queryArg.fieldManager, + fieldValidation: queryArg.fieldValidation, + }, + }), + invalidatesTags: ['SSOSetting'], + }), + deleteSsoSetting: build.mutation({ + query: (queryArg) => ({ + url: `/ssosettings/${queryArg.name}`, + method: 'DELETE', + params: { + pretty: queryArg.pretty, + dryRun: queryArg.dryRun, + gracePeriodSeconds: queryArg.gracePeriodSeconds, + ignoreStoreReadErrorWithClusterBreakingPotential: queryArg.ignoreStoreReadErrorWithClusterBreakingPotential, + orphanDependents: queryArg.orphanDependents, + propagationPolicy: queryArg.propagationPolicy, + }, + }), + invalidatesTags: ['SSOSetting'], + }), + updateSsoSetting: build.mutation({ + query: (queryArg) => ({ + url: `/ssosettings/${queryArg.name}`, + method: 'PATCH', + body: queryArg.patch, + params: { + pretty: queryArg.pretty, + dryRun: queryArg.dryRun, + fieldManager: queryArg.fieldManager, + fieldValidation: queryArg.fieldValidation, + force: queryArg.force, + }, + }), + invalidatesTags: ['SSOSetting'], + }), + listTeamBinding: build.query({ + query: (queryArg) => ({ + url: `/teambindings`, + params: { + pretty: queryArg.pretty, + allowWatchBookmarks: queryArg.allowWatchBookmarks, + continue: queryArg['continue'], + fieldSelector: queryArg.fieldSelector, + labelSelector: queryArg.labelSelector, + limit: queryArg.limit, + resourceVersion: queryArg.resourceVersion, + resourceVersionMatch: queryArg.resourceVersionMatch, + sendInitialEvents: queryArg.sendInitialEvents, + timeoutSeconds: queryArg.timeoutSeconds, + watch: queryArg.watch, + }, + }), + providesTags: ['TeamBinding'], + }), + createTeamBinding: build.mutation({ + query: (queryArg) => ({ + url: `/teambindings`, + method: 'POST', + body: queryArg.teamBinding, + params: { + pretty: queryArg.pretty, + dryRun: queryArg.dryRun, + fieldManager: queryArg.fieldManager, + fieldValidation: queryArg.fieldValidation, + }, + }), + invalidatesTags: ['TeamBinding'], + }), + deletecollectionTeamBinding: build.mutation< + DeletecollectionTeamBindingApiResponse, + DeletecollectionTeamBindingApiArg + >({ + query: (queryArg) => ({ + url: `/teambindings`, + method: 'DELETE', + params: { + pretty: queryArg.pretty, + continue: queryArg['continue'], + dryRun: queryArg.dryRun, + fieldSelector: queryArg.fieldSelector, + gracePeriodSeconds: queryArg.gracePeriodSeconds, + ignoreStoreReadErrorWithClusterBreakingPotential: queryArg.ignoreStoreReadErrorWithClusterBreakingPotential, + labelSelector: queryArg.labelSelector, + limit: queryArg.limit, + orphanDependents: queryArg.orphanDependents, + propagationPolicy: queryArg.propagationPolicy, + resourceVersion: queryArg.resourceVersion, + resourceVersionMatch: queryArg.resourceVersionMatch, + sendInitialEvents: queryArg.sendInitialEvents, + timeoutSeconds: queryArg.timeoutSeconds, + }, + }), + invalidatesTags: ['TeamBinding'], + }), + getTeamBinding: build.query({ + query: (queryArg) => ({ + url: `/teambindings/${queryArg.name}`, + params: { + pretty: queryArg.pretty, + }, + }), + providesTags: ['TeamBinding'], + }), + replaceTeamBinding: build.mutation({ + query: (queryArg) => ({ + url: `/teambindings/${queryArg.name}`, + method: 'PUT', + body: queryArg.teamBinding, + params: { + pretty: queryArg.pretty, + dryRun: queryArg.dryRun, + fieldManager: queryArg.fieldManager, + fieldValidation: queryArg.fieldValidation, + }, + }), + invalidatesTags: ['TeamBinding'], + }), + deleteTeamBinding: build.mutation({ + query: (queryArg) => ({ + url: `/teambindings/${queryArg.name}`, + method: 'DELETE', + params: { + pretty: queryArg.pretty, + dryRun: queryArg.dryRun, + gracePeriodSeconds: queryArg.gracePeriodSeconds, + ignoreStoreReadErrorWithClusterBreakingPotential: queryArg.ignoreStoreReadErrorWithClusterBreakingPotential, + orphanDependents: queryArg.orphanDependents, + propagationPolicy: queryArg.propagationPolicy, + }, + }), + invalidatesTags: ['TeamBinding'], + }), + updateTeamBinding: build.mutation({ + query: (queryArg) => ({ + url: `/teambindings/${queryArg.name}`, + method: 'PATCH', + body: queryArg.patch, + params: { + pretty: queryArg.pretty, + dryRun: queryArg.dryRun, + fieldManager: queryArg.fieldManager, + fieldValidation: queryArg.fieldValidation, + force: queryArg.force, + }, + }), + invalidatesTags: ['TeamBinding'], + }), + listTeam: build.query({ + query: (queryArg) => ({ + url: `/teams`, + params: { + pretty: queryArg.pretty, + allowWatchBookmarks: queryArg.allowWatchBookmarks, + continue: queryArg['continue'], + fieldSelector: queryArg.fieldSelector, + labelSelector: queryArg.labelSelector, + limit: queryArg.limit, + resourceVersion: queryArg.resourceVersion, + resourceVersionMatch: queryArg.resourceVersionMatch, + sendInitialEvents: queryArg.sendInitialEvents, + timeoutSeconds: queryArg.timeoutSeconds, + watch: queryArg.watch, + }, + }), + providesTags: ['Team'], + }), + createTeam: build.mutation({ + query: (queryArg) => ({ + url: `/teams`, + method: 'POST', + body: queryArg.team, + params: { + pretty: queryArg.pretty, + dryRun: queryArg.dryRun, + fieldManager: queryArg.fieldManager, + fieldValidation: queryArg.fieldValidation, + }, + }), + invalidatesTags: ['Team'], + }), + deletecollectionTeam: build.mutation({ + query: (queryArg) => ({ + url: `/teams`, + method: 'DELETE', + params: { + pretty: queryArg.pretty, + continue: queryArg['continue'], + dryRun: queryArg.dryRun, + fieldSelector: queryArg.fieldSelector, + gracePeriodSeconds: queryArg.gracePeriodSeconds, + ignoreStoreReadErrorWithClusterBreakingPotential: queryArg.ignoreStoreReadErrorWithClusterBreakingPotential, + labelSelector: queryArg.labelSelector, + limit: queryArg.limit, + orphanDependents: queryArg.orphanDependents, + propagationPolicy: queryArg.propagationPolicy, + resourceVersion: queryArg.resourceVersion, + resourceVersionMatch: queryArg.resourceVersionMatch, + sendInitialEvents: queryArg.sendInitialEvents, + timeoutSeconds: queryArg.timeoutSeconds, + }, + }), + invalidatesTags: ['Team'], + }), + getTeam: build.query({ + query: (queryArg) => ({ + url: `/teams/${queryArg.name}`, + params: { + pretty: queryArg.pretty, + }, + }), + providesTags: ['Team'], + }), + replaceTeam: build.mutation({ + query: (queryArg) => ({ + url: `/teams/${queryArg.name}`, + method: 'PUT', + body: queryArg.team, + params: { + pretty: queryArg.pretty, + dryRun: queryArg.dryRun, + fieldManager: queryArg.fieldManager, + fieldValidation: queryArg.fieldValidation, + }, + }), + invalidatesTags: ['Team'], + }), + deleteTeam: build.mutation({ + query: (queryArg) => ({ + url: `/teams/${queryArg.name}`, + method: 'DELETE', + params: { + pretty: queryArg.pretty, + dryRun: queryArg.dryRun, + gracePeriodSeconds: queryArg.gracePeriodSeconds, + ignoreStoreReadErrorWithClusterBreakingPotential: queryArg.ignoreStoreReadErrorWithClusterBreakingPotential, + orphanDependents: queryArg.orphanDependents, + propagationPolicy: queryArg.propagationPolicy, + }, + }), + invalidatesTags: ['Team'], + }), + updateTeam: build.mutation({ + query: (queryArg) => ({ + url: `/teams/${queryArg.name}`, + method: 'PATCH', + body: queryArg.patch, + params: { + pretty: queryArg.pretty, + dryRun: queryArg.dryRun, + fieldManager: queryArg.fieldManager, + fieldValidation: queryArg.fieldValidation, + force: queryArg.force, + }, + }), + invalidatesTags: ['Team'], + }), + getTeamMembers: build.query({ + query: (queryArg) => ({ url: `/teams/${queryArg.name}/members` }), + providesTags: ['Team'], + }), + listUser: build.query({ + query: (queryArg) => ({ + url: `/users`, + params: { + pretty: queryArg.pretty, + allowWatchBookmarks: queryArg.allowWatchBookmarks, + continue: queryArg['continue'], + fieldSelector: queryArg.fieldSelector, + labelSelector: queryArg.labelSelector, + limit: queryArg.limit, + resourceVersion: queryArg.resourceVersion, + resourceVersionMatch: queryArg.resourceVersionMatch, + sendInitialEvents: queryArg.sendInitialEvents, + timeoutSeconds: queryArg.timeoutSeconds, + watch: queryArg.watch, + }, + }), + providesTags: ['User'], + }), + createUser: build.mutation({ + query: (queryArg) => ({ + url: `/users`, + method: 'POST', + body: queryArg.user, + params: { + pretty: queryArg.pretty, + dryRun: queryArg.dryRun, + fieldManager: queryArg.fieldManager, + fieldValidation: queryArg.fieldValidation, + }, + }), + invalidatesTags: ['User'], + }), + deletecollectionUser: build.mutation({ + query: (queryArg) => ({ + url: `/users`, + method: 'DELETE', + params: { + pretty: queryArg.pretty, + continue: queryArg['continue'], + dryRun: queryArg.dryRun, + fieldSelector: queryArg.fieldSelector, + gracePeriodSeconds: queryArg.gracePeriodSeconds, + ignoreStoreReadErrorWithClusterBreakingPotential: queryArg.ignoreStoreReadErrorWithClusterBreakingPotential, + labelSelector: queryArg.labelSelector, + limit: queryArg.limit, + orphanDependents: queryArg.orphanDependents, + propagationPolicy: queryArg.propagationPolicy, + resourceVersion: queryArg.resourceVersion, + resourceVersionMatch: queryArg.resourceVersionMatch, + sendInitialEvents: queryArg.sendInitialEvents, + timeoutSeconds: queryArg.timeoutSeconds, + }, + }), + invalidatesTags: ['User'], + }), + getUser: build.query({ + query: (queryArg) => ({ + url: `/users/${queryArg.name}`, + params: { + pretty: queryArg.pretty, + }, + }), + providesTags: ['User'], + }), + replaceUser: build.mutation({ + query: (queryArg) => ({ + url: `/users/${queryArg.name}`, + method: 'PUT', + body: queryArg.user, + params: { + pretty: queryArg.pretty, + dryRun: queryArg.dryRun, + fieldManager: queryArg.fieldManager, + fieldValidation: queryArg.fieldValidation, + }, + }), + invalidatesTags: ['User'], + }), + deleteUser: build.mutation({ + query: (queryArg) => ({ + url: `/users/${queryArg.name}`, + method: 'DELETE', + params: { + pretty: queryArg.pretty, + dryRun: queryArg.dryRun, + gracePeriodSeconds: queryArg.gracePeriodSeconds, + ignoreStoreReadErrorWithClusterBreakingPotential: queryArg.ignoreStoreReadErrorWithClusterBreakingPotential, + orphanDependents: queryArg.orphanDependents, + propagationPolicy: queryArg.propagationPolicy, + }, + }), + invalidatesTags: ['User'], + }), + updateUser: build.mutation({ + query: (queryArg) => ({ + url: `/users/${queryArg.name}`, + method: 'PATCH', + body: queryArg.patch, + params: { + pretty: queryArg.pretty, + dryRun: queryArg.dryRun, + fieldManager: queryArg.fieldManager, + fieldValidation: queryArg.fieldValidation, + force: queryArg.force, + }, + }), + invalidatesTags: ['User'], + }), + getUserTeams: build.query({ + query: (queryArg) => ({ url: `/users/${queryArg.name}/teams` }), + providesTags: ['User'], + }), }), overrideExisting: false, }); export { injectedRtkApi as generatedAPI }; +export type GetApiResourcesApiResponse = /** status 200 OK */ ApiResourceList; +export type GetApiResourcesApiArg = void; export type GetDisplayMappingApiResponse = /** status 200 undefined */ DisplayList; export type GetDisplayMappingApiArg = { /** Display keys */ key: string[]; }; +export type ListServiceAccountApiResponse = /** status 200 OK */ ServiceAccountList; +export type ListServiceAccountApiArg = { + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; + /** allowWatchBookmarks requests watch events with type "BOOKMARK". Servers that do not implement bookmarks may ignore this flag and bookmarks are sent at the server's discretion. Clients should not assume bookmarks are returned at any specific interval, nor may they assume the server will send any BOOKMARK event during a session. If this is not a watch, this field is ignored. */ + allowWatchBookmarks?: boolean; + /** The continue option should be set when retrieving more results from the server. Since this value is server defined, clients may only use the continue value from a previous query result with identical query parameters (except for the value of continue) and the server may reject a continue value it does not recognize. If the specified continue value is no longer valid whether due to expiration (generally five to fifteen minutes) or a configuration change on the server, the server will respond with a 410 ResourceExpired error together with a continue token. If the client needs a consistent list, it must restart their list without the continue field. Otherwise, the client may send another list request with the token received with the 410 error, the server will respond with a list starting from the next key, but from the latest snapshot, which is inconsistent from the previous list results - objects that are created, modified, or deleted after the first list request will be included in the response, as long as their keys are after the "next key". + + This field is not supported when watch is true. Clients may start a watch from the last resourceVersion value returned by the server and not miss any modifications. */ + continue?: string; + /** A selector to restrict the list of returned objects by their fields. Defaults to everything. */ + fieldSelector?: string; + /** A selector to restrict the list of returned objects by their labels. Defaults to everything. */ + labelSelector?: string; + /** limit is a maximum number of responses to return for a list call. If more items exist, the server will set the `continue` field on the list metadata to a value that can be used with the same initial query to retrieve the next set of results. Setting a limit may return fewer than the requested amount of items (up to zero items) in the event all requested objects are filtered out and clients should only use the presence of the continue field to determine whether more results are available. Servers may choose not to support the limit argument and will return all of the available results. If limit is specified and the continue field is empty, clients may assume that no more results are available. This field is not supported if watch is true. + + The server guarantees that the objects returned when using continue will be identical to issuing a single list call without a limit - that is, no objects created, modified, or deleted after the first request is issued will be included in any subsequent continued requests. This is sometimes referred to as a consistent snapshot, and ensures that a client that is using limit to receive smaller chunks of a very large result can ensure they see all possible objects. If objects are updated during a chunked list the version of the object that was present at the time the first list result was calculated is returned. */ + limit?: number; + /** resourceVersion sets a constraint on what resource versions a request may be served from. See https://kubernetes.io/docs/reference/using-api/api-concepts/#resource-versions for details. + + Defaults to unset */ + resourceVersion?: string; + /** resourceVersionMatch determines how resourceVersion is applied to list calls. It is highly recommended that resourceVersionMatch be set for list calls where resourceVersion is set See https://kubernetes.io/docs/reference/using-api/api-concepts/#resource-versions for details. + + Defaults to unset */ + resourceVersionMatch?: string; + /** `sendInitialEvents=true` may be set together with `watch=true`. In that case, the watch stream will begin with synthetic events to produce the current state of objects in the collection. Once all such events have been sent, a synthetic "Bookmark" event will be sent. The bookmark will report the ResourceVersion (RV) corresponding to the set of objects, and be marked with `"k8s.io/initial-events-end": "true"` annotation. Afterwards, the watch stream will proceed as usual, sending watch events corresponding to changes (subsequent to the RV) to objects watched. + + When `sendInitialEvents` option is set, we require `resourceVersionMatch` option to also be set. The semantic of the watch request is as following: - `resourceVersionMatch` = NotOlderThan + is interpreted as "data at least as new as the provided `resourceVersion`" + and the bookmark event is send when the state is synced + to a `resourceVersion` at least as fresh as the one provided by the ListOptions. + If `resourceVersion` is unset, this is interpreted as "consistent read" and the + bookmark event is send when the state is synced at least to the moment + when request started being processed. + - `resourceVersionMatch` set to any other value or unset + Invalid error is returned. + + Defaults to true if `resourceVersion=""` or `resourceVersion="0"` (for backward compatibility reasons) and to false otherwise. */ + sendInitialEvents?: boolean; + /** Timeout for the list/watch call. This limits the duration of the call, regardless of any activity or inactivity. */ + timeoutSeconds?: number; + /** Watch for changes to the described resources and return them as a stream of add, update, and remove notifications. Specify resourceVersion. */ + watch?: boolean; +}; +export type CreateServiceAccountApiResponse = /** status 200 OK */ + | ServiceAccount + | /** status 201 Created */ ServiceAccount + | /** status 202 Accepted */ ServiceAccount; +export type CreateServiceAccountApiArg = { + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; + /** When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed */ + dryRun?: string; + /** fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint. */ + fieldManager?: string; + /** fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields. Valid values are: - Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23. - Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default in v1.23+ - Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered. */ + fieldValidation?: string; + serviceAccount: ServiceAccount; +}; +export type DeletecollectionServiceAccountApiResponse = /** status 200 OK */ Status; +export type DeletecollectionServiceAccountApiArg = { + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; + /** The continue option should be set when retrieving more results from the server. Since this value is server defined, clients may only use the continue value from a previous query result with identical query parameters (except for the value of continue) and the server may reject a continue value it does not recognize. If the specified continue value is no longer valid whether due to expiration (generally five to fifteen minutes) or a configuration change on the server, the server will respond with a 410 ResourceExpired error together with a continue token. If the client needs a consistent list, it must restart their list without the continue field. Otherwise, the client may send another list request with the token received with the 410 error, the server will respond with a list starting from the next key, but from the latest snapshot, which is inconsistent from the previous list results - objects that are created, modified, or deleted after the first list request will be included in the response, as long as their keys are after the "next key". + + This field is not supported when watch is true. Clients may start a watch from the last resourceVersion value returned by the server and not miss any modifications. */ + continue?: string; + /** When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed */ + dryRun?: string; + /** A selector to restrict the list of returned objects by their fields. Defaults to everything. */ + fieldSelector?: string; + /** The duration in seconds before the object should be deleted. Value must be non-negative integer. The value zero indicates delete immediately. If this value is nil, the default grace period for the specified type will be used. Defaults to a per object value if not specified. zero means delete immediately. */ + gracePeriodSeconds?: number; + /** if set to true, it will trigger an unsafe deletion of the resource in case the normal deletion flow fails with a corrupt object error. A resource is considered corrupt if it can not be retrieved from the underlying storage successfully because of a) its data can not be transformed e.g. decryption failure, or b) it fails to decode into an object. NOTE: unsafe deletion ignores finalizer constraints, skips precondition checks, and removes the object from the storage. WARNING: This may potentially break the cluster if the workload associated with the resource being unsafe-deleted relies on normal deletion flow. Use only if you REALLY know what you are doing. The default value is false, and the user must opt in to enable it */ + ignoreStoreReadErrorWithClusterBreakingPotential?: boolean; + /** A selector to restrict the list of returned objects by their labels. Defaults to everything. */ + labelSelector?: string; + /** limit is a maximum number of responses to return for a list call. If more items exist, the server will set the `continue` field on the list metadata to a value that can be used with the same initial query to retrieve the next set of results. Setting a limit may return fewer than the requested amount of items (up to zero items) in the event all requested objects are filtered out and clients should only use the presence of the continue field to determine whether more results are available. Servers may choose not to support the limit argument and will return all of the available results. If limit is specified and the continue field is empty, clients may assume that no more results are available. This field is not supported if watch is true. + + The server guarantees that the objects returned when using continue will be identical to issuing a single list call without a limit - that is, no objects created, modified, or deleted after the first request is issued will be included in any subsequent continued requests. This is sometimes referred to as a consistent snapshot, and ensures that a client that is using limit to receive smaller chunks of a very large result can ensure they see all possible objects. If objects are updated during a chunked list the version of the object that was present at the time the first list result was calculated is returned. */ + limit?: number; + /** Deprecated: please use the PropagationPolicy, this field will be deprecated in 1.7. Should the dependent objects be orphaned. If true/false, the "orphan" finalizer will be added to/removed from the object's finalizers list. Either this field or PropagationPolicy may be set, but not both. */ + orphanDependents?: boolean; + /** Whether and how garbage collection will be performed. Either this field or OrphanDependents may be set, but not both. The default policy is decided by the existing finalizer set in the metadata.finalizers and the resource-specific default policy. Acceptable values are: 'Orphan' - orphan the dependents; 'Background' - allow the garbage collector to delete the dependents in the background; 'Foreground' - a cascading policy that deletes all dependents in the foreground. */ + propagationPolicy?: string; + /** resourceVersion sets a constraint on what resource versions a request may be served from. See https://kubernetes.io/docs/reference/using-api/api-concepts/#resource-versions for details. + + Defaults to unset */ + resourceVersion?: string; + /** resourceVersionMatch determines how resourceVersion is applied to list calls. It is highly recommended that resourceVersionMatch be set for list calls where resourceVersion is set See https://kubernetes.io/docs/reference/using-api/api-concepts/#resource-versions for details. + + Defaults to unset */ + resourceVersionMatch?: string; + /** `sendInitialEvents=true` may be set together with `watch=true`. In that case, the watch stream will begin with synthetic events to produce the current state of objects in the collection. Once all such events have been sent, a synthetic "Bookmark" event will be sent. The bookmark will report the ResourceVersion (RV) corresponding to the set of objects, and be marked with `"k8s.io/initial-events-end": "true"` annotation. Afterwards, the watch stream will proceed as usual, sending watch events corresponding to changes (subsequent to the RV) to objects watched. + + When `sendInitialEvents` option is set, we require `resourceVersionMatch` option to also be set. The semantic of the watch request is as following: - `resourceVersionMatch` = NotOlderThan + is interpreted as "data at least as new as the provided `resourceVersion`" + and the bookmark event is send when the state is synced + to a `resourceVersion` at least as fresh as the one provided by the ListOptions. + If `resourceVersion` is unset, this is interpreted as "consistent read" and the + bookmark event is send when the state is synced at least to the moment + when request started being processed. + - `resourceVersionMatch` set to any other value or unset + Invalid error is returned. + + Defaults to true if `resourceVersion=""` or `resourceVersion="0"` (for backward compatibility reasons) and to false otherwise. */ + sendInitialEvents?: boolean; + /** Timeout for the list/watch call. This limits the duration of the call, regardless of any activity or inactivity. */ + timeoutSeconds?: number; +}; +export type GetServiceAccountApiResponse = /** status 200 OK */ ServiceAccount; +export type GetServiceAccountApiArg = { + /** name of the ServiceAccount */ + name: string; + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; +}; +export type ReplaceServiceAccountApiResponse = /** status 200 OK */ + | ServiceAccount + | /** status 201 Created */ ServiceAccount; +export type ReplaceServiceAccountApiArg = { + /** name of the ServiceAccount */ + name: string; + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; + /** When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed */ + dryRun?: string; + /** fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint. */ + fieldManager?: string; + /** fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields. Valid values are: - Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23. - Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default in v1.23+ - Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered. */ + fieldValidation?: string; + serviceAccount: ServiceAccount; +}; +export type DeleteServiceAccountApiResponse = /** status 200 OK */ Status | /** status 202 Accepted */ Status; +export type DeleteServiceAccountApiArg = { + /** name of the ServiceAccount */ + name: string; + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; + /** When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed */ + dryRun?: string; + /** The duration in seconds before the object should be deleted. Value must be non-negative integer. The value zero indicates delete immediately. If this value is nil, the default grace period for the specified type will be used. Defaults to a per object value if not specified. zero means delete immediately. */ + gracePeriodSeconds?: number; + /** if set to true, it will trigger an unsafe deletion of the resource in case the normal deletion flow fails with a corrupt object error. A resource is considered corrupt if it can not be retrieved from the underlying storage successfully because of a) its data can not be transformed e.g. decryption failure, or b) it fails to decode into an object. NOTE: unsafe deletion ignores finalizer constraints, skips precondition checks, and removes the object from the storage. WARNING: This may potentially break the cluster if the workload associated with the resource being unsafe-deleted relies on normal deletion flow. Use only if you REALLY know what you are doing. The default value is false, and the user must opt in to enable it */ + ignoreStoreReadErrorWithClusterBreakingPotential?: boolean; + /** Deprecated: please use the PropagationPolicy, this field will be deprecated in 1.7. Should the dependent objects be orphaned. If true/false, the "orphan" finalizer will be added to/removed from the object's finalizers list. Either this field or PropagationPolicy may be set, but not both. */ + orphanDependents?: boolean; + /** Whether and how garbage collection will be performed. Either this field or OrphanDependents may be set, but not both. The default policy is decided by the existing finalizer set in the metadata.finalizers and the resource-specific default policy. Acceptable values are: 'Orphan' - orphan the dependents; 'Background' - allow the garbage collector to delete the dependents in the background; 'Foreground' - a cascading policy that deletes all dependents in the foreground. */ + propagationPolicy?: string; +}; +export type UpdateServiceAccountApiResponse = /** status 200 OK */ + | ServiceAccount + | /** status 201 Created */ ServiceAccount; +export type UpdateServiceAccountApiArg = { + /** name of the ServiceAccount */ + name: string; + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; + /** When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed */ + dryRun?: string; + /** fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint. This field is required for apply requests (application/apply-patch) but optional for non-apply patch types (JsonPatch, MergePatch, StrategicMergePatch). */ + fieldManager?: string; + /** fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields. Valid values are: - Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23. - Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default in v1.23+ - Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered. */ + fieldValidation?: string; + /** Force is going to "force" Apply requests. It means user will re-acquire conflicting fields owned by other people. Force flag must be unset for non-apply patch requests. */ + force?: boolean; + patch: Patch; +}; +export type GetServiceAccountTokensApiResponse = /** status 200 OK */ ServiceAccountTokenList; +export type GetServiceAccountTokensApiArg = { + /** name of the ServiceAccountTokenList */ + name: string; +}; +export type ListSsoSettingApiResponse = /** status 200 OK */ SsoSettingList; +export type ListSsoSettingApiArg = { + /** allowWatchBookmarks requests watch events with type "BOOKMARK". Servers that do not implement bookmarks may ignore this flag and bookmarks are sent at the server's discretion. Clients should not assume bookmarks are returned at any specific interval, nor may they assume the server will send any BOOKMARK event during a session. If this is not a watch, this field is ignored. */ + allowWatchBookmarks?: boolean; + /** The continue option should be set when retrieving more results from the server. Since this value is server defined, clients may only use the continue value from a previous query result with identical query parameters (except for the value of continue) and the server may reject a continue value it does not recognize. If the specified continue value is no longer valid whether due to expiration (generally five to fifteen minutes) or a configuration change on the server, the server will respond with a 410 ResourceExpired error together with a continue token. If the client needs a consistent list, it must restart their list without the continue field. Otherwise, the client may send another list request with the token received with the 410 error, the server will respond with a list starting from the next key, but from the latest snapshot, which is inconsistent from the previous list results - objects that are created, modified, or deleted after the first list request will be included in the response, as long as their keys are after the "next key". + + This field is not supported when watch is true. Clients may start a watch from the last resourceVersion value returned by the server and not miss any modifications. */ + continue?: string; + /** A selector to restrict the list of returned objects by their fields. Defaults to everything. */ + fieldSelector?: string; + /** A selector to restrict the list of returned objects by their labels. Defaults to everything. */ + labelSelector?: string; + /** limit is a maximum number of responses to return for a list call. If more items exist, the server will set the `continue` field on the list metadata to a value that can be used with the same initial query to retrieve the next set of results. Setting a limit may return fewer than the requested amount of items (up to zero items) in the event all requested objects are filtered out and clients should only use the presence of the continue field to determine whether more results are available. Servers may choose not to support the limit argument and will return all of the available results. If limit is specified and the continue field is empty, clients may assume that no more results are available. This field is not supported if watch is true. + + The server guarantees that the objects returned when using continue will be identical to issuing a single list call without a limit - that is, no objects created, modified, or deleted after the first request is issued will be included in any subsequent continued requests. This is sometimes referred to as a consistent snapshot, and ensures that a client that is using limit to receive smaller chunks of a very large result can ensure they see all possible objects. If objects are updated during a chunked list the version of the object that was present at the time the first list result was calculated is returned. */ + limit?: number; + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; + /** resourceVersion sets a constraint on what resource versions a request may be served from. See https://kubernetes.io/docs/reference/using-api/api-concepts/#resource-versions for details. + + Defaults to unset */ + resourceVersion?: string; + /** resourceVersionMatch determines how resourceVersion is applied to list calls. It is highly recommended that resourceVersionMatch be set for list calls where resourceVersion is set See https://kubernetes.io/docs/reference/using-api/api-concepts/#resource-versions for details. + + Defaults to unset */ + resourceVersionMatch?: string; + /** `sendInitialEvents=true` may be set together with `watch=true`. In that case, the watch stream will begin with synthetic events to produce the current state of objects in the collection. Once all such events have been sent, a synthetic "Bookmark" event will be sent. The bookmark will report the ResourceVersion (RV) corresponding to the set of objects, and be marked with `"k8s.io/initial-events-end": "true"` annotation. Afterwards, the watch stream will proceed as usual, sending watch events corresponding to changes (subsequent to the RV) to objects watched. + + When `sendInitialEvents` option is set, we require `resourceVersionMatch` option to also be set. The semantic of the watch request is as following: - `resourceVersionMatch` = NotOlderThan + is interpreted as "data at least as new as the provided `resourceVersion`" + and the bookmark event is send when the state is synced + to a `resourceVersion` at least as fresh as the one provided by the ListOptions. + If `resourceVersion` is unset, this is interpreted as "consistent read" and the + bookmark event is send when the state is synced at least to the moment + when request started being processed. + - `resourceVersionMatch` set to any other value or unset + Invalid error is returned. + + Defaults to true if `resourceVersion=""` or `resourceVersion="0"` (for backward compatibility reasons) and to false otherwise. */ + sendInitialEvents?: boolean; + /** Timeout for the list/watch call. This limits the duration of the call, regardless of any activity or inactivity. */ + timeoutSeconds?: number; + /** Watch for changes to the described resources and return them as a stream of add, update, and remove notifications. Specify resourceVersion. */ + watch?: boolean; +}; +export type GetSsoSettingApiResponse = /** status 200 OK */ SsoSetting; +export type GetSsoSettingApiArg = { + /** name of the SSOSetting */ + name: string; + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; +}; +export type ReplaceSsoSettingApiResponse = /** status 200 OK */ SsoSetting | /** status 201 Created */ SsoSetting; +export type ReplaceSsoSettingApiArg = { + /** name of the SSOSetting */ + name: string; + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; + /** When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed */ + dryRun?: string; + /** fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint. */ + fieldManager?: string; + /** fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields. Valid values are: - Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23. - Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default in v1.23+ - Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered. */ + fieldValidation?: string; + ssoSetting: SsoSetting; +}; +export type DeleteSsoSettingApiResponse = /** status 200 OK */ Status | /** status 202 Accepted */ Status; +export type DeleteSsoSettingApiArg = { + /** name of the SSOSetting */ + name: string; + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; + /** When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed */ + dryRun?: string; + /** The duration in seconds before the object should be deleted. Value must be non-negative integer. The value zero indicates delete immediately. If this value is nil, the default grace period for the specified type will be used. Defaults to a per object value if not specified. zero means delete immediately. */ + gracePeriodSeconds?: number; + /** if set to true, it will trigger an unsafe deletion of the resource in case the normal deletion flow fails with a corrupt object error. A resource is considered corrupt if it can not be retrieved from the underlying storage successfully because of a) its data can not be transformed e.g. decryption failure, or b) it fails to decode into an object. NOTE: unsafe deletion ignores finalizer constraints, skips precondition checks, and removes the object from the storage. WARNING: This may potentially break the cluster if the workload associated with the resource being unsafe-deleted relies on normal deletion flow. Use only if you REALLY know what you are doing. The default value is false, and the user must opt in to enable it */ + ignoreStoreReadErrorWithClusterBreakingPotential?: boolean; + /** Deprecated: please use the PropagationPolicy, this field will be deprecated in 1.7. Should the dependent objects be orphaned. If true/false, the "orphan" finalizer will be added to/removed from the object's finalizers list. Either this field or PropagationPolicy may be set, but not both. */ + orphanDependents?: boolean; + /** Whether and how garbage collection will be performed. Either this field or OrphanDependents may be set, but not both. The default policy is decided by the existing finalizer set in the metadata.finalizers and the resource-specific default policy. Acceptable values are: 'Orphan' - orphan the dependents; 'Background' - allow the garbage collector to delete the dependents in the background; 'Foreground' - a cascading policy that deletes all dependents in the foreground. */ + propagationPolicy?: string; +}; +export type UpdateSsoSettingApiResponse = /** status 200 OK */ SsoSetting | /** status 201 Created */ SsoSetting; +export type UpdateSsoSettingApiArg = { + /** name of the SSOSetting */ + name: string; + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; + /** When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed */ + dryRun?: string; + /** fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint. This field is required for apply requests (application/apply-patch) but optional for non-apply patch types (JsonPatch, MergePatch, StrategicMergePatch). */ + fieldManager?: string; + /** fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields. Valid values are: - Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23. - Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default in v1.23+ - Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered. */ + fieldValidation?: string; + /** Force is going to "force" Apply requests. It means user will re-acquire conflicting fields owned by other people. Force flag must be unset for non-apply patch requests. */ + force?: boolean; + patch: Patch; +}; +export type ListTeamBindingApiResponse = /** status 200 OK */ TeamBindingList; +export type ListTeamBindingApiArg = { + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; + /** allowWatchBookmarks requests watch events with type "BOOKMARK". Servers that do not implement bookmarks may ignore this flag and bookmarks are sent at the server's discretion. Clients should not assume bookmarks are returned at any specific interval, nor may they assume the server will send any BOOKMARK event during a session. If this is not a watch, this field is ignored. */ + allowWatchBookmarks?: boolean; + /** The continue option should be set when retrieving more results from the server. Since this value is server defined, clients may only use the continue value from a previous query result with identical query parameters (except for the value of continue) and the server may reject a continue value it does not recognize. If the specified continue value is no longer valid whether due to expiration (generally five to fifteen minutes) or a configuration change on the server, the server will respond with a 410 ResourceExpired error together with a continue token. If the client needs a consistent list, it must restart their list without the continue field. Otherwise, the client may send another list request with the token received with the 410 error, the server will respond with a list starting from the next key, but from the latest snapshot, which is inconsistent from the previous list results - objects that are created, modified, or deleted after the first list request will be included in the response, as long as their keys are after the "next key". + + This field is not supported when watch is true. Clients may start a watch from the last resourceVersion value returned by the server and not miss any modifications. */ + continue?: string; + /** A selector to restrict the list of returned objects by their fields. Defaults to everything. */ + fieldSelector?: string; + /** A selector to restrict the list of returned objects by their labels. Defaults to everything. */ + labelSelector?: string; + /** limit is a maximum number of responses to return for a list call. If more items exist, the server will set the `continue` field on the list metadata to a value that can be used with the same initial query to retrieve the next set of results. Setting a limit may return fewer than the requested amount of items (up to zero items) in the event all requested objects are filtered out and clients should only use the presence of the continue field to determine whether more results are available. Servers may choose not to support the limit argument and will return all of the available results. If limit is specified and the continue field is empty, clients may assume that no more results are available. This field is not supported if watch is true. + + The server guarantees that the objects returned when using continue will be identical to issuing a single list call without a limit - that is, no objects created, modified, or deleted after the first request is issued will be included in any subsequent continued requests. This is sometimes referred to as a consistent snapshot, and ensures that a client that is using limit to receive smaller chunks of a very large result can ensure they see all possible objects. If objects are updated during a chunked list the version of the object that was present at the time the first list result was calculated is returned. */ + limit?: number; + /** resourceVersion sets a constraint on what resource versions a request may be served from. See https://kubernetes.io/docs/reference/using-api/api-concepts/#resource-versions for details. + + Defaults to unset */ + resourceVersion?: string; + /** resourceVersionMatch determines how resourceVersion is applied to list calls. It is highly recommended that resourceVersionMatch be set for list calls where resourceVersion is set See https://kubernetes.io/docs/reference/using-api/api-concepts/#resource-versions for details. + + Defaults to unset */ + resourceVersionMatch?: string; + /** `sendInitialEvents=true` may be set together with `watch=true`. In that case, the watch stream will begin with synthetic events to produce the current state of objects in the collection. Once all such events have been sent, a synthetic "Bookmark" event will be sent. The bookmark will report the ResourceVersion (RV) corresponding to the set of objects, and be marked with `"k8s.io/initial-events-end": "true"` annotation. Afterwards, the watch stream will proceed as usual, sending watch events corresponding to changes (subsequent to the RV) to objects watched. + + When `sendInitialEvents` option is set, we require `resourceVersionMatch` option to also be set. The semantic of the watch request is as following: - `resourceVersionMatch` = NotOlderThan + is interpreted as "data at least as new as the provided `resourceVersion`" + and the bookmark event is send when the state is synced + to a `resourceVersion` at least as fresh as the one provided by the ListOptions. + If `resourceVersion` is unset, this is interpreted as "consistent read" and the + bookmark event is send when the state is synced at least to the moment + when request started being processed. + - `resourceVersionMatch` set to any other value or unset + Invalid error is returned. + + Defaults to true if `resourceVersion=""` or `resourceVersion="0"` (for backward compatibility reasons) and to false otherwise. */ + sendInitialEvents?: boolean; + /** Timeout for the list/watch call. This limits the duration of the call, regardless of any activity or inactivity. */ + timeoutSeconds?: number; + /** Watch for changes to the described resources and return them as a stream of add, update, and remove notifications. Specify resourceVersion. */ + watch?: boolean; +}; +export type CreateTeamBindingApiResponse = /** status 200 OK */ + | TeamBinding + | /** status 201 Created */ TeamBinding + | /** status 202 Accepted */ TeamBinding; +export type CreateTeamBindingApiArg = { + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; + /** When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed */ + dryRun?: string; + /** fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint. */ + fieldManager?: string; + /** fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields. Valid values are: - Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23. - Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default in v1.23+ - Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered. */ + fieldValidation?: string; + teamBinding: TeamBinding; +}; +export type DeletecollectionTeamBindingApiResponse = /** status 200 OK */ Status; +export type DeletecollectionTeamBindingApiArg = { + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; + /** The continue option should be set when retrieving more results from the server. Since this value is server defined, clients may only use the continue value from a previous query result with identical query parameters (except for the value of continue) and the server may reject a continue value it does not recognize. If the specified continue value is no longer valid whether due to expiration (generally five to fifteen minutes) or a configuration change on the server, the server will respond with a 410 ResourceExpired error together with a continue token. If the client needs a consistent list, it must restart their list without the continue field. Otherwise, the client may send another list request with the token received with the 410 error, the server will respond with a list starting from the next key, but from the latest snapshot, which is inconsistent from the previous list results - objects that are created, modified, or deleted after the first list request will be included in the response, as long as their keys are after the "next key". + + This field is not supported when watch is true. Clients may start a watch from the last resourceVersion value returned by the server and not miss any modifications. */ + continue?: string; + /** When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed */ + dryRun?: string; + /** A selector to restrict the list of returned objects by their fields. Defaults to everything. */ + fieldSelector?: string; + /** The duration in seconds before the object should be deleted. Value must be non-negative integer. The value zero indicates delete immediately. If this value is nil, the default grace period for the specified type will be used. Defaults to a per object value if not specified. zero means delete immediately. */ + gracePeriodSeconds?: number; + /** if set to true, it will trigger an unsafe deletion of the resource in case the normal deletion flow fails with a corrupt object error. A resource is considered corrupt if it can not be retrieved from the underlying storage successfully because of a) its data can not be transformed e.g. decryption failure, or b) it fails to decode into an object. NOTE: unsafe deletion ignores finalizer constraints, skips precondition checks, and removes the object from the storage. WARNING: This may potentially break the cluster if the workload associated with the resource being unsafe-deleted relies on normal deletion flow. Use only if you REALLY know what you are doing. The default value is false, and the user must opt in to enable it */ + ignoreStoreReadErrorWithClusterBreakingPotential?: boolean; + /** A selector to restrict the list of returned objects by their labels. Defaults to everything. */ + labelSelector?: string; + /** limit is a maximum number of responses to return for a list call. If more items exist, the server will set the `continue` field on the list metadata to a value that can be used with the same initial query to retrieve the next set of results. Setting a limit may return fewer than the requested amount of items (up to zero items) in the event all requested objects are filtered out and clients should only use the presence of the continue field to determine whether more results are available. Servers may choose not to support the limit argument and will return all of the available results. If limit is specified and the continue field is empty, clients may assume that no more results are available. This field is not supported if watch is true. + + The server guarantees that the objects returned when using continue will be identical to issuing a single list call without a limit - that is, no objects created, modified, or deleted after the first request is issued will be included in any subsequent continued requests. This is sometimes referred to as a consistent snapshot, and ensures that a client that is using limit to receive smaller chunks of a very large result can ensure they see all possible objects. If objects are updated during a chunked list the version of the object that was present at the time the first list result was calculated is returned. */ + limit?: number; + /** Deprecated: please use the PropagationPolicy, this field will be deprecated in 1.7. Should the dependent objects be orphaned. If true/false, the "orphan" finalizer will be added to/removed from the object's finalizers list. Either this field or PropagationPolicy may be set, but not both. */ + orphanDependents?: boolean; + /** Whether and how garbage collection will be performed. Either this field or OrphanDependents may be set, but not both. The default policy is decided by the existing finalizer set in the metadata.finalizers and the resource-specific default policy. Acceptable values are: 'Orphan' - orphan the dependents; 'Background' - allow the garbage collector to delete the dependents in the background; 'Foreground' - a cascading policy that deletes all dependents in the foreground. */ + propagationPolicy?: string; + /** resourceVersion sets a constraint on what resource versions a request may be served from. See https://kubernetes.io/docs/reference/using-api/api-concepts/#resource-versions for details. + + Defaults to unset */ + resourceVersion?: string; + /** resourceVersionMatch determines how resourceVersion is applied to list calls. It is highly recommended that resourceVersionMatch be set for list calls where resourceVersion is set See https://kubernetes.io/docs/reference/using-api/api-concepts/#resource-versions for details. + + Defaults to unset */ + resourceVersionMatch?: string; + /** `sendInitialEvents=true` may be set together with `watch=true`. In that case, the watch stream will begin with synthetic events to produce the current state of objects in the collection. Once all such events have been sent, a synthetic "Bookmark" event will be sent. The bookmark will report the ResourceVersion (RV) corresponding to the set of objects, and be marked with `"k8s.io/initial-events-end": "true"` annotation. Afterwards, the watch stream will proceed as usual, sending watch events corresponding to changes (subsequent to the RV) to objects watched. + + When `sendInitialEvents` option is set, we require `resourceVersionMatch` option to also be set. The semantic of the watch request is as following: - `resourceVersionMatch` = NotOlderThan + is interpreted as "data at least as new as the provided `resourceVersion`" + and the bookmark event is send when the state is synced + to a `resourceVersion` at least as fresh as the one provided by the ListOptions. + If `resourceVersion` is unset, this is interpreted as "consistent read" and the + bookmark event is send when the state is synced at least to the moment + when request started being processed. + - `resourceVersionMatch` set to any other value or unset + Invalid error is returned. + + Defaults to true if `resourceVersion=""` or `resourceVersion="0"` (for backward compatibility reasons) and to false otherwise. */ + sendInitialEvents?: boolean; + /** Timeout for the list/watch call. This limits the duration of the call, regardless of any activity or inactivity. */ + timeoutSeconds?: number; +}; +export type GetTeamBindingApiResponse = /** status 200 OK */ TeamBinding; +export type GetTeamBindingApiArg = { + /** name of the TeamBinding */ + name: string; + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; +}; +export type ReplaceTeamBindingApiResponse = /** status 200 OK */ TeamBinding | /** status 201 Created */ TeamBinding; +export type ReplaceTeamBindingApiArg = { + /** name of the TeamBinding */ + name: string; + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; + /** When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed */ + dryRun?: string; + /** fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint. */ + fieldManager?: string; + /** fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields. Valid values are: - Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23. - Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default in v1.23+ - Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered. */ + fieldValidation?: string; + teamBinding: TeamBinding; +}; +export type DeleteTeamBindingApiResponse = /** status 200 OK */ Status | /** status 202 Accepted */ Status; +export type DeleteTeamBindingApiArg = { + /** name of the TeamBinding */ + name: string; + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; + /** When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed */ + dryRun?: string; + /** The duration in seconds before the object should be deleted. Value must be non-negative integer. The value zero indicates delete immediately. If this value is nil, the default grace period for the specified type will be used. Defaults to a per object value if not specified. zero means delete immediately. */ + gracePeriodSeconds?: number; + /** if set to true, it will trigger an unsafe deletion of the resource in case the normal deletion flow fails with a corrupt object error. A resource is considered corrupt if it can not be retrieved from the underlying storage successfully because of a) its data can not be transformed e.g. decryption failure, or b) it fails to decode into an object. NOTE: unsafe deletion ignores finalizer constraints, skips precondition checks, and removes the object from the storage. WARNING: This may potentially break the cluster if the workload associated with the resource being unsafe-deleted relies on normal deletion flow. Use only if you REALLY know what you are doing. The default value is false, and the user must opt in to enable it */ + ignoreStoreReadErrorWithClusterBreakingPotential?: boolean; + /** Deprecated: please use the PropagationPolicy, this field will be deprecated in 1.7. Should the dependent objects be orphaned. If true/false, the "orphan" finalizer will be added to/removed from the object's finalizers list. Either this field or PropagationPolicy may be set, but not both. */ + orphanDependents?: boolean; + /** Whether and how garbage collection will be performed. Either this field or OrphanDependents may be set, but not both. The default policy is decided by the existing finalizer set in the metadata.finalizers and the resource-specific default policy. Acceptable values are: 'Orphan' - orphan the dependents; 'Background' - allow the garbage collector to delete the dependents in the background; 'Foreground' - a cascading policy that deletes all dependents in the foreground. */ + propagationPolicy?: string; +}; +export type UpdateTeamBindingApiResponse = /** status 200 OK */ TeamBinding | /** status 201 Created */ TeamBinding; +export type UpdateTeamBindingApiArg = { + /** name of the TeamBinding */ + name: string; + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; + /** When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed */ + dryRun?: string; + /** fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint. This field is required for apply requests (application/apply-patch) but optional for non-apply patch types (JsonPatch, MergePatch, StrategicMergePatch). */ + fieldManager?: string; + /** fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields. Valid values are: - Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23. - Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default in v1.23+ - Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered. */ + fieldValidation?: string; + /** Force is going to "force" Apply requests. It means user will re-acquire conflicting fields owned by other people. Force flag must be unset for non-apply patch requests. */ + force?: boolean; + patch: Patch; +}; +export type ListTeamApiResponse = /** status 200 OK */ TeamList; +export type ListTeamApiArg = { + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; + /** allowWatchBookmarks requests watch events with type "BOOKMARK". Servers that do not implement bookmarks may ignore this flag and bookmarks are sent at the server's discretion. Clients should not assume bookmarks are returned at any specific interval, nor may they assume the server will send any BOOKMARK event during a session. If this is not a watch, this field is ignored. */ + allowWatchBookmarks?: boolean; + /** The continue option should be set when retrieving more results from the server. Since this value is server defined, clients may only use the continue value from a previous query result with identical query parameters (except for the value of continue) and the server may reject a continue value it does not recognize. If the specified continue value is no longer valid whether due to expiration (generally five to fifteen minutes) or a configuration change on the server, the server will respond with a 410 ResourceExpired error together with a continue token. If the client needs a consistent list, it must restart their list without the continue field. Otherwise, the client may send another list request with the token received with the 410 error, the server will respond with a list starting from the next key, but from the latest snapshot, which is inconsistent from the previous list results - objects that are created, modified, or deleted after the first list request will be included in the response, as long as their keys are after the "next key". + + This field is not supported when watch is true. Clients may start a watch from the last resourceVersion value returned by the server and not miss any modifications. */ + continue?: string; + /** A selector to restrict the list of returned objects by their fields. Defaults to everything. */ + fieldSelector?: string; + /** A selector to restrict the list of returned objects by their labels. Defaults to everything. */ + labelSelector?: string; + /** limit is a maximum number of responses to return for a list call. If more items exist, the server will set the `continue` field on the list metadata to a value that can be used with the same initial query to retrieve the next set of results. Setting a limit may return fewer than the requested amount of items (up to zero items) in the event all requested objects are filtered out and clients should only use the presence of the continue field to determine whether more results are available. Servers may choose not to support the limit argument and will return all of the available results. If limit is specified and the continue field is empty, clients may assume that no more results are available. This field is not supported if watch is true. + + The server guarantees that the objects returned when using continue will be identical to issuing a single list call without a limit - that is, no objects created, modified, or deleted after the first request is issued will be included in any subsequent continued requests. This is sometimes referred to as a consistent snapshot, and ensures that a client that is using limit to receive smaller chunks of a very large result can ensure they see all possible objects. If objects are updated during a chunked list the version of the object that was present at the time the first list result was calculated is returned. */ + limit?: number; + /** resourceVersion sets a constraint on what resource versions a request may be served from. See https://kubernetes.io/docs/reference/using-api/api-concepts/#resource-versions for details. + + Defaults to unset */ + resourceVersion?: string; + /** resourceVersionMatch determines how resourceVersion is applied to list calls. It is highly recommended that resourceVersionMatch be set for list calls where resourceVersion is set See https://kubernetes.io/docs/reference/using-api/api-concepts/#resource-versions for details. + + Defaults to unset */ + resourceVersionMatch?: string; + /** `sendInitialEvents=true` may be set together with `watch=true`. In that case, the watch stream will begin with synthetic events to produce the current state of objects in the collection. Once all such events have been sent, a synthetic "Bookmark" event will be sent. The bookmark will report the ResourceVersion (RV) corresponding to the set of objects, and be marked with `"k8s.io/initial-events-end": "true"` annotation. Afterwards, the watch stream will proceed as usual, sending watch events corresponding to changes (subsequent to the RV) to objects watched. + + When `sendInitialEvents` option is set, we require `resourceVersionMatch` option to also be set. The semantic of the watch request is as following: - `resourceVersionMatch` = NotOlderThan + is interpreted as "data at least as new as the provided `resourceVersion`" + and the bookmark event is send when the state is synced + to a `resourceVersion` at least as fresh as the one provided by the ListOptions. + If `resourceVersion` is unset, this is interpreted as "consistent read" and the + bookmark event is send when the state is synced at least to the moment + when request started being processed. + - `resourceVersionMatch` set to any other value or unset + Invalid error is returned. + + Defaults to true if `resourceVersion=""` or `resourceVersion="0"` (for backward compatibility reasons) and to false otherwise. */ + sendInitialEvents?: boolean; + /** Timeout for the list/watch call. This limits the duration of the call, regardless of any activity or inactivity. */ + timeoutSeconds?: number; + /** Watch for changes to the described resources and return them as a stream of add, update, and remove notifications. Specify resourceVersion. */ + watch?: boolean; +}; +export type CreateTeamApiResponse = /** status 200 OK */ + | Team + | /** status 201 Created */ Team + | /** status 202 Accepted */ Team; +export type CreateTeamApiArg = { + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; + /** When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed */ + dryRun?: string; + /** fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint. */ + fieldManager?: string; + /** fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields. Valid values are: - Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23. - Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default in v1.23+ - Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered. */ + fieldValidation?: string; + team: Team; +}; +export type DeletecollectionTeamApiResponse = /** status 200 OK */ Status; +export type DeletecollectionTeamApiArg = { + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; + /** The continue option should be set when retrieving more results from the server. Since this value is server defined, clients may only use the continue value from a previous query result with identical query parameters (except for the value of continue) and the server may reject a continue value it does not recognize. If the specified continue value is no longer valid whether due to expiration (generally five to fifteen minutes) or a configuration change on the server, the server will respond with a 410 ResourceExpired error together with a continue token. If the client needs a consistent list, it must restart their list without the continue field. Otherwise, the client may send another list request with the token received with the 410 error, the server will respond with a list starting from the next key, but from the latest snapshot, which is inconsistent from the previous list results - objects that are created, modified, or deleted after the first list request will be included in the response, as long as their keys are after the "next key". + + This field is not supported when watch is true. Clients may start a watch from the last resourceVersion value returned by the server and not miss any modifications. */ + continue?: string; + /** When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed */ + dryRun?: string; + /** A selector to restrict the list of returned objects by their fields. Defaults to everything. */ + fieldSelector?: string; + /** The duration in seconds before the object should be deleted. Value must be non-negative integer. The value zero indicates delete immediately. If this value is nil, the default grace period for the specified type will be used. Defaults to a per object value if not specified. zero means delete immediately. */ + gracePeriodSeconds?: number; + /** if set to true, it will trigger an unsafe deletion of the resource in case the normal deletion flow fails with a corrupt object error. A resource is considered corrupt if it can not be retrieved from the underlying storage successfully because of a) its data can not be transformed e.g. decryption failure, or b) it fails to decode into an object. NOTE: unsafe deletion ignores finalizer constraints, skips precondition checks, and removes the object from the storage. WARNING: This may potentially break the cluster if the workload associated with the resource being unsafe-deleted relies on normal deletion flow. Use only if you REALLY know what you are doing. The default value is false, and the user must opt in to enable it */ + ignoreStoreReadErrorWithClusterBreakingPotential?: boolean; + /** A selector to restrict the list of returned objects by their labels. Defaults to everything. */ + labelSelector?: string; + /** limit is a maximum number of responses to return for a list call. If more items exist, the server will set the `continue` field on the list metadata to a value that can be used with the same initial query to retrieve the next set of results. Setting a limit may return fewer than the requested amount of items (up to zero items) in the event all requested objects are filtered out and clients should only use the presence of the continue field to determine whether more results are available. Servers may choose not to support the limit argument and will return all of the available results. If limit is specified and the continue field is empty, clients may assume that no more results are available. This field is not supported if watch is true. + + The server guarantees that the objects returned when using continue will be identical to issuing a single list call without a limit - that is, no objects created, modified, or deleted after the first request is issued will be included in any subsequent continued requests. This is sometimes referred to as a consistent snapshot, and ensures that a client that is using limit to receive smaller chunks of a very large result can ensure they see all possible objects. If objects are updated during a chunked list the version of the object that was present at the time the first list result was calculated is returned. */ + limit?: number; + /** Deprecated: please use the PropagationPolicy, this field will be deprecated in 1.7. Should the dependent objects be orphaned. If true/false, the "orphan" finalizer will be added to/removed from the object's finalizers list. Either this field or PropagationPolicy may be set, but not both. */ + orphanDependents?: boolean; + /** Whether and how garbage collection will be performed. Either this field or OrphanDependents may be set, but not both. The default policy is decided by the existing finalizer set in the metadata.finalizers and the resource-specific default policy. Acceptable values are: 'Orphan' - orphan the dependents; 'Background' - allow the garbage collector to delete the dependents in the background; 'Foreground' - a cascading policy that deletes all dependents in the foreground. */ + propagationPolicy?: string; + /** resourceVersion sets a constraint on what resource versions a request may be served from. See https://kubernetes.io/docs/reference/using-api/api-concepts/#resource-versions for details. + + Defaults to unset */ + resourceVersion?: string; + /** resourceVersionMatch determines how resourceVersion is applied to list calls. It is highly recommended that resourceVersionMatch be set for list calls where resourceVersion is set See https://kubernetes.io/docs/reference/using-api/api-concepts/#resource-versions for details. + + Defaults to unset */ + resourceVersionMatch?: string; + /** `sendInitialEvents=true` may be set together with `watch=true`. In that case, the watch stream will begin with synthetic events to produce the current state of objects in the collection. Once all such events have been sent, a synthetic "Bookmark" event will be sent. The bookmark will report the ResourceVersion (RV) corresponding to the set of objects, and be marked with `"k8s.io/initial-events-end": "true"` annotation. Afterwards, the watch stream will proceed as usual, sending watch events corresponding to changes (subsequent to the RV) to objects watched. + + When `sendInitialEvents` option is set, we require `resourceVersionMatch` option to also be set. The semantic of the watch request is as following: - `resourceVersionMatch` = NotOlderThan + is interpreted as "data at least as new as the provided `resourceVersion`" + and the bookmark event is send when the state is synced + to a `resourceVersion` at least as fresh as the one provided by the ListOptions. + If `resourceVersion` is unset, this is interpreted as "consistent read" and the + bookmark event is send when the state is synced at least to the moment + when request started being processed. + - `resourceVersionMatch` set to any other value or unset + Invalid error is returned. + + Defaults to true if `resourceVersion=""` or `resourceVersion="0"` (for backward compatibility reasons) and to false otherwise. */ + sendInitialEvents?: boolean; + /** Timeout for the list/watch call. This limits the duration of the call, regardless of any activity or inactivity. */ + timeoutSeconds?: number; +}; +export type GetTeamApiResponse = /** status 200 OK */ Team; +export type GetTeamApiArg = { + /** name of the Team */ + name: string; + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; +}; +export type ReplaceTeamApiResponse = /** status 200 OK */ Team | /** status 201 Created */ Team; +export type ReplaceTeamApiArg = { + /** name of the Team */ + name: string; + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; + /** When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed */ + dryRun?: string; + /** fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint. */ + fieldManager?: string; + /** fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields. Valid values are: - Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23. - Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default in v1.23+ - Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered. */ + fieldValidation?: string; + team: Team; +}; +export type DeleteTeamApiResponse = /** status 200 OK */ Status | /** status 202 Accepted */ Status; +export type DeleteTeamApiArg = { + /** name of the Team */ + name: string; + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; + /** When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed */ + dryRun?: string; + /** The duration in seconds before the object should be deleted. Value must be non-negative integer. The value zero indicates delete immediately. If this value is nil, the default grace period for the specified type will be used. Defaults to a per object value if not specified. zero means delete immediately. */ + gracePeriodSeconds?: number; + /** if set to true, it will trigger an unsafe deletion of the resource in case the normal deletion flow fails with a corrupt object error. A resource is considered corrupt if it can not be retrieved from the underlying storage successfully because of a) its data can not be transformed e.g. decryption failure, or b) it fails to decode into an object. NOTE: unsafe deletion ignores finalizer constraints, skips precondition checks, and removes the object from the storage. WARNING: This may potentially break the cluster if the workload associated with the resource being unsafe-deleted relies on normal deletion flow. Use only if you REALLY know what you are doing. The default value is false, and the user must opt in to enable it */ + ignoreStoreReadErrorWithClusterBreakingPotential?: boolean; + /** Deprecated: please use the PropagationPolicy, this field will be deprecated in 1.7. Should the dependent objects be orphaned. If true/false, the "orphan" finalizer will be added to/removed from the object's finalizers list. Either this field or PropagationPolicy may be set, but not both. */ + orphanDependents?: boolean; + /** Whether and how garbage collection will be performed. Either this field or OrphanDependents may be set, but not both. The default policy is decided by the existing finalizer set in the metadata.finalizers and the resource-specific default policy. Acceptable values are: 'Orphan' - orphan the dependents; 'Background' - allow the garbage collector to delete the dependents in the background; 'Foreground' - a cascading policy that deletes all dependents in the foreground. */ + propagationPolicy?: string; +}; +export type UpdateTeamApiResponse = /** status 200 OK */ Team | /** status 201 Created */ Team; +export type UpdateTeamApiArg = { + /** name of the Team */ + name: string; + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; + /** When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed */ + dryRun?: string; + /** fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint. This field is required for apply requests (application/apply-patch) but optional for non-apply patch types (JsonPatch, MergePatch, StrategicMergePatch). */ + fieldManager?: string; + /** fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields. Valid values are: - Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23. - Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default in v1.23+ - Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered. */ + fieldValidation?: string; + /** Force is going to "force" Apply requests. It means user will re-acquire conflicting fields owned by other people. Force flag must be unset for non-apply patch requests. */ + force?: boolean; + patch: Patch; +}; +export type GetTeamMembersApiResponse = /** status 200 OK */ TeamMemberList; +export type GetTeamMembersApiArg = { + /** name of the TeamMemberList */ + name: string; +}; +export type ListUserApiResponse = /** status 200 OK */ UserList; +export type ListUserApiArg = { + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; + /** allowWatchBookmarks requests watch events with type "BOOKMARK". Servers that do not implement bookmarks may ignore this flag and bookmarks are sent at the server's discretion. Clients should not assume bookmarks are returned at any specific interval, nor may they assume the server will send any BOOKMARK event during a session. If this is not a watch, this field is ignored. */ + allowWatchBookmarks?: boolean; + /** The continue option should be set when retrieving more results from the server. Since this value is server defined, clients may only use the continue value from a previous query result with identical query parameters (except for the value of continue) and the server may reject a continue value it does not recognize. If the specified continue value is no longer valid whether due to expiration (generally five to fifteen minutes) or a configuration change on the server, the server will respond with a 410 ResourceExpired error together with a continue token. If the client needs a consistent list, it must restart their list without the continue field. Otherwise, the client may send another list request with the token received with the 410 error, the server will respond with a list starting from the next key, but from the latest snapshot, which is inconsistent from the previous list results - objects that are created, modified, or deleted after the first list request will be included in the response, as long as their keys are after the "next key". + + This field is not supported when watch is true. Clients may start a watch from the last resourceVersion value returned by the server and not miss any modifications. */ + continue?: string; + /** A selector to restrict the list of returned objects by their fields. Defaults to everything. */ + fieldSelector?: string; + /** A selector to restrict the list of returned objects by their labels. Defaults to everything. */ + labelSelector?: string; + /** limit is a maximum number of responses to return for a list call. If more items exist, the server will set the `continue` field on the list metadata to a value that can be used with the same initial query to retrieve the next set of results. Setting a limit may return fewer than the requested amount of items (up to zero items) in the event all requested objects are filtered out and clients should only use the presence of the continue field to determine whether more results are available. Servers may choose not to support the limit argument and will return all of the available results. If limit is specified and the continue field is empty, clients may assume that no more results are available. This field is not supported if watch is true. + + The server guarantees that the objects returned when using continue will be identical to issuing a single list call without a limit - that is, no objects created, modified, or deleted after the first request is issued will be included in any subsequent continued requests. This is sometimes referred to as a consistent snapshot, and ensures that a client that is using limit to receive smaller chunks of a very large result can ensure they see all possible objects. If objects are updated during a chunked list the version of the object that was present at the time the first list result was calculated is returned. */ + limit?: number; + /** resourceVersion sets a constraint on what resource versions a request may be served from. See https://kubernetes.io/docs/reference/using-api/api-concepts/#resource-versions for details. + + Defaults to unset */ + resourceVersion?: string; + /** resourceVersionMatch determines how resourceVersion is applied to list calls. It is highly recommended that resourceVersionMatch be set for list calls where resourceVersion is set See https://kubernetes.io/docs/reference/using-api/api-concepts/#resource-versions for details. + + Defaults to unset */ + resourceVersionMatch?: string; + /** `sendInitialEvents=true` may be set together with `watch=true`. In that case, the watch stream will begin with synthetic events to produce the current state of objects in the collection. Once all such events have been sent, a synthetic "Bookmark" event will be sent. The bookmark will report the ResourceVersion (RV) corresponding to the set of objects, and be marked with `"k8s.io/initial-events-end": "true"` annotation. Afterwards, the watch stream will proceed as usual, sending watch events corresponding to changes (subsequent to the RV) to objects watched. + + When `sendInitialEvents` option is set, we require `resourceVersionMatch` option to also be set. The semantic of the watch request is as following: - `resourceVersionMatch` = NotOlderThan + is interpreted as "data at least as new as the provided `resourceVersion`" + and the bookmark event is send when the state is synced + to a `resourceVersion` at least as fresh as the one provided by the ListOptions. + If `resourceVersion` is unset, this is interpreted as "consistent read" and the + bookmark event is send when the state is synced at least to the moment + when request started being processed. + - `resourceVersionMatch` set to any other value or unset + Invalid error is returned. + + Defaults to true if `resourceVersion=""` or `resourceVersion="0"` (for backward compatibility reasons) and to false otherwise. */ + sendInitialEvents?: boolean; + /** Timeout for the list/watch call. This limits the duration of the call, regardless of any activity or inactivity. */ + timeoutSeconds?: number; + /** Watch for changes to the described resources and return them as a stream of add, update, and remove notifications. Specify resourceVersion. */ + watch?: boolean; +}; +export type CreateUserApiResponse = /** status 200 OK */ + | User + | /** status 201 Created */ User + | /** status 202 Accepted */ User; +export type CreateUserApiArg = { + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; + /** When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed */ + dryRun?: string; + /** fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint. */ + fieldManager?: string; + /** fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields. Valid values are: - Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23. - Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default in v1.23+ - Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered. */ + fieldValidation?: string; + user: User; +}; +export type DeletecollectionUserApiResponse = /** status 200 OK */ Status; +export type DeletecollectionUserApiArg = { + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; + /** The continue option should be set when retrieving more results from the server. Since this value is server defined, clients may only use the continue value from a previous query result with identical query parameters (except for the value of continue) and the server may reject a continue value it does not recognize. If the specified continue value is no longer valid whether due to expiration (generally five to fifteen minutes) or a configuration change on the server, the server will respond with a 410 ResourceExpired error together with a continue token. If the client needs a consistent list, it must restart their list without the continue field. Otherwise, the client may send another list request with the token received with the 410 error, the server will respond with a list starting from the next key, but from the latest snapshot, which is inconsistent from the previous list results - objects that are created, modified, or deleted after the first list request will be included in the response, as long as their keys are after the "next key". + + This field is not supported when watch is true. Clients may start a watch from the last resourceVersion value returned by the server and not miss any modifications. */ + continue?: string; + /** When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed */ + dryRun?: string; + /** A selector to restrict the list of returned objects by their fields. Defaults to everything. */ + fieldSelector?: string; + /** The duration in seconds before the object should be deleted. Value must be non-negative integer. The value zero indicates delete immediately. If this value is nil, the default grace period for the specified type will be used. Defaults to a per object value if not specified. zero means delete immediately. */ + gracePeriodSeconds?: number; + /** if set to true, it will trigger an unsafe deletion of the resource in case the normal deletion flow fails with a corrupt object error. A resource is considered corrupt if it can not be retrieved from the underlying storage successfully because of a) its data can not be transformed e.g. decryption failure, or b) it fails to decode into an object. NOTE: unsafe deletion ignores finalizer constraints, skips precondition checks, and removes the object from the storage. WARNING: This may potentially break the cluster if the workload associated with the resource being unsafe-deleted relies on normal deletion flow. Use only if you REALLY know what you are doing. The default value is false, and the user must opt in to enable it */ + ignoreStoreReadErrorWithClusterBreakingPotential?: boolean; + /** A selector to restrict the list of returned objects by their labels. Defaults to everything. */ + labelSelector?: string; + /** limit is a maximum number of responses to return for a list call. If more items exist, the server will set the `continue` field on the list metadata to a value that can be used with the same initial query to retrieve the next set of results. Setting a limit may return fewer than the requested amount of items (up to zero items) in the event all requested objects are filtered out and clients should only use the presence of the continue field to determine whether more results are available. Servers may choose not to support the limit argument and will return all of the available results. If limit is specified and the continue field is empty, clients may assume that no more results are available. This field is not supported if watch is true. + + The server guarantees that the objects returned when using continue will be identical to issuing a single list call without a limit - that is, no objects created, modified, or deleted after the first request is issued will be included in any subsequent continued requests. This is sometimes referred to as a consistent snapshot, and ensures that a client that is using limit to receive smaller chunks of a very large result can ensure they see all possible objects. If objects are updated during a chunked list the version of the object that was present at the time the first list result was calculated is returned. */ + limit?: number; + /** Deprecated: please use the PropagationPolicy, this field will be deprecated in 1.7. Should the dependent objects be orphaned. If true/false, the "orphan" finalizer will be added to/removed from the object's finalizers list. Either this field or PropagationPolicy may be set, but not both. */ + orphanDependents?: boolean; + /** Whether and how garbage collection will be performed. Either this field or OrphanDependents may be set, but not both. The default policy is decided by the existing finalizer set in the metadata.finalizers and the resource-specific default policy. Acceptable values are: 'Orphan' - orphan the dependents; 'Background' - allow the garbage collector to delete the dependents in the background; 'Foreground' - a cascading policy that deletes all dependents in the foreground. */ + propagationPolicy?: string; + /** resourceVersion sets a constraint on what resource versions a request may be served from. See https://kubernetes.io/docs/reference/using-api/api-concepts/#resource-versions for details. + + Defaults to unset */ + resourceVersion?: string; + /** resourceVersionMatch determines how resourceVersion is applied to list calls. It is highly recommended that resourceVersionMatch be set for list calls where resourceVersion is set See https://kubernetes.io/docs/reference/using-api/api-concepts/#resource-versions for details. + + Defaults to unset */ + resourceVersionMatch?: string; + /** `sendInitialEvents=true` may be set together with `watch=true`. In that case, the watch stream will begin with synthetic events to produce the current state of objects in the collection. Once all such events have been sent, a synthetic "Bookmark" event will be sent. The bookmark will report the ResourceVersion (RV) corresponding to the set of objects, and be marked with `"k8s.io/initial-events-end": "true"` annotation. Afterwards, the watch stream will proceed as usual, sending watch events corresponding to changes (subsequent to the RV) to objects watched. + + When `sendInitialEvents` option is set, we require `resourceVersionMatch` option to also be set. The semantic of the watch request is as following: - `resourceVersionMatch` = NotOlderThan + is interpreted as "data at least as new as the provided `resourceVersion`" + and the bookmark event is send when the state is synced + to a `resourceVersion` at least as fresh as the one provided by the ListOptions. + If `resourceVersion` is unset, this is interpreted as "consistent read" and the + bookmark event is send when the state is synced at least to the moment + when request started being processed. + - `resourceVersionMatch` set to any other value or unset + Invalid error is returned. + + Defaults to true if `resourceVersion=""` or `resourceVersion="0"` (for backward compatibility reasons) and to false otherwise. */ + sendInitialEvents?: boolean; + /** Timeout for the list/watch call. This limits the duration of the call, regardless of any activity or inactivity. */ + timeoutSeconds?: number; +}; +export type GetUserApiResponse = /** status 200 OK */ User; +export type GetUserApiArg = { + /** name of the User */ + name: string; + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; +}; +export type ReplaceUserApiResponse = /** status 200 OK */ User | /** status 201 Created */ User; +export type ReplaceUserApiArg = { + /** name of the User */ + name: string; + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; + /** When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed */ + dryRun?: string; + /** fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint. */ + fieldManager?: string; + /** fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields. Valid values are: - Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23. - Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default in v1.23+ - Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered. */ + fieldValidation?: string; + user: User; +}; +export type DeleteUserApiResponse = /** status 200 OK */ Status | /** status 202 Accepted */ Status; +export type DeleteUserApiArg = { + /** name of the User */ + name: string; + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; + /** When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed */ + dryRun?: string; + /** The duration in seconds before the object should be deleted. Value must be non-negative integer. The value zero indicates delete immediately. If this value is nil, the default grace period for the specified type will be used. Defaults to a per object value if not specified. zero means delete immediately. */ + gracePeriodSeconds?: number; + /** if set to true, it will trigger an unsafe deletion of the resource in case the normal deletion flow fails with a corrupt object error. A resource is considered corrupt if it can not be retrieved from the underlying storage successfully because of a) its data can not be transformed e.g. decryption failure, or b) it fails to decode into an object. NOTE: unsafe deletion ignores finalizer constraints, skips precondition checks, and removes the object from the storage. WARNING: This may potentially break the cluster if the workload associated with the resource being unsafe-deleted relies on normal deletion flow. Use only if you REALLY know what you are doing. The default value is false, and the user must opt in to enable it */ + ignoreStoreReadErrorWithClusterBreakingPotential?: boolean; + /** Deprecated: please use the PropagationPolicy, this field will be deprecated in 1.7. Should the dependent objects be orphaned. If true/false, the "orphan" finalizer will be added to/removed from the object's finalizers list. Either this field or PropagationPolicy may be set, but not both. */ + orphanDependents?: boolean; + /** Whether and how garbage collection will be performed. Either this field or OrphanDependents may be set, but not both. The default policy is decided by the existing finalizer set in the metadata.finalizers and the resource-specific default policy. Acceptable values are: 'Orphan' - orphan the dependents; 'Background' - allow the garbage collector to delete the dependents in the background; 'Foreground' - a cascading policy that deletes all dependents in the foreground. */ + propagationPolicy?: string; +}; +export type UpdateUserApiResponse = /** status 200 OK */ User | /** status 201 Created */ User; +export type UpdateUserApiArg = { + /** name of the User */ + name: string; + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; + /** When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed */ + dryRun?: string; + /** fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint. This field is required for apply requests (application/apply-patch) but optional for non-apply patch types (JsonPatch, MergePatch, StrategicMergePatch). */ + fieldManager?: string; + /** fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields. Valid values are: - Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23. - Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default in v1.23+ - Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered. */ + fieldValidation?: string; + /** Force is going to "force" Apply requests. It means user will re-acquire conflicting fields owned by other people. Force flag must be unset for non-apply patch requests. */ + force?: boolean; + patch: Patch; +}; +export type GetUserTeamsApiResponse = /** status 200 OK */ UserTeamList; +export type GetUserTeamsApiArg = { + /** name of the UserTeamList */ + name: string; +}; +export type ApiResource = { + /** categories is a list of the grouped resources this resource belongs to (e.g. 'all') */ + categories?: string[]; + /** group is the preferred group of the resource. Empty implies the group of the containing resource list. For subresources, this may have a different value, for example: Scale". */ + group?: string; + /** kind is the kind for the resource (e.g. 'Foo' is the kind for a resource 'foo') */ + kind: string; + /** name is the plural name of the resource. */ + name: string; + /** namespaced indicates if a resource is namespaced or not. */ + namespaced: boolean; + /** shortNames is a list of suggested short names of the resource. */ + shortNames?: string[]; + /** singularName is the singular name of the resource. This allows clients to handle plural and singular opaquely. The singularName is more correct for reporting status on a single item and both singular and plural are allowed from the kubectl CLI interface. */ + singularName: string; + /** The hash value of the storage version, the version this resource is converted to when written to the data store. Value must be treated as opaque by clients. Only equality comparison on the value is valid. This is an alpha feature and may change or be removed in the future. The field is populated by the apiserver only if the StorageVersionHash feature gate is enabled. This field will remain optional even if it graduates. */ + storageVersionHash?: string; + /** verbs is a list of supported kube verbs (this includes get, list, watch, create, update, patch, delete, deletecollection, and proxy) */ + verbs: string[]; + /** version is the preferred version of the resource. Empty implies the version of the containing resource list For subresources, this may have a different value, for example: v1 (while inside a v1beta1 version of the core resource's group)". */ + version?: string; +}; +export type ApiResourceList = { + /** APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources */ + apiVersion?: string; + /** groupVersion is the group and version this APIResourceList is for. */ + groupVersion: string; + /** Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds */ + kind?: string; + /** resources contains the name of the resources and if they are namespaced. */ + resources: ApiResource[]; +}; export type IdentityRef = { /** Name is the unique identifier for identity, guaranteed to be a unique value for the type within a namespace. */ name: string; @@ -62,3 +1412,362 @@ export type DisplayList = { kind?: string; metadata?: ListMeta; }; +export type Time = string; +export type FieldsV1 = object; +export type ManagedFieldsEntry = { + /** APIVersion defines the version of this resource that this field set applies to. The format is "group/version" just like the top-level APIVersion field. It is necessary to track the version of a field set because it cannot be automatically converted. */ + apiVersion?: string; + /** FieldsType is the discriminator for the different fields format and version. There is currently only one possible value: "FieldsV1" */ + fieldsType?: string; + /** FieldsV1 holds the first JSON version format as described in the "FieldsV1" type. */ + fieldsV1?: FieldsV1; + /** Manager is an identifier of the workflow managing these fields. */ + manager?: string; + /** Operation is the type of operation which lead to this ManagedFieldsEntry being created. The only valid values for this field are 'Apply' and 'Update'. */ + operation?: string; + /** Subresource is the name of the subresource used to update that object, or empty string if the object was updated through the main resource. The value of this field is used to distinguish between managers, even if they share the same name. For example, a status update will be distinct from a regular update using the same manager name. Note that the APIVersion field is not related to the Subresource field and it always corresponds to the version of the main resource. */ + subresource?: string; + /** Time is the timestamp of when the ManagedFields entry was added. The timestamp will also be updated if a field is added, the manager changes any of the owned fields value or removes a field. The timestamp does not update when a field is removed from the entry because another manager took it over. */ + time?: Time; +}; +export type OwnerReference = { + /** API version of the referent. */ + apiVersion: string; + /** If true, AND if the owner has the "foregroundDeletion" finalizer, then the owner cannot be deleted from the key-value store until this reference is removed. See https://kubernetes.io/docs/concepts/architecture/garbage-collection/#foreground-deletion for how the garbage collector interacts with this field and enforces the foreground deletion. Defaults to false. To set this field, a user needs "delete" permission of the owner, otherwise 422 (Unprocessable Entity) will be returned. */ + blockOwnerDeletion?: boolean; + /** If true, this reference points to the managing controller. */ + controller?: boolean; + /** Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds */ + kind: string; + /** Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names */ + name: string; + /** UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#uids */ + uid: string; +}; +export type ObjectMeta = { + /** Annotations is an unstructured key value map stored with a resource that may be set by external tools to store and retrieve arbitrary metadata. They are not queryable and should be preserved when modifying objects. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations */ + annotations?: { + [key: string]: string; + }; + /** CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC. + + Populated by the system. Read-only. Null for lists. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata */ + creationTimestamp?: Time; + /** Number of seconds allowed for this object to gracefully terminate before it will be removed from the system. Only set when deletionTimestamp is also set. May only be shortened. Read-only. */ + deletionGracePeriodSeconds?: number; + /** DeletionTimestamp is RFC 3339 date and time at which this resource will be deleted. This field is set by the server when a graceful deletion is requested by the user, and is not directly settable by a client. The resource is expected to be deleted (no longer visible from resource lists, and not reachable by name) after the time in this field, once the finalizers list is empty. As long as the finalizers list contains items, deletion is blocked. Once the deletionTimestamp is set, this value may not be unset or be set further into the future, although it may be shortened or the resource may be deleted prior to this time. For example, a user may request that a pod is deleted in 30 seconds. The Kubelet will react by sending a graceful termination signal to the containers in the pod. After that 30 seconds, the Kubelet will send a hard termination signal (SIGKILL) to the container and after cleanup, remove the pod from the API. In the presence of network partitions, this object may still exist after this timestamp, until an administrator or automated process can determine the resource is fully terminated. If not set, graceful deletion of the object has not been requested. + + Populated by the system when a graceful deletion is requested. Read-only. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata */ + deletionTimestamp?: Time; + /** Must be empty before the object is deleted from the registry. Each entry is an identifier for the responsible component that will remove the entry from the list. If the deletionTimestamp of the object is non-nil, entries in this list can only be removed. Finalizers may be processed and removed in any order. Order is NOT enforced because it introduces significant risk of stuck finalizers. finalizers is a shared field, any actor with permission can reorder it. If the finalizer list is processed in order, then this can lead to a situation in which the component responsible for the first finalizer in the list is waiting for a signal (field value, external system, or other) produced by a component responsible for a finalizer later in the list, resulting in a deadlock. Without enforced ordering finalizers are free to order amongst themselves and are not vulnerable to ordering changes in the list. */ + finalizers?: string[]; + /** GenerateName is an optional prefix, used by the server, to generate a unique name ONLY IF the Name field has not been provided. If this field is used, the name returned to the client will be different than the name passed. This value will also be combined with a unique suffix. The provided value has the same validation rules as the Name field, and may be truncated by the length of the suffix required to make the value unique on the server. + + If this field is specified and the generated name exists, the server will return a 409. + + Applied only if Name is not specified. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#idempotency */ + generateName?: string; + /** A sequence number representing a specific generation of the desired state. Populated by the system. Read-only. */ + generation?: number; + /** Map of string keys and values that can be used to organize and categorize (scope and select) objects. May match selectors of replication controllers and services. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels */ + labels?: { + [key: string]: string; + }; + /** ManagedFields maps workflow-id and version to the set of fields that are managed by that workflow. This is mostly for internal housekeeping, and users typically shouldn't need to set or understand this field. A workflow can be the user's name, a controller's name, or the name of a specific apply path like "ci-cd". The set of fields is always in the version that the workflow used when modifying the object. */ + managedFields?: ManagedFieldsEntry[]; + /** Name must be unique within a namespace. Is required when creating resources, although some resources may allow a client to request the generation of an appropriate name automatically. Name is primarily intended for creation idempotence and configuration definition. Cannot be updated. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names */ + name?: string; + /** Namespace defines the space within which each name must be unique. An empty namespace is equivalent to the "default" namespace, but "default" is the canonical representation. Not all objects are required to be scoped to a namespace - the value of this field for those objects will be empty. + + Must be a DNS_LABEL. Cannot be updated. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces */ + namespace?: string; + /** List of objects depended by this object. If ALL objects in the list have been deleted, this object will be garbage collected. If this object is managed by a controller, then an entry in this list will point to this controller, with the controller field set to true. There cannot be more than one managing controller. */ + ownerReferences?: OwnerReference[]; + /** An opaque value that represents the internal version of this object that can be used by clients to determine when objects have changed. May be used for optimistic concurrency, change detection, and the watch operation on a resource or set of resources. Clients must treat these values as opaque and passed unmodified back to the server. They may only be valid for a particular resource or set of resources. + + Populated by the system. Read-only. Value must be treated as opaque by clients and . More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency */ + resourceVersion?: string; + /** Deprecated: selfLink is a legacy read-only field that is no longer populated by the system. */ + selfLink?: string; + /** UID is the unique in time and space value for this object. It is typically generated by the server on successful creation of a resource and is not allowed to change on PUT operations. + + Populated by the system. Read-only. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#uids */ + uid?: string; +}; +export type ServiceAccountSpec = { + disabled: boolean; + plugin: string; + role: string; + title: string; +}; +export type ServiceAccount = { + /** APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources */ + apiVersion?: string; + /** Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds */ + kind?: string; + metadata: ObjectMeta; + /** Spec is the spec of the ServiceAccount */ + spec: ServiceAccountSpec; +}; +export type ServiceAccountList = { + /** APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources */ + apiVersion?: string; + items: ServiceAccount[]; + /** Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds */ + kind?: string; + metadata: ListMeta; +}; +export type StatusCause = { + /** The field of the resource that has caused this error, as named by its JSON serialization. May include dot and postfix notation for nested attributes. Arrays are zero-indexed. Fields may appear more than once in an array of causes due to fields having multiple errors. Optional. + + Examples: + "name" - the field "name" on the current resource + "items[0].name" - the field "name" on the first array entry in "items" */ + field?: string; + /** A human-readable description of the cause of the error. This field may be presented as-is to a reader. */ + message?: string; + /** A machine-readable description of the cause of the error. If this value is empty there is no information available. */ + reason?: string; +}; +export type StatusDetails = { + /** The Causes array includes more details associated with the StatusReason failure. Not all StatusReasons may provide detailed causes. */ + causes?: StatusCause[]; + /** The group attribute of the resource associated with the status StatusReason. */ + group?: string; + /** The kind attribute of the resource associated with the status StatusReason. On some operations may differ from the requested resource Kind. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds */ + kind?: string; + /** The name attribute of the resource associated with the status StatusReason (when there is a single name which can be described). */ + name?: string; + /** If specified, the time in seconds before the operation should be retried. Some errors may indicate the client must take an alternate action - for those errors this field may indicate how long to wait before taking the alternate action. */ + retryAfterSeconds?: number; + /** UID of the resource. (when there is a single resource which can be described). More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#uids */ + uid?: string; +}; +export type Status = { + /** APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources */ + apiVersion?: string; + /** Suggested HTTP return code for this status, 0 if not set. */ + code?: number; + /** Extended data associated with the reason. Each reason may define its own extended details. This field is optional and the data returned is not guaranteed to conform to any schema except that defined by the reason type. */ + details?: StatusDetails; + /** Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds */ + kind?: string; + /** A human-readable description of the status of this operation. */ + message?: string; + /** Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds */ + metadata?: ListMeta; + /** A machine-readable description of why this operation is in the "Failure" status. If this value is empty there is no information available. A Reason clarifies an HTTP status code but does not override it. */ + reason?: string; + /** Status of the operation. One of: "Success" or "Failure". More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status */ + status?: string; +}; +export type Patch = object; +export type ServiceAccountToken = { + created: Time; + expires?: Time; + lastUsed?: Time; + name?: string; + revoked?: boolean; +}; +export type ServiceAccountTokenList = { + /** APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources */ + apiVersion?: string; + items: ServiceAccountToken[]; + /** Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds */ + kind?: string; + metadata?: ListMeta; +}; +export type Unstructured = { + [key: string]: any; +}; +export type SsoSettingSpec = { + settings: Unstructured; + /** Possible enum values: + - `"db"` + - `"system"` system is from config file, env or argument */ + source: 'db' | 'system'; +}; +export type SsoSetting = { + /** APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources */ + apiVersion?: string; + /** Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds */ + kind?: string; + /** Standard object's metadata More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata */ + metadata?: ObjectMeta; + spec?: SsoSettingSpec; +}; +export type SsoSettingList = { + /** APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources */ + apiVersion?: string; + items: SsoSetting[]; + /** Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds */ + kind?: string; + metadata?: ListMeta; +}; +export type TeamBindingspecSubject = { + /** uid of the identity */ + name: string; +}; +export type TeamBindingTeamRef = { + /** Name is the unique identifier for a team. */ + name: string; +}; +export type TeamBindingSpec = { + external: boolean; + /** permission of the identity in the team */ + permission: string; + subject: TeamBindingspecSubject; + teamRef: TeamBindingTeamRef; +}; +export type TeamBinding = { + /** APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources */ + apiVersion?: string; + /** Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds */ + kind?: string; + metadata: ObjectMeta; + /** Spec is the spec of the TeamBinding */ + spec: TeamBindingSpec; +}; +export type TeamBindingList = { + /** APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources */ + apiVersion?: string; + items: TeamBinding[]; + /** Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds */ + kind?: string; + metadata: ListMeta; +}; +export type TeamSpec = { + email: string; + externalUID: string; + provisioned: boolean; + title: string; +}; +export type Team = { + /** APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources */ + apiVersion?: string; + /** Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds */ + kind?: string; + metadata: ObjectMeta; + /** Spec is the spec of the Team */ + spec: TeamSpec; +}; +export type TeamList = { + /** APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources */ + apiVersion?: string; + items: Team[]; + /** Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds */ + kind?: string; + metadata: ListMeta; +}; +export type TeamMember = { + /** AvatarURL is the url where we can get the avatar for identity */ + avatarURL?: string; + /** Display name for identity. */ + displayName: string; + /** External is set if member ship was synced from external IDP. */ + external?: boolean; + identity: IdentityRef; + /** InternalID is the legacy numeric id for identity, Deprecated: use the identityRef where possible */ + internalId?: number; + /** Permission member has in team. + + Possible enum values: + - `"admin"` + - `"member"` */ + permission?: 'admin' | 'member'; +}; +export type TeamMemberList = { + /** APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources */ + apiVersion?: string; + items: TeamMember[]; + /** Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds */ + kind?: string; + metadata?: ListMeta; +}; +export type UserSpec = { + disabled: boolean; + email: string; + emailVerified: boolean; + grafanaAdmin: boolean; + login: string; + provisioned: boolean; + role: string; + title: string; +}; +export type User = { + /** APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources */ + apiVersion?: string; + /** Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds */ + kind?: string; + metadata: ObjectMeta; + /** Spec is the spec of the User */ + spec: UserSpec; +}; +export type UserList = { + /** APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources */ + apiVersion?: string; + items: User[]; + /** Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds */ + kind?: string; + metadata: ListMeta; +}; +export type TeamRef = { + /** Name is the unique identifier for a team. */ + name?: string; +}; +export type UserTeam = { + /** Possible enum values: + - `"admin"` + - `"member"` */ + permission?: 'admin' | 'member'; + teamRef?: TeamRef; + title?: string; +}; +export type UserTeamList = { + /** APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources */ + apiVersion?: string; + items: UserTeam[]; + /** Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds */ + kind?: string; + metadata?: ListMeta; +}; +export const { + useGetApiResourcesQuery, + useGetDisplayMappingQuery, + useListServiceAccountQuery, + useCreateServiceAccountMutation, + useDeletecollectionServiceAccountMutation, + useGetServiceAccountQuery, + useReplaceServiceAccountMutation, + useDeleteServiceAccountMutation, + useUpdateServiceAccountMutation, + useGetServiceAccountTokensQuery, + useListSsoSettingQuery, + useGetSsoSettingQuery, + useReplaceSsoSettingMutation, + useDeleteSsoSettingMutation, + useUpdateSsoSettingMutation, + useListTeamBindingQuery, + useCreateTeamBindingMutation, + useDeletecollectionTeamBindingMutation, + useGetTeamBindingQuery, + useReplaceTeamBindingMutation, + useDeleteTeamBindingMutation, + useUpdateTeamBindingMutation, + useListTeamQuery, + useCreateTeamMutation, + useDeletecollectionTeamMutation, + useGetTeamQuery, + useReplaceTeamMutation, + useDeleteTeamMutation, + useUpdateTeamMutation, + useGetTeamMembersQuery, + useListUserQuery, + useCreateUserMutation, + useDeletecollectionUserMutation, + useGetUserQuery, + useReplaceUserMutation, + useDeleteUserMutation, + useUpdateUserMutation, + useGetUserTeamsQuery, +} = injectedRtkApi; diff --git a/packages/grafana-api-clients/src/clients/rtkq/legacy/baseAPI.ts b/packages/grafana-api-clients/src/clients/rtkq/legacy/baseAPI.ts new file mode 100644 index 00000000000..a9a3a0c84bb --- /dev/null +++ b/packages/grafana-api-clients/src/clients/rtkq/legacy/baseAPI.ts @@ -0,0 +1,9 @@ +import { createApi } from '@reduxjs/toolkit/query/react'; + +import { createBaseQuery } from '../createBaseQuery'; + +export const api = createApi({ + reducerPath: 'legacyAPI', + baseQuery: createBaseQuery({ baseURL: '/api' }), + endpoints: () => ({}), +}); diff --git a/packages/grafana-api-clients/src/clients/rtkq/legacy/endpoints.gen.ts b/packages/grafana-api-clients/src/clients/rtkq/legacy/endpoints.gen.ts new file mode 100644 index 00000000000..eb201201379 --- /dev/null +++ b/packages/grafana-api-clients/src/clients/rtkq/legacy/endpoints.gen.ts @@ -0,0 +1,6820 @@ +import { api } from './baseAPI'; +export const addTagTypes = [ + 'enterprise', + 'access_control', + 'ldap_debug', + 'admin_ldap', + 'access_control_provisioning', + 'admin_provisioning', + 'admin', + 'admin_users', + 'quota', + 'annotations', + 'devices', + 'migrations', + 'convert_prometheus', + 'dashboards', + 'snapshots', + 'dashboard_public', + 'permissions', + 'versions', + 'datasources', + 'correlations', + 'health', + 'folders', + 'group_attribute_sync', + 'library_elements', + 'licensing', + 'saml', + 'org', + 'invites', + 'preferences', + 'orgs', + 'playlists', + 'query_history', + 'recording_rules', + 'reports', + 'search', + 'service_accounts', + 'signing_keys', + 'teams', + 'sync_team_groups', + 'signed_in_user', + 'user', + 'users', + 'provisioning', + 'sso_settings', +] as const; +const injectedRtkApi = api + .enhanceEndpoints({ + addTagTypes, + }) + .injectEndpoints({ + endpoints: (build) => ({ + searchResult: build.mutation({ + query: () => ({ url: `/access-control/assignments/search`, method: 'POST' }), + invalidatesTags: ['enterprise'], + }), + listRoles: build.query({ + query: (queryArg) => ({ + url: `/access-control/roles`, + params: { + delegatable: queryArg.delegatable, + includeHidden: queryArg.includeHidden, + }, + }), + providesTags: ['access_control', 'enterprise'], + }), + createRole: build.mutation({ + query: (queryArg) => ({ url: `/access-control/roles`, method: 'POST', body: queryArg.createRoleForm }), + invalidatesTags: ['access_control', 'enterprise'], + }), + deleteRole: build.mutation({ + query: (queryArg) => ({ + url: `/access-control/roles/${queryArg.roleUid}`, + method: 'DELETE', + params: { + force: queryArg.force, + global: queryArg['global'], + }, + }), + invalidatesTags: ['access_control', 'enterprise'], + }), + getRole: build.query({ + query: (queryArg) => ({ url: `/access-control/roles/${queryArg.roleUid}` }), + providesTags: ['access_control', 'enterprise'], + }), + updateRole: build.mutation({ + query: (queryArg) => ({ + url: `/access-control/roles/${queryArg.roleUid}`, + method: 'PUT', + body: queryArg.updateRoleCommand, + }), + invalidatesTags: ['access_control', 'enterprise'], + }), + getRoleAssignments: build.query({ + query: (queryArg) => ({ url: `/access-control/roles/${queryArg.roleUid}/assignments` }), + providesTags: ['access_control', 'enterprise'], + }), + setRoleAssignments: build.mutation({ + query: (queryArg) => ({ + url: `/access-control/roles/${queryArg.roleUid}/assignments`, + method: 'PUT', + body: queryArg.setRoleAssignmentsCommand, + }), + invalidatesTags: ['access_control', 'enterprise'], + }), + getAccessControlStatus: build.query({ + query: () => ({ url: `/access-control/status` }), + providesTags: ['access_control', 'enterprise'], + }), + listTeamsRoles: build.mutation({ + query: (queryArg) => ({ + url: `/access-control/teams/roles/search`, + method: 'POST', + body: queryArg.rolesSearchQuery, + }), + invalidatesTags: ['access_control', 'enterprise'], + }), + listTeamRoles: build.query({ + query: (queryArg) => ({ url: `/access-control/teams/${queryArg.teamId}/roles` }), + providesTags: ['access_control', 'enterprise'], + }), + addTeamRole: build.mutation({ + query: (queryArg) => ({ + url: `/access-control/teams/${queryArg.teamId}/roles`, + method: 'POST', + body: queryArg.addTeamRoleCommand, + }), + invalidatesTags: ['access_control', 'enterprise'], + }), + setTeamRoles: build.mutation({ + query: (queryArg) => ({ url: `/access-control/teams/${queryArg.teamId}/roles`, method: 'PUT' }), + invalidatesTags: ['access_control', 'enterprise'], + }), + removeTeamRole: build.mutation({ + query: (queryArg) => ({ + url: `/access-control/teams/${queryArg.teamId}/roles/${queryArg.roleUid}`, + method: 'DELETE', + }), + invalidatesTags: ['access_control', 'enterprise'], + }), + listUsersRoles: build.mutation({ + query: (queryArg) => ({ + url: `/access-control/users/roles/search`, + method: 'POST', + body: queryArg.rolesSearchQuery, + }), + invalidatesTags: ['access_control', 'enterprise'], + }), + listUserRoles: build.query({ + query: (queryArg) => ({ url: `/access-control/users/${queryArg.userId}/roles` }), + providesTags: ['access_control', 'enterprise'], + }), + addUserRole: build.mutation({ + query: (queryArg) => ({ + url: `/access-control/users/${queryArg.userId}/roles`, + method: 'POST', + body: queryArg.addUserRoleCommand, + }), + invalidatesTags: ['access_control', 'enterprise'], + }), + setUserRoles: build.mutation({ + query: (queryArg) => ({ + url: `/access-control/users/${queryArg.userId}/roles`, + method: 'PUT', + body: queryArg.setUserRolesCommand, + }), + invalidatesTags: ['access_control', 'enterprise'], + }), + removeUserRole: build.mutation({ + query: (queryArg) => ({ + url: `/access-control/users/${queryArg.userId}/roles/${queryArg.roleUid}`, + method: 'DELETE', + params: { + global: queryArg['global'], + }, + }), + invalidatesTags: ['access_control', 'enterprise'], + }), + getResourceDescription: build.query({ + query: (queryArg) => ({ url: `/access-control/${queryArg.resource}/description` }), + providesTags: ['access_control'], + }), + getResourcePermissions: build.query({ + query: (queryArg) => ({ url: `/access-control/${queryArg.resource}/${queryArg.resourceId}` }), + providesTags: ['access_control'], + }), + setResourcePermissions: build.mutation({ + query: (queryArg) => ({ + url: `/access-control/${queryArg.resource}/${queryArg.resourceId}`, + method: 'POST', + body: queryArg.setPermissionsCommand, + }), + invalidatesTags: ['access_control'], + }), + setResourcePermissionsForBuiltInRole: build.mutation< + SetResourcePermissionsForBuiltInRoleApiResponse, + SetResourcePermissionsForBuiltInRoleApiArg + >({ + query: (queryArg) => ({ + url: `/access-control/${queryArg.resource}/${queryArg.resourceId}/builtInRoles/${queryArg.builtInRole}`, + method: 'POST', + body: queryArg.setPermissionCommand, + }), + invalidatesTags: ['access_control'], + }), + setResourcePermissionsForTeam: build.mutation< + SetResourcePermissionsForTeamApiResponse, + SetResourcePermissionsForTeamApiArg + >({ + query: (queryArg) => ({ + url: `/access-control/${queryArg.resource}/${queryArg.resourceId}/teams/${queryArg.teamId}`, + method: 'POST', + body: queryArg.setPermissionCommand, + }), + invalidatesTags: ['access_control'], + }), + setResourcePermissionsForUser: build.mutation< + SetResourcePermissionsForUserApiResponse, + SetResourcePermissionsForUserApiArg + >({ + query: (queryArg) => ({ + url: `/access-control/${queryArg.resource}/${queryArg.resourceId}/users/${queryArg.userId}`, + method: 'POST', + body: queryArg.setPermissionCommand, + }), + invalidatesTags: ['access_control'], + }), + getSyncStatus: build.query({ + query: () => ({ url: `/admin/ldap-sync-status` }), + providesTags: ['ldap_debug', 'enterprise'], + }), + reloadLdapCfg: build.mutation({ + query: () => ({ url: `/admin/ldap/reload`, method: 'POST' }), + invalidatesTags: ['admin_ldap'], + }), + getLdapStatus: build.query({ + query: () => ({ url: `/admin/ldap/status` }), + providesTags: ['admin_ldap'], + }), + postSyncUserWithLdap: build.mutation({ + query: (queryArg) => ({ url: `/admin/ldap/sync/${queryArg.userId}`, method: 'POST' }), + invalidatesTags: ['admin_ldap'], + }), + getUserFromLdap: build.query({ + query: (queryArg) => ({ url: `/admin/ldap/${queryArg.userName}` }), + providesTags: ['admin_ldap'], + }), + adminProvisioningReloadAccessControl: build.mutation< + AdminProvisioningReloadAccessControlApiResponse, + AdminProvisioningReloadAccessControlApiArg + >({ + query: () => ({ url: `/admin/provisioning/access-control/reload`, method: 'POST' }), + invalidatesTags: ['access_control_provisioning', 'enterprise'], + }), + adminProvisioningReloadDashboards: build.mutation< + AdminProvisioningReloadDashboardsApiResponse, + AdminProvisioningReloadDashboardsApiArg + >({ + query: () => ({ url: `/admin/provisioning/dashboards/reload`, method: 'POST' }), + invalidatesTags: ['admin_provisioning'], + }), + adminProvisioningReloadDatasources: build.mutation< + AdminProvisioningReloadDatasourcesApiResponse, + AdminProvisioningReloadDatasourcesApiArg + >({ + query: () => ({ url: `/admin/provisioning/datasources/reload`, method: 'POST' }), + invalidatesTags: ['admin_provisioning'], + }), + adminProvisioningReloadPlugins: build.mutation< + AdminProvisioningReloadPluginsApiResponse, + AdminProvisioningReloadPluginsApiArg + >({ + query: () => ({ url: `/admin/provisioning/plugins/reload`, method: 'POST' }), + invalidatesTags: ['admin_provisioning'], + }), + adminGetSettings: build.query({ + query: () => ({ url: `/admin/settings` }), + providesTags: ['admin'], + }), + adminGetStats: build.query({ + query: () => ({ url: `/admin/stats` }), + providesTags: ['admin'], + }), + adminCreateUser: build.mutation({ + query: (queryArg) => ({ url: `/admin/users`, method: 'POST', body: queryArg.adminCreateUserForm }), + invalidatesTags: ['admin_users'], + }), + adminDeleteUser: build.mutation({ + query: (queryArg) => ({ url: `/admin/users/${queryArg.userId}`, method: 'DELETE' }), + invalidatesTags: ['admin_users'], + }), + adminGetUserAuthTokens: build.query({ + query: (queryArg) => ({ url: `/admin/users/${queryArg.userId}/auth-tokens` }), + providesTags: ['admin_users'], + }), + adminDisableUser: build.mutation({ + query: (queryArg) => ({ url: `/admin/users/${queryArg.userId}/disable`, method: 'POST' }), + invalidatesTags: ['admin_users'], + }), + adminEnableUser: build.mutation({ + query: (queryArg) => ({ url: `/admin/users/${queryArg.userId}/enable`, method: 'POST' }), + invalidatesTags: ['admin_users'], + }), + adminLogoutUser: build.mutation({ + query: (queryArg) => ({ url: `/admin/users/${queryArg.userId}/logout`, method: 'POST' }), + invalidatesTags: ['admin_users'], + }), + adminUpdateUserPassword: build.mutation({ + query: (queryArg) => ({ + url: `/admin/users/${queryArg.userId}/password`, + method: 'PUT', + body: queryArg.adminUpdateUserPasswordForm, + }), + invalidatesTags: ['admin_users'], + }), + adminUpdateUserPermissions: build.mutation< + AdminUpdateUserPermissionsApiResponse, + AdminUpdateUserPermissionsApiArg + >({ + query: (queryArg) => ({ + url: `/admin/users/${queryArg.userId}/permissions`, + method: 'PUT', + body: queryArg.adminUpdateUserPermissionsForm, + }), + invalidatesTags: ['admin_users'], + }), + getUserQuota: build.query({ + query: (queryArg) => ({ url: `/admin/users/${queryArg.userId}/quotas` }), + providesTags: ['quota', 'admin_users'], + }), + updateUserQuota: build.mutation({ + query: (queryArg) => ({ + url: `/admin/users/${queryArg.userId}/quotas/${queryArg.quotaTarget}`, + method: 'PUT', + body: queryArg.updateQuotaCmd, + }), + invalidatesTags: ['quota', 'admin_users'], + }), + adminRevokeUserAuthToken: build.mutation({ + query: (queryArg) => ({ + url: `/admin/users/${queryArg.userId}/revoke-auth-token`, + method: 'POST', + body: queryArg.revokeAuthTokenCmd, + }), + invalidatesTags: ['admin_users'], + }), + getAnnotations: build.query({ + query: (queryArg) => ({ + url: `/annotations`, + params: { + from: queryArg['from'], + to: queryArg.to, + userId: queryArg.userId, + alertId: queryArg.alertId, + alertUID: queryArg.alertUid, + dashboardId: queryArg.dashboardId, + dashboardUID: queryArg.dashboardUid, + panelId: queryArg.panelId, + limit: queryArg.limit, + tags: queryArg.tags, + type: queryArg['type'], + matchAny: queryArg.matchAny, + }, + }), + providesTags: ['annotations'], + }), + postAnnotation: build.mutation({ + query: (queryArg) => ({ url: `/annotations`, method: 'POST', body: queryArg.postAnnotationsCmd }), + invalidatesTags: ['annotations'], + }), + postGraphiteAnnotation: build.mutation({ + query: (queryArg) => ({ + url: `/annotations/graphite`, + method: 'POST', + body: queryArg.postGraphiteAnnotationsCmd, + }), + invalidatesTags: ['annotations'], + }), + massDeleteAnnotations: build.mutation({ + query: (queryArg) => ({ + url: `/annotations/mass-delete`, + method: 'POST', + body: queryArg.massDeleteAnnotationsCmd, + }), + invalidatesTags: ['annotations'], + }), + getAnnotationTags: build.query({ + query: (queryArg) => ({ + url: `/annotations/tags`, + params: { + tag: queryArg.tag, + limit: queryArg.limit, + }, + }), + providesTags: ['annotations'], + }), + deleteAnnotationById: build.mutation({ + query: (queryArg) => ({ url: `/annotations/${queryArg.annotationId}`, method: 'DELETE' }), + invalidatesTags: ['annotations'], + }), + getAnnotationById: build.query({ + query: (queryArg) => ({ url: `/annotations/${queryArg.annotationId}` }), + providesTags: ['annotations'], + }), + patchAnnotation: build.mutation({ + query: (queryArg) => ({ + url: `/annotations/${queryArg.annotationId}`, + method: 'PATCH', + body: queryArg.patchAnnotationsCmd, + }), + invalidatesTags: ['annotations'], + }), + updateAnnotation: build.mutation({ + query: (queryArg) => ({ + url: `/annotations/${queryArg.annotationId}`, + method: 'PUT', + body: queryArg.updateAnnotationsCmd, + }), + invalidatesTags: ['annotations'], + }), + listDevices: build.query({ + query: () => ({ url: `/anonymous/devices` }), + providesTags: ['devices'], + }), + searchDevices: build.query({ + query: () => ({ url: `/anonymous/search` }), + providesTags: ['devices'], + }), + getSessionList: build.query({ + query: () => ({ url: `/cloudmigration/migration` }), + providesTags: ['migrations'], + }), + createSession: build.mutation({ + query: (queryArg) => ({ + url: `/cloudmigration/migration`, + method: 'POST', + body: queryArg.cloudMigrationSessionRequestDto, + }), + invalidatesTags: ['migrations'], + }), + deleteSession: build.mutation({ + query: (queryArg) => ({ url: `/cloudmigration/migration/${queryArg.uid}`, method: 'DELETE' }), + invalidatesTags: ['migrations'], + }), + getSession: build.query({ + query: (queryArg) => ({ url: `/cloudmigration/migration/${queryArg.uid}` }), + providesTags: ['migrations'], + }), + createSnapshot: build.mutation({ + query: (queryArg) => ({ + url: `/cloudmigration/migration/${queryArg.uid}/snapshot`, + method: 'POST', + body: queryArg.createSnapshotRequestDto, + }), + invalidatesTags: ['migrations'], + }), + getSnapshot: build.query({ + query: (queryArg) => ({ + url: `/cloudmigration/migration/${queryArg.uid}/snapshot/${queryArg.snapshotUid}`, + params: { + resultPage: queryArg.resultPage, + resultLimit: queryArg.resultLimit, + resultSortColumn: queryArg.resultSortColumn, + resultSortOrder: queryArg.resultSortOrder, + errorsOnly: queryArg.errorsOnly, + }, + }), + providesTags: ['migrations'], + }), + cancelSnapshot: build.mutation({ + query: (queryArg) => ({ + url: `/cloudmigration/migration/${queryArg.uid}/snapshot/${queryArg.snapshotUid}/cancel`, + method: 'POST', + }), + invalidatesTags: ['migrations'], + }), + uploadSnapshot: build.mutation({ + query: (queryArg) => ({ + url: `/cloudmigration/migration/${queryArg.uid}/snapshot/${queryArg.snapshotUid}/upload`, + method: 'POST', + }), + invalidatesTags: ['migrations'], + }), + getShapshotList: build.query({ + query: (queryArg) => ({ + url: `/cloudmigration/migration/${queryArg.uid}/snapshots`, + params: { + page: queryArg.page, + limit: queryArg.limit, + sort: queryArg.sort, + }, + }), + providesTags: ['migrations'], + }), + getResourceDependencies: build.query({ + query: () => ({ url: `/cloudmigration/resources/dependencies` }), + providesTags: ['migrations'], + }), + getCloudMigrationToken: build.query({ + query: () => ({ url: `/cloudmigration/token` }), + providesTags: ['migrations'], + }), + createCloudMigrationToken: build.mutation({ + query: () => ({ url: `/cloudmigration/token`, method: 'POST' }), + invalidatesTags: ['migrations'], + }), + deleteCloudMigrationToken: build.mutation({ + query: (queryArg) => ({ url: `/cloudmigration/token/${queryArg.uid}`, method: 'DELETE' }), + invalidatesTags: ['migrations'], + }), + routeConvertPrometheusCortexGetRules: build.query< + RouteConvertPrometheusCortexGetRulesApiResponse, + RouteConvertPrometheusCortexGetRulesApiArg + >({ + query: () => ({ url: `/convert/api/prom/rules` }), + providesTags: ['convert_prometheus'], + }), + routeConvertPrometheusCortexPostRuleGroups: build.mutation< + RouteConvertPrometheusCortexPostRuleGroupsApiResponse, + RouteConvertPrometheusCortexPostRuleGroupsApiArg + >({ + query: () => ({ url: `/convert/api/prom/rules`, method: 'POST' }), + invalidatesTags: ['convert_prometheus'], + }), + routeConvertPrometheusCortexDeleteNamespace: build.mutation< + RouteConvertPrometheusCortexDeleteNamespaceApiResponse, + RouteConvertPrometheusCortexDeleteNamespaceApiArg + >({ + query: (queryArg) => ({ url: `/convert/api/prom/rules/${queryArg.namespaceTitle}`, method: 'DELETE' }), + invalidatesTags: ['convert_prometheus'], + }), + routeConvertPrometheusCortexGetNamespace: build.query< + RouteConvertPrometheusCortexGetNamespaceApiResponse, + RouteConvertPrometheusCortexGetNamespaceApiArg + >({ + query: (queryArg) => ({ url: `/convert/api/prom/rules/${queryArg.namespaceTitle}` }), + providesTags: ['convert_prometheus'], + }), + routeConvertPrometheusCortexPostRuleGroup: build.mutation< + RouteConvertPrometheusCortexPostRuleGroupApiResponse, + RouteConvertPrometheusCortexPostRuleGroupApiArg + >({ + query: (queryArg) => ({ + url: `/convert/api/prom/rules/${queryArg.namespaceTitle}`, + method: 'POST', + body: queryArg.prometheusRuleGroup, + headers: { + 'x-grafana-alerting-datasource-uid': queryArg['x-grafana-alerting-datasource-uid'], + 'x-grafana-alerting-recording-rules-paused': queryArg['x-grafana-alerting-recording-rules-paused'], + 'x-grafana-alerting-alert-rules-paused': queryArg['x-grafana-alerting-alert-rules-paused'], + 'x-grafana-alerting-target-datasource-uid': queryArg['x-grafana-alerting-target-datasource-uid'], + 'x-grafana-alerting-folder-uid': queryArg['x-grafana-alerting-folder-uid'], + 'x-grafana-alerting-notification-receiver': queryArg['x-grafana-alerting-notification-receiver'], + }, + }), + invalidatesTags: ['convert_prometheus'], + }), + routeConvertPrometheusCortexDeleteRuleGroup: build.mutation< + RouteConvertPrometheusCortexDeleteRuleGroupApiResponse, + RouteConvertPrometheusCortexDeleteRuleGroupApiArg + >({ + query: (queryArg) => ({ + url: `/convert/api/prom/rules/${queryArg.namespaceTitle}/${queryArg.group}`, + method: 'DELETE', + }), + invalidatesTags: ['convert_prometheus'], + }), + routeConvertPrometheusCortexGetRuleGroup: build.query< + RouteConvertPrometheusCortexGetRuleGroupApiResponse, + RouteConvertPrometheusCortexGetRuleGroupApiArg + >({ + query: (queryArg) => ({ url: `/convert/api/prom/rules/${queryArg.namespaceTitle}/${queryArg.group}` }), + providesTags: ['convert_prometheus'], + }), + routeConvertPrometheusGetRules: build.query< + RouteConvertPrometheusGetRulesApiResponse, + RouteConvertPrometheusGetRulesApiArg + >({ + query: () => ({ url: `/convert/prometheus/config/v1/rules` }), + providesTags: ['convert_prometheus'], + }), + routeConvertPrometheusPostRuleGroups: build.mutation< + RouteConvertPrometheusPostRuleGroupsApiResponse, + RouteConvertPrometheusPostRuleGroupsApiArg + >({ + query: () => ({ url: `/convert/prometheus/config/v1/rules`, method: 'POST' }), + invalidatesTags: ['convert_prometheus'], + }), + routeConvertPrometheusDeleteNamespace: build.mutation< + RouteConvertPrometheusDeleteNamespaceApiResponse, + RouteConvertPrometheusDeleteNamespaceApiArg + >({ + query: (queryArg) => ({ + url: `/convert/prometheus/config/v1/rules/${queryArg.namespaceTitle}`, + method: 'DELETE', + }), + invalidatesTags: ['convert_prometheus'], + }), + routeConvertPrometheusGetNamespace: build.query< + RouteConvertPrometheusGetNamespaceApiResponse, + RouteConvertPrometheusGetNamespaceApiArg + >({ + query: (queryArg) => ({ url: `/convert/prometheus/config/v1/rules/${queryArg.namespaceTitle}` }), + providesTags: ['convert_prometheus'], + }), + routeConvertPrometheusPostRuleGroup: build.mutation< + RouteConvertPrometheusPostRuleGroupApiResponse, + RouteConvertPrometheusPostRuleGroupApiArg + >({ + query: (queryArg) => ({ + url: `/convert/prometheus/config/v1/rules/${queryArg.namespaceTitle}`, + method: 'POST', + body: queryArg.prometheusRuleGroup, + headers: { + 'x-grafana-alerting-datasource-uid': queryArg['x-grafana-alerting-datasource-uid'], + 'x-grafana-alerting-recording-rules-paused': queryArg['x-grafana-alerting-recording-rules-paused'], + 'x-grafana-alerting-alert-rules-paused': queryArg['x-grafana-alerting-alert-rules-paused'], + 'x-grafana-alerting-target-datasource-uid': queryArg['x-grafana-alerting-target-datasource-uid'], + 'x-grafana-alerting-folder-uid': queryArg['x-grafana-alerting-folder-uid'], + 'x-grafana-alerting-notification-receiver': queryArg['x-grafana-alerting-notification-receiver'], + }, + }), + invalidatesTags: ['convert_prometheus'], + }), + routeConvertPrometheusDeleteRuleGroup: build.mutation< + RouteConvertPrometheusDeleteRuleGroupApiResponse, + RouteConvertPrometheusDeleteRuleGroupApiArg + >({ + query: (queryArg) => ({ + url: `/convert/prometheus/config/v1/rules/${queryArg.namespaceTitle}/${queryArg.group}`, + method: 'DELETE', + }), + invalidatesTags: ['convert_prometheus'], + }), + routeConvertPrometheusGetRuleGroup: build.query< + RouteConvertPrometheusGetRuleGroupApiResponse, + RouteConvertPrometheusGetRuleGroupApiArg + >({ + query: (queryArg) => ({ + url: `/convert/prometheus/config/v1/rules/${queryArg.namespaceTitle}/${queryArg.group}`, + }), + providesTags: ['convert_prometheus'], + }), + searchDashboardSnapshots: build.query({ + query: (queryArg) => ({ + url: `/dashboard/snapshots`, + params: { + query: queryArg.query, + limit: queryArg.limit, + }, + }), + providesTags: ['dashboards', 'snapshots'], + }), + calculateDashboardDiff: build.mutation({ + query: (queryArg) => ({ url: `/dashboards/calculate-diff`, method: 'POST', body: queryArg.body }), + invalidatesTags: ['dashboards'], + }), + postDashboard: build.mutation({ + query: (queryArg) => ({ url: `/dashboards/db`, method: 'POST', body: queryArg.saveDashboardCommand }), + invalidatesTags: ['dashboards'], + }), + getHomeDashboard: build.query({ + query: () => ({ url: `/dashboards/home` }), + providesTags: ['dashboards'], + }), + importDashboard: build.mutation({ + query: (queryArg) => ({ url: `/dashboards/import`, method: 'POST', body: queryArg.importDashboardRequest }), + invalidatesTags: ['dashboards'], + }), + interpolateDashboard: build.mutation({ + query: () => ({ url: `/dashboards/interpolate`, method: 'POST' }), + invalidatesTags: ['dashboards'], + }), + listPublicDashboards: build.query({ + query: () => ({ url: `/dashboards/public-dashboards` }), + providesTags: ['dashboards', 'dashboard_public'], + }), + getDashboardTags: build.query({ + query: () => ({ url: `/dashboards/tags` }), + providesTags: ['dashboards'], + }), + getPublicDashboard: build.query({ + query: (queryArg) => ({ url: `/dashboards/uid/${queryArg.dashboardUid}/public-dashboards` }), + providesTags: ['dashboards', 'dashboard_public'], + }), + createPublicDashboard: build.mutation({ + query: (queryArg) => ({ + url: `/dashboards/uid/${queryArg.dashboardUid}/public-dashboards`, + method: 'POST', + body: queryArg.publicDashboardDto, + }), + invalidatesTags: ['dashboards', 'dashboard_public'], + }), + deletePublicDashboard: build.mutation({ + query: (queryArg) => ({ + url: `/dashboards/uid/${queryArg.dashboardUid}/public-dashboards/${queryArg.uid}`, + method: 'DELETE', + }), + invalidatesTags: ['dashboards', 'dashboard_public'], + }), + updatePublicDashboard: build.mutation({ + query: (queryArg) => ({ + url: `/dashboards/uid/${queryArg.dashboardUid}/public-dashboards/${queryArg.uid}`, + method: 'PATCH', + body: queryArg.publicDashboardDto, + }), + invalidatesTags: ['dashboards', 'dashboard_public'], + }), + deleteDashboardByUid: build.mutation({ + query: (queryArg) => ({ url: `/dashboards/uid/${queryArg.uid}`, method: 'DELETE' }), + invalidatesTags: ['dashboards'], + }), + getDashboardByUid: build.query({ + query: (queryArg) => ({ url: `/dashboards/uid/${queryArg.uid}` }), + providesTags: ['dashboards'], + }), + getDashboardPermissionsListByUid: build.query< + GetDashboardPermissionsListByUidApiResponse, + GetDashboardPermissionsListByUidApiArg + >({ + query: (queryArg) => ({ url: `/dashboards/uid/${queryArg.uid}/permissions` }), + providesTags: ['dashboards', 'permissions'], + }), + updateDashboardPermissionsByUid: build.mutation< + UpdateDashboardPermissionsByUidApiResponse, + UpdateDashboardPermissionsByUidApiArg + >({ + query: (queryArg) => ({ + url: `/dashboards/uid/${queryArg.uid}/permissions`, + method: 'POST', + body: queryArg.updateDashboardAclCommand, + }), + invalidatesTags: ['dashboards', 'permissions'], + }), + restoreDashboardVersionByUid: build.mutation< + RestoreDashboardVersionByUidApiResponse, + RestoreDashboardVersionByUidApiArg + >({ + query: (queryArg) => ({ + url: `/dashboards/uid/${queryArg.uid}/restore`, + method: 'POST', + body: queryArg.restoreDashboardVersionCommand, + }), + invalidatesTags: ['dashboards', 'versions'], + }), + getDashboardVersionsByUid: build.query({ + query: (queryArg) => ({ + url: `/dashboards/uid/${queryArg.uid}/versions`, + params: { + limit: queryArg.limit, + start: queryArg.start, + }, + }), + providesTags: ['dashboards', 'versions'], + }), + getDashboardVersionByUid: build.query({ + query: (queryArg) => ({ url: `/dashboards/uid/${queryArg.uid}/versions/${queryArg.dashboardVersionId}` }), + providesTags: ['dashboards', 'versions'], + }), + getDataSources: build.query({ + query: () => ({ url: `/datasources` }), + providesTags: ['datasources'], + }), + addDataSource: build.mutation({ + query: (queryArg) => ({ url: `/datasources`, method: 'POST', body: queryArg.addDataSourceCommand }), + invalidatesTags: ['datasources'], + }), + getCorrelations: build.query({ + query: (queryArg) => ({ + url: `/datasources/correlations`, + params: { + limit: queryArg.limit, + page: queryArg.page, + sourceUID: queryArg.sourceUid, + }, + }), + providesTags: ['datasources', 'correlations'], + }), + getDataSourceIdByName: build.query({ + query: (queryArg) => ({ url: `/datasources/id/${queryArg.name}` }), + providesTags: ['datasources'], + }), + deleteDataSourceByName: build.mutation({ + query: (queryArg) => ({ url: `/datasources/name/${queryArg.name}`, method: 'DELETE' }), + invalidatesTags: ['datasources'], + }), + getDataSourceByName: build.query({ + query: (queryArg) => ({ url: `/datasources/name/${queryArg.name}` }), + providesTags: ['datasources'], + }), + datasourceProxyDeleteByUiDcalls: build.mutation< + DatasourceProxyDeleteByUiDcallsApiResponse, + DatasourceProxyDeleteByUiDcallsApiArg + >({ + query: (queryArg) => ({ + url: `/datasources/proxy/uid/${queryArg.uid}/${queryArg.datasourceProxyRoute}`, + method: 'DELETE', + }), + invalidatesTags: ['datasources'], + }), + datasourceProxyGetByUiDcalls: build.query< + DatasourceProxyGetByUiDcallsApiResponse, + DatasourceProxyGetByUiDcallsApiArg + >({ + query: (queryArg) => ({ url: `/datasources/proxy/uid/${queryArg.uid}/${queryArg.datasourceProxyRoute}` }), + providesTags: ['datasources'], + }), + datasourceProxyPostByUiDcalls: build.mutation< + DatasourceProxyPostByUiDcallsApiResponse, + DatasourceProxyPostByUiDcallsApiArg + >({ + query: (queryArg) => ({ + url: `/datasources/proxy/uid/${queryArg.uid}/${queryArg.datasourceProxyRoute}`, + method: 'POST', + body: queryArg.body, + }), + invalidatesTags: ['datasources'], + }), + getCorrelationsBySourceUid: build.query({ + query: (queryArg) => ({ url: `/datasources/uid/${queryArg.sourceUid}/correlations` }), + providesTags: ['datasources', 'correlations'], + }), + createCorrelation: build.mutation({ + query: (queryArg) => ({ + url: `/datasources/uid/${queryArg.sourceUid}/correlations`, + method: 'POST', + body: queryArg.createCorrelationCommand, + }), + invalidatesTags: ['datasources', 'correlations'], + }), + getCorrelation: build.query({ + query: (queryArg) => ({ + url: `/datasources/uid/${queryArg.sourceUid}/correlations/${queryArg.correlationUid}`, + }), + providesTags: ['datasources', 'correlations'], + }), + updateCorrelation: build.mutation({ + query: (queryArg) => ({ + url: `/datasources/uid/${queryArg.sourceUid}/correlations/${queryArg.correlationUid}`, + method: 'PATCH', + body: queryArg.updateCorrelationCommand, + }), + invalidatesTags: ['datasources', 'correlations'], + }), + deleteDataSourceByUid: build.mutation({ + query: (queryArg) => ({ url: `/datasources/uid/${queryArg.uid}`, method: 'DELETE' }), + invalidatesTags: ['datasources'], + }), + getDataSourceByUid: build.query({ + query: (queryArg) => ({ url: `/datasources/uid/${queryArg.uid}` }), + providesTags: ['datasources'], + }), + updateDataSourceByUid: build.mutation({ + query: (queryArg) => ({ + url: `/datasources/uid/${queryArg.uid}`, + method: 'PUT', + body: queryArg.updateDataSourceCommand, + }), + invalidatesTags: ['datasources'], + }), + deleteCorrelation: build.mutation({ + query: (queryArg) => ({ + url: `/datasources/uid/${queryArg.uid}/correlations/${queryArg.correlationUid}`, + method: 'DELETE', + }), + invalidatesTags: ['datasources', 'correlations'], + }), + checkDatasourceHealthWithUid: build.query< + CheckDatasourceHealthWithUidApiResponse, + CheckDatasourceHealthWithUidApiArg + >({ + query: (queryArg) => ({ url: `/datasources/uid/${queryArg.uid}/health` }), + providesTags: ['datasources', 'health'], + }), + getTeamLbacRulesApi: build.query({ + query: (queryArg) => ({ url: `/datasources/uid/${queryArg.uid}/lbac/teams` }), + providesTags: ['enterprise'], + }), + updateTeamLbacRulesApi: build.mutation({ + query: (queryArg) => ({ + url: `/datasources/uid/${queryArg.uid}/lbac/teams`, + method: 'PUT', + body: queryArg.updateTeamLbacCommand, + }), + invalidatesTags: ['enterprise'], + }), + callDatasourceResourceWithUid: build.query< + CallDatasourceResourceWithUidApiResponse, + CallDatasourceResourceWithUidApiArg + >({ + query: (queryArg) => ({ url: `/datasources/uid/${queryArg.uid}/resources/${queryArg.datasourceProxyRoute}` }), + providesTags: ['datasources'], + }), + getDataSourceCacheConfig: build.query({ + query: (queryArg) => ({ url: `/datasources/${queryArg.dataSourceUid}/cache` }), + providesTags: ['enterprise'], + }), + setDataSourceCacheConfig: build.mutation({ + query: (queryArg) => ({ + url: `/datasources/${queryArg.dataSourceUid}/cache`, + method: 'POST', + body: queryArg.cacheConfigSetter, + }), + invalidatesTags: ['enterprise'], + }), + cleanDataSourceCache: build.mutation({ + query: (queryArg) => ({ url: `/datasources/${queryArg.dataSourceUid}/cache/clean`, method: 'POST' }), + invalidatesTags: ['enterprise'], + }), + disableDataSourceCache: build.mutation({ + query: (queryArg) => ({ url: `/datasources/${queryArg.dataSourceUid}/cache/disable`, method: 'POST' }), + invalidatesTags: ['enterprise'], + }), + enableDataSourceCache: build.mutation({ + query: (queryArg) => ({ url: `/datasources/${queryArg.dataSourceUid}/cache/enable`, method: 'POST' }), + invalidatesTags: ['enterprise'], + }), + queryMetricsWithExpressions: build.mutation< + QueryMetricsWithExpressionsApiResponse, + QueryMetricsWithExpressionsApiArg + >({ + query: (queryArg) => ({ url: `/ds/query`, method: 'POST', body: queryArg.metricRequest }), + invalidatesTags: ['datasources'], + }), + getFolders: build.query({ + query: (queryArg) => ({ + url: `/folders`, + params: { + limit: queryArg.limit, + page: queryArg.page, + parentUid: queryArg.parentUid, + permission: queryArg.permission, + }, + }), + providesTags: ['folders'], + }), + createFolder: build.mutation({ + query: (queryArg) => ({ url: `/folders`, method: 'POST', body: queryArg.createFolderCommand }), + invalidatesTags: ['folders'], + }), + deleteFolder: build.mutation({ + query: (queryArg) => ({ + url: `/folders/${queryArg.folderUid}`, + method: 'DELETE', + params: { + forceDeleteRules: queryArg.forceDeleteRules, + }, + }), + invalidatesTags: ['folders'], + }), + getFolderByUid: build.query({ + query: (queryArg) => ({ url: `/folders/${queryArg.folderUid}` }), + providesTags: ['folders'], + }), + updateFolder: build.mutation({ + query: (queryArg) => ({ + url: `/folders/${queryArg.folderUid}`, + method: 'PUT', + body: queryArg.updateFolderCommand, + }), + invalidatesTags: ['folders'], + }), + getFolderDescendantCounts: build.query({ + query: (queryArg) => ({ url: `/folders/${queryArg.folderUid}/counts` }), + providesTags: ['folders'], + }), + moveFolder: build.mutation({ + query: (queryArg) => ({ + url: `/folders/${queryArg.folderUid}/move`, + method: 'POST', + body: queryArg.moveFolderCommand, + }), + invalidatesTags: ['folders'], + }), + getFolderPermissionList: build.query({ + query: (queryArg) => ({ url: `/folders/${queryArg.folderUid}/permissions` }), + providesTags: ['folders', 'permissions'], + }), + updateFolderPermissions: build.mutation({ + query: (queryArg) => ({ + url: `/folders/${queryArg.folderUid}/permissions`, + method: 'POST', + body: queryArg.updateDashboardAclCommand, + }), + invalidatesTags: ['folders', 'permissions'], + }), + getMappedGroups: build.query({ + query: () => ({ url: `/groupsync/groups` }), + providesTags: ['group_attribute_sync', 'enterprise'], + }), + deleteGroupMappings: build.mutation({ + query: (queryArg) => ({ url: `/groupsync/groups/${queryArg.groupId}`, method: 'DELETE' }), + invalidatesTags: ['group_attribute_sync', 'enterprise'], + }), + createGroupMappings: build.mutation({ + query: (queryArg) => ({ + url: `/groupsync/groups/${queryArg.groupId}`, + method: 'POST', + body: queryArg.groupAttributes, + }), + invalidatesTags: ['group_attribute_sync', 'enterprise'], + }), + updateGroupMappings: build.mutation({ + query: (queryArg) => ({ + url: `/groupsync/groups/${queryArg.groupId}`, + method: 'PUT', + body: queryArg.groupAttributes, + }), + invalidatesTags: ['group_attribute_sync', 'enterprise'], + }), + getGroupRoles: build.query({ + query: (queryArg) => ({ url: `/groupsync/groups/${queryArg.groupId}/roles` }), + providesTags: ['group_attribute_sync', 'enterprise'], + }), + getHealth: build.query({ + query: () => ({ url: `/health` }), + providesTags: ['health'], + }), + getLibraryElements: build.query({ + query: (queryArg) => ({ + url: `/library-elements`, + params: { + searchString: queryArg.searchString, + kind: queryArg.kind, + sortDirection: queryArg.sortDirection, + typeFilter: queryArg.typeFilter, + excludeUid: queryArg.excludeUid, + folderFilter: queryArg.folderFilter, + perPage: queryArg.perPage, + page: queryArg.page, + }, + }), + providesTags: ['library_elements'], + }), + createLibraryElement: build.mutation({ + query: (queryArg) => ({ url: `/library-elements`, method: 'POST', body: queryArg.createLibraryElementCommand }), + invalidatesTags: ['library_elements'], + }), + getLibraryElementByName: build.query({ + query: (queryArg) => ({ url: `/library-elements/name/${queryArg.libraryElementName}` }), + providesTags: ['library_elements'], + }), + deleteLibraryElementByUid: build.mutation({ + query: (queryArg) => ({ url: `/library-elements/${queryArg.libraryElementUid}`, method: 'DELETE' }), + invalidatesTags: ['library_elements'], + }), + getLibraryElementByUid: build.query({ + query: (queryArg) => ({ url: `/library-elements/${queryArg.libraryElementUid}` }), + providesTags: ['library_elements'], + }), + updateLibraryElement: build.mutation({ + query: (queryArg) => ({ + url: `/library-elements/${queryArg.libraryElementUid}`, + method: 'PATCH', + body: queryArg.patchLibraryElementCommand, + }), + invalidatesTags: ['library_elements'], + }), + getLibraryElementConnections: build.query< + GetLibraryElementConnectionsApiResponse, + GetLibraryElementConnectionsApiArg + >({ + query: (queryArg) => ({ url: `/library-elements/${queryArg.libraryElementUid}/connections/` }), + providesTags: ['library_elements'], + }), + getStatus: build.query({ + query: () => ({ url: `/licensing/check` }), + providesTags: ['licensing', 'enterprise'], + }), + refreshLicenseStats: build.query({ + query: () => ({ url: `/licensing/refresh-stats` }), + providesTags: ['licensing', 'enterprise'], + }), + deleteLicenseToken: build.mutation({ + query: (queryArg) => ({ url: `/licensing/token`, method: 'DELETE', body: queryArg.deleteTokenCommand }), + invalidatesTags: ['licensing', 'enterprise'], + }), + getLicenseToken: build.query({ + query: () => ({ url: `/licensing/token` }), + providesTags: ['licensing', 'enterprise'], + }), + postLicenseToken: build.mutation({ + query: (queryArg) => ({ url: `/licensing/token`, method: 'POST', body: queryArg.deleteTokenCommand }), + invalidatesTags: ['licensing', 'enterprise'], + }), + postRenewLicenseToken: build.mutation({ + query: (queryArg) => ({ url: `/licensing/token/renew`, method: 'POST', body: queryArg.body }), + invalidatesTags: ['licensing', 'enterprise'], + }), + getSamlLogout: build.query({ + query: () => ({ url: `/logout/saml` }), + providesTags: ['saml', 'enterprise'], + }), + getCurrentOrg: build.query({ + query: () => ({ url: `/org` }), + providesTags: ['org'], + }), + updateCurrentOrg: build.mutation({ + query: (queryArg) => ({ url: `/org`, method: 'PUT', body: queryArg.updateOrgForm }), + invalidatesTags: ['org'], + }), + updateCurrentOrgAddress: build.mutation({ + query: (queryArg) => ({ url: `/org/address`, method: 'PUT', body: queryArg.updateOrgAddressForm }), + invalidatesTags: ['org'], + }), + getPendingOrgInvites: build.query({ + query: () => ({ url: `/org/invites` }), + providesTags: ['org', 'invites'], + }), + addOrgInvite: build.mutation({ + query: (queryArg) => ({ url: `/org/invites`, method: 'POST', body: queryArg.addInviteForm }), + invalidatesTags: ['org', 'invites'], + }), + revokeInvite: build.mutation({ + query: (queryArg) => ({ url: `/org/invites/${queryArg.invitationCode}/revoke`, method: 'DELETE' }), + invalidatesTags: ['org', 'invites'], + }), + getOrgPreferences: build.query({ + query: () => ({ url: `/org/preferences` }), + providesTags: ['org', 'preferences'], + }), + patchOrgPreferences: build.mutation({ + query: (queryArg) => ({ url: `/org/preferences`, method: 'PATCH', body: queryArg.patchPrefsCmd }), + invalidatesTags: ['org', 'preferences'], + }), + updateOrgPreferences: build.mutation({ + query: (queryArg) => ({ url: `/org/preferences`, method: 'PUT', body: queryArg.updatePrefsCmd }), + invalidatesTags: ['org', 'preferences'], + }), + getCurrentOrgQuota: build.query({ + query: () => ({ url: `/org/quotas` }), + providesTags: ['quota', 'org'], + }), + getOrgUsersForCurrentOrg: build.query({ + query: (queryArg) => ({ + url: `/org/users`, + params: { + query: queryArg.query, + limit: queryArg.limit, + }, + }), + providesTags: ['org'], + }), + addOrgUserToCurrentOrg: build.mutation({ + query: (queryArg) => ({ url: `/org/users`, method: 'POST', body: queryArg.addOrgUserCommand }), + invalidatesTags: ['org'], + }), + getOrgUsersForCurrentOrgLookup: build.query< + GetOrgUsersForCurrentOrgLookupApiResponse, + GetOrgUsersForCurrentOrgLookupApiArg + >({ + query: (queryArg) => ({ + url: `/org/users/lookup`, + params: { + query: queryArg.query, + limit: queryArg.limit, + }, + }), + providesTags: ['org'], + }), + removeOrgUserForCurrentOrg: build.mutation< + RemoveOrgUserForCurrentOrgApiResponse, + RemoveOrgUserForCurrentOrgApiArg + >({ + query: (queryArg) => ({ url: `/org/users/${queryArg.userId}`, method: 'DELETE' }), + invalidatesTags: ['org'], + }), + updateOrgUserForCurrentOrg: build.mutation< + UpdateOrgUserForCurrentOrgApiResponse, + UpdateOrgUserForCurrentOrgApiArg + >({ + query: (queryArg) => ({ + url: `/org/users/${queryArg.userId}`, + method: 'PATCH', + body: queryArg.updateOrgUserCommand, + }), + invalidatesTags: ['org'], + }), + searchOrgs: build.query({ + query: (queryArg) => ({ + url: `/orgs`, + params: { + page: queryArg.page, + perpage: queryArg.perpage, + name: queryArg.name, + query: queryArg.query, + }, + }), + providesTags: ['orgs'], + }), + createOrg: build.mutation({ + query: (queryArg) => ({ url: `/orgs`, method: 'POST', body: queryArg.createOrgCommand }), + invalidatesTags: ['orgs'], + }), + getOrgByName: build.query({ + query: (queryArg) => ({ url: `/orgs/name/${queryArg.orgName}` }), + providesTags: ['orgs'], + }), + deleteOrgById: build.mutation({ + query: (queryArg) => ({ url: `/orgs/${queryArg.orgId}`, method: 'DELETE' }), + invalidatesTags: ['orgs'], + }), + getOrgById: build.query({ + query: (queryArg) => ({ url: `/orgs/${queryArg.orgId}` }), + providesTags: ['orgs'], + }), + updateOrg: build.mutation({ + query: (queryArg) => ({ url: `/orgs/${queryArg.orgId}`, method: 'PUT', body: queryArg.updateOrgForm }), + invalidatesTags: ['orgs'], + }), + updateOrgAddress: build.mutation({ + query: (queryArg) => ({ + url: `/orgs/${queryArg.orgId}/address`, + method: 'PUT', + body: queryArg.updateOrgAddressForm, + }), + invalidatesTags: ['orgs'], + }), + getOrgQuota: build.query({ + query: (queryArg) => ({ url: `/orgs/${queryArg.orgId}/quotas` }), + providesTags: ['quota', 'orgs'], + }), + updateOrgQuota: build.mutation({ + query: (queryArg) => ({ + url: `/orgs/${queryArg.orgId}/quotas/${queryArg.quotaTarget}`, + method: 'PUT', + body: queryArg.updateQuotaCmd, + }), + invalidatesTags: ['quota', 'orgs'], + }), + getOrgUsers: build.query({ + query: (queryArg) => ({ url: `/orgs/${queryArg.orgId}/users` }), + providesTags: ['orgs'], + }), + addOrgUser: build.mutation({ + query: (queryArg) => ({ + url: `/orgs/${queryArg.orgId}/users`, + method: 'POST', + body: queryArg.addOrgUserCommand, + }), + invalidatesTags: ['orgs'], + }), + searchOrgUsers: build.query({ + query: (queryArg) => ({ url: `/orgs/${queryArg.orgId}/users/search` }), + providesTags: ['orgs'], + }), + removeOrgUser: build.mutation({ + query: (queryArg) => ({ url: `/orgs/${queryArg.orgId}/users/${queryArg.userId}`, method: 'DELETE' }), + invalidatesTags: ['orgs'], + }), + updateOrgUser: build.mutation({ + query: (queryArg) => ({ + url: `/orgs/${queryArg.orgId}/users/${queryArg.userId}`, + method: 'PATCH', + body: queryArg.updateOrgUserCommand, + }), + invalidatesTags: ['orgs'], + }), + searchPlaylists: build.query({ + query: (queryArg) => ({ + url: `/playlists`, + params: { + query: queryArg.query, + limit: queryArg.limit, + }, + }), + providesTags: ['playlists'], + }), + createPlaylist: build.mutation({ + query: (queryArg) => ({ url: `/playlists`, method: 'POST', body: queryArg.createPlaylistCommand }), + invalidatesTags: ['playlists'], + }), + deletePlaylist: build.mutation({ + query: (queryArg) => ({ url: `/playlists/${queryArg.uid}`, method: 'DELETE' }), + invalidatesTags: ['playlists'], + }), + getPlaylist: build.query({ + query: (queryArg) => ({ url: `/playlists/${queryArg.uid}` }), + providesTags: ['playlists'], + }), + updatePlaylist: build.mutation({ + query: (queryArg) => ({ + url: `/playlists/${queryArg.uid}`, + method: 'PUT', + body: queryArg.updatePlaylistCommand, + }), + invalidatesTags: ['playlists'], + }), + getPlaylistItems: build.query({ + query: (queryArg) => ({ url: `/playlists/${queryArg.uid}/items` }), + providesTags: ['playlists'], + }), + viewPublicDashboard: build.query({ + query: (queryArg) => ({ url: `/public/dashboards/${queryArg.accessToken}` }), + providesTags: ['dashboards', 'dashboard_public'], + }), + getPublicAnnotations: build.query({ + query: (queryArg) => ({ url: `/public/dashboards/${queryArg.accessToken}/annotations` }), + providesTags: ['dashboards', 'annotations', 'dashboard_public'], + }), + queryPublicDashboard: build.mutation({ + query: (queryArg) => ({ + url: `/public/dashboards/${queryArg.accessToken}/panels/${queryArg.panelId}/query`, + method: 'POST', + }), + invalidatesTags: ['dashboards', 'dashboard_public'], + }), + searchQueries: build.query({ + query: (queryArg) => ({ + url: `/query-history`, + params: { + datasourceUid: queryArg.datasourceUid, + searchString: queryArg.searchString, + onlyStarred: queryArg.onlyStarred, + sort: queryArg.sort, + page: queryArg.page, + limit: queryArg.limit, + from: queryArg['from'], + to: queryArg.to, + }, + }), + providesTags: ['query_history'], + }), + createQuery: build.mutation({ + query: (queryArg) => ({ + url: `/query-history`, + method: 'POST', + body: queryArg.createQueryInQueryHistoryCommand, + }), + invalidatesTags: ['query_history'], + }), + unstarQuery: build.mutation({ + query: (queryArg) => ({ url: `/query-history/star/${queryArg.queryHistoryUid}`, method: 'DELETE' }), + invalidatesTags: ['query_history'], + }), + starQuery: build.mutation({ + query: (queryArg) => ({ url: `/query-history/star/${queryArg.queryHistoryUid}`, method: 'POST' }), + invalidatesTags: ['query_history'], + }), + deleteQuery: build.mutation({ + query: (queryArg) => ({ url: `/query-history/${queryArg.queryHistoryUid}`, method: 'DELETE' }), + invalidatesTags: ['query_history'], + }), + patchQueryComment: build.mutation({ + query: (queryArg) => ({ + url: `/query-history/${queryArg.queryHistoryUid}`, + method: 'PATCH', + body: queryArg.patchQueryCommentInQueryHistoryCommand, + }), + invalidatesTags: ['query_history'], + }), + listRecordingRules: build.query({ + query: () => ({ url: `/recording-rules` }), + providesTags: ['recording_rules', 'enterprise'], + }), + createRecordingRule: build.mutation({ + query: (queryArg) => ({ url: `/recording-rules`, method: 'POST', body: queryArg.recordingRuleJson }), + invalidatesTags: ['recording_rules', 'enterprise'], + }), + updateRecordingRule: build.mutation({ + query: (queryArg) => ({ url: `/recording-rules`, method: 'PUT', body: queryArg.recordingRuleJson }), + invalidatesTags: ['recording_rules', 'enterprise'], + }), + testCreateRecordingRule: build.mutation({ + query: (queryArg) => ({ url: `/recording-rules/test`, method: 'POST', body: queryArg.recordingRuleJson }), + invalidatesTags: ['recording_rules', 'enterprise'], + }), + deleteRecordingRuleWriteTarget: build.mutation< + DeleteRecordingRuleWriteTargetApiResponse, + DeleteRecordingRuleWriteTargetApiArg + >({ + query: () => ({ url: `/recording-rules/writer`, method: 'DELETE' }), + invalidatesTags: ['recording_rules', 'enterprise'], + }), + getRecordingRuleWriteTarget: build.query< + GetRecordingRuleWriteTargetApiResponse, + GetRecordingRuleWriteTargetApiArg + >({ + query: () => ({ url: `/recording-rules/writer` }), + providesTags: ['recording_rules', 'enterprise'], + }), + createRecordingRuleWriteTarget: build.mutation< + CreateRecordingRuleWriteTargetApiResponse, + CreateRecordingRuleWriteTargetApiArg + >({ + query: (queryArg) => ({ + url: `/recording-rules/writer`, + method: 'POST', + body: queryArg.prometheusRemoteWriteTargetJson, + }), + invalidatesTags: ['recording_rules', 'enterprise'], + }), + deleteRecordingRule: build.mutation({ + query: (queryArg) => ({ url: `/recording-rules/${queryArg.recordingRuleId}`, method: 'DELETE' }), + invalidatesTags: ['recording_rules', 'enterprise'], + }), + getReports: build.query({ + query: () => ({ url: `/reports` }), + providesTags: ['reports', 'enterprise'], + }), + createReport: build.mutation({ + query: (queryArg) => ({ url: `/reports`, method: 'POST', body: queryArg.createOrUpdateReport }), + invalidatesTags: ['reports', 'enterprise'], + }), + getReportsByDashboardUid: build.query({ + query: (queryArg) => ({ url: `/reports/dashboards/${queryArg.uid}` }), + providesTags: ['reports', 'enterprise'], + }), + sendReport: build.mutation({ + query: (queryArg) => ({ url: `/reports/email`, method: 'POST', body: queryArg.reportEmail }), + invalidatesTags: ['reports', 'enterprise'], + }), + getSettingsImage: build.query({ + query: () => ({ url: `/reports/images/:image` }), + providesTags: ['reports', 'enterprise'], + }), + renderReportCsVs: build.query({ + query: (queryArg) => ({ + url: `/reports/render/csvs`, + params: { + dashboards: queryArg.dashboards, + title: queryArg.title, + }, + }), + providesTags: ['reports', 'enterprise'], + }), + renderReportPdFs: build.query({ + query: (queryArg) => ({ + url: `/reports/render/pdfs`, + params: { + dashboards: queryArg.dashboards, + orientation: queryArg.orientation, + layout: queryArg.layout, + title: queryArg.title, + scaleFactor: queryArg.scaleFactor, + includeTables: queryArg.includeTables, + }, + }), + providesTags: ['reports', 'enterprise'], + }), + getReportSettings: build.query({ + query: () => ({ url: `/reports/settings` }), + providesTags: ['reports', 'enterprise'], + }), + saveReportSettings: build.mutation({ + query: (queryArg) => ({ url: `/reports/settings`, method: 'POST', body: queryArg.reportSettings }), + invalidatesTags: ['reports', 'enterprise'], + }), + sendTestEmail: build.mutation({ + query: (queryArg) => ({ url: `/reports/test-email`, method: 'POST', body: queryArg.createOrUpdateReport }), + invalidatesTags: ['reports', 'enterprise'], + }), + postAcs: build.mutation({ + query: (queryArg) => ({ + url: `/saml/acs`, + method: 'POST', + params: { + RelayState: queryArg.relayState, + }, + }), + invalidatesTags: ['saml', 'enterprise'], + }), + getMetadata: build.query({ + query: () => ({ url: `/saml/metadata` }), + providesTags: ['saml', 'enterprise'], + }), + getSlo: build.query({ + query: () => ({ url: `/saml/slo` }), + providesTags: ['saml', 'enterprise'], + }), + postSlo: build.mutation({ + query: (queryArg) => ({ + url: `/saml/slo`, + method: 'POST', + params: { + SAMLRequest: queryArg.samlRequest, + SAMLResponse: queryArg.samlResponse, + }, + }), + invalidatesTags: ['saml', 'enterprise'], + }), + search: build.query({ + query: (queryArg) => ({ + url: `/search`, + params: { + query: queryArg.query, + tag: queryArg.tag, + type: queryArg['type'], + dashboardIds: queryArg.dashboardIds, + dashboardUIDs: queryArg.dashboardUiDs, + folderIds: queryArg.folderIds, + folderUIDs: queryArg.folderUiDs, + starred: queryArg.starred, + limit: queryArg.limit, + page: queryArg.page, + permission: queryArg.permission, + sort: queryArg.sort, + deleted: queryArg.deleted, + }, + }), + providesTags: ['search'], + }), + listSortOptions: build.query({ + query: () => ({ url: `/search/sorting` }), + providesTags: ['search'], + }), + createServiceAccount: build.mutation({ + query: (queryArg) => ({ url: `/serviceaccounts`, method: 'POST', body: queryArg.createServiceAccountForm }), + invalidatesTags: ['service_accounts'], + }), + searchOrgServiceAccountsWithPaging: build.query< + SearchOrgServiceAccountsWithPagingApiResponse, + SearchOrgServiceAccountsWithPagingApiArg + >({ + query: (queryArg) => ({ + url: `/serviceaccounts/search`, + params: { + Disabled: queryArg.disabled, + expiredTokens: queryArg.expiredTokens, + query: queryArg.query, + perpage: queryArg.perpage, + page: queryArg.page, + }, + }), + providesTags: ['service_accounts'], + }), + deleteServiceAccount: build.mutation({ + query: (queryArg) => ({ url: `/serviceaccounts/${queryArg.serviceAccountId}`, method: 'DELETE' }), + invalidatesTags: ['service_accounts'], + }), + retrieveServiceAccount: build.query({ + query: (queryArg) => ({ url: `/serviceaccounts/${queryArg.serviceAccountId}` }), + providesTags: ['service_accounts'], + }), + updateServiceAccount: build.mutation({ + query: (queryArg) => ({ + url: `/serviceaccounts/${queryArg.serviceAccountId}`, + method: 'PATCH', + body: queryArg.updateServiceAccountForm, + }), + invalidatesTags: ['service_accounts'], + }), + listTokens: build.query({ + query: (queryArg) => ({ url: `/serviceaccounts/${queryArg.serviceAccountId}/tokens` }), + providesTags: ['service_accounts'], + }), + createToken: build.mutation({ + query: (queryArg) => ({ + url: `/serviceaccounts/${queryArg.serviceAccountId}/tokens`, + method: 'POST', + body: queryArg.addServiceAccountTokenCommand, + }), + invalidatesTags: ['service_accounts'], + }), + deleteToken: build.mutation({ + query: (queryArg) => ({ + url: `/serviceaccounts/${queryArg.serviceAccountId}/tokens/${queryArg.tokenId}`, + method: 'DELETE', + }), + invalidatesTags: ['service_accounts'], + }), + retrieveJwks: build.query({ + query: () => ({ url: `/signing-keys/keys` }), + providesTags: ['signing_keys'], + }), + getSharingOptions: build.query({ + query: () => ({ url: `/snapshot/shared-options` }), + providesTags: ['snapshots'], + }), + createDashboardSnapshot: build.mutation({ + query: (queryArg) => ({ url: `/snapshots`, method: 'POST', body: queryArg.createDashboardSnapshotCommand }), + invalidatesTags: ['dashboards', 'snapshots'], + }), + deleteDashboardSnapshotByDeleteKey: build.query< + DeleteDashboardSnapshotByDeleteKeyApiResponse, + DeleteDashboardSnapshotByDeleteKeyApiArg + >({ + query: (queryArg) => ({ url: `/snapshots-delete/${queryArg.deleteKey}` }), + providesTags: ['dashboards', 'snapshots'], + }), + deleteDashboardSnapshot: build.mutation({ + query: (queryArg) => ({ url: `/snapshots/${queryArg.key}`, method: 'DELETE' }), + invalidatesTags: ['dashboards', 'snapshots'], + }), + getDashboardSnapshot: build.query({ + query: (queryArg) => ({ url: `/snapshots/${queryArg.key}` }), + providesTags: ['dashboards', 'snapshots'], + }), + createTeam: build.mutation({ + query: (queryArg) => ({ url: `/teams`, method: 'POST', body: queryArg.createTeamCommand }), + invalidatesTags: ['teams'], + }), + searchTeams: build.query({ + query: (queryArg) => ({ + url: `/teams/search`, + params: { + page: queryArg.page, + perpage: queryArg.perpage, + name: queryArg.name, + query: queryArg.query, + }, + }), + providesTags: ['teams'], + }), + removeTeamGroupApiQuery: build.mutation({ + query: (queryArg) => ({ + url: `/teams/${queryArg.teamId}/groups`, + method: 'DELETE', + params: { + groupId: queryArg.groupId, + }, + }), + invalidatesTags: ['sync_team_groups', 'enterprise'], + }), + getTeamGroupsApi: build.query({ + query: (queryArg) => ({ url: `/teams/${queryArg.teamId}/groups` }), + providesTags: ['sync_team_groups', 'enterprise'], + }), + addTeamGroupApi: build.mutation({ + query: (queryArg) => ({ + url: `/teams/${queryArg.teamId}/groups`, + method: 'POST', + body: queryArg.teamGroupMapping, + }), + invalidatesTags: ['sync_team_groups', 'enterprise'], + }), + searchTeamGroups: build.query({ + query: (queryArg) => ({ + url: `/teams/${queryArg.teamId}/groups/search`, + params: { + page: queryArg.page, + perpage: queryArg.perpage, + query: queryArg.query, + name: queryArg.name, + }, + }), + providesTags: ['sync_team_groups', 'enterprise'], + }), + deleteTeamById: build.mutation({ + query: (queryArg) => ({ url: `/teams/${queryArg.teamId}`, method: 'DELETE' }), + invalidatesTags: ['teams'], + }), + getTeamById: build.query({ + query: (queryArg) => ({ url: `/teams/${queryArg.teamId}` }), + providesTags: ['teams'], + }), + updateTeam: build.mutation({ + query: (queryArg) => ({ url: `/teams/${queryArg.teamId}`, method: 'PUT', body: queryArg.updateTeamCommand }), + invalidatesTags: ['teams'], + }), + getTeamMembers: build.query({ + query: (queryArg) => ({ url: `/teams/${queryArg.teamId}/members` }), + providesTags: ['teams'], + }), + addTeamMember: build.mutation({ + query: (queryArg) => ({ + url: `/teams/${queryArg.teamId}/members`, + method: 'POST', + body: queryArg.addTeamMemberCommand, + }), + invalidatesTags: ['teams'], + }), + setTeamMemberships: build.mutation({ + query: (queryArg) => ({ + url: `/teams/${queryArg.teamId}/members`, + method: 'PUT', + body: queryArg.setTeamMembershipsCommand, + }), + invalidatesTags: ['teams'], + }), + removeTeamMember: build.mutation({ + query: (queryArg) => ({ url: `/teams/${queryArg.teamId}/members/${queryArg.userId}`, method: 'DELETE' }), + invalidatesTags: ['teams'], + }), + updateTeamMember: build.mutation({ + query: (queryArg) => ({ + url: `/teams/${queryArg.teamId}/members/${queryArg.userId}`, + method: 'PUT', + body: queryArg.updateTeamMemberCommand, + }), + invalidatesTags: ['teams'], + }), + getTeamPreferences: build.query({ + query: (queryArg) => ({ url: `/teams/${queryArg.teamId}/preferences` }), + providesTags: ['teams', 'preferences'], + }), + updateTeamPreferences: build.mutation({ + query: (queryArg) => ({ + url: `/teams/${queryArg.teamId}/preferences`, + method: 'PUT', + body: queryArg.updatePrefsCmd, + }), + invalidatesTags: ['teams', 'preferences'], + }), + getSignedInUser: build.query({ + query: () => ({ url: `/user` }), + providesTags: ['signed_in_user'], + }), + updateSignedInUser: build.mutation({ + query: (queryArg) => ({ url: `/user`, method: 'PUT', body: queryArg.updateUserCommand }), + invalidatesTags: ['signed_in_user'], + }), + getUserAuthTokens: build.query({ + query: () => ({ url: `/user/auth-tokens` }), + providesTags: ['signed_in_user'], + }), + updateUserEmail: build.query({ + query: () => ({ url: `/user/email/update` }), + providesTags: ['user'], + }), + clearHelpFlags: build.query({ + query: () => ({ url: `/user/helpflags/clear` }), + providesTags: ['signed_in_user'], + }), + setHelpFlag: build.mutation({ + query: (queryArg) => ({ url: `/user/helpflags/${queryArg.flagId}`, method: 'PUT' }), + invalidatesTags: ['signed_in_user'], + }), + getSignedInUserOrgList: build.query({ + query: () => ({ url: `/user/orgs` }), + providesTags: ['signed_in_user'], + }), + changeUserPassword: build.mutation({ + query: (queryArg) => ({ url: `/user/password`, method: 'PUT', body: queryArg.changeUserPasswordCommand }), + invalidatesTags: ['signed_in_user'], + }), + getUserPreferences: build.query({ + query: () => ({ url: `/user/preferences` }), + providesTags: ['signed_in_user', 'preferences'], + }), + patchUserPreferences: build.mutation({ + query: (queryArg) => ({ url: `/user/preferences`, method: 'PATCH', body: queryArg.patchPrefsCmd }), + invalidatesTags: ['signed_in_user', 'preferences'], + }), + updateUserPreferences: build.mutation({ + query: (queryArg) => ({ url: `/user/preferences`, method: 'PUT', body: queryArg.updatePrefsCmd }), + invalidatesTags: ['signed_in_user', 'preferences'], + }), + getUserQuotas: build.query({ + query: () => ({ url: `/user/quotas` }), + providesTags: ['quota', 'signed_in_user'], + }), + revokeUserAuthToken: build.mutation({ + query: (queryArg) => ({ url: `/user/revoke-auth-token`, method: 'POST', body: queryArg.revokeAuthTokenCmd }), + invalidatesTags: ['signed_in_user'], + }), + unstarDashboardByUid: build.mutation({ + query: (queryArg) => ({ url: `/user/stars/dashboard/uid/${queryArg.dashboardUid}`, method: 'DELETE' }), + invalidatesTags: ['signed_in_user'], + }), + starDashboardByUid: build.mutation({ + query: (queryArg) => ({ url: `/user/stars/dashboard/uid/${queryArg.dashboardUid}`, method: 'POST' }), + invalidatesTags: ['signed_in_user'], + }), + getSignedInUserTeamList: build.query({ + query: () => ({ url: `/user/teams` }), + providesTags: ['signed_in_user'], + }), + userSetUsingOrg: build.mutation({ + query: (queryArg) => ({ url: `/user/using/${queryArg.orgId}`, method: 'POST' }), + invalidatesTags: ['signed_in_user'], + }), + searchUsers: build.query({ + query: (queryArg) => ({ + url: `/users`, + params: { + perpage: queryArg.perpage, + page: queryArg.page, + }, + }), + providesTags: ['users'], + }), + getUserByLoginOrEmail: build.query({ + query: (queryArg) => ({ + url: `/users/lookup`, + params: { + loginOrEmail: queryArg.loginOrEmail, + }, + }), + providesTags: ['users'], + }), + searchUsersWithPaging: build.query({ + query: () => ({ url: `/users/search` }), + providesTags: ['users'], + }), + getUserById: build.query({ + query: (queryArg) => ({ url: `/users/${queryArg.userId}` }), + providesTags: ['users'], + }), + updateUser: build.mutation({ + query: (queryArg) => ({ url: `/users/${queryArg.userId}`, method: 'PUT', body: queryArg.updateUserCommand }), + invalidatesTags: ['users'], + }), + getUserOrgList: build.query({ + query: (queryArg) => ({ url: `/users/${queryArg.userId}/orgs` }), + providesTags: ['users'], + }), + getUserTeams: build.query({ + query: (queryArg) => ({ url: `/users/${queryArg.userId}/teams` }), + providesTags: ['users'], + }), + routeGetAlertRules: build.query({ + query: () => ({ url: `/v1/provisioning/alert-rules` }), + providesTags: ['provisioning'], + }), + routePostAlertRule: build.mutation({ + query: (queryArg) => ({ + url: `/v1/provisioning/alert-rules`, + method: 'POST', + body: queryArg.provisionedAlertRule, + headers: { + 'X-Disable-Provenance': queryArg['X-Disable-Provenance'], + }, + }), + invalidatesTags: ['provisioning'], + }), + routeGetAlertRulesExport: build.query({ + query: (queryArg) => ({ + url: `/v1/provisioning/alert-rules/export`, + params: { + download: queryArg.download, + format: queryArg.format, + folderUid: queryArg.folderUid, + group: queryArg.group, + ruleUid: queryArg.ruleUid, + }, + }), + providesTags: ['provisioning'], + }), + routeDeleteAlertRule: build.mutation({ + query: (queryArg) => ({ + url: `/v1/provisioning/alert-rules/${queryArg.uid}`, + method: 'DELETE', + headers: { + 'X-Disable-Provenance': queryArg['X-Disable-Provenance'], + }, + }), + invalidatesTags: ['provisioning'], + }), + routeGetAlertRule: build.query({ + query: (queryArg) => ({ url: `/v1/provisioning/alert-rules/${queryArg.uid}` }), + providesTags: ['provisioning'], + }), + routePutAlertRule: build.mutation({ + query: (queryArg) => ({ + url: `/v1/provisioning/alert-rules/${queryArg.uid}`, + method: 'PUT', + body: queryArg.provisionedAlertRule, + headers: { + 'X-Disable-Provenance': queryArg['X-Disable-Provenance'], + }, + }), + invalidatesTags: ['provisioning'], + }), + routeGetAlertRuleExport: build.query({ + query: (queryArg) => ({ + url: `/v1/provisioning/alert-rules/${queryArg.uid}/export`, + params: { + download: queryArg.download, + format: queryArg.format, + }, + }), + providesTags: ['provisioning'], + }), + routeGetContactpoints: build.query({ + query: (queryArg) => ({ + url: `/v1/provisioning/contact-points`, + params: { + name: queryArg.name, + }, + }), + providesTags: ['provisioning'], + }), + routePostContactpoints: build.mutation({ + query: (queryArg) => ({ + url: `/v1/provisioning/contact-points`, + method: 'POST', + body: queryArg.embeddedContactPoint, + headers: { + 'X-Disable-Provenance': queryArg['X-Disable-Provenance'], + }, + }), + invalidatesTags: ['provisioning'], + }), + routeGetContactpointsExport: build.query< + RouteGetContactpointsExportApiResponse, + RouteGetContactpointsExportApiArg + >({ + query: (queryArg) => ({ + url: `/v1/provisioning/contact-points/export`, + params: { + download: queryArg.download, + format: queryArg.format, + decrypt: queryArg.decrypt, + name: queryArg.name, + }, + }), + providesTags: ['provisioning'], + }), + routeDeleteContactpoints: build.mutation({ + query: (queryArg) => ({ url: `/v1/provisioning/contact-points/${queryArg.uid}`, method: 'DELETE' }), + invalidatesTags: ['provisioning'], + }), + routePutContactpoint: build.mutation({ + query: (queryArg) => ({ + url: `/v1/provisioning/contact-points/${queryArg.uid}`, + method: 'PUT', + body: queryArg.embeddedContactPoint, + headers: { + 'X-Disable-Provenance': queryArg['X-Disable-Provenance'], + }, + }), + invalidatesTags: ['provisioning'], + }), + routeDeleteAlertRuleGroup: build.mutation({ + query: (queryArg) => ({ + url: `/v1/provisioning/folder/${queryArg.folderUid}/rule-groups/${queryArg.group}`, + method: 'DELETE', + }), + invalidatesTags: ['provisioning'], + }), + routeGetAlertRuleGroup: build.query({ + query: (queryArg) => ({ url: `/v1/provisioning/folder/${queryArg.folderUid}/rule-groups/${queryArg.group}` }), + providesTags: ['provisioning'], + }), + routePutAlertRuleGroup: build.mutation({ + query: (queryArg) => ({ + url: `/v1/provisioning/folder/${queryArg.folderUid}/rule-groups/${queryArg.group}`, + method: 'PUT', + body: queryArg.alertRuleGroup, + headers: { + 'X-Disable-Provenance': queryArg['X-Disable-Provenance'], + }, + }), + invalidatesTags: ['provisioning'], + }), + routeGetAlertRuleGroupExport: build.query< + RouteGetAlertRuleGroupExportApiResponse, + RouteGetAlertRuleGroupExportApiArg + >({ + query: (queryArg) => ({ + url: `/v1/provisioning/folder/${queryArg.folderUid}/rule-groups/${queryArg.group}/export`, + params: { + download: queryArg.download, + format: queryArg.format, + }, + }), + providesTags: ['provisioning'], + }), + routeGetMuteTimings: build.query({ + query: () => ({ url: `/v1/provisioning/mute-timings` }), + providesTags: ['provisioning'], + }), + routePostMuteTiming: build.mutation({ + query: (queryArg) => ({ + url: `/v1/provisioning/mute-timings`, + method: 'POST', + body: queryArg.muteTimeInterval, + headers: { + 'X-Disable-Provenance': queryArg['X-Disable-Provenance'], + }, + }), + invalidatesTags: ['provisioning'], + }), + routeExportMuteTimings: build.query({ + query: (queryArg) => ({ + url: `/v1/provisioning/mute-timings/export`, + params: { + download: queryArg.download, + format: queryArg.format, + }, + }), + providesTags: ['provisioning'], + }), + routeDeleteMuteTiming: build.mutation({ + query: (queryArg) => ({ + url: `/v1/provisioning/mute-timings/${queryArg.name}`, + method: 'DELETE', + headers: { + 'X-Disable-Provenance': queryArg['X-Disable-Provenance'], + }, + params: { + version: queryArg.version, + }, + }), + invalidatesTags: ['provisioning'], + }), + routeGetMuteTiming: build.query({ + query: (queryArg) => ({ url: `/v1/provisioning/mute-timings/${queryArg.name}` }), + providesTags: ['provisioning'], + }), + routePutMuteTiming: build.mutation({ + query: (queryArg) => ({ + url: `/v1/provisioning/mute-timings/${queryArg.name}`, + method: 'PUT', + body: queryArg.muteTimeInterval, + headers: { + 'X-Disable-Provenance': queryArg['X-Disable-Provenance'], + }, + }), + invalidatesTags: ['provisioning'], + }), + routeExportMuteTiming: build.query({ + query: (queryArg) => ({ + url: `/v1/provisioning/mute-timings/${queryArg.name}/export`, + params: { + download: queryArg.download, + format: queryArg.format, + }, + }), + providesTags: ['provisioning'], + }), + routeResetPolicyTree: build.mutation({ + query: () => ({ url: `/v1/provisioning/policies`, method: 'DELETE' }), + invalidatesTags: ['provisioning'], + }), + routeGetPolicyTree: build.query({ + query: () => ({ url: `/v1/provisioning/policies` }), + providesTags: ['provisioning'], + }), + routePutPolicyTree: build.mutation({ + query: (queryArg) => ({ + url: `/v1/provisioning/policies`, + method: 'PUT', + body: queryArg.route, + headers: { + 'X-Disable-Provenance': queryArg['X-Disable-Provenance'], + }, + }), + invalidatesTags: ['provisioning'], + }), + routeGetPolicyTreeExport: build.query({ + query: () => ({ url: `/v1/provisioning/policies/export` }), + providesTags: ['provisioning'], + }), + routeGetTemplates: build.query({ + query: () => ({ url: `/v1/provisioning/templates` }), + providesTags: ['provisioning'], + }), + routeDeleteTemplate: build.mutation({ + query: (queryArg) => ({ + url: `/v1/provisioning/templates/${queryArg.name}`, + method: 'DELETE', + params: { + version: queryArg.version, + }, + }), + invalidatesTags: ['provisioning'], + }), + routeGetTemplate: build.query({ + query: (queryArg) => ({ url: `/v1/provisioning/templates/${queryArg.name}` }), + providesTags: ['provisioning'], + }), + routePutTemplate: build.mutation({ + query: (queryArg) => ({ + url: `/v1/provisioning/templates/${queryArg.name}`, + method: 'PUT', + body: queryArg.notificationTemplateContent, + headers: { + 'X-Disable-Provenance': queryArg['X-Disable-Provenance'], + }, + }), + invalidatesTags: ['provisioning'], + }), + listAllProvidersSettings: build.query({ + query: () => ({ url: `/v1/sso-settings` }), + providesTags: ['sso_settings'], + }), + removeProviderSettings: build.mutation({ + query: (queryArg) => ({ url: `/v1/sso-settings/${queryArg.key}`, method: 'DELETE' }), + invalidatesTags: ['sso_settings'], + }), + getProviderSettings: build.query({ + query: (queryArg) => ({ url: `/v1/sso-settings/${queryArg.key}` }), + providesTags: ['sso_settings'], + }), + updateProviderSettings: build.mutation({ + query: (queryArg) => ({ url: `/v1/sso-settings/${queryArg.key}`, method: 'PUT', body: queryArg.body }), + invalidatesTags: ['sso_settings'], + }), + }), + overrideExisting: false, + }); +export { injectedRtkApi as generatedAPI }; +export type SearchResultApiResponse = /** status 200 (empty) */ SearchResult; +export type SearchResultApiArg = void; +export type ListRolesApiResponse = /** status 200 (empty) */ RoleDto[]; +export type ListRolesApiArg = { + delegatable?: boolean; + includeHidden?: boolean; +}; +export type CreateRoleApiResponse = /** status 201 (empty) */ RoleDto; +export type CreateRoleApiArg = { + createRoleForm: CreateRoleForm; +}; +export type DeleteRoleApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type DeleteRoleApiArg = { + force?: boolean; + global?: boolean; + roleUid: string; +}; +export type GetRoleApiResponse = /** status 200 (empty) */ RoleDto; +export type GetRoleApiArg = { + roleUid: string; +}; +export type UpdateRoleApiResponse = /** status 200 (empty) */ RoleDto; +export type UpdateRoleApiArg = { + roleUid: string; + updateRoleCommand: UpdateRoleCommand; +}; +export type GetRoleAssignmentsApiResponse = /** status 200 (empty) */ RoleAssignmentsDto; +export type GetRoleAssignmentsApiArg = { + roleUid: string; +}; +export type SetRoleAssignmentsApiResponse = /** status 200 (empty) */ RoleAssignmentsDto; +export type SetRoleAssignmentsApiArg = { + roleUid: string; + setRoleAssignmentsCommand: SetRoleAssignmentsCommand; +}; +export type GetAccessControlStatusApiResponse = /** status 200 (empty) */ Status; +export type GetAccessControlStatusApiArg = void; +export type ListTeamsRolesApiResponse = /** status 200 (empty) */ { + [key: string]: RoleDto[]; +}; +export type ListTeamsRolesApiArg = { + rolesSearchQuery: RolesSearchQuery; +}; +export type ListTeamRolesApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type ListTeamRolesApiArg = { + teamId: number; +}; +export type AddTeamRoleApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type AddTeamRoleApiArg = { + teamId: number; + addTeamRoleCommand: AddTeamRoleCommand; +}; +export type SetTeamRolesApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type SetTeamRolesApiArg = { + teamId: number; +}; +export type RemoveTeamRoleApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type RemoveTeamRoleApiArg = { + roleUid: string; + teamId: number; +}; +export type ListUsersRolesApiResponse = /** status 200 (empty) */ { + [key: string]: RoleDto[]; +}; +export type ListUsersRolesApiArg = { + rolesSearchQuery: RolesSearchQuery; +}; +export type ListUserRolesApiResponse = /** status 200 (empty) */ RoleDto[]; +export type ListUserRolesApiArg = { + userId: number; +}; +export type AddUserRoleApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type AddUserRoleApiArg = { + userId: number; + addUserRoleCommand: AddUserRoleCommand; +}; +export type SetUserRolesApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type SetUserRolesApiArg = { + userId: number; + setUserRolesCommand: SetUserRolesCommand; +}; +export type RemoveUserRoleApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type RemoveUserRoleApiArg = { + /** A flag indicating if the assignment is global or not. If set to false, the default org ID of the authenticated user will be used from the request to remove assignment. */ + global?: boolean; + roleUid: string; + userId: number; +}; +export type GetResourceDescriptionApiResponse = /** status 200 (empty) */ Description; +export type GetResourceDescriptionApiArg = { + resource: string; +}; +export type GetResourcePermissionsApiResponse = /** status 200 (empty) */ ResourcePermissionDto[]; +export type GetResourcePermissionsApiArg = { + resource: string; + resourceId: string; +}; +export type SetResourcePermissionsApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type SetResourcePermissionsApiArg = { + resource: string; + resourceId: string; + setPermissionsCommand: SetPermissionsCommand; +}; +export type SetResourcePermissionsForBuiltInRoleApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type SetResourcePermissionsForBuiltInRoleApiArg = { + resource: string; + resourceId: string; + builtInRole: string; + setPermissionCommand: SetPermissionCommand; +}; +export type SetResourcePermissionsForTeamApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type SetResourcePermissionsForTeamApiArg = { + resource: string; + resourceId: string; + teamId: number; + setPermissionCommand: SetPermissionCommand; +}; +export type SetResourcePermissionsForUserApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type SetResourcePermissionsForUserApiArg = { + resource: string; + resourceId: string; + userId: number; + setPermissionCommand: SetPermissionCommand; +}; +export type GetSyncStatusApiResponse = /** status 200 (empty) */ ActiveSyncStatusDto; +export type GetSyncStatusApiArg = void; +export type ReloadLdapCfgApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type ReloadLdapCfgApiArg = void; +export type GetLdapStatusApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type GetLdapStatusApiArg = void; +export type PostSyncUserWithLdapApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type PostSyncUserWithLdapApiArg = { + userId: number; +}; +export type GetUserFromLdapApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type GetUserFromLdapApiArg = { + userName: string; +}; +export type AdminProvisioningReloadAccessControlApiResponse = /** status 202 AcceptedResponse */ ErrorResponseBody; +export type AdminProvisioningReloadAccessControlApiArg = void; +export type AdminProvisioningReloadDashboardsApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type AdminProvisioningReloadDashboardsApiArg = void; +export type AdminProvisioningReloadDatasourcesApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type AdminProvisioningReloadDatasourcesApiArg = void; +export type AdminProvisioningReloadPluginsApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type AdminProvisioningReloadPluginsApiArg = void; +export type AdminGetSettingsApiResponse = /** status 200 (empty) */ SettingsBag; +export type AdminGetSettingsApiArg = void; +export type AdminGetStatsApiResponse = /** status 200 (empty) */ AdminStats; +export type AdminGetStatsApiArg = void; +export type AdminCreateUserApiResponse = /** status 200 (empty) */ AdminCreateUserResponse; +export type AdminCreateUserApiArg = { + adminCreateUserForm: AdminCreateUserForm; +}; +export type AdminDeleteUserApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type AdminDeleteUserApiArg = { + userId: number; +}; +export type AdminGetUserAuthTokensApiResponse = /** status 200 (empty) */ UserToken[]; +export type AdminGetUserAuthTokensApiArg = { + userId: number; +}; +export type AdminDisableUserApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type AdminDisableUserApiArg = { + userId: number; +}; +export type AdminEnableUserApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type AdminEnableUserApiArg = { + userId: number; +}; +export type AdminLogoutUserApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type AdminLogoutUserApiArg = { + userId: number; +}; +export type AdminUpdateUserPasswordApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type AdminUpdateUserPasswordApiArg = { + userId: number; + adminUpdateUserPasswordForm: AdminUpdateUserPasswordForm; +}; +export type AdminUpdateUserPermissionsApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type AdminUpdateUserPermissionsApiArg = { + userId: number; + adminUpdateUserPermissionsForm: AdminUpdateUserPermissionsForm; +}; +export type GetUserQuotaApiResponse = /** status 200 (empty) */ QuotaDto[]; +export type GetUserQuotaApiArg = { + userId: number; +}; +export type UpdateUserQuotaApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type UpdateUserQuotaApiArg = { + quotaTarget: string; + userId: number; + updateQuotaCmd: UpdateQuotaCmd; +}; +export type AdminRevokeUserAuthTokenApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type AdminRevokeUserAuthTokenApiArg = { + userId: number; + revokeAuthTokenCmd: RevokeAuthTokenCmd; +}; +export type GetAnnotationsApiResponse = /** status 200 (empty) */ Annotation[]; +export type GetAnnotationsApiArg = { + /** Find annotations created after specific epoch datetime in milliseconds. */ + from?: number; + /** Find annotations created before specific epoch datetime in milliseconds. */ + to?: number; + /** Limit response to annotations created by specific user. */ + userId?: number; + /** Find annotations for a specified alert rule by its ID. + deprecated: AlertID is deprecated and will be removed in future versions. Please use AlertUID instead. */ + alertId?: number; + /** Find annotations for a specified alert rule by its UID. */ + alertUid?: string; + /** Find annotations that are scoped to a specific dashboard */ + dashboardId?: number; + /** Find annotations that are scoped to a specific dashboard */ + dashboardUid?: string; + /** Find annotations that are scoped to a specific panel */ + panelId?: number; + /** Max limit for results returned. */ + limit?: number; + /** Use this to filter organization annotations. Organization annotations are annotations from an annotation data source that are not connected specifically to a dashboard or panel. You can filter by multiple tags. */ + tags?: string[]; + /** Return alerts or user created annotations */ + type?: 'alert' | 'annotation'; + /** Match any or all tags */ + matchAny?: boolean; +}; +export type PostAnnotationApiResponse = /** status 200 (empty) */ { + /** ID Identifier of the created annotation. */ + id: number; + /** Message Message of the created annotation. */ + message: string; +}; +export type PostAnnotationApiArg = { + postAnnotationsCmd: PostAnnotationsCmd; +}; +export type PostGraphiteAnnotationApiResponse = /** status 200 (empty) */ { + /** ID Identifier of the created annotation. */ + id: number; + /** Message Message of the created annotation. */ + message: string; +}; +export type PostGraphiteAnnotationApiArg = { + postGraphiteAnnotationsCmd: PostGraphiteAnnotationsCmd; +}; +export type MassDeleteAnnotationsApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type MassDeleteAnnotationsApiArg = { + massDeleteAnnotationsCmd: MassDeleteAnnotationsCmd; +}; +export type GetAnnotationTagsApiResponse = + /** status 200 (empty) */ GetAnnotationTagsResponseIsAResponseStructForFindTagsResult; +export type GetAnnotationTagsApiArg = { + /** Tag is a string that you can use to filter tags. */ + tag?: string; + /** Max limit for results returned. */ + limit?: string; +}; +export type DeleteAnnotationByIdApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type DeleteAnnotationByIdApiArg = { + annotationId: string; +}; +export type GetAnnotationByIdApiResponse = /** status 200 (empty) */ Annotation; +export type GetAnnotationByIdApiArg = { + annotationId: string; +}; +export type PatchAnnotationApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type PatchAnnotationApiArg = { + annotationId: string; + patchAnnotationsCmd: PatchAnnotationsCmd; +}; +export type UpdateAnnotationApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type UpdateAnnotationApiArg = { + annotationId: string; + updateAnnotationsCmd: UpdateAnnotationsCmd; +}; +export type ListDevicesApiResponse = /** status 200 (empty) */ DeviceDto[]; +export type ListDevicesApiArg = void; +export type SearchDevicesApiResponse = /** status 200 (empty) */ SearchDeviceQueryResult; +export type SearchDevicesApiArg = void; +export type GetSessionListApiResponse = /** status 200 (empty) */ CloudMigrationSessionListResponseDto; +export type GetSessionListApiArg = void; +export type CreateSessionApiResponse = /** status 200 (empty) */ CloudMigrationSessionResponseDto; +export type CreateSessionApiArg = { + cloudMigrationSessionRequestDto: CloudMigrationSessionRequestDto; +}; +export type DeleteSessionApiResponse = unknown; +export type DeleteSessionApiArg = { + /** UID of a migration session */ + uid: string; +}; +export type GetSessionApiResponse = /** status 200 (empty) */ CloudMigrationSessionResponseDto; +export type GetSessionApiArg = { + /** UID of a migration session */ + uid: string; +}; +export type CreateSnapshotApiResponse = /** status 200 (empty) */ CreateSnapshotResponseDto; +export type CreateSnapshotApiArg = { + /** UID of a session */ + uid: string; + createSnapshotRequestDto: CreateSnapshotRequestDto; +}; +export type GetSnapshotApiResponse = /** status 200 (empty) */ GetSnapshotResponseDto; +export type GetSnapshotApiArg = { + /** ResultPage is used for pagination with ResultLimit */ + resultPage?: number; + /** Max limit for snapshot results returned. */ + resultLimit?: number; + /** ResultSortColumn can be used to override the default system sort. Valid values are "name", "resource_type", and "status". */ + resultSortColumn?: string; + /** ResultSortOrder is used with ResultSortColumn. Valid values are ASC and DESC. */ + resultSortOrder?: string; + /** ErrorsOnly is used to only return resources with error statuses */ + errorsOnly?: boolean; + /** Session UID of a session */ + uid: string; + /** UID of a snapshot */ + snapshotUid: string; +}; +export type CancelSnapshotApiResponse = unknown; +export type CancelSnapshotApiArg = { + /** Session UID of a session */ + uid: string; + /** UID of a snapshot */ + snapshotUid: string; +}; +export type UploadSnapshotApiResponse = unknown; +export type UploadSnapshotApiArg = { + /** Session UID of a session */ + uid: string; + /** UID of a snapshot */ + snapshotUid: string; +}; +export type GetShapshotListApiResponse = /** status 200 (empty) */ SnapshotListResponseDto; +export type GetShapshotListApiArg = { + /** Page is used for pagination with limit */ + page?: number; + /** Max limit for results returned. */ + limit?: number; + /** Session UID of a session */ + uid: string; + /** Sort with value latest to return results sorted in descending order. */ + sort?: string; +}; +export type GetResourceDependenciesApiResponse = /** status 200 (empty) */ ResourceDependenciesResponseDto; +export type GetResourceDependenciesApiArg = void; +export type GetCloudMigrationTokenApiResponse = /** status 200 (empty) */ GetAccessTokenResponseDto; +export type GetCloudMigrationTokenApiArg = void; +export type CreateCloudMigrationTokenApiResponse = /** status 200 (empty) */ CreateAccessTokenResponseDto; +export type CreateCloudMigrationTokenApiArg = void; +export type DeleteCloudMigrationTokenApiResponse = unknown; +export type DeleteCloudMigrationTokenApiArg = { + /** UID of a cloud migration token */ + uid: string; +}; +export type RouteConvertPrometheusCortexGetRulesApiResponse = unknown; +export type RouteConvertPrometheusCortexGetRulesApiArg = void; +export type RouteConvertPrometheusCortexPostRuleGroupsApiResponse = + /** status 202 ConvertPrometheusResponse */ ConvertPrometheusResponse; +export type RouteConvertPrometheusCortexPostRuleGroupsApiArg = void; +export type RouteConvertPrometheusCortexDeleteNamespaceApiResponse = + /** status 202 ConvertPrometheusResponse */ ConvertPrometheusResponse; +export type RouteConvertPrometheusCortexDeleteNamespaceApiArg = { + namespaceTitle: string; +}; +export type RouteConvertPrometheusCortexGetNamespaceApiResponse = unknown; +export type RouteConvertPrometheusCortexGetNamespaceApiArg = { + namespaceTitle: string; +}; +export type RouteConvertPrometheusCortexPostRuleGroupApiResponse = + /** status 202 ConvertPrometheusResponse */ ConvertPrometheusResponse; +export type RouteConvertPrometheusCortexPostRuleGroupApiArg = { + namespaceTitle: string; + 'x-grafana-alerting-datasource-uid'?: string; + 'x-grafana-alerting-recording-rules-paused'?: boolean; + 'x-grafana-alerting-alert-rules-paused'?: boolean; + 'x-grafana-alerting-target-datasource-uid'?: string; + 'x-grafana-alerting-folder-uid'?: string; + 'x-grafana-alerting-notification-receiver'?: string; + prometheusRuleGroup: PrometheusRuleGroup; +}; +export type RouteConvertPrometheusCortexDeleteRuleGroupApiResponse = + /** status 202 ConvertPrometheusResponse */ ConvertPrometheusResponse; +export type RouteConvertPrometheusCortexDeleteRuleGroupApiArg = { + namespaceTitle: string; + group: string; +}; +export type RouteConvertPrometheusCortexGetRuleGroupApiResponse = unknown; +export type RouteConvertPrometheusCortexGetRuleGroupApiArg = { + namespaceTitle: string; + group: string; +}; +export type RouteConvertPrometheusGetRulesApiResponse = unknown; +export type RouteConvertPrometheusGetRulesApiArg = void; +export type RouteConvertPrometheusPostRuleGroupsApiResponse = + /** status 202 ConvertPrometheusResponse */ ConvertPrometheusResponse; +export type RouteConvertPrometheusPostRuleGroupsApiArg = void; +export type RouteConvertPrometheusDeleteNamespaceApiResponse = + /** status 202 ConvertPrometheusResponse */ ConvertPrometheusResponse; +export type RouteConvertPrometheusDeleteNamespaceApiArg = { + namespaceTitle: string; +}; +export type RouteConvertPrometheusGetNamespaceApiResponse = unknown; +export type RouteConvertPrometheusGetNamespaceApiArg = { + namespaceTitle: string; +}; +export type RouteConvertPrometheusPostRuleGroupApiResponse = + /** status 202 ConvertPrometheusResponse */ ConvertPrometheusResponse; +export type RouteConvertPrometheusPostRuleGroupApiArg = { + namespaceTitle: string; + 'x-grafana-alerting-datasource-uid'?: string; + 'x-grafana-alerting-recording-rules-paused'?: boolean; + 'x-grafana-alerting-alert-rules-paused'?: boolean; + 'x-grafana-alerting-target-datasource-uid'?: string; + 'x-grafana-alerting-folder-uid'?: string; + 'x-grafana-alerting-notification-receiver'?: string; + prometheusRuleGroup: PrometheusRuleGroup; +}; +export type RouteConvertPrometheusDeleteRuleGroupApiResponse = + /** status 202 ConvertPrometheusResponse */ ConvertPrometheusResponse; +export type RouteConvertPrometheusDeleteRuleGroupApiArg = { + namespaceTitle: string; + group: string; +}; +export type RouteConvertPrometheusGetRuleGroupApiResponse = unknown; +export type RouteConvertPrometheusGetRuleGroupApiArg = { + namespaceTitle: string; + group: string; +}; +export type SearchDashboardSnapshotsApiResponse = /** status 200 (empty) */ DashboardSnapshotDto[]; +export type SearchDashboardSnapshotsApiArg = { + /** Search Query */ + query?: string; + /** Limit the number of returned results */ + limit?: number; +}; +export type CalculateDashboardDiffApiResponse = /** status 200 (empty) */ number[]; +export type CalculateDashboardDiffApiArg = { + body: { + base?: CalculateDiffTarget; + /** The type of diff to return + Description: + `basic` + `json` */ + diffType?: 'basic' | 'json'; + new?: CalculateDiffTarget; + }; +}; +export type PostDashboardApiResponse = /** status 200 (empty) */ { + /** FolderUID The unique identifier (uid) of the folder the dashboard belongs to. */ + folderUid?: string; + /** ID The unique identifier (id) of the created/updated dashboard. */ + id: number; + /** Status status of the response. */ + status: string; + /** Slug The slug of the dashboard. */ + title: string; + /** UID The unique identifier (uid) of the created/updated dashboard. */ + uid: string; + /** URL The relative URL for accessing the created/updated dashboard. */ + url: string; + /** Version The version of the dashboard. */ + version: number; +}; +export type PostDashboardApiArg = { + saveDashboardCommand: SaveDashboardCommand; +}; +export type GetHomeDashboardApiResponse = /** status 200 (empty) */ GetHomeDashboardResponse; +export type GetHomeDashboardApiArg = void; +export type ImportDashboardApiResponse = + /** status 200 (empty) */ ImportDashboardResponseResponseObjectReturnedWhenImportingADashboard; +export type ImportDashboardApiArg = { + importDashboardRequest: ImportDashboardRequestRequestObjectForImportingADashboard; +}; +export type InterpolateDashboardApiResponse = /** status 200 (empty) */ any; +export type InterpolateDashboardApiArg = void; +export type ListPublicDashboardsApiResponse = /** status 200 (empty) */ PublicDashboardListResponseWithPagination; +export type ListPublicDashboardsApiArg = void; +export type GetDashboardTagsApiResponse = /** status 200 (empty) */ DashboardTagCloudItem[]; +export type GetDashboardTagsApiArg = void; +export type GetPublicDashboardApiResponse = /** status 200 (empty) */ PublicDashboard; +export type GetPublicDashboardApiArg = { + dashboardUid: string; +}; +export type CreatePublicDashboardApiResponse = /** status 200 (empty) */ PublicDashboard; +export type CreatePublicDashboardApiArg = { + dashboardUid: string; + publicDashboardDto: PublicDashboardDto; +}; +export type DeletePublicDashboardApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type DeletePublicDashboardApiArg = { + dashboardUid: string; + uid: string; +}; +export type UpdatePublicDashboardApiResponse = /** status 200 (empty) */ PublicDashboard; +export type UpdatePublicDashboardApiArg = { + dashboardUid: string; + uid: string; + publicDashboardDto: PublicDashboardDto; +}; +export type DeleteDashboardByUidApiResponse = /** status 200 (empty) */ { + /** Message Message of the deleted dashboard. */ + message: string; + /** Title Title of the deleted dashboard. */ + title: string; + /** UID Identifier of the deleted dashboard. */ + uid: string; +}; +export type DeleteDashboardByUidApiArg = { + uid: string; +}; +export type GetDashboardByUidApiResponse = /** status 200 (empty) */ DashboardFullWithMeta; +export type GetDashboardByUidApiArg = { + uid: string; +}; +export type GetDashboardPermissionsListByUidApiResponse = /** status 200 (empty) */ DashboardAclInfoDto[]; +export type GetDashboardPermissionsListByUidApiArg = { + uid: string; +}; +export type UpdateDashboardPermissionsByUidApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type UpdateDashboardPermissionsByUidApiArg = { + uid: string; + updateDashboardAclCommand: UpdateDashboardAclCommand; +}; +export type RestoreDashboardVersionByUidApiResponse = /** status 200 (empty) */ { + /** FolderUID The unique identifier (uid) of the folder the dashboard belongs to. */ + folderUid?: string; + /** ID The unique identifier (id) of the created/updated dashboard. */ + id: number; + /** Status status of the response. */ + status: string; + /** Slug The slug of the dashboard. */ + title: string; + /** UID The unique identifier (uid) of the created/updated dashboard. */ + uid: string; + /** URL The relative URL for accessing the created/updated dashboard. */ + url: string; + /** Version The version of the dashboard. */ + version: number; +}; +export type RestoreDashboardVersionByUidApiArg = { + uid: string; + restoreDashboardVersionCommand: RestoreDashboardVersionCommand; +}; +export type GetDashboardVersionsByUidApiResponse = /** status 200 (empty) */ DashboardVersionResponseMeta; +export type GetDashboardVersionsByUidApiArg = { + uid: string; + /** Maximum number of results to return */ + limit?: number; + /** Version to start from when returning queries */ + start?: number; +}; +export type GetDashboardVersionByUidApiResponse = /** status 200 (empty) */ DashboardVersionMeta; +export type GetDashboardVersionByUidApiArg = { + dashboardVersionId: number; + uid: string; +}; +export type GetDataSourcesApiResponse = /** status 200 (empty) */ DataSourceList; +export type GetDataSourcesApiArg = void; +export type AddDataSourceApiResponse = /** status 200 (empty) */ { + datasource: DataSource; + /** ID Identifier of the new data source. */ + id: number; + /** Message Message of the deleted dashboard. */ + message: string; + /** Name of the new data source. */ + name: string; +}; +export type AddDataSourceApiArg = { + addDataSourceCommand: AddDataSourceCommand; +}; +export type GetCorrelationsApiResponse = /** status 200 (empty) */ Correlation[]; +export type GetCorrelationsApiArg = { + /** Limit the maximum number of correlations to return per page */ + limit?: number; + /** Page index for starting fetching correlations */ + page?: number; + /** Source datasource UID filter to be applied to correlations */ + sourceUid?: string[]; +}; +export type GetDataSourceIdByNameApiResponse = /** status 200 (empty) */ { + /** ID Identifier of the data source. */ + id: number; +}; +export type GetDataSourceIdByNameApiArg = { + name: string; +}; +export type DeleteDataSourceByNameApiResponse = /** status 200 (empty) */ { + /** ID Identifier of the deleted data source. */ + id: number; + /** Message Message of the deleted dashboard. */ + message: string; +}; +export type DeleteDataSourceByNameApiArg = { + name: string; +}; +export type GetDataSourceByNameApiResponse = /** status 200 (empty) */ DataSource; +export type GetDataSourceByNameApiArg = { + name: string; +}; +export type DatasourceProxyDeleteByUiDcallsApiResponse = unknown; +export type DatasourceProxyDeleteByUiDcallsApiArg = { + uid: string; + datasourceProxyRoute: string; +}; +export type DatasourceProxyGetByUiDcallsApiResponse = unknown; +export type DatasourceProxyGetByUiDcallsApiArg = { + datasourceProxyRoute: string; + uid: string; +}; +export type DatasourceProxyPostByUiDcallsApiResponse = unknown; +export type DatasourceProxyPostByUiDcallsApiArg = { + datasourceProxyRoute: string; + uid: string; + body: any; +}; +export type GetCorrelationsBySourceUidApiResponse = /** status 200 (empty) */ Correlation[]; +export type GetCorrelationsBySourceUidApiArg = { + sourceUid: string; +}; +export type CreateCorrelationApiResponse = /** status 200 (empty) */ CreateCorrelationResponseBody; +export type CreateCorrelationApiArg = { + sourceUid: string; + createCorrelationCommand: CreateCorrelationCommand; +}; +export type GetCorrelationApiResponse = /** status 200 (empty) */ Correlation; +export type GetCorrelationApiArg = { + sourceUid: string; + correlationUid: string; +}; +export type UpdateCorrelationApiResponse = /** status 200 (empty) */ UpdateCorrelationResponseBody; +export type UpdateCorrelationApiArg = { + sourceUid: string; + correlationUid: string; + updateCorrelationCommand: UpdateCorrelationCommand; +}; +export type DeleteDataSourceByUidApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type DeleteDataSourceByUidApiArg = { + uid: string; +}; +export type GetDataSourceByUidApiResponse = /** status 200 (empty) */ DataSource; +export type GetDataSourceByUidApiArg = { + uid: string; +}; +export type UpdateDataSourceByUidApiResponse = /** status 200 (empty) */ { + datasource: DataSource; + /** ID Identifier of the new data source. */ + id: number; + /** Message Message of the deleted dashboard. */ + message: string; + /** Name of the new data source. */ + name: string; +}; +export type UpdateDataSourceByUidApiArg = { + uid: string; + updateDataSourceCommand: UpdateDataSourceCommand; +}; +export type DeleteCorrelationApiResponse = /** status 200 (empty) */ DeleteCorrelationResponseBody; +export type DeleteCorrelationApiArg = { + uid: string; + correlationUid: string; +}; +export type CheckDatasourceHealthWithUidApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type CheckDatasourceHealthWithUidApiArg = { + uid: string; +}; +export type GetTeamLbacRulesApiApiResponse = /** status 200 (empty) */ TeamLbacRules; +export type GetTeamLbacRulesApiApiArg = { + uid: string; +}; +export type UpdateTeamLbacRulesApiApiResponse = /** status 200 (empty) */ { + id?: number; + message?: string; + name?: string; + rules?: TeamLbacRule[]; + uid?: string; +}; +export type UpdateTeamLbacRulesApiApiArg = { + uid: string; + updateTeamLbacCommand: UpdateTeamLbacCommand; +}; +export type CallDatasourceResourceWithUidApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type CallDatasourceResourceWithUidApiArg = { + datasourceProxyRoute: string; + uid: string; +}; +export type GetDataSourceCacheConfigApiResponse = /** status 200 CacheConfigResponse */ CacheConfigResponse; +export type GetDataSourceCacheConfigApiArg = { + dataSourceUid: string; +}; +export type SetDataSourceCacheConfigApiResponse = /** status 200 CacheConfigResponse */ CacheConfigResponse; +export type SetDataSourceCacheConfigApiArg = { + dataSourceUid: string; + cacheConfigSetter: CacheConfigSetter; +}; +export type CleanDataSourceCacheApiResponse = /** status 200 CacheConfigResponse */ CacheConfigResponse; +export type CleanDataSourceCacheApiArg = { + dataSourceUid: string; +}; +export type DisableDataSourceCacheApiResponse = /** status 200 CacheConfigResponse */ CacheConfigResponse; +export type DisableDataSourceCacheApiArg = { + dataSourceUid: string; +}; +export type EnableDataSourceCacheApiResponse = /** status 200 CacheConfigResponse */ CacheConfigResponse; +export type EnableDataSourceCacheApiArg = { + dataSourceUid: string; +}; +export type QueryMetricsWithExpressionsApiResponse = /** status 200 (empty) */ + | QueryDataResponseContainsTheResultsFromAQueryDataRequest + | /** status 207 (empty) */ QueryDataResponseContainsTheResultsFromAQueryDataRequest; +export type QueryMetricsWithExpressionsApiArg = { + metricRequest: MetricRequest; +}; +export type GetFoldersApiResponse = /** status 200 (empty) */ FolderSearchHit[]; +export type GetFoldersApiArg = { + /** Limit the maximum number of folders to return */ + limit?: number; + /** Page index for starting fetching folders */ + page?: number; + /** The parent folder UID */ + parentUid?: string; + /** Set to `Edit` to return folders that the user can edit */ + permission?: 'Edit' | 'View'; +}; +export type CreateFolderApiResponse = /** status 200 (empty) */ Folder; +export type CreateFolderApiArg = { + createFolderCommand: CreateFolderCommand; +}; +export type DeleteFolderApiResponse = /** status 200 (empty) */ { + /** ID Identifier of the deleted folder. */ + id: number; + /** Message Message of the deleted folder. */ + message: string; + /** Title of the deleted folder. */ + title: string; +}; +export type DeleteFolderApiArg = { + folderUid: string; + /** If `true` any Grafana 8 Alerts under this folder will be deleted. + Set to `false` so that the request will fail if the folder contains any Grafana 8 Alerts. */ + forceDeleteRules?: boolean; +}; +export type GetFolderByUidApiResponse = /** status 200 (empty) */ Folder; +export type GetFolderByUidApiArg = { + folderUid: string; +}; +export type UpdateFolderApiResponse = /** status 200 (empty) */ Folder; +export type UpdateFolderApiArg = { + folderUid: string; + /** To change the unique identifier (uid), provide another one. + To overwrite an existing folder with newer version, set `overwrite` to `true`. + Provide the current version to safelly update the folder: if the provided version differs from the stored one the request will fail, unless `overwrite` is `true`. */ + updateFolderCommand: UpdateFolderCommand; +}; +export type GetFolderDescendantCountsApiResponse = /** status 200 (empty) */ DescendantCounts; +export type GetFolderDescendantCountsApiArg = { + folderUid: string; +}; +export type MoveFolderApiResponse = /** status 200 (empty) */ Folder; +export type MoveFolderApiArg = { + folderUid: string; + moveFolderCommand: MoveFolderCommand; +}; +export type GetFolderPermissionListApiResponse = /** status 200 (empty) */ DashboardAclInfoDto[]; +export type GetFolderPermissionListApiArg = { + folderUid: string; +}; +export type UpdateFolderPermissionsApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type UpdateFolderPermissionsApiArg = { + folderUid: string; + updateDashboardAclCommand: UpdateDashboardAclCommand; +}; +export type GetMappedGroupsApiResponse = /** status 200 (empty) */ GetGroupsResponse; +export type GetMappedGroupsApiArg = void; +export type DeleteGroupMappingsApiResponse = + /** status 204 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type DeleteGroupMappingsApiArg = { + groupId: string; +}; +export type CreateGroupMappingsApiResponse = /** status 201 (empty) */ MessageResponse; +export type CreateGroupMappingsApiArg = { + groupId: string; + groupAttributes: GroupAttributes; +}; +export type UpdateGroupMappingsApiResponse = /** status 201 (empty) */ MessageResponse; +export type UpdateGroupMappingsApiArg = { + groupId: string; + groupAttributes: GroupAttributes; +}; +export type GetGroupRolesApiResponse = /** status 200 (empty) */ RoleDto[]; +export type GetGroupRolesApiArg = { + groupId: string; +}; +export type GetHealthApiResponse = /** status 200 healthResponse */ HealthResponse; +export type GetHealthApiArg = void; +export type GetLibraryElementsApiResponse = + /** status 200 (empty) */ LibraryElementSearchResponseIsAResponseStructForLibraryElementSearchResult; +export type GetLibraryElementsApiArg = { + /** Part of the name or description searched for. */ + searchString?: string; + /** Kind of element to search for. */ + kind?: 1; + /** Sort order of elements. */ + sortDirection?: 'alpha-asc' | 'alpha-desc'; + /** A comma separated list of types to filter the elements by */ + typeFilter?: string; + /** Element UID to exclude from search results. */ + excludeUid?: string; + /** A comma separated list of folder ID(s) to filter the elements by. */ + folderFilter?: string; + /** The number of results per page. */ + perPage?: number; + /** The page for a set of records, given that only perPage records are returned at a time. Numbering starts at 1. */ + page?: number; +}; +export type CreateLibraryElementApiResponse = + /** status 200 (empty) */ LibraryElementResponseIsAResponseStructForLibraryElementDto; +export type CreateLibraryElementApiArg = { + createLibraryElementCommand: CreateLibraryElementCommand; +}; +export type GetLibraryElementByNameApiResponse = + /** status 200 (empty) */ LibraryElementArrayResponseIsAResponseStructForAnArrayOfLibraryElementDto; +export type GetLibraryElementByNameApiArg = { + libraryElementName: string; +}; +export type DeleteLibraryElementByUidApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type DeleteLibraryElementByUidApiArg = { + libraryElementUid: string; +}; +export type GetLibraryElementByUidApiResponse = + /** status 200 (empty) */ LibraryElementResponseIsAResponseStructForLibraryElementDto; +export type GetLibraryElementByUidApiArg = { + libraryElementUid: string; +}; +export type UpdateLibraryElementApiResponse = + /** status 200 (empty) */ LibraryElementResponseIsAResponseStructForLibraryElementDto; +export type UpdateLibraryElementApiArg = { + libraryElementUid: string; + patchLibraryElementCommand: PatchLibraryElementCommand; +}; +export type GetLibraryElementConnectionsApiResponse = + /** status 200 (empty) */ LibraryElementConnectionsResponseIsAResponseStructForAnArrayOfLibraryElementConnectionDto; +export type GetLibraryElementConnectionsApiArg = { + libraryElementUid: string; +}; +export type GetStatusApiResponse = unknown; +export type GetStatusApiArg = void; +export type RefreshLicenseStatsApiResponse = /** status 200 (empty) */ ActiveUserStats; +export type RefreshLicenseStatsApiArg = void; +export type DeleteLicenseTokenApiResponse = /** status 202 AcceptedResponse */ ErrorResponseBody; +export type DeleteLicenseTokenApiArg = { + deleteTokenCommand: DeleteTokenCommand; +}; +export type GetLicenseTokenApiResponse = /** status 200 (empty) */ Token; +export type GetLicenseTokenApiArg = void; +export type PostLicenseTokenApiResponse = /** status 200 (empty) */ Token; +export type PostLicenseTokenApiArg = { + deleteTokenCommand: DeleteTokenCommand; +}; +export type PostRenewLicenseTokenApiResponse = unknown; +export type PostRenewLicenseTokenApiArg = { + body: object; +}; +export type GetSamlLogoutApiResponse = unknown; +export type GetSamlLogoutApiArg = void; +export type GetCurrentOrgApiResponse = /** status 200 (empty) */ OrgDetailsDto; +export type GetCurrentOrgApiArg = void; +export type UpdateCurrentOrgApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type UpdateCurrentOrgApiArg = { + updateOrgForm: UpdateOrgForm; +}; +export type UpdateCurrentOrgAddressApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type UpdateCurrentOrgAddressApiArg = { + updateOrgAddressForm: UpdateOrgAddressForm; +}; +export type GetPendingOrgInvitesApiResponse = /** status 200 (empty) */ TempUserDto[]; +export type GetPendingOrgInvitesApiArg = void; +export type AddOrgInviteApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type AddOrgInviteApiArg = { + addInviteForm: AddInviteForm; +}; +export type RevokeInviteApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type RevokeInviteApiArg = { + invitationCode: string; +}; +export type GetOrgPreferencesApiResponse = /** status 200 (empty) */ PreferencesSpec; +export type GetOrgPreferencesApiArg = void; +export type PatchOrgPreferencesApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type PatchOrgPreferencesApiArg = { + patchPrefsCmd: PatchPrefsCmd; +}; +export type UpdateOrgPreferencesApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type UpdateOrgPreferencesApiArg = { + updatePrefsCmd: UpdatePrefsCmd; +}; +export type GetCurrentOrgQuotaApiResponse = /** status 200 (empty) */ QuotaDto[]; +export type GetCurrentOrgQuotaApiArg = void; +export type GetOrgUsersForCurrentOrgApiResponse = /** status 200 (empty) */ OrgUserDto[]; +export type GetOrgUsersForCurrentOrgApiArg = { + query?: string; + limit?: number; +}; +export type AddOrgUserToCurrentOrgApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type AddOrgUserToCurrentOrgApiArg = { + addOrgUserCommand: AddOrgUserCommand; +}; +export type GetOrgUsersForCurrentOrgLookupApiResponse = /** status 200 (empty) */ UserLookupDto[]; +export type GetOrgUsersForCurrentOrgLookupApiArg = { + query?: string; + limit?: number; +}; +export type RemoveOrgUserForCurrentOrgApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type RemoveOrgUserForCurrentOrgApiArg = { + userId: number; +}; +export type UpdateOrgUserForCurrentOrgApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type UpdateOrgUserForCurrentOrgApiArg = { + userId: number; + updateOrgUserCommand: UpdateOrgUserCommand; +}; +export type SearchOrgsApiResponse = /** status 200 (empty) */ OrgDto[]; +export type SearchOrgsApiArg = { + page?: number; + /** Number of items per page + The totalCount field in the response can be used for pagination list E.g. if totalCount is equal to 100 teams and the perpage parameter is set to 10 then there are 10 pages of teams. */ + perpage?: number; + name?: string; + /** If set it will return results where the query value is contained in the name field. Query values with spaces need to be URL encoded. */ + query?: string; +}; +export type CreateOrgApiResponse = /** status 200 (empty) */ { + /** Message Message of the created org. */ + message: string; + /** ID Identifier of the created org. */ + orgId: number; +}; +export type CreateOrgApiArg = { + createOrgCommand: CreateOrgCommand; +}; +export type GetOrgByNameApiResponse = /** status 200 (empty) */ OrgDetailsDto; +export type GetOrgByNameApiArg = { + orgName: string; +}; +export type DeleteOrgByIdApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type DeleteOrgByIdApiArg = { + orgId: number; +}; +export type GetOrgByIdApiResponse = /** status 200 (empty) */ OrgDetailsDto; +export type GetOrgByIdApiArg = { + orgId: number; +}; +export type UpdateOrgApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type UpdateOrgApiArg = { + orgId: number; + updateOrgForm: UpdateOrgForm; +}; +export type UpdateOrgAddressApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type UpdateOrgAddressApiArg = { + orgId: number; + updateOrgAddressForm: UpdateOrgAddressForm; +}; +export type GetOrgQuotaApiResponse = /** status 200 (empty) */ QuotaDto[]; +export type GetOrgQuotaApiArg = { + orgId: number; +}; +export type UpdateOrgQuotaApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type UpdateOrgQuotaApiArg = { + quotaTarget: string; + orgId: number; + updateQuotaCmd: UpdateQuotaCmd; +}; +export type GetOrgUsersApiResponse = /** status 200 (empty) */ OrgUserDto[]; +export type GetOrgUsersApiArg = { + orgId: number; +}; +export type AddOrgUserApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type AddOrgUserApiArg = { + orgId: number; + addOrgUserCommand: AddOrgUserCommand; +}; +export type SearchOrgUsersApiResponse = /** status 200 (empty) */ SearchOrgUsersQueryResult; +export type SearchOrgUsersApiArg = { + orgId: number; +}; +export type RemoveOrgUserApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type RemoveOrgUserApiArg = { + orgId: number; + userId: number; +}; +export type UpdateOrgUserApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type UpdateOrgUserApiArg = { + orgId: number; + userId: number; + updateOrgUserCommand: UpdateOrgUserCommand; +}; +export type SearchPlaylistsApiResponse = /** status 200 (empty) */ Playlists; +export type SearchPlaylistsApiArg = { + query?: string; + /** in:limit */ + limit?: number; +}; +export type CreatePlaylistApiResponse = /** status 200 (empty) */ Playlist; +export type CreatePlaylistApiArg = { + createPlaylistCommand: CreatePlaylistCommand; +}; +export type DeletePlaylistApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type DeletePlaylistApiArg = { + uid: string; +}; +export type GetPlaylistApiResponse = /** status 200 (empty) */ PlaylistDto; +export type GetPlaylistApiArg = { + uid: string; +}; +export type UpdatePlaylistApiResponse = /** status 200 (empty) */ PlaylistDto; +export type UpdatePlaylistApiArg = { + uid: string; + updatePlaylistCommand: UpdatePlaylistCommand; +}; +export type GetPlaylistItemsApiResponse = /** status 200 (empty) */ PlaylistItemDto[]; +export type GetPlaylistItemsApiArg = { + uid: string; +}; +export type ViewPublicDashboardApiResponse = /** status 200 (empty) */ DashboardFullWithMeta; +export type ViewPublicDashboardApiArg = { + accessToken: string; +}; +export type GetPublicAnnotationsApiResponse = /** status 200 (empty) */ AnnotationEvent[]; +export type GetPublicAnnotationsApiArg = { + accessToken: string; +}; +export type QueryPublicDashboardApiResponse = + /** status 200 (empty) */ QueryDataResponseContainsTheResultsFromAQueryDataRequest; +export type QueryPublicDashboardApiArg = { + accessToken: string; + panelId: number; +}; +export type SearchQueriesApiResponse = /** status 200 (empty) */ QueryHistorySearchResponse; +export type SearchQueriesApiArg = { + /** List of data source UIDs to search for */ + datasourceUid?: string[]; + /** Text inside query or comments that is searched for */ + searchString?: string; + /** Flag indicating if only starred queries should be returned */ + onlyStarred?: boolean; + /** Sort method */ + sort?: 'time-desc' | 'time-asc'; + /** Use this parameter to access hits beyond limit. Numbering starts at 1. limit param acts as page size. */ + page?: number; + /** Limit the number of returned results */ + limit?: number; + /** From range for the query history search */ + from?: number; + /** To range for the query history search */ + to?: number; +}; +export type CreateQueryApiResponse = /** status 200 (empty) */ QueryHistoryResponse; +export type CreateQueryApiArg = { + createQueryInQueryHistoryCommand: CreateQueryInQueryHistoryCommand; +}; +export type UnstarQueryApiResponse = /** status 200 (empty) */ QueryHistoryResponse; +export type UnstarQueryApiArg = { + queryHistoryUid: string; +}; +export type StarQueryApiResponse = /** status 200 (empty) */ QueryHistoryResponse; +export type StarQueryApiArg = { + queryHistoryUid: string; +}; +export type DeleteQueryApiResponse = /** status 200 (empty) */ QueryHistoryDeleteQueryResponse; +export type DeleteQueryApiArg = { + queryHistoryUid: string; +}; +export type PatchQueryCommentApiResponse = /** status 200 (empty) */ QueryHistoryResponse; +export type PatchQueryCommentApiArg = { + queryHistoryUid: string; + patchQueryCommentInQueryHistoryCommand: PatchQueryCommentInQueryHistoryCommand; +}; +export type ListRecordingRulesApiResponse = /** status 200 (empty) */ RecordingRuleJson[]; +export type ListRecordingRulesApiArg = void; +export type CreateRecordingRuleApiResponse = /** status 200 (empty) */ RecordingRuleJson; +export type CreateRecordingRuleApiArg = { + recordingRuleJson: RecordingRuleJson; +}; +export type UpdateRecordingRuleApiResponse = /** status 200 (empty) */ RecordingRuleJson; +export type UpdateRecordingRuleApiArg = { + recordingRuleJson: RecordingRuleJson; +}; +export type TestCreateRecordingRuleApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type TestCreateRecordingRuleApiArg = { + recordingRuleJson: RecordingRuleJson; +}; +export type DeleteRecordingRuleWriteTargetApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type DeleteRecordingRuleWriteTargetApiArg = void; +export type GetRecordingRuleWriteTargetApiResponse = /** status 200 (empty) */ PrometheusRemoteWriteTargetJson; +export type GetRecordingRuleWriteTargetApiArg = void; +export type CreateRecordingRuleWriteTargetApiResponse = /** status 200 (empty) */ PrometheusRemoteWriteTargetJson; +export type CreateRecordingRuleWriteTargetApiArg = { + prometheusRemoteWriteTargetJson: PrometheusRemoteWriteTargetJson; +}; +export type DeleteRecordingRuleApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type DeleteRecordingRuleApiArg = { + recordingRuleId: number; +}; +export type GetReportsApiResponse = /** status 200 (empty) */ Report[]; +export type GetReportsApiArg = void; +export type CreateReportApiResponse = /** status 200 (empty) */ { + id?: number; + message?: string; +}; +export type CreateReportApiArg = { + createOrUpdateReport: CreateOrUpdateReport; +}; +export type GetReportsByDashboardUidApiResponse = /** status 200 (empty) */ Report[]; +export type GetReportsByDashboardUidApiArg = { + uid: string; +}; +export type SendReportApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type SendReportApiArg = { + reportEmail: ReportEmail; +}; +export type GetSettingsImageApiResponse = /** status 200 (empty) */ number[]; +export type GetSettingsImageApiArg = void; +export type RenderReportCsVsApiResponse = /** status 200 (empty) */ number[] | /** status 204 (empty) */ object; +export type RenderReportCsVsApiArg = { + dashboards?: string; + title?: string; +}; +export type RenderReportPdFsApiResponse = /** status 200 (empty) */ number[]; +export type RenderReportPdFsApiArg = { + dashboards?: string; + orientation?: string; + layout?: string; + title?: string; + scaleFactor?: string; + includeTables?: string; +}; +export type GetReportSettingsApiResponse = /** status 200 (empty) */ ReportSettings; +export type GetReportSettingsApiArg = void; +export type SaveReportSettingsApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type SaveReportSettingsApiArg = { + reportSettings: ReportSettings; +}; +export type SendTestEmailApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type SendTestEmailApiArg = { + createOrUpdateReport: CreateOrUpdateReport; +}; +export type PostAcsApiResponse = unknown; +export type PostAcsApiArg = { + relayState?: string; +}; +export type GetMetadataApiResponse = /** status 200 (empty) */ number[]; +export type GetMetadataApiArg = void; +export type GetSloApiResponse = unknown; +export type GetSloApiArg = void; +export type PostSloApiResponse = unknown; +export type PostSloApiArg = { + samlRequest?: string; + samlResponse?: string; +}; +export type SearchApiResponse = /** status 200 (empty) */ HitList; +export type SearchApiArg = { + /** Search Query */ + query?: string; + /** List of tags to search for */ + tag?: string[]; + /** Type to search for, dash-folder or dash-db */ + type?: 'dash-folder' | 'dash-db'; + /** List of dashboard id’s to search for + This is deprecated: users should use the `dashboardUIDs` query parameter instead */ + dashboardIds?: number[]; + /** List of dashboard uid’s to search for */ + dashboardUiDs?: string[]; + /** List of folder id’s to search in for dashboards + If it's `0` then it will query for the top level folders + This is deprecated: users should use the `folderUIDs` query parameter instead */ + folderIds?: number[]; + /** List of folder UID’s to search in for dashboards + If it's an empty string then it will query for the top level folders */ + folderUiDs?: string[]; + /** Flag indicating if only starred Dashboards should be returned */ + starred?: boolean; + /** Limit the number of returned results (max 5000) */ + limit?: number; + /** Use this parameter to access hits beyond limit. Numbering starts at 1. limit param acts as page size. Only available in Grafana v6.2+. */ + page?: number; + /** Set to `Edit` to return dashboards/folders that the user can edit */ + permission?: 'Edit' | 'View'; + /** Sort method; for listing all the possible sort methods use the search sorting endpoint. */ + sort?: 'alpha-asc' | 'alpha-desc'; + /** Flag indicating if only soft deleted Dashboards should be returned */ + deleted?: boolean; +}; +export type ListSortOptionsApiResponse = /** status 200 (empty) */ { + description?: string; + displayName?: string; + meta?: string; + name?: string; +}; +export type ListSortOptionsApiArg = void; +export type CreateServiceAccountApiResponse = /** status 201 (empty) */ ServiceAccountDto; +export type CreateServiceAccountApiArg = { + createServiceAccountForm: CreateServiceAccountForm; +}; +export type SearchOrgServiceAccountsWithPagingApiResponse = /** status 200 (empty) */ SearchOrgServiceAccountsResult; +export type SearchOrgServiceAccountsWithPagingApiArg = { + disabled?: boolean; + expiredTokens?: boolean; + /** It will return results where the query value is contained in one of the name. + Query values with spaces need to be URL encoded. */ + query?: string; + /** The default value is 1000. */ + perpage?: number; + /** The default value is 1. */ + page?: number; +}; +export type DeleteServiceAccountApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type DeleteServiceAccountApiArg = { + serviceAccountId: number; +}; +export type RetrieveServiceAccountApiResponse = /** status 200 (empty) */ ServiceAccountDto; +export type RetrieveServiceAccountApiArg = { + serviceAccountId: number; +}; +export type UpdateServiceAccountApiResponse = /** status 200 (empty) */ { + id?: number; + message?: string; + name?: string; + serviceaccount?: ServiceAccountProfileDto; +}; +export type UpdateServiceAccountApiArg = { + serviceAccountId: number; + updateServiceAccountForm: UpdateServiceAccountForm; +}; +export type ListTokensApiResponse = /** status 200 (empty) */ TokenDto[]; +export type ListTokensApiArg = { + serviceAccountId: number; +}; +export type CreateTokenApiResponse = /** status 200 (empty) */ NewApiKeyResult; +export type CreateTokenApiArg = { + serviceAccountId: number; + addServiceAccountTokenCommand: AddServiceAccountTokenCommand; +}; +export type DeleteTokenApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type DeleteTokenApiArg = { + tokenId: number; + serviceAccountId: number; +}; +export type RetrieveJwksApiResponse = /** status 200 (empty) */ { + keys?: JsonWebKey[]; +}; +export type RetrieveJwksApiArg = void; +export type GetSharingOptionsApiResponse = /** status 200 (empty) */ { + externalEnabled?: boolean; + externalSnapshotName?: string; + externalSnapshotURL?: string; +}; +export type GetSharingOptionsApiArg = void; +export type CreateDashboardSnapshotApiResponse = /** status 200 (empty) */ { + /** Unique key used to delete the snapshot. It is different from the key so that only the creator can delete the snapshot. */ + deleteKey?: string; + deleteUrl?: string; + /** Snapshot id */ + id?: number; + /** Unique key */ + key?: string; + url?: string; +}; +export type CreateDashboardSnapshotApiArg = { + createDashboardSnapshotCommand: CreateDashboardSnapshotCommand; +}; +export type DeleteDashboardSnapshotByDeleteKeyApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type DeleteDashboardSnapshotByDeleteKeyApiArg = { + deleteKey: string; +}; +export type DeleteDashboardSnapshotApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type DeleteDashboardSnapshotApiArg = { + key: string; +}; +export type GetDashboardSnapshotApiResponse = unknown; +export type GetDashboardSnapshotApiArg = { + key: string; +}; +export type CreateTeamApiResponse = /** status 200 (empty) */ { + message?: string; + teamId?: number; + uid?: string; +}; +export type CreateTeamApiArg = { + createTeamCommand: CreateTeamCommand; +}; +export type SearchTeamsApiResponse = /** status 200 (empty) */ SearchTeamQueryResult; +export type SearchTeamsApiArg = { + page?: number; + /** Number of items per page + The totalCount field in the response can be used for pagination list E.g. if totalCount is equal to 100 teams and the perpage parameter is set to 10 then there are 10 pages of teams. */ + perpage?: number; + name?: string; + /** If set it will return results where the query value is contained in the name field. Query values with spaces need to be URL encoded. */ + query?: string; +}; +export type RemoveTeamGroupApiQueryApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type RemoveTeamGroupApiQueryApiArg = { + groupId?: string; + teamId: number; +}; +export type GetTeamGroupsApiApiResponse = /** status 200 (empty) */ TeamGroupDto[]; +export type GetTeamGroupsApiApiArg = { + teamId: number; +}; +export type AddTeamGroupApiApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type AddTeamGroupApiApiArg = { + teamId: number; + teamGroupMapping: TeamGroupMapping; +}; +export type SearchTeamGroupsApiResponse = /** status 200 (empty) */ SearchTeamGroupsQueryResult; +export type SearchTeamGroupsApiArg = { + teamId: number; + page?: number; + /** Number of items per page */ + perpage?: number; + /** If set it will return results where the query value is contained in the name field. Query values with spaces need to be URL encoded. */ + query?: string; + /** Filter by exact name match */ + name?: string; +}; +export type DeleteTeamByIdApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type DeleteTeamByIdApiArg = { + teamId: string; +}; +export type GetTeamByIdApiResponse = /** status 200 (empty) */ TeamDto; +export type GetTeamByIdApiArg = { + teamId: string; +}; +export type UpdateTeamApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type UpdateTeamApiArg = { + teamId: string; + updateTeamCommand: UpdateTeamCommand; +}; +export type GetTeamMembersApiResponse = /** status 200 (empty) */ TeamMemberDto[]; +export type GetTeamMembersApiArg = { + teamId: string; +}; +export type AddTeamMemberApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type AddTeamMemberApiArg = { + teamId: string; + addTeamMemberCommand: AddTeamMemberCommand; +}; +export type SetTeamMembershipsApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type SetTeamMembershipsApiArg = { + teamId: string; + setTeamMembershipsCommand: SetTeamMembershipsCommand; +}; +export type RemoveTeamMemberApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type RemoveTeamMemberApiArg = { + teamId: string; + userId: number; +}; +export type UpdateTeamMemberApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type UpdateTeamMemberApiArg = { + teamId: string; + userId: number; + updateTeamMemberCommand: UpdateTeamMemberCommand; +}; +export type GetTeamPreferencesApiResponse = /** status 200 (empty) */ PreferencesSpec; +export type GetTeamPreferencesApiArg = { + teamId: string; +}; +export type UpdateTeamPreferencesApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type UpdateTeamPreferencesApiArg = { + teamId: string; + updatePrefsCmd: UpdatePrefsCmd; +}; +export type GetSignedInUserApiResponse = /** status 200 (empty) */ UserProfileDto; +export type GetSignedInUserApiArg = void; +export type UpdateSignedInUserApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type UpdateSignedInUserApiArg = { + /** To change the email, name, login, theme, provide another one. */ + updateUserCommand: UpdateUserCommand; +}; +export type GetUserAuthTokensApiResponse = /** status 200 (empty) */ UserToken[]; +export type GetUserAuthTokensApiArg = void; +export type UpdateUserEmailApiResponse = unknown; +export type UpdateUserEmailApiArg = void; +export type ClearHelpFlagsApiResponse = /** status 200 (empty) */ { + helpFlags1?: number; + message?: string; +}; +export type ClearHelpFlagsApiArg = void; +export type SetHelpFlagApiResponse = /** status 200 (empty) */ { + helpFlags1?: number; + message?: string; +}; +export type SetHelpFlagApiArg = { + flagId: string; +}; +export type GetSignedInUserOrgListApiResponse = /** status 200 (empty) */ UserOrgDto[]; +export type GetSignedInUserOrgListApiArg = void; +export type ChangeUserPasswordApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type ChangeUserPasswordApiArg = { + /** To change the email, name, login, theme, provide another one. */ + changeUserPasswordCommand: ChangeUserPasswordCommand; +}; +export type GetUserPreferencesApiResponse = /** status 200 (empty) */ PreferencesSpec; +export type GetUserPreferencesApiArg = void; +export type PatchUserPreferencesApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type PatchUserPreferencesApiArg = { + patchPrefsCmd: PatchPrefsCmd; +}; +export type UpdateUserPreferencesApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type UpdateUserPreferencesApiArg = { + updatePrefsCmd: UpdatePrefsCmd; +}; +export type GetUserQuotasApiResponse = /** status 200 (empty) */ QuotaDto[]; +export type GetUserQuotasApiArg = void; +export type RevokeUserAuthTokenApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type RevokeUserAuthTokenApiArg = { + revokeAuthTokenCmd: RevokeAuthTokenCmd; +}; +export type UnstarDashboardByUidApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type UnstarDashboardByUidApiArg = { + dashboardUid: string; +}; +export type StarDashboardByUidApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type StarDashboardByUidApiArg = { + dashboardUid: string; +}; +export type GetSignedInUserTeamListApiResponse = /** status 200 (empty) */ TeamDto[]; +export type GetSignedInUserTeamListApiArg = void; +export type UserSetUsingOrgApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type UserSetUsingOrgApiArg = { + orgId: number; +}; +export type SearchUsersApiResponse = /** status 200 (empty) */ UserSearchHitDto[]; +export type SearchUsersApiArg = { + /** Limit the maximum number of users to return per page */ + perpage?: number; + /** Page index for starting fetching users */ + page?: number; +}; +export type GetUserByLoginOrEmailApiResponse = /** status 200 (empty) */ UserProfileDto; +export type GetUserByLoginOrEmailApiArg = { + /** loginOrEmail of the user */ + loginOrEmail: string; +}; +export type SearchUsersWithPagingApiResponse = /** status 200 (empty) */ SearchUserQueryResult; +export type SearchUsersWithPagingApiArg = void; +export type GetUserByIdApiResponse = /** status 200 (empty) */ UserProfileDto; +export type GetUserByIdApiArg = { + userId: number; +}; +export type UpdateUserApiResponse = + /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type UpdateUserApiArg = { + userId: number; + /** To change the email, name, login, theme, provide another one. */ + updateUserCommand: UpdateUserCommand; +}; +export type GetUserOrgListApiResponse = /** status 200 (empty) */ UserOrgDto[]; +export type GetUserOrgListApiArg = { + userId: number; +}; +export type GetUserTeamsApiResponse = /** status 200 (empty) */ TeamDto[]; +export type GetUserTeamsApiArg = { + userId: number; +}; +export type RouteGetAlertRulesApiResponse = /** status 200 ProvisionedAlertRules */ ProvisionedAlertRulesRead; +export type RouteGetAlertRulesApiArg = void; +export type RoutePostAlertRuleApiResponse = /** status 201 ProvisionedAlertRule */ ProvisionedAlertRuleRead; +export type RoutePostAlertRuleApiArg = { + 'X-Disable-Provenance'?: string; + provisionedAlertRule: ProvisionedAlertRule; +}; +export type RouteGetAlertRulesExportApiResponse = + /** status 200 AlertingFileExport */ AlertingFileExportIsTheFullProvisionedFileExport; +export type RouteGetAlertRulesExportApiArg = { + /** Whether to initiate a download of the file or not. */ + download?: boolean; + /** Format of the downloaded file. Supported yaml, json or hcl. Accept header can also be used, but the query parameter will take precedence. */ + format?: 'yaml' | 'json' | 'hcl'; + /** UIDs of folders from which to export rules */ + folderUid?: string[]; + /** Name of group of rules to export. Must be specified only together with a single folder UID */ + group?: string; + /** UID of alert rule to export. If specified, parameters folderUid and group must be empty. */ + ruleUid?: string; +}; +export type RouteDeleteAlertRuleApiResponse = unknown; +export type RouteDeleteAlertRuleApiArg = { + /** Alert rule UID */ + uid: string; + 'X-Disable-Provenance'?: string; +}; +export type RouteGetAlertRuleApiResponse = /** status 200 ProvisionedAlertRule */ ProvisionedAlertRuleRead; +export type RouteGetAlertRuleApiArg = { + /** Alert rule UID */ + uid: string; +}; +export type RoutePutAlertRuleApiResponse = /** status 200 ProvisionedAlertRule */ ProvisionedAlertRuleRead; +export type RoutePutAlertRuleApiArg = { + /** Alert rule UID */ + uid: string; + 'X-Disable-Provenance'?: string; + provisionedAlertRule: ProvisionedAlertRule; +}; +export type RouteGetAlertRuleExportApiResponse = + /** status 200 AlertingFileExport */ AlertingFileExportIsTheFullProvisionedFileExport; +export type RouteGetAlertRuleExportApiArg = { + /** Whether to initiate a download of the file or not. */ + download?: boolean; + /** Format of the downloaded file. Supported yaml, json or hcl. Accept header can also be used, but the query parameter will take precedence. */ + format?: 'yaml' | 'json' | 'hcl'; + /** Alert rule UID */ + uid: string; +}; +export type RouteGetContactpointsApiResponse = /** status 200 ContactPoints */ ContactPointsRead; +export type RouteGetContactpointsApiArg = { + /** Filter by name */ + name?: string; +}; +export type RoutePostContactpointsApiResponse = /** status 202 EmbeddedContactPoint */ EmbeddedContactPointRead; +export type RoutePostContactpointsApiArg = { + 'X-Disable-Provenance'?: string; + embeddedContactPoint: EmbeddedContactPoint; +}; +export type RouteGetContactpointsExportApiResponse = + /** status 200 AlertingFileExport */ AlertingFileExportIsTheFullProvisionedFileExport; +export type RouteGetContactpointsExportApiArg = { + /** Whether to initiate a download of the file or not. */ + download?: boolean; + /** Format of the downloaded file. Supported yaml, json or hcl. Accept header can also be used, but the query parameter will take precedence. */ + format?: 'yaml' | 'json' | 'hcl'; + /** Whether any contained secure settings should be decrypted or left redacted. Redacted settings will contain RedactedValue instead. Currently, only org admin can view decrypted secure settings. */ + decrypt?: boolean; + /** Filter by name */ + name?: string; +}; +export type RouteDeleteContactpointsApiResponse = unknown; +export type RouteDeleteContactpointsApiArg = { + /** UID is the contact point unique identifier */ + uid: string; +}; +export type RoutePutContactpointApiResponse = /** status 202 Ack */ Ack; +export type RoutePutContactpointApiArg = { + /** UID is the contact point unique identifier */ + uid: string; + 'X-Disable-Provenance'?: string; + embeddedContactPoint: EmbeddedContactPoint; +}; +export type RouteDeleteAlertRuleGroupApiResponse = unknown; +export type RouteDeleteAlertRuleGroupApiArg = { + folderUid: string; + group: string; +}; +export type RouteGetAlertRuleGroupApiResponse = /** status 200 AlertRuleGroup */ AlertRuleGroupRead; +export type RouteGetAlertRuleGroupApiArg = { + folderUid: string; + group: string; +}; +export type RoutePutAlertRuleGroupApiResponse = /** status 200 AlertRuleGroup */ AlertRuleGroupRead; +export type RoutePutAlertRuleGroupApiArg = { + 'X-Disable-Provenance'?: string; + folderUid: string; + group: string; + alertRuleGroup: AlertRuleGroup; +}; +export type RouteGetAlertRuleGroupExportApiResponse = + /** status 200 AlertingFileExport */ AlertingFileExportIsTheFullProvisionedFileExport; +export type RouteGetAlertRuleGroupExportApiArg = { + /** Whether to initiate a download of the file or not. */ + download?: boolean; + /** Format of the downloaded file. Supported yaml, json or hcl. Accept header can also be used, but the query parameter will take precedence. */ + format?: 'yaml' | 'json' | 'hcl'; + folderUid: string; + group: string; +}; +export type RouteGetMuteTimingsApiResponse = /** status 200 MuteTimings */ MuteTimings; +export type RouteGetMuteTimingsApiArg = void; +export type RoutePostMuteTimingApiResponse = + /** status 201 MuteTimeInterval */ MuteTimeIntervalRepresentsANamedSetOfTimeIntervalsForWhichARouteShouldBeMuted; +export type RoutePostMuteTimingApiArg = { + 'X-Disable-Provenance'?: string; + muteTimeInterval: MuteTimeIntervalRepresentsANamedSetOfTimeIntervalsForWhichARouteShouldBeMuted; +}; +export type RouteExportMuteTimingsApiResponse = + /** status 200 AlertingFileExport */ AlertingFileExportIsTheFullProvisionedFileExport; +export type RouteExportMuteTimingsApiArg = { + /** Whether to initiate a download of the file or not. */ + download?: boolean; + /** Format of the downloaded file. Supported yaml, json or hcl. Accept header can also be used, but the query parameter will take precedence. */ + format?: 'yaml' | 'json' | 'hcl'; +}; +export type RouteDeleteMuteTimingApiResponse = unknown; +export type RouteDeleteMuteTimingApiArg = { + /** Mute timing name */ + name: string; + /** Version of mute timing to use for optimistic concurrency. Leave empty to disable validation */ + version?: string; + 'X-Disable-Provenance'?: string; +}; +export type RouteGetMuteTimingApiResponse = + /** status 200 MuteTimeInterval */ MuteTimeIntervalRepresentsANamedSetOfTimeIntervalsForWhichARouteShouldBeMuted; +export type RouteGetMuteTimingApiArg = { + /** Mute timing name */ + name: string; +}; +export type RoutePutMuteTimingApiResponse = + /** status 202 MuteTimeInterval */ MuteTimeIntervalRepresentsANamedSetOfTimeIntervalsForWhichARouteShouldBeMuted; +export type RoutePutMuteTimingApiArg = { + /** Mute timing name */ + name: string; + 'X-Disable-Provenance'?: string; + muteTimeInterval: MuteTimeIntervalRepresentsANamedSetOfTimeIntervalsForWhichARouteShouldBeMuted; +}; +export type RouteExportMuteTimingApiResponse = + /** status 200 AlertingFileExport */ AlertingFileExportIsTheFullProvisionedFileExport; +export type RouteExportMuteTimingApiArg = { + /** Whether to initiate a download of the file or not. */ + download?: boolean; + /** Format of the downloaded file. Supported yaml, json or hcl. Accept header can also be used, but the query parameter will take precedence. */ + format?: 'yaml' | 'json' | 'hcl'; + /** Mute timing name */ + name: string; +}; +export type RouteResetPolicyTreeApiResponse = /** status 202 Ack */ Ack; +export type RouteResetPolicyTreeApiArg = void; +export type RouteGetPolicyTreeApiResponse = /** status 200 Route */ Route; +export type RouteGetPolicyTreeApiArg = void; +export type RoutePutPolicyTreeApiResponse = /** status 202 Ack */ Ack; +export type RoutePutPolicyTreeApiArg = { + 'X-Disable-Provenance'?: string; + /** The new notification routing tree to use */ + route: Route; +}; +export type RouteGetPolicyTreeExportApiResponse = + /** status 200 AlertingFileExport */ AlertingFileExportIsTheFullProvisionedFileExport; +export type RouteGetPolicyTreeExportApiArg = void; +export type RouteGetTemplatesApiResponse = /** status 200 NotificationTemplates */ NotificationTemplates; +export type RouteGetTemplatesApiArg = void; +export type RouteDeleteTemplateApiResponse = unknown; +export type RouteDeleteTemplateApiArg = { + /** Template group name */ + name: string; + /** Version of template to use for optimistic concurrency. Leave empty to disable validation */ + version?: string; +}; +export type RouteGetTemplateApiResponse = /** status 200 NotificationTemplate */ NotificationTemplate; +export type RouteGetTemplateApiArg = { + /** Template group name */ + name: string; +}; +export type RoutePutTemplateApiResponse = /** status 202 NotificationTemplate */ NotificationTemplate; +export type RoutePutTemplateApiArg = { + /** Template group name */ + name: string; + 'X-Disable-Provenance'?: string; + notificationTemplateContent: NotificationTemplateContent; +}; +export type ListAllProvidersSettingsApiResponse = /** status 200 (empty) */ { + id?: string; + provider?: string; + settings?: { + [key: string]: any; + }; + source?: string; +}[]; +export type ListAllProvidersSettingsApiArg = void; +export type RemoveProviderSettingsApiResponse = + /** status 204 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type RemoveProviderSettingsApiArg = { + key: string; +}; +export type GetProviderSettingsApiResponse = /** status 200 (empty) */ { + id?: string; + provider?: string; + settings?: { + [key: string]: any; + }; + source?: string; +}; +export type GetProviderSettingsApiArg = { + key: string; +}; +export type UpdateProviderSettingsApiResponse = + /** status 204 An OKResponse is returned if the request was successful. */ SuccessResponseBody; +export type UpdateProviderSettingsApiArg = { + key: string; + body: { + id?: string; + provider?: string; + settings?: { + [key: string]: any; + }; + }; +}; +export type SearchResultItem = { + action?: string; + basicRole?: string; + orgId?: number; + roleName?: string; + scope?: string; + teamId?: number; + userId?: number; + version?: number; +}; +export type SearchResult = { + result?: SearchResultItem[]; +}; +export type ErrorResponseBody = { + /** Error An optional detailed description of the actual error. Only included if running in developer mode. */ + error?: string; + /** a human readable version of the error */ + message: string; + /** Status An optional status to denote the cause of the error. + + For example, a 412 Precondition Failed error may include additional information of why that error happened. */ + status?: string; +}; +export type PermissionIsTheModelForAccessControlPermissions = { + action?: string; + created?: string; + scope?: string; + updated?: string; +}; +export type RoleDto = { + created?: string; + delegatable?: boolean; + description?: string; + displayName?: string; + global?: boolean; + group?: string; + hidden?: boolean; + mapped?: boolean; + name?: string; + permissions?: PermissionIsTheModelForAccessControlPermissions[]; + uid?: string; + updated?: string; + version?: number; +}; +export type CreateRoleForm = { + description?: string; + displayName?: string; + global?: boolean; + group?: string; + hidden?: boolean; + name?: string; + permissions?: PermissionIsTheModelForAccessControlPermissions[]; + uid?: string; + version?: number; +}; +export type SuccessResponseBody = { + message?: string; +}; +export type UpdateRoleCommand = { + description: string; + displayName: string; + global?: boolean; + group: string; + hidden?: boolean; + name?: string; + permissions?: PermissionIsTheModelForAccessControlPermissions[]; + version?: number; +}; +export type RoleAssignmentsDto = { + role_uid?: string; + service_accounts?: number[]; + teams?: number[]; + users?: number[]; +}; +export type SetRoleAssignmentsCommand = { + service_accounts?: number[]; + teams?: number[]; + users?: number[]; +}; +export type Status = number; +export type RolesSearchQuery = { + includeHidden?: boolean; + orgId?: number; + teamIds?: number[]; + userIds?: number[]; +}; +export type AddTeamRoleCommand = { + roleUid?: string; +}; +export type AddUserRoleCommand = { + global?: boolean; + roleUid?: string; +}; +export type SetUserRolesCommand = { + global?: boolean; + includeHidden?: boolean; + roleUids?: string[]; +}; +export type Assignments = { + builtInRoles?: boolean; + serviceAccounts?: boolean; + teams?: boolean; + users?: boolean; +}; +export type Description = { + assignments?: Assignments; + permissions?: string[]; +}; +export type ResourcePermissionDto = { + actions?: string[]; + builtInRole?: string; + id?: number; + isInherited?: boolean; + isManaged?: boolean; + isServiceAccount?: boolean; + permission?: string; + roleName?: string; + team?: string; + teamAvatarUrl?: string; + teamId?: number; + teamUid?: string; + userAvatarUrl?: string; + userId?: number; + userLogin?: string; + userUid?: string; +}; +export type SetResourcePermissionCommand = { + builtInRole?: string; + permission?: string; + teamId?: number; + userId?: number; +}; +export type SetPermissionsCommand = { + permissions?: SetResourcePermissionCommand[]; +}; +export type SetPermissionCommand = { + permission?: string; +}; +export type Duration = number; +export type FailedUser = { + Error?: string; + Login?: string; +}; +export type SyncResultHoldsTheResultOfASyncWithLdapThisGivesUsInformationOnWhichUsersWereUpdatedAndHow = { + Elapsed?: Duration; + FailedUsers?: FailedUser[]; + MissingUserIds?: number[]; + Started?: string; + UpdatedUserIds?: number[]; +}; +export type ActiveSyncStatusDto = { + enabled?: boolean; + nextSync?: string; + prevSync?: SyncResultHoldsTheResultOfASyncWithLdapThisGivesUsInformationOnWhichUsersWereUpdatedAndHow; + schedule?: string; +}; +export type SettingsBag = { + [key: string]: { + [key: string]: string; + }; +}; +export type AdminStats = { + activeAdmins?: number; + activeDevices?: number; + activeEditors?: number; + activeSessions?: number; + activeUsers?: number; + activeViewers?: number; + admins?: number; + alerts?: number; + dailyActiveAdmins?: number; + dailyActiveEditors?: number; + dailyActiveSessions?: number; + dailyActiveUsers?: number; + dailyActiveViewers?: number; + dashboards?: number; + datasources?: number; + editors?: number; + monthlyActiveUsers?: number; + orgs?: number; + playlists?: number; + snapshots?: number; + stars?: number; + tags?: number; + users?: number; + viewers?: number; +}; +export type AdminCreateUserResponse = { + id?: number; + message?: string; + uid?: string; +}; +export type Password = string; +export type AdminCreateUserForm = { + email?: string; + login?: string; + name?: string; + orgId?: number; + password?: Password; +}; +export type UserToken = { + AuthToken?: string; + AuthTokenSeen?: boolean; + ClientIp?: string; + CreatedAt?: number; + ExternalSessionId?: number; + Id?: number; + PrevAuthToken?: string; + RevokedAt?: number; + RotatedAt?: number; + SeenAt?: number; + UnhashedToken?: string; + UpdatedAt?: number; + UserAgent?: string; + UserId?: number; +}; +export type AdminUpdateUserPasswordForm = { + password?: Password; +}; +export type AdminUpdateUserPermissionsForm = { + isGrafanaAdmin?: boolean; +}; +export type QuotaDto = { + limit?: number; + org_id?: number; + target?: string; + used?: number; + user_id?: number; +}; +export type UpdateQuotaCmd = { + limit?: number; + target?: string; +}; +export type RevokeAuthTokenCmd = { + authTokenId?: number; +}; +export type Json = object; +export type Annotation = { + alertId?: number; + alertName?: string; + avatarUrl?: string; + created?: number; + /** Deprecated: Use DashboardUID and OrgID instead */ + dashboardId?: number; + dashboardUID?: string; + data?: Json; + email?: string; + id?: number; + login?: string; + newState?: string; + panelId?: number; + prevState?: string; + tags?: string[]; + text?: string; + time?: number; + timeEnd?: number; + updated?: number; + userId?: number; +}; +export type PostAnnotationsCmd = { + dashboardId?: number; + dashboardUID?: string; + data?: Json; + panelId?: number; + tags?: string[]; + text: string; + time?: number; + timeEnd?: number; +}; +export type PostGraphiteAnnotationsCmd = { + data?: string; + tags?: any; + what?: string; + when?: number; +}; +export type MassDeleteAnnotationsCmd = { + annotationId?: number; + dashboardId?: number; + dashboardUID?: string; + panelId?: number; +}; +export type TagsDtoIsTheFrontendDtoForTag = { + count?: number; + tag?: string; +}; +export type FindTagsResultIsTheResultOfATagsSearch = { + tags?: TagsDtoIsTheFrontendDtoForTag[]; +}; +export type GetAnnotationTagsResponseIsAResponseStructForFindTagsResult = { + result?: FindTagsResultIsTheResultOfATagsSearch; +}; +export type PatchAnnotationsCmd = { + data?: Json; + id?: number; + tags?: string[]; + text?: string; + time?: number; + timeEnd?: number; +}; +export type UpdateAnnotationsCmd = { + data?: Json; + id?: number; + tags?: string[]; + text?: string; + time?: number; + timeEnd?: number; +}; +export type DeviceDto = { + avatarUrl?: string; + clientIp?: string; + createdAt?: string; + deviceId?: string; + lastSeenAt?: string; + updatedAt?: string; + userAgent?: string; +}; +export type DeviceSearchHitDto = { + clientIp?: string; + createdAt?: string; + deviceId?: string; + lastSeenAt?: string; + updatedAt?: string; + userAgent?: string; +}; +export type SearchDeviceQueryResult = { + devices?: DeviceSearchHitDto[]; + page?: number; + perPage?: number; + totalCount?: number; +}; +export type CloudMigrationSessionResponseDto = { + created?: string; + slug?: string; + uid?: string; + updated?: string; +}; +export type CloudMigrationSessionListResponseDto = { + sessions?: CloudMigrationSessionResponseDto[]; +}; +export type CloudMigrationSessionRequestDto = { + authToken?: string; +}; +export type CreateSnapshotResponseDto = { + uid?: string; +}; +export type CreateSnapshotRequestDto = { + resourceTypes?: ( + | 'DASHBOARD' + | 'DATASOURCE' + | 'FOLDER' + | 'LIBRARY_ELEMENT' + | 'ALERT_RULE' + | 'ALERT_RULE_GROUP' + | 'CONTACT_POINT' + | 'NOTIFICATION_POLICY' + | 'NOTIFICATION_TEMPLATE' + | 'MUTE_TIMING' + | 'PLUGIN' + )[]; +}; +export type MigrateDataResponseItemDto = { + errorCode?: + | 'ALERT_RULES_QUOTA_REACHED' + | 'ALERT_RULES_GROUP_QUOTA_REACHED' + | 'DATASOURCE_NAME_CONFLICT' + | 'DATASOURCE_INVALID_URL' + | 'DATASOURCE_ALREADY_MANAGED' + | 'FOLDER_NAME_CONFLICT' + | 'DASHBOARD_ALREADY_MANAGED' + | 'LIBRARY_ELEMENT_NAME_CONFLICT' + | 'UNSUPPORTED_DATA_TYPE' + | 'RESOURCE_CONFLICT' + | 'UNEXPECTED_STATUS_CODE' + | 'INTERNAL_SERVICE_ERROR' + | 'GENERIC_ERROR'; + message?: string; + name?: string; + parentName?: string; + refId: string; + status: 'OK' | 'WARNING' | 'ERROR' | 'PENDING' | 'UNKNOWN'; + type: + | 'DASHBOARD' + | 'DATASOURCE' + | 'FOLDER' + | 'LIBRARY_ELEMENT' + | 'ALERT_RULE' + | 'ALERT_RULE_GROUP' + | 'CONTACT_POINT' + | 'NOTIFICATION_POLICY' + | 'NOTIFICATION_TEMPLATE' + | 'MUTE_TIMING' + | 'PLUGIN'; +}; +export type SnapshotResourceStats = { + statuses?: { + [key: string]: number; + }; + total?: number; + types?: { + [key: string]: number; + }; +}; +export type GetSnapshotResponseDto = { + created?: string; + finished?: string; + results?: MigrateDataResponseItemDto[]; + sessionUid?: string; + stats?: SnapshotResourceStats; + status?: + | 'INITIALIZING' + | 'CREATING' + | 'PENDING_UPLOAD' + | 'UPLOADING' + | 'PENDING_PROCESSING' + | 'PROCESSING' + | 'FINISHED' + | 'CANCELED' + | 'ERROR' + | 'UNKNOWN'; + uid?: string; +}; +export type SnapshotDto = { + created?: string; + finished?: string; + sessionUid?: string; + status?: + | 'INITIALIZING' + | 'CREATING' + | 'PENDING_UPLOAD' + | 'UPLOADING' + | 'PENDING_PROCESSING' + | 'PROCESSING' + | 'FINISHED' + | 'CANCELED' + | 'ERROR' + | 'UNKNOWN'; + uid?: string; +}; +export type SnapshotListResponseDto = { + snapshots?: SnapshotDto[]; +}; +export type ResourceDependencyDto = { + dependencies?: ( + | 'DASHBOARD' + | 'DATASOURCE' + | 'FOLDER' + | 'LIBRARY_ELEMENT' + | 'ALERT_RULE' + | 'ALERT_RULE_GROUP' + | 'CONTACT_POINT' + | 'NOTIFICATION_POLICY' + | 'NOTIFICATION_TEMPLATE' + | 'MUTE_TIMING' + | 'PLUGIN' + )[]; + resourceType?: + | 'DASHBOARD' + | 'DATASOURCE' + | 'FOLDER' + | 'LIBRARY_ELEMENT' + | 'ALERT_RULE' + | 'ALERT_RULE_GROUP' + | 'CONTACT_POINT' + | 'NOTIFICATION_POLICY' + | 'NOTIFICATION_TEMPLATE' + | 'MUTE_TIMING' + | 'PLUGIN'; +}; +export type ResourceDependenciesResponseDto = { + resourceDependencies?: ResourceDependencyDto[]; +}; +export type GetAccessTokenResponseDto = { + createdAt?: string; + displayName?: string; + expiresAt?: string; + firstUsedAt?: string; + id?: string; + lastUsedAt?: string; +}; +export type CreateAccessTokenResponseDto = { + token?: string; +}; +export type ConvertPrometheusResponse = { + error?: string; + errorType?: string; + status?: string; +}; +export type PublicError = { + extra?: { + [key: string]: any; + }; + message?: string; + messageId?: string; + statusCode?: number; +}; +export type ForbiddenError = { + body?: PublicError; +}; +export type PrometheusRule = { + alert?: string; + annotations?: { + [key: string]: string; + }; + expr?: string; + for?: string; + keep_firing_for?: string; + labels?: { + [key: string]: string; + }; + record?: string; +}; +export type PrometheusRuleGroup = { + interval?: Duration; + labels?: { + [key: string]: string; + }; + limit?: number; + name?: string; + query_offset?: string; + rules?: PrometheusRule[]; +}; +export type DashboardSnapshotDto = { + created?: string; + expires?: string; + external?: boolean; + externalUrl?: string; + key?: string; + name?: string; + updated?: string; +}; +export type CalculateDiffTarget = { + dashboardId?: number; + unsavedDashboard?: Json; + version?: number; +}; +export type SaveDashboardCommand = { + UpdatedAt?: string; + dashboard?: Json; + /** Deprecated: use FolderUID instead */ + folderId?: number; + folderUid?: string; + isFolder?: boolean; + message?: string; + overwrite?: boolean; + userId?: number; +}; +export type AnnotationActions = { + canAdd?: boolean; + canDelete?: boolean; + canEdit?: boolean; +}; +export type AnnotationPermission = { + dashboard?: AnnotationActions; + organization?: AnnotationActions; +}; +export type DashboardMeta = { + annotationsPermissions?: AnnotationPermission; + apiVersion?: string; + canAdmin?: boolean; + canDelete?: boolean; + canEdit?: boolean; + canSave?: boolean; + canStar?: boolean; + created?: string; + createdBy?: string; + expires?: string; + /** Deprecated: use FolderUID instead */ + folderId?: number; + folderTitle?: string; + folderUid?: string; + folderUrl?: string; + hasAcl?: boolean; + isFolder?: boolean; + isSnapshot?: boolean; + isStarred?: boolean; + provisioned?: boolean; + provisionedExternalId?: string; + publicDashboardEnabled?: boolean; + slug?: string; + type?: string; + updated?: string; + updatedBy?: string; + url?: string; + version?: number; +}; +export type GetHomeDashboardResponse = { + dashboard?: Json; + meta?: DashboardMeta; +} & { + redirectUri?: string; +}; +export type ImportDashboardResponseResponseObjectReturnedWhenImportingADashboard = { + dashboardId?: number; + description?: string; + /** Deprecated: use FolderUID instead */ + folderId?: number; + folderUid?: string; + imported?: boolean; + importedRevision?: number; + importedUri?: string; + importedUrl?: string; + path?: string; + pluginId?: string; + removed?: boolean; + revision?: number; + slug?: string; + title?: string; + uid?: string; +}; +export type ImportDashboardInputDefinitionOfInputParametersWhenImportingADashboard = { + name?: string; + pluginId?: string; + type?: string; + value?: string; +}; +export type ImportDashboardRequestRequestObjectForImportingADashboard = { + dashboard?: Json; + /** Deprecated: use FolderUID instead */ + folderId?: number; + folderUid?: string; + inputs?: ImportDashboardInputDefinitionOfInputParametersWhenImportingADashboard[]; + overwrite?: boolean; + path?: string; + pluginId?: string; +}; +export type PublicDashboardListResponse = { + accessToken?: string; + dashboardUid?: string; + isEnabled?: boolean; + slug?: string; + title?: string; + uid?: string; +}; +export type PublicDashboardListResponseWithPagination = { + page?: number; + perPage?: number; + publicDashboards?: PublicDashboardListResponse[]; + totalCount?: number; +}; +export type PublicError2 = { + /** Extra Additional information about the error */ + extra?: { + [key: string]: any; + }; + /** Message A human readable message */ + message?: string; + /** MessageID A unique identifier for the error */ + messageId: string; + /** StatusCode The HTTP status code returned */ + statusCode: number; +}; +export type DashboardTagCloudItem = { + count?: number; + term?: string; +}; +export type EmailDto = { + recipient?: string; + uid?: string; +}; +export type ShareType = string; +export type PublicDashboard = { + accessToken?: string; + annotationsEnabled?: boolean; + createdAt?: string; + createdBy?: number; + dashboardUid?: string; + isEnabled?: boolean; + recipients?: EmailDto[]; + share?: ShareType; + timeSelectionEnabled?: boolean; + uid?: string; + updatedAt?: string; + updatedBy?: number; +}; +export type PublicDashboardDto = { + accessToken?: string; + annotationsEnabled?: boolean; + isEnabled?: boolean; + share?: ShareType; + timeSelectionEnabled?: boolean; + uid?: string; +}; +export type DashboardFullWithMeta = { + dashboard?: Json; + meta?: DashboardMeta; +}; +export type PermissionType = number; +export type DashboardAclInfoDto = { + created?: string; + dashboardId?: number; + /** Deprecated: use FolderUID instead */ + folderId?: number; + folderUid?: string; + inherited?: boolean; + isFolder?: boolean; + permission?: PermissionType; + permissionName?: string; + role?: 'None' | 'Viewer' | 'Editor' | 'Admin'; + slug?: string; + team?: string; + teamAvatarUrl?: string; + teamEmail?: string; + teamId?: number; + teamUid?: string; + title?: string; + uid?: string; + updated?: string; + url?: string; + userAvatarUrl?: string; + userEmail?: string; + userId?: number; + userLogin?: string; + userUid?: string; +}; +export type DashboardAclUpdateItem = { + permission?: PermissionType; + role?: 'None' | 'Viewer' | 'Editor' | 'Admin'; + teamId?: number; + userId?: number; +}; +export type UpdateDashboardAclCommand = { + items?: DashboardAclUpdateItem[]; +}; +export type RestoreDashboardVersionCommand = { + version?: number; +}; +export type DashboardVersionMeta = { + created?: string; + createdBy?: string; + dashboardId?: number; + data?: Json; + id?: number; + message?: string; + parentVersion?: number; + restoredFrom?: number; + uid?: string; + version?: number; +}; +export type DashboardVersionResponseMeta = { + continueToken?: string; + versions?: DashboardVersionMeta[]; +}; +export type DsAccess = string; +export type DataSourceListItemDto = { + access?: DsAccess; + basicAuth?: boolean; + database?: string; + id?: number; + isDefault?: boolean; + jsonData?: Json; + name?: string; + orgId?: number; + readOnly?: boolean; + type?: string; + typeLogoUrl?: string; + typeName?: string; + uid?: string; + url?: string; + user?: string; +}; +export type DataSourceList = DataSourceListItemDto[]; +export type Metadata = { + [key: string]: boolean; +}; +export type DataSource = { + access?: DsAccess; + accessControl?: Metadata; + basicAuth?: boolean; + basicAuthUser?: string; + database?: string; + id?: number; + isDefault?: boolean; + jsonData?: Json; + name?: string; + orgId?: number; + readOnly?: boolean; + secureJsonFields?: { + [key: string]: boolean; + }; + type?: string; + typeLogoUrl?: string; + uid?: string; + url?: string; + user?: string; + version?: number; + withCredentials?: boolean; +}; +export type AddDataSourceCommand = { + access?: DsAccess; + basicAuth?: boolean; + basicAuthUser?: string; + database?: string; + isDefault?: boolean; + jsonData?: Json; + name?: string; + secureJsonData?: { + [key: string]: string; + }; + type?: string; + uid?: string; + url?: string; + user?: string; + withCredentials?: boolean; +}; +export type Transformation = { + expression?: string; + field?: string; + mapValue?: string; + type?: 'regex' | 'logfmt'; +}; +export type Transformations = Transformation[]; +export type CorrelationType = string; +export type CorrelationConfig = { + /** Field used to attach the correlation link */ + field: string; + /** Target data query */ + target: { + [key: string]: any; + }; + transformations?: Transformations; + type?: CorrelationType; +}; +export type Correlation = { + config?: CorrelationConfig; + /** Description of the correlation */ + description?: string; + /** Label identifying the correlation */ + label?: string; + /** OrgID of the data source the correlation originates from */ + orgId?: number; + /** Provisioned True if the correlation was created during provisioning */ + provisioned?: boolean; + /** UID of the data source the correlation originates from */ + sourceUID?: string; + /** UID of the data source the correlation points to */ + targetUID?: string; + type?: CorrelationType; + /** Unique identifier of the correlation */ + uid?: string; +}; +export type CreateCorrelationResponseBody = { + message?: string; + result?: Correlation; +}; +export type CreateCorrelationCommand = { + config?: CorrelationConfig; + /** Optional description of the correlation */ + description?: string; + /** Optional label identifying the correlation */ + label?: string; + /** True if correlation was created with provisioning. This makes it read-only. */ + provisioned?: boolean; + /** Target data source UID to which the correlation is created. required if type = query */ + targetUID?: string; + type?: CorrelationType; +}; +export type UpdateCorrelationResponseBody = { + message?: string; + result?: Correlation; +}; +export type CorrelationConfigUpdateDto = { + /** Field used to attach the correlation link */ + field?: string; + /** Target data query */ + target?: { + [key: string]: any; + }; + /** Source data transformations */ + transformations?: Transformation[]; +}; +export type UpdateCorrelationCommand = { + config?: CorrelationConfigUpdateDto; + /** Optional description of the correlation */ + description?: string; + /** Optional label identifying the correlation */ + label?: string; + type?: CorrelationType; +}; +export type UpdateDataSourceCommand = { + access?: DsAccess; + basicAuth?: boolean; + basicAuthUser?: string; + database?: string; + isDefault?: boolean; + jsonData?: Json; + name?: string; + secureJsonData?: { + [key: string]: string; + }; + type?: string; + uid?: string; + url?: string; + user?: string; + /** The previous version -- used for optimistic locking */ + version?: number; + withCredentials?: boolean; +}; +export type DeleteCorrelationResponseBody = { + message?: string; +}; +export type TeamLbacRule = { + rules?: string[]; + teamId?: string; + teamUid?: string; +}; +export type TeamLbacRules = { + rules?: TeamLbacRule[]; +}; +export type UpdateTeamLbacCommand = { + rules?: TeamLbacRule[]; +}; +export type CacheConfigResponse = { + created?: string; + /** Fields that can be set by the API caller - read/write */ + dataSourceID?: number; + dataSourceUID?: string; + /** These are returned by the HTTP API, but are managed internally - read-only + Note: 'created' and 'updated' are special properties managed automatically by xorm, but we are setting them manually */ + defaultTTLMs?: number; + enabled?: boolean; + message?: string; + /** TTL MS, or "time to live", is how long a cached item will stay in the cache before it is removed (in milliseconds) */ + ttlQueriesMs?: number; + ttlResourcesMs?: number; + updated?: string; + /** If UseDefaultTTL is enabled, then the TTLQueriesMS and TTLResourcesMS in this object is always sent as the default TTL located in grafana.ini */ + useDefaultTTL?: boolean; +}; +export type CacheConfigSetter = { + dataSourceID?: number; + dataSourceUID?: string; + enabled?: boolean; + /** TTL MS, or "time to live", is how long a cached item will stay in the cache before it is removed (in milliseconds) */ + ttlQueriesMs?: number; + ttlResourcesMs?: number; + /** If UseDefaultTTL is enabled, then the TTLQueriesMS and TTLResourcesMS in this object is always sent as the default TTL located in grafana.ini */ + useDefaultTTL?: boolean; +}; +export type SourceTypeDefinesTheStatusSource = string; +export type ExplorePanelsState = any; +export type TimeRange = { + from?: string; + to?: string; +}; +export type SupportedTransformationTypes = string; +export type LinkTransformationConfig = { + expression?: string; + field?: string; + mapValue?: string; + type?: SupportedTransformationTypes; +}; +export type InternalDataLink = { + datasourceName?: string; + datasourceUid?: string; + panelsState?: ExplorePanelsState; + query?: any; + timeRange?: TimeRange; + transformations?: LinkTransformationConfig[]; +}; +export type DataLink = { + internal?: InternalDataLink; + targetBlank?: boolean; + title?: string; + url?: string; +}; +export type ValueMapping = object; +export type ValueMappings = ValueMapping[]; +export type ConfFloat64 = number; +export type ThresholdsMode = string; +export type Threshold = { + color?: string; + state?: string; + value?: ConfFloat64; +}; +export type ThresholdsConfig = { + mode?: ThresholdsMode; + /** Must be sorted by 'value', first value is always -Infinity */ + steps?: Threshold[]; +}; +export type EnumFieldConfig = { + /** Color is the color value for a given index (empty is undefined) */ + color?: string[]; + /** Description of the enum state */ + description?: string[]; + /** Icon supports setting an icon for a given index value */ + icon?: string[]; + /** Value is the string display value for a given index */ + text?: string[]; +}; +export type FieldTypeConfig = { + enum?: EnumFieldConfig; +}; +export type FieldConfigRepresentsTheDisplayPropertiesForAField = { + /** Map values to a display color + NOTE: this interface is under development in the frontend... so simple map for now */ + color?: { + [key: string]: any; + }; + /** Panel Specific Values */ + custom?: { + [key: string]: any; + }; + decimals?: number; + /** Description is human readable field metadata */ + description?: string; + /** DisplayName overrides Grafana default naming, should not be used from a data source */ + displayName?: string; + /** DisplayNameFromDS overrides Grafana default naming strategy. */ + displayNameFromDS?: string; + /** Filterable indicates if the Field's data can be filtered by additional calls. */ + filterable?: boolean; + /** Interval indicates the expected regular step between values in the series. + When an interval exists, consumers can identify "missing" values when the expected value is not present. + The grafana timeseries visualization will render disconnected values when missing values are found it the time field. + The interval uses the same units as the values. For time.Time, this is defined in milliseconds. */ + interval?: number; + /** The behavior when clicking on a result */ + links?: DataLink[]; + mappings?: ValueMappings; + max?: ConfFloat64; + min?: ConfFloat64; + /** Alternative to empty string */ + noValue?: string; + /** Path is an explicit path to the field in the datasource. When the frame meta includes a path, + this will default to `${frame.meta.path}/${field.name} + + When defined, this value can be used as an identifier within the datasource scope, and + may be used as an identifier to update values in a subsequent request */ + path?: string; + thresholds?: ThresholdsConfig; + type?: FieldTypeConfig; + /** Numeric Options */ + unit?: string; + /** Writeable indicates that the datasource knows how to update this value */ + writeable?: boolean; +}; +export type FrameLabels = { + [key: string]: string; +}; +export type FieldRepresentsATypedColumnOfDataWithinAFrame = { + config?: FieldConfigRepresentsTheDisplayPropertiesForAField; + labels?: FrameLabels; + /** Name is default identifier of the field. The name does not have to be unique, but the combination + of name and Labels should be unique for proper behavior in all situations. */ + name?: string; +}; +export type DataTopicIsUsedToIdentifyWhichTopicTheFrameShouldBeAssignedTo = string; +export type InspectTypeIsATypeForTheInspectPropertyOfANotice = number; +export type NoticeSeverityIsATypeForTheSeverityPropertyOfANotice = number; +export type NoticeProvidesAStructureForPresentingNotificationsInGrafanasUserInterface = { + inspect?: InspectTypeIsATypeForTheInspectPropertyOfANotice; + /** Link is an optional link for display in the user interface and can be an + absolute URL or a path relative to Grafana's root url. */ + link?: string; + severity?: NoticeSeverityIsATypeForTheSeverityPropertyOfANotice; + /** Text is freeform descriptive text for the notice. */ + text?: string; +}; +export type VisTypeIsUsedToIndicateHowTheDataShouldBeVisualizedInExplore = string; +export type QueryStatIsUsedForStoringArbitraryStatisticsMetadataRelatedToAQueryAndItsResultEGTotalRequestTimeDataProcessingTime = + { + /** Map values to a display color + NOTE: this interface is under development in the frontend... so simple map for now */ + color?: { + [key: string]: any; + }; + /** Panel Specific Values */ + custom?: { + [key: string]: any; + }; + decimals?: number; + /** Description is human readable field metadata */ + description?: string; + /** DisplayName overrides Grafana default naming, should not be used from a data source */ + displayName?: string; + /** DisplayNameFromDS overrides Grafana default naming strategy. */ + displayNameFromDS?: string; + /** Filterable indicates if the Field's data can be filtered by additional calls. */ + filterable?: boolean; + /** Interval indicates the expected regular step between values in the series. + When an interval exists, consumers can identify "missing" values when the expected value is not present. + The grafana timeseries visualization will render disconnected values when missing values are found it the time field. + The interval uses the same units as the values. For time.Time, this is defined in milliseconds. */ + interval?: number; + /** The behavior when clicking on a result */ + links?: DataLink[]; + mappings?: ValueMappings; + max?: ConfFloat64; + min?: ConfFloat64; + /** Alternative to empty string */ + noValue?: string; + /** Path is an explicit path to the field in the datasource. When the frame meta includes a path, + this will default to `${frame.meta.path}/${field.name} + + When defined, this value can be used as an identifier within the datasource scope, and + may be used as an identifier to update values in a subsequent request */ + path?: string; + thresholds?: ThresholdsConfig; + type?: FieldTypeConfig; + /** Numeric Options */ + unit?: string; + value?: number; + /** Writeable indicates that the datasource knows how to update this value */ + writeable?: boolean; + }; +export type FrameType = string; +export type FrameTypeIsA2NumberVersionMajorMinor = number[]; +export type FrameMetaMatches = { + /** Channel is the path to a stream in grafana live that has real-time updates for this data. */ + channel?: string; + /** Custom datasource specific values. */ + custom?: any; + dataTopic?: DataTopicIsUsedToIdentifyWhichTopicTheFrameShouldBeAssignedTo; + /** ExecutedQueryString is the raw query sent to the underlying system. All macros and templating + have been applied. When metadata contains this value, it will be shown in the query inspector. */ + executedQueryString?: string; + /** Notices provide additional information about the data in the Frame that + Grafana can display to the user in the user interface. */ + notices?: NoticeProvidesAStructureForPresentingNotificationsInGrafanasUserInterface[]; + /** Path is a browsable path on the datasource. */ + path?: string; + /** PathSeparator defines the separator pattern to decode a hierarchy. The default separator is '/'. */ + pathSeparator?: string; + /** PreferredVisualizationPluginId sets the panel plugin id to use to render the data when using Explore. If + the plugin cannot be found will fall back to PreferredVisualization. */ + preferredVisualisationPluginId?: string; + preferredVisualisationType?: VisTypeIsUsedToIndicateHowTheDataShouldBeVisualizedInExplore; + /** Stats is an array of query result statistics. */ + stats?: QueryStatIsUsedForStoringArbitraryStatisticsMetadataRelatedToAQueryAndItsResultEGTotalRequestTimeDataProcessingTime[]; + type?: FrameType; + typeVersion?: FrameTypeIsA2NumberVersionMajorMinor; + /** Array of field indices which values create a unique id for each row. Ideally this should be globally unique ID + but that isn't guarantied. Should help with keeping track and deduplicating rows in visualizations, especially + with streaming data with frequent updates. */ + uniqueRowIdFields?: number[]; +}; +export type FrameIsAColumnarDataStructureWhereEachColumnIsAField = { + /** Fields are the columns of a frame. + All Fields must be of the same the length when marshalling the Frame for transmission. + There should be no `nil` entries in the Fields slice (making them pointers was a mistake). */ + Fields?: FieldRepresentsATypedColumnOfDataWithinAFrame[]; + Meta?: FrameMetaMatches; + /** Name is used in some Grafana visualizations. */ + Name?: string; + /** RefID is a property that can be set to match a Frame to its originating query. */ + RefID?: string; +}; +export type FramesIsASliceOfFramePointers = FrameIsAColumnarDataStructureWhereEachColumnIsAField[]; +export type DataResponseContainsTheResultsFromADataQuery = { + /** Error is a property to be set if the corresponding DataQuery has an error. */ + Error?: string; + ErrorSource?: SourceTypeDefinesTheStatusSource; + Frames?: FramesIsASliceOfFramePointers; + Status?: Status; +}; +export type ResponsesIsAMapOfRefIDsUniqueQueryIdToDataResponses = { + [key: string]: DataResponseContainsTheResultsFromADataQuery; +}; +export type QueryDataResponseContainsTheResultsFromAQueryDataRequest = { + results?: ResponsesIsAMapOfRefIDsUniqueQueryIdToDataResponses; +}; +export type MetricRequest = { + debug?: boolean; + /** From Start time in epoch timestamps in milliseconds or relative using Grafana time units. */ + from: string; + /** queries.refId – Specifies an identifier of the query. Is optional and default to “A”. + queries.datasourceId – Specifies the data source to be queried. Each query in the request must have an unique datasourceId. + queries.maxDataPoints - Species maximum amount of data points that dashboard panel can render. Is optional and default to 100. + queries.intervalMs - Specifies the time interval in milliseconds of time series. Is optional and defaults to 1000. */ + queries: Json[]; + /** To End time in epoch timestamps in milliseconds or relative using Grafana time units. */ + to: string; +}; +export type ManagerKindIsTheTypeOfManagerWhichIsResponsibleForManagingTheResource = string; +export type FolderSearchHit = { + id?: number; + managedBy?: ManagerKindIsTheTypeOfManagerWhichIsResponsibleForManagingTheResource; + parentUid?: string; + title?: string; + uid?: string; +}; +export type Folder = { + accessControl?: Metadata; + canAdmin?: boolean; + canDelete?: boolean; + canEdit?: boolean; + canSave?: boolean; + created?: string; + createdBy?: string; + hasAcl?: boolean; + /** Deprecated: use UID instead */ + id?: number; + managedBy?: ManagerKindIsTheTypeOfManagerWhichIsResponsibleForManagingTheResource; + orgId?: number; + /** only used if nested folders are enabled */ + parentUid?: string; + /** the parent folders starting from the root going down */ + parents?: Folder[]; + title?: string; + uid?: string; + updated?: string; + updatedBy?: string; + url?: string; + version?: number; +}; +export type CreateFolderCommand = { + description?: string; + parentUid?: string; + title?: string; + uid?: string; +}; +export type UpdateFolderCommand = { + /** NewDescription it's an optional parameter used for overriding the existing folder description */ + description?: string; + /** Overwrite only used by the legacy folder implementation */ + overwrite?: boolean; + /** NewTitle it's an optional parameter used for overriding the existing folder title */ + title?: string; + /** Version only used by the legacy folder implementation */ + version?: number; +}; +export type DescendantCounts = { + [key: string]: number; +}; +export type MoveFolderCommand = { + parentUid?: string; +}; +export type Group = { + groupID?: string; + mappings?: any; +}; +export type GetGroupsResponse = { + groups?: Group[]; + total?: number; +}; +export type MessageResponse = { + message?: string; +}; +export type GroupAttributes = { + roles?: string[]; +}; +export type HealthResponse = { + commit?: string; + database?: string; + enterpriseCommit?: string; + version?: string; +}; +export type LibraryElementDtoMetaUser = { + avatarUrl?: string; + id?: number; + name?: string; +}; +export type LibraryElementDtoMetaIsTheMetaInformationForLibraryElementDto = { + connectedDashboards?: number; + created?: string; + createdBy?: LibraryElementDtoMetaUser; + folderName?: string; + folderUid?: string; + updated?: string; + updatedBy?: LibraryElementDtoMetaUser; +}; +export type LibraryElementDtoIsTheFrontendDtoForEntities = { + description?: string; + /** Deprecated: use FolderUID instead */ + folderId?: number; + folderUid?: string; + id?: number; + kind?: number; + meta?: LibraryElementDtoMetaIsTheMetaInformationForLibraryElementDto; + model?: object; + name?: string; + orgId?: number; + schemaVersion?: number; + type?: string; + uid?: string; + version?: number; +}; +export type LibraryElementSearchResultIsTheSearchResultForEntities = { + elements?: LibraryElementDtoIsTheFrontendDtoForEntities[]; + page?: number; + perPage?: number; + totalCount?: number; +}; +export type LibraryElementSearchResponseIsAResponseStructForLibraryElementSearchResult = { + result?: LibraryElementSearchResultIsTheSearchResultForEntities; +}; +export type LibraryElementResponseIsAResponseStructForLibraryElementDto = { + result?: LibraryElementDtoIsTheFrontendDtoForEntities; +}; +export type CreateLibraryElementCommand = { + /** ID of the folder where the library element is stored. + + Deprecated: use FolderUID instead */ + folderId?: number; + /** UID of the folder where the library element is stored. */ + folderUid?: string; + /** Kind of element to create, Use 1 for library panels or 2 for c. + Description: + 1 - library panels */ + kind?: 1; + /** The JSON model for the library element. */ + model?: object; + /** Name of the library element. */ + name?: string; + uid?: string; +}; +export type LibraryElementArrayResponseIsAResponseStructForAnArrayOfLibraryElementDto = { + result?: LibraryElementDtoIsTheFrontendDtoForEntities[]; +}; +export type PatchLibraryElementCommand = { + /** ID of the folder where the library element is stored. + + Deprecated: use FolderUID instead */ + folderId?: number; + /** UID of the folder where the library element is stored. */ + folderUid?: string; + /** Kind of element to create, Use 1 for library panels or 2 for c. + Description: + 1 - library panels */ + kind?: 1; + /** The JSON model for the library element. */ + model?: object; + /** Name of the library element. */ + name?: string; + uid?: string; + /** Version of the library element you are updating. */ + version?: number; +}; +export type LibraryElementConnectionDtoIsTheFrontendDtoForElementConnections = { + connectionId?: number; + connectionUid?: string; + created?: string; + createdBy?: LibraryElementDtoMetaUser; + elementId?: number; + /** Deprecated: this field will be removed in the future */ + id?: number; + kind?: number; +}; +export type LibraryElementConnectionsResponseIsAResponseStructForAnArrayOfLibraryElementConnectionDto = { + result?: LibraryElementConnectionDtoIsTheFrontendDtoForElementConnections[]; +}; +export type ActiveUserStats = { + active_admins_and_editors?: number; + active_anonymous_devices?: number; + active_users?: number; + active_viewers?: number; +}; +export type DeleteTokenCommand = { + instance?: string; +}; +export type TokenStatus = number; +export type Token = { + account?: string; + anonymousRatio?: number; + company?: string; + details_url?: string; + exp?: number; + iat?: number; + included_users?: number; + iss?: string; + jti?: string; + lexp?: number; + lic_exp_warn_days?: number; + lid?: string; + limit_by?: string; + max_concurrent_user_sessions?: number; + nbf?: number; + prod?: string[]; + slug?: string; + status?: TokenStatus; + sub?: string; + tok_exp_warn_days?: number; + trial?: boolean; + trial_exp?: number; + update_days?: number; + usage_billing?: boolean; +}; +export type Address = { + address1?: string; + address2?: string; + city?: string; + country?: string; + state?: string; + zipCode?: string; +}; +export type OrgDetailsDto = { + address?: Address; + id?: number; + name?: string; +}; +export type UpdateOrgForm = { + name?: string; +}; +export type UpdateOrgAddressForm = { + address1?: string; + address2?: string; + city?: string; + country?: string; + state?: string; + zipcode?: string; +}; +export type TempUserStatus = string; +export type TempUserDto = { + code?: string; + createdOn?: string; + email?: string; + emailSent?: boolean; + emailSentOn?: string; + id?: number; + invitedByEmail?: string; + invitedByLogin?: string; + invitedByName?: string; + name?: string; + orgId?: number; + role?: 'None' | 'Viewer' | 'Editor' | 'Admin'; + status?: TempUserStatus; + url?: string; +}; +export type AddInviteForm = { + loginOrEmail?: string; + name?: string; + role?: 'None' | 'Viewer' | 'Editor' | 'Admin'; + sendEmail?: boolean; +}; +export type PreferencesCookiePreferences = { + analytics?: any; + functional?: any; + performance?: any; +}; +export type PreferencesNavbarPreference = { + bookmarkUrls?: string[]; +}; +export type PreferencesQueryHistoryPreference = { + /** one of: '' | 'query' | 'starred'; */ + homeTab?: string; +}; +export type PreferencesSpec = { + cookiePreferences?: PreferencesCookiePreferences; + /** UID for the home dashboard */ + homeDashboardUID?: string; + /** Selected language (beta) */ + language?: string; + navbar?: PreferencesNavbarPreference; + queryHistory?: PreferencesQueryHistoryPreference; + /** Selected locale (beta) */ + regionalFormat?: string; + /** light, dark, empty is default */ + theme?: string; + /** The timezone selection + TODO: this should use the timezone defined in common */ + timezone?: string; + /** day of the week (sunday, monday, etc) */ + weekStart?: string; +}; +export type CookieType = string; +export type NavbarPreference = { + bookmarkUrls?: string[]; +}; +export type QueryHistoryPreference = { + homeTab?: string; +}; +export type PatchPrefsCmd = { + cookies?: CookieType[]; + /** The numerical :id of a favorited dashboard */ + homeDashboardId?: number; + homeDashboardUID?: string; + language?: string; + navbar?: NavbarPreference; + queryHistory?: QueryHistoryPreference; + regionalFormat?: string; + theme?: 'light' | 'dark'; + timezone?: 'utc' | 'browser'; + weekStart?: string; +}; +export type UpdatePrefsCmd = { + cookies?: CookieType[]; + /** The numerical :id of a favorited dashboard */ + homeDashboardId?: number; + homeDashboardUID?: string; + language?: string; + navbar?: NavbarPreference; + queryHistory?: QueryHistoryPreference; + regionalFormat?: string; + theme?: 'light' | 'dark' | 'system'; + timezone?: 'utc' | 'browser'; + weekStart?: string; +}; +export type OrgUserDto = { + accessControl?: { + [key: string]: boolean; + }; + authLabels?: string[]; + avatarUrl?: string; + email?: string; + isDisabled?: boolean; + isExternallySynced?: boolean; + isProvisioned?: boolean; + lastSeenAt?: string; + lastSeenAtAge?: string; + login?: string; + name?: string; + orgId?: number; + role?: string; + uid?: string; + userId?: number; +}; +export type AddOrgUserCommand = { + loginOrEmail?: string; + role?: 'None' | 'Viewer' | 'Editor' | 'Admin'; +}; +export type UserLookupDto = { + avatarUrl?: string; + login?: string; + uid?: string; + userId?: number; +}; +export type UpdateOrgUserCommand = { + role?: 'None' | 'Viewer' | 'Editor' | 'Admin'; +}; +export type OrgDto = { + id?: number; + name?: string; +}; +export type CreateOrgCommand = { + name?: string; +}; +export type SearchOrgUsersQueryResult = { + orgUsers?: OrgUserDto[]; + page?: number; + perPage?: number; + totalCount?: number; +}; +export type Playlist = { + id?: number; + interval?: string; + name?: string; + uid?: string; +}; +export type Playlists = Playlist[]; +export type PlaylistItem = { + Id?: number; + PlaylistId?: number; + order?: number; + title?: string; + type?: string; + value?: string; +}; +export type CreatePlaylistCommand = { + interval?: string; + items?: PlaylistItem[]; + name?: string; +}; +export type PlaylistItemDto = { + /** Title is an unused property -- it will be removed in the future */ + title?: string; + /** Type of the item. */ + type?: string; + /** Value depends on type and describes the playlist item. + + dashboard_by_id: The value is an internal numerical identifier set by Grafana. This + is not portable as the numerical identifier is non-deterministic between different instances. + Will be replaced by dashboard_by_uid in the future. (deprecated) + dashboard_by_tag: The value is a tag which is set on any number of dashboards. All + dashboards behind the tag will be added to the playlist. + dashboard_by_uid: The value is the dashboard UID */ + value?: string; +}; +export type PlaylistDto = { + /** Interval sets the time between switching views in a playlist. */ + interval?: string; + /** The ordered list of items that the playlist will iterate over. */ + items?: PlaylistItemDto[]; + /** Name of the playlist. */ + name?: string; + /** Unique playlist identifier. Generated on creation, either by the + creator of the playlist of by the application. */ + uid?: string; +}; +export type UpdatePlaylistCommand = { + interval?: string; + items?: PlaylistItem[]; + name?: string; + uid?: string; +}; +export type DataSourceRef = { + /** The plugin type-id */ + type?: string; + /** Specific datasource instance */ + uid?: string; +}; +export type AnnotationPanelFilter = { + /** Should the specified panels be included or excluded */ + exclude?: boolean; + /** Panel IDs that should be included or excluded */ + ids?: number[]; +}; +export type AnnotationTarget = { + /** Only required/valid for the grafana datasource... + but code+tests is already depending on it so hard to change */ + limit?: number; + /** Only required/valid for the grafana datasource... + but code+tests is already depending on it so hard to change */ + matchAny?: boolean; + /** Only required/valid for the grafana datasource... + but code+tests is already depending on it so hard to change */ + tags?: string[]; + /** Only required/valid for the grafana datasource... + but code+tests is already depending on it so hard to change */ + type?: string; +}; +export type AnnotationQuery = { + /** Set to 1 for the standard annotation query all dashboards have by default. */ + builtIn?: number; + datasource?: DataSourceRef; + /** When enabled the annotation query is issued with every dashboard refresh */ + enable?: boolean; + filter?: AnnotationPanelFilter; + /** Annotation queries can be toggled on or off at the top of the dashboard. + When hide is true, the toggle is not shown in the dashboard. */ + hide?: boolean; + /** Color to use for the annotation event markers */ + iconColor?: string; + /** Name of annotation. */ + name?: string; + target?: AnnotationTarget; + /** TODO -- this should not exist here, it is based on the --grafana-- datasource */ + type?: string; +}; +export type AnnotationEvent = { + color?: string; + dashboardId?: number; + dashboardUID?: string; + id?: number; + isRegion?: boolean; + panelId?: number; + source?: AnnotationQuery; + tags?: string[]; + text?: string; + time?: number; + timeEnd?: number; +}; +export type QueryHistoryDto = { + comment?: string; + createdAt?: number; + createdBy?: number; + datasourceUid?: string; + queries?: Json; + starred?: boolean; + uid?: string; +}; +export type QueryHistorySearchResult = { + page?: number; + perPage?: number; + queryHistory?: QueryHistoryDto[]; + totalCount?: number; +}; +export type QueryHistorySearchResponse = { + result?: QueryHistorySearchResult; +}; +export type QueryHistoryResponse = { + result?: QueryHistoryDto; +}; +export type CreateQueryInQueryHistoryCommand = { + /** UID of the data source for which are queries stored. */ + datasourceUid?: string; + queries: Json; +}; +export type QueryHistoryDeleteQueryResponse = { + id?: number; + message?: string; +}; +export type PatchQueryCommentInQueryHistoryCommand = { + /** Updated comment */ + comment?: string; +}; +export type RecordingRuleJson = { + active?: boolean; + count?: boolean; + description?: string; + dest_data_source_uid?: string; + id?: string; + interval?: number; + name?: string; + prom_name?: string; + queries?: { + [key: string]: any; + }[]; + range?: number; + target_ref_id?: string; +}; +export type PrometheusRemoteWriteTargetJson = { + data_source_uid?: string; + id?: string; + remote_write_path?: string; +}; +export type ReportDashboardId = { + id?: number; + name?: string; + uid?: string; +}; +export type ReportTimeRange = { + from?: string; + to?: string; +}; +export type ReportDashboard = { + dashboard?: ReportDashboardId; + reportVariables?: object; + timeRange?: ReportTimeRange; +}; +export type Type = string; +export type ReportOptions = { + layout?: string; + orientation?: string; + pdfCombineOneFile?: boolean; + pdfShowTemplateVariables?: boolean; + timeRange?: ReportTimeRange; +}; +export type ReportSchedule = { + dayOfMonth?: string; + endDate?: string; + frequency?: string; + intervalAmount?: number; + intervalFrequency?: string; + startDate?: string; + timeZone?: string; + workdaysOnly?: boolean; +}; +export type State = string; +export type Report = { + created?: string; + dashboards?: ReportDashboard[]; + enableCsv?: boolean; + enableDashboardUrl?: boolean; + formats?: Type[]; + id?: number; + message?: string; + name?: string; + options?: ReportOptions; + orgId?: number; + recipients?: string; + replyTo?: string; + scaleFactor?: number; + schedule?: ReportSchedule; + state?: State; + subject?: string; + uid?: string; + updated?: string; + userId?: number; +}; +export type CreateOrUpdateReport = { + dashboards?: ReportDashboard[]; + enableCsv?: boolean; + enableDashboardUrl?: boolean; + formats?: Type[]; + message?: string; + name?: string; + options?: ReportOptions; + recipients?: string; + replyTo?: string; + scaleFactor?: number; + schedule?: ReportSchedule; + state?: State; + subject?: string; +}; +export type ReportEmail = { + /** Comma-separated list of emails to which to send the report to. */ + emails?: string; + /** Send the report to the emails specified in the report. Required if emails is not present. */ + id?: string; + /** Send the report to the emails specified in the report. Required if emails is not present. */ + useEmailsFromReport?: boolean; +}; +export type ReportBrandingOptions = { + emailFooterLink?: string; + emailFooterMode?: string; + emailFooterText?: string; + emailLogoUrl?: string; + reportLogoUrl?: string; +}; +export type ReportSettings = { + branding?: ReportBrandingOptions; + embeddedImageTheme?: string; + id?: number; + orgId?: number; + pdfTheme?: string; + userId?: number; +}; +export type HitType = string; +export type Hit = { + description?: string; + folderId?: number; + folderTitle?: string; + folderUid?: string; + folderUrl?: string; + id?: number; + isDeleted?: boolean; + isStarred?: boolean; + orgId?: number; + permanentlyDeleteDate?: string; + slug?: string; + sortMeta?: number; + sortMetaName?: string; + tags?: string[]; + title?: string; + type?: HitType; + uid?: string; + uri?: string; + url?: string; +}; +export type HitList = Hit[]; +export type ServiceAccountDto = { + accessControl?: { + [key: string]: boolean; + }; + avatarUrl?: string; + id?: number; + isDisabled?: boolean; + isExternal?: boolean; + login?: string; + name?: string; + orgId?: number; + role?: string; + tokens?: number; + uid?: string; +}; +export type CreateServiceAccountForm = { + isDisabled?: boolean; + name?: string; + role?: 'None' | 'Viewer' | 'Editor' | 'Admin'; +}; +export type SearchOrgServiceAccountsResult = { + page?: number; + perPage?: number; + serviceAccounts?: ServiceAccountDto[]; + /** It can be used for pagination of the user list + E.g. if totalCount is equal to 100 users and + the perpage parameter is set to 10 then there are 10 pages of users. */ + totalCount?: number; +}; +export type ServiceAccountProfileDto = { + accessControl?: { + [key: string]: boolean; + }; + avatarUrl?: string; + createdAt?: string; + id?: number; + isDisabled?: boolean; + isExternal?: boolean; + login?: string; + name?: string; + orgId?: number; + requiredBy?: string; + role?: string; + teams?: string[]; + tokens?: number; + uid?: string; + updatedAt?: string; +}; +export type UpdateServiceAccountForm = { + isDisabled?: boolean; + name?: string; + role?: 'None' | 'Viewer' | 'Editor' | 'Admin'; + serviceAccountId?: number; +}; +export type TokenDto = { + created?: string; + expiration?: string; + hasExpired?: boolean; + id?: number; + isRevoked?: boolean; + lastUsedAt?: string; + name?: string; + secondsUntilExpiration?: number; +}; +export type NewApiKeyResult = { + id?: number; + key?: string; + name?: string; +}; +export type AddServiceAccountTokenCommand = { + name?: string; + secondsToLive?: number; +}; +export type AnIpMaskIsABitmaskThatCanBeUsedToManipulateIpAddressesForIpAddressingAndRouting = number[]; +export type AnIpNetRepresentsAnIpNetwork = { + IP?: string; + Mask?: AnIpMaskIsABitmaskThatCanBeUsedToManipulateIpAddressesForIpAddressingAndRouting; +}; +export type ExtKeyUsageRepresentsAnExtendedSetOfActionsThatAreValidForAGivenKey = number; +export type AnObjectIdentifierRepresentsAnAsn1ObjectIdentifier = number[]; +export type Extension = { + Critical?: boolean; + Id?: AnObjectIdentifierRepresentsAnAsn1ObjectIdentifier; + Value?: number[]; +}; +export type AttributeTypeAndValue = { + Type?: AnObjectIdentifierRepresentsAnAsn1ObjectIdentifier; + Value?: any; +}; +export type Name = { + Country?: string[]; + /** ExtraNames contains attributes to be copied, raw, into any marshaled + distinguished names. Values override any attributes with the same OID. + The ExtraNames field is not populated when parsing, see Names. */ + ExtraNames?: AttributeTypeAndValue[]; + Locality?: string[]; + /** Names contains all parsed attributes. When parsing distinguished names, + this can be used to extract non-standard attributes that are not parsed + by this package. When marshaling to RDNSequences, the Names field is + ignored, see ExtraNames. */ + Names?: AttributeTypeAndValue[]; + SerialNumber?: string; + StreetAddress?: string[]; +}; +export type KeyUsage = number; +export type PolicyMappingRepresentsAPolicyMappingEntryInThePolicyMappingsExtension = { + /** IssuerDomainPolicy contains a policy OID the issuing certificate considers + equivalent to SubjectDomainPolicy in the subject certificate. */ + IssuerDomainPolicy?: string; + /** SubjectDomainPolicy contains a OID the issuing certificate considers + equivalent to IssuerDomainPolicy in the subject certificate. */ + SubjectDomainPolicy?: string; +}; +export type PublicKeyAlgorithm = number; +export type SignatureAlgorithm = number; +export type Userinfo = object; +export type AUrlRepresentsAParsedUrlTechnicallyAUriReference = { + ForceQuery?: boolean; + Fragment?: string; + Host?: string; + OmitHost?: boolean; + Opaque?: string; + Path?: string; + RawFragment?: string; + RawPath?: string; + RawQuery?: string; + Scheme?: string; + User?: Userinfo; +}; +export type ACertificateRepresentsAnX509Certificate = { + AuthorityKeyId?: number[]; + /** BasicConstraintsValid indicates whether IsCA, MaxPathLen, + and MaxPathLenZero are valid. */ + BasicConstraintsValid?: boolean; + /** CRL Distribution Points */ + CRLDistributionPoints?: string[]; + /** Subject Alternate Name values. (Note that these values may not be valid + if invalid values were contained within a parsed certificate. For + example, an element of DNSNames may not be a valid DNS domain name.) */ + DNSNames?: string[]; + EmailAddresses?: string[]; + ExcludedDNSDomains?: string[]; + ExcludedEmailAddresses?: string[]; + ExcludedIPRanges?: AnIpNetRepresentsAnIpNetwork[]; + ExcludedURIDomains?: string[]; + ExtKeyUsage?: ExtKeyUsageRepresentsAnExtendedSetOfActionsThatAreValidForAGivenKey[]; + /** Extensions contains raw X.509 extensions. When parsing certificates, + this can be used to extract non-critical extensions that are not + parsed by this package. When marshaling certificates, the Extensions + field is ignored, see ExtraExtensions. */ + Extensions?: Extension[]; + /** ExtraExtensions contains extensions to be copied, raw, into any + marshaled certificates. Values override any extensions that would + otherwise be produced based on the other fields. The ExtraExtensions + field is not populated when parsing certificates, see Extensions. */ + ExtraExtensions?: Extension[]; + IPAddresses?: string[]; + /** InhibitAnyPolicy and InhibitAnyPolicyZero indicate the presence and value + of the inhibitAnyPolicy extension. + + The value of InhibitAnyPolicy indicates the number of additional + certificates in the path after this certificate that may use the + anyPolicy policy OID to indicate a match with any other policy. + + When parsing a certificate, a positive non-zero InhibitAnyPolicy means + that the field was specified, -1 means it was unset, and + InhibitAnyPolicyZero being true mean that the field was explicitly set to + zero. The case of InhibitAnyPolicy==0 with InhibitAnyPolicyZero==false + should be treated equivalent to -1 (unset). */ + InhibitAnyPolicy?: number; + /** InhibitAnyPolicyZero indicates that InhibitAnyPolicy==0 should be + interpreted as an actual maximum path length of zero. Otherwise, that + combination is interpreted as InhibitAnyPolicy not being set. */ + InhibitAnyPolicyZero?: boolean; + /** InhibitPolicyMapping and InhibitPolicyMappingZero indicate the presence + and value of the inhibitPolicyMapping field of the policyConstraints + extension. + + The value of InhibitPolicyMapping indicates the number of additional + certificates in the path after this certificate that may use policy + mapping. + + When parsing a certificate, a positive non-zero InhibitPolicyMapping + means that the field was specified, -1 means it was unset, and + InhibitPolicyMappingZero being true mean that the field was explicitly + set to zero. The case of InhibitPolicyMapping==0 with + InhibitPolicyMappingZero==false should be treated equivalent to -1 + (unset). */ + InhibitPolicyMapping?: number; + /** InhibitPolicyMappingZero indicates that InhibitPolicyMapping==0 should be + interpreted as an actual maximum path length of zero. Otherwise, that + combination is interpreted as InhibitAnyPolicy not being set. */ + InhibitPolicyMappingZero?: boolean; + IsCA?: boolean; + Issuer?: Name; + IssuingCertificateURL?: string[]; + KeyUsage?: KeyUsage; + /** MaxPathLen and MaxPathLenZero indicate the presence and + value of the BasicConstraints' "pathLenConstraint". + + When parsing a certificate, a positive non-zero MaxPathLen + means that the field was specified, -1 means it was unset, + and MaxPathLenZero being true mean that the field was + explicitly set to zero. The case of MaxPathLen==0 with MaxPathLenZero==false + should be treated equivalent to -1 (unset). + + When generating a certificate, an unset pathLenConstraint + can be requested with either MaxPathLen == -1 or using the + zero value for both MaxPathLen and MaxPathLenZero. */ + MaxPathLen?: number; + /** MaxPathLenZero indicates that BasicConstraintsValid==true + and MaxPathLen==0 should be interpreted as an actual + maximum path length of zero. Otherwise, that combination is + interpreted as MaxPathLen not being set. */ + MaxPathLenZero?: boolean; + NotBefore?: string; + /** RFC 5280, 4.2.2.1 (Authority Information Access) */ + OCSPServer?: string[]; + PermittedDNSDomains?: string[]; + /** Name constraints */ + PermittedDNSDomainsCritical?: boolean; + PermittedEmailAddresses?: string[]; + PermittedIPRanges?: AnIpNetRepresentsAnIpNetwork[]; + PermittedURIDomains?: string[]; + /** Policies contains all policy identifiers included in the certificate. + See CreateCertificate for context about how this field and the PolicyIdentifiers field + interact. + In Go 1.22, encoding/gob cannot handle and ignores this field. */ + Policies?: string[]; + /** PolicyIdentifiers contains asn1.ObjectIdentifiers, the components + of which are limited to int32. If a certificate contains a policy which + cannot be represented by asn1.ObjectIdentifier, it will not be included in + PolicyIdentifiers, but will be present in Policies, which contains all parsed + policy OIDs. + See CreateCertificate for context about how this field and the Policies field + interact. */ + PolicyIdentifiers?: AnObjectIdentifierRepresentsAnAsn1ObjectIdentifier[]; + /** PolicyMappings contains a list of policy mappings included in the certificate. */ + PolicyMappings?: PolicyMappingRepresentsAPolicyMappingEntryInThePolicyMappingsExtension[]; + PublicKey?: any; + PublicKeyAlgorithm?: PublicKeyAlgorithm; + Raw?: number[]; + RawIssuer?: number[]; + RawSubject?: number[]; + RawSubjectPublicKeyInfo?: number[]; + RawTBSCertificate?: number[]; + /** RequireExplicitPolicy and RequireExplicitPolicyZero indicate the presence + and value of the requireExplicitPolicy field of the policyConstraints + extension. + + The value of RequireExplicitPolicy indicates the number of additional + certificates in the path after this certificate before an explicit policy + is required for the rest of the path. When an explicit policy is required, + each subsequent certificate in the path must contain a required policy OID, + or a policy OID which has been declared as equivalent through the policy + mapping extension. + + When parsing a certificate, a positive non-zero RequireExplicitPolicy + means that the field was specified, -1 means it was unset, and + RequireExplicitPolicyZero being true mean that the field was explicitly + set to zero. The case of RequireExplicitPolicy==0 with + RequireExplicitPolicyZero==false should be treated equivalent to -1 + (unset). */ + RequireExplicitPolicy?: number; + /** RequireExplicitPolicyZero indicates that RequireExplicitPolicy==0 should be + interpreted as an actual maximum path length of zero. Otherwise, that + combination is interpreted as InhibitAnyPolicy not being set. */ + RequireExplicitPolicyZero?: boolean; + SerialNumber?: string; + Signature?: number[]; + SignatureAlgorithm?: SignatureAlgorithm; + Subject?: Name; + SubjectKeyId?: number[]; + URIs?: AUrlRepresentsAParsedUrlTechnicallyAUriReference[]; + /** UnhandledCriticalExtensions contains a list of extension IDs that + were not (fully) processed when parsing. Verify will fail if this + slice is non-empty, unless verification is delegated to an OS + library which understands all the critical extensions. + + Users can access these extensions using Extensions and can remove + elements from this slice if they believe that they have been + handled. */ + UnhandledCriticalExtensions?: AnObjectIdentifierRepresentsAnAsn1ObjectIdentifier[]; + UnknownExtKeyUsage?: AnObjectIdentifierRepresentsAnAsn1ObjectIdentifier[]; + Version?: number; +}; +export type JsonWebKey = { + /** Key algorithm, parsed from `alg` header. */ + Algorithm?: string; + /** X.509 certificate thumbprint (SHA-1), parsed from `x5t` header. */ + CertificateThumbprintSHA1?: number[]; + /** X.509 certificate thumbprint (SHA-256), parsed from `x5t#S256` header. */ + CertificateThumbprintSHA256?: number[]; + /** X.509 certificate chain, parsed from `x5c` header. */ + Certificates?: ACertificateRepresentsAnX509Certificate[]; + CertificatesURL?: AUrlRepresentsAParsedUrlTechnicallyAUriReference; + /** Key is the Go in-memory representation of this key. It must have one + of these types: + ed25519.PublicKey + ed25519.PrivateKey + ecdsa.PublicKey + ecdsa.PrivateKey + rsa.PublicKey + rsa.PrivateKey + []byte (a symmetric key) + + When marshaling this JSONWebKey into JSON, the "kty" header parameter + will be automatically set based on the type of this field. */ + Key?: any; + /** Key identifier, parsed from `kid` header. */ + KeyID?: string; + /** Key use, parsed from `use` header. */ + Use?: string; +}; +export type Unstructured = { + /** Object is a JSON compatible map with string, float, int, bool, []any, + or map[string]any children. */ + Object?: { + [key: string]: any; + }; +}; +export type CreateDashboardSnapshotCommand = { + /** APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + +optional */ + apiVersion?: string; + dashboard: Unstructured; + /** Unique key used to delete the snapshot. It is different from the `key` so that only the creator can delete the snapshot. Required if `external` is `true`. */ + deleteKey?: string; + /** When the snapshot should expire in seconds in seconds. Default is never to expire. */ + expires?: number; + /** these are passed when storing an external snapshot ref + Save the snapshot on an external server rather than locally. */ + external?: boolean; + /** Define the unique key. Required if `external` is `true`. */ + key?: string; + /** Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + +optional */ + kind?: string; + /** Snapshot name */ + name?: string; +}; +export type CreateTeamCommand = { + email?: string; + name?: string; +}; +export type TeamDto = { + accessControl?: { + [key: string]: boolean; + }; + avatarUrl?: string; + email?: string; + externalUID?: string; + id?: number; + isProvisioned?: boolean; + memberCount?: number; + name?: string; + orgId?: number; + permission?: PermissionType; + uid?: string; +}; +export type SearchTeamQueryResult = { + page?: number; + perPage?: number; + teams?: TeamDto[]; + totalCount?: number; +}; +export type TeamGroupDto = { + groupId?: string; + orgId?: number; + teamId?: number; +}; +export type TeamGroupMapping = { + groupId?: string; +}; +export type SearchTeamGroupsQueryResult = { + page?: number; + perPage?: number; + teamGroups?: TeamGroupDto[]; + totalCount?: number; +}; +export type UpdateTeamCommand = { + Email?: string; + ExternalUID?: string; + ID?: number; + Name?: string; +}; +export type TeamMemberDto = { + auth_module?: string; + avatarUrl?: string; + email?: string; + labels?: string[]; + login?: string; + name?: string; + orgId?: number; + permission?: PermissionType; + teamId?: number; + teamUID?: string; + uid?: string; + userId?: number; + userUID?: string; +}; +export type AddTeamMemberCommand = { + userId?: number; +}; +export type SetTeamMembershipsCommand = { + admins?: string[]; + members?: string[]; +}; +export type UpdateTeamMemberCommand = { + permission?: PermissionType; +}; +export type UserProfileDto = { + accessControl?: { + [key: string]: boolean; + }; + authLabels?: string[]; + avatarUrl?: string; + createdAt?: string; + email?: string; + id?: number; + isDisabled?: boolean; + isExternal?: boolean; + isExternallySynced?: boolean; + isGrafanaAdmin?: boolean; + isGrafanaAdminExternallySynced?: boolean; + isProvisioned?: boolean; + login?: string; + name?: string; + orgId?: number; + theme?: string; + uid?: string; + updatedAt?: string; +}; +export type UpdateUserCommand = { + email?: string; + login?: string; + name?: string; + theme?: string; +}; +export type UserOrgDto = { + name?: string; + orgId?: number; + role?: 'None' | 'Viewer' | 'Editor' | 'Admin'; +}; +export type ChangeUserPasswordCommand = { + newPassword?: Password; + oldPassword?: Password; +}; +export type UserSearchHitDto = { + authLabels?: string[]; + avatarUrl?: string; + email?: string; + id?: number; + isAdmin?: boolean; + isDisabled?: boolean; + isProvisioned?: boolean; + lastSeenAt?: string; + lastSeenAtAge?: string; + login?: string; + name?: string; + uid?: string; +}; +export type SearchUserQueryResult = { + page?: number; + perPage?: number; + totalCount?: number; + users?: UserSearchHitDto[]; +}; +export type RelativeTimeRange = { + from?: Duration; + to?: Duration; +}; +export type AlertQueryRepresentsASingleQueryAssociatedWithAnAlertDefinition = { + /** Grafana data source unique identifier; it should be '__expr__' for a Server Side Expression operation. */ + datasourceUid?: string; + /** JSON is the raw JSON query and includes the above properties as well as custom properties. */ + model?: object; + /** QueryType is an optional identifier for the type of query. + It can be used to distinguish different types of queries. */ + queryType?: string; + /** RefID is the unique identifier of the query, set by the frontend call. */ + refId?: string; + relativeTimeRange?: RelativeTimeRange; +}; +export type AlertRuleNotificationSettings = { + /** Override the times when notifications should not be muted. These must match the name of a mute time interval defined + in the alertmanager configuration time_intervals section. All notifications will be suppressed unless they are sent + at the time that matches any interval. */ + active_time_intervals?: string[]; + /** Override the labels by which incoming alerts are grouped together. For example, multiple alerts coming in for + cluster=A and alertname=LatencyHigh would be batched into a single group. To aggregate by all possible labels + use the special value '...' as the sole label name. + This effectively disables aggregation entirely, passing through all alerts as-is. This is unlikely to be what + you want, unless you have a very low alert volume or your upstream notification system performs its own grouping. + Must include 'alertname' and 'grafana_folder' if not using '...'. */ + group_by?: string[]; + /** Override how long to wait before sending a notification about new alerts that are added to a group of alerts for + which an initial notification has already been sent. (Usually ~5m or more.) */ + group_interval?: string; + /** Override how long to initially wait to send a notification for a group of alerts. Allows to wait for an + inhibiting alert to arrive or collect more initial alerts for the same group. (Usually ~0s to few minutes.) */ + group_wait?: string; + /** Override the times when notifications should be muted. These must match the name of a mute time interval defined + in the alertmanager configuration time_intervals section. When muted it will not send any notifications, but + otherwise acts normally. */ + mute_time_intervals?: string[]; + /** Name of the receiver to send notifications to. */ + receiver: string; + /** Override how long to wait before sending a notification again if it has already been sent successfully for an + alert. (Usually ~3h or more). + Note that this parameter is implicitly bound by Alertmanager's `--data.retention` configuration flag. + Notifications will be resent after either repeat_interval or the data retention period have passed, whichever + occurs first. `repeat_interval` should not be less than `group_interval`. */ + repeat_interval?: string; +}; +export type Provenance = string; +export type Record = { + /** Which expression node should be used as the input for the recorded metric. */ + from: string; + /** Name of the recorded metric. */ + metric: string; + /** Which data source should be used to write the output of the recording rule, specified by UID. */ + target_datasource_uid?: string; +}; +export type ProvisionedAlertRule = { + annotations?: { + [key: string]: string; + }; + condition: string; + data: AlertQueryRepresentsASingleQueryAssociatedWithAnAlertDefinition[]; + execErrState: 'OK' | 'Alerting' | 'Error'; + folderUID: string; + for: string; + id?: number; + isPaused?: boolean; + keep_firing_for?: string; + labels?: { + [key: string]: string; + }; + missingSeriesEvalsToResolve?: number; + noDataState: 'Alerting' | 'NoData' | 'OK'; + notification_settings?: AlertRuleNotificationSettings; + orgID: number; + provenance?: Provenance; + record?: Record; + ruleGroup: string; + title: string; + uid?: string; +}; +export type ProvisionedAlertRuleRead = { + annotations?: { + [key: string]: string; + }; + condition: string; + data: AlertQueryRepresentsASingleQueryAssociatedWithAnAlertDefinition[]; + execErrState: 'OK' | 'Alerting' | 'Error'; + folderUID: string; + for: string; + id?: number; + isPaused?: boolean; + keep_firing_for?: string; + labels?: { + [key: string]: string; + }; + missingSeriesEvalsToResolve?: number; + noDataState: 'Alerting' | 'NoData' | 'OK'; + notification_settings?: AlertRuleNotificationSettings; + orgID: number; + provenance?: Provenance; + record?: Record; + ruleGroup: string; + title: string; + uid?: string; + updated?: string; +}; +export type ProvisionedAlertRules = ProvisionedAlertRule[]; +export type ProvisionedAlertRulesRead = ProvisionedAlertRuleRead[]; +export type ValidationError = { + message?: string; +}; +export type RawMessage = object; +export type ReceiverExportIsTheProvisionedFileExportOfAlertingReceiverV1 = { + disableResolveMessage?: boolean; + settings?: RawMessage; + type?: string; + uid?: string; +}; +export type ContactPointExportIsTheProvisionedFileExportOfAlertingContactPointV1 = { + name?: string; + orgId?: number; + receivers?: ReceiverExportIsTheProvisionedFileExportOfAlertingReceiverV1[]; +}; +export type RelativeTimeRangeExport = { + from?: number; + to?: number; +}; +export type AlertQueryExportIsTheProvisionedExportOfModelsAlertQuery = { + datasourceUid?: string; + model?: { + [key: string]: any; + }; + queryType?: string; + refId?: string; + relativeTimeRange?: RelativeTimeRangeExport; +}; +export type AlertRuleNotificationSettingsExportIsTheProvisionedExportOfModelsNotificationSettings = { + active_time_intervals?: string[]; + group_by?: string[]; + group_interval?: string; + group_wait?: string; + mute_time_intervals?: string[]; + receiver?: string; + repeat_interval?: string; +}; +export type RecordIsTheProvisionedExportOfModelsRecord = { + from?: string; + metric?: string; + targetDatasourceUid?: string; +}; +export type AlertRuleExportIsTheProvisionedFileExportOfModelsAlertRule = { + annotations?: { + [key: string]: string; + }; + condition?: string; + dashboardUid?: string; + data?: AlertQueryExportIsTheProvisionedExportOfModelsAlertQuery[]; + execErrState?: 'OK' | 'Alerting' | 'Error'; + for?: Duration; + isPaused?: boolean; + keepFiringFor?: Duration; + labels?: { + [key: string]: string; + }; + missing_series_evals_to_resolve?: number; + noDataState?: 'Alerting' | 'NoData' | 'OK'; + notification_settings?: AlertRuleNotificationSettingsExportIsTheProvisionedExportOfModelsNotificationSettings; + panelId?: number; + record?: RecordIsTheProvisionedExportOfModelsRecord; + title?: string; + uid?: string; +}; +export type AlertRuleGroupExportIsTheProvisionedFileExportOfAlertRuleGroupV1 = { + folder?: string; + interval?: Duration; + name?: string; + orgId?: number; + rules?: AlertRuleExportIsTheProvisionedFileExportOfModelsAlertRule[]; +}; +export type TimeIntervalRepresentsANamedSetOfTimeIntervalsForWhichARouteShouldBeMuted = { + name?: string; + time_intervals?: TimeIntervalRepresentsANamedSetOfTimeIntervalsForWhichARouteShouldBeMuted[]; +}; +export type MuteTimeIntervalExport = { + name?: string; + orgId?: number; + time_intervals?: TimeIntervalRepresentsANamedSetOfTimeIntervalsForWhichARouteShouldBeMuted[]; +}; +export type MatchRegexpsRepresentsAMapOfRegexp = { + [key: string]: string; +}; +export type MatchTypeIsAnEnumForLabelMatchingTypes = number; +export type MatcherModelsTheMatchingOfALabel = { + Name?: string; + Type?: MatchTypeIsAnEnumForLabelMatchingTypes; + Value?: string; +}; +export type Matchers = MatcherModelsTheMatchingOfALabel[]; +export type ObjectMatcherIsAMatcherThatCanBeUsedToFilterAlerts = string[]; +export type ObjectMatchersIsAListOfMatchersThatCanBeUsedToFilterAlerts = + ObjectMatcherIsAMatcherThatCanBeUsedToFilterAlerts[]; +export type RouteExport = { + active_time_intervals?: string[]; + continue?: boolean; + group_by?: string[]; + group_interval?: string; + group_wait?: string; + /** Deprecated. Remove before v1.0 release. */ + match?: { + [key: string]: string; + }; + match_re?: MatchRegexpsRepresentsAMapOfRegexp; + matchers?: Matchers; + mute_time_intervals?: string[]; + object_matchers?: ObjectMatchersIsAListOfMatchersThatCanBeUsedToFilterAlerts; + receiver?: string; + repeat_interval?: string; + routes?: RouteExport[]; +}; +export type NotificationPolicyExportIsTheProvisionedFileExportOfAlertingNotificiationPolicyV1 = { + active_time_intervals?: string[]; + continue?: boolean; + group_by?: string[]; + group_interval?: string; + group_wait?: string; + /** Deprecated. Remove before v1.0 release. */ + match?: { + [key: string]: string; + }; + match_re?: MatchRegexpsRepresentsAMapOfRegexp; + matchers?: Matchers; + mute_time_intervals?: string[]; + object_matchers?: ObjectMatchersIsAListOfMatchersThatCanBeUsedToFilterAlerts; + orgId?: number; + receiver?: string; + repeat_interval?: string; + routes?: RouteExport[]; +}; +export type AlertingFileExportIsTheFullProvisionedFileExport = { + apiVersion?: number; + contactPoints?: ContactPointExportIsTheProvisionedFileExportOfAlertingContactPointV1[]; + groups?: AlertRuleGroupExportIsTheProvisionedFileExportOfAlertRuleGroupV1[]; + muteTimes?: MuteTimeIntervalExport[]; + policies?: NotificationPolicyExportIsTheProvisionedFileExportOfAlertingNotificiationPolicyV1[]; +}; +export type EmbeddedContactPoint = { + disableResolveMessage?: boolean; + /** Name is used as grouping key in the UI. Contact points with the + same name will be grouped in the UI. */ + name?: string; + settings: Json; + type: + | 'alertmanager' + | 'dingding' + | 'discord' + | 'email' + | 'googlechat' + | 'kafka' + | 'line' + | 'opsgenie' + | 'pagerduty' + | 'pushover' + | 'sensugo' + | 'slack' + | 'teams' + | 'telegram' + | 'threema' + | 'victorops' + | 'webhook' + | 'wecom'; + /** UID is the unique identifier of the contact point. The UID can be + set by the user. */ + uid?: string; +}; +export type EmbeddedContactPointRead = { + disableResolveMessage?: boolean; + /** Name is used as grouping key in the UI. Contact points with the + same name will be grouped in the UI. */ + name?: string; + provenance?: string; + settings: Json; + type: + | 'alertmanager' + | 'dingding' + | 'discord' + | 'email' + | 'googlechat' + | 'kafka' + | 'line' + | 'opsgenie' + | 'pagerduty' + | 'pushover' + | 'sensugo' + | 'slack' + | 'teams' + | 'telegram' + | 'threema' + | 'victorops' + | 'webhook' + | 'wecom'; + /** UID is the unique identifier of the contact point. The UID can be + set by the user. */ + uid?: string; +}; +export type ContactPoints = EmbeddedContactPoint[]; +export type ContactPointsRead = EmbeddedContactPointRead[]; +export type PermissionDenied = object; +export type Ack = object; +export type NotFound = object; +export type AlertRuleGroup = { + folderUid?: string; + interval?: number; + rules?: ProvisionedAlertRule[]; + title?: string; +}; +export type AlertRuleGroupRead = { + folderUid?: string; + interval?: number; + rules?: ProvisionedAlertRuleRead[]; + title?: string; +}; +export type MuteTimeIntervalRepresentsANamedSetOfTimeIntervalsForWhichARouteShouldBeMuted = { + name?: string; + time_intervals?: TimeIntervalRepresentsANamedSetOfTimeIntervalsForWhichARouteShouldBeMuted[]; +}; +export type MuteTimings = MuteTimeIntervalRepresentsANamedSetOfTimeIntervalsForWhichARouteShouldBeMuted[]; +export type Route = { + active_time_intervals?: string[]; + continue?: boolean; + group_by?: string[]; + group_interval?: string; + group_wait?: string; + /** Deprecated. Remove before v1.0 release. */ + match?: { + [key: string]: string; + }; + match_re?: MatchRegexpsRepresentsAMapOfRegexp; + matchers?: Matchers; + mute_time_intervals?: string[]; + object_matchers?: ObjectMatchersIsAListOfMatchersThatCanBeUsedToFilterAlerts; + provenance?: Provenance; + receiver?: string; + repeat_interval?: string; + routes?: Route[]; +}; +export type NotificationTemplate = { + name?: string; + provenance?: Provenance; + template?: string; + version?: string; +}; +export type NotificationTemplates = NotificationTemplate[]; +export type NotificationTemplateContent = { + template?: string; + version?: string; +}; +export const { + useSearchResultMutation, + useListRolesQuery, + useCreateRoleMutation, + useDeleteRoleMutation, + useGetRoleQuery, + useUpdateRoleMutation, + useGetRoleAssignmentsQuery, + useSetRoleAssignmentsMutation, + useGetAccessControlStatusQuery, + useListTeamsRolesMutation, + useListTeamRolesQuery, + useAddTeamRoleMutation, + useSetTeamRolesMutation, + useRemoveTeamRoleMutation, + useListUsersRolesMutation, + useListUserRolesQuery, + useAddUserRoleMutation, + useSetUserRolesMutation, + useRemoveUserRoleMutation, + useGetResourceDescriptionQuery, + useGetResourcePermissionsQuery, + useSetResourcePermissionsMutation, + useSetResourcePermissionsForBuiltInRoleMutation, + useSetResourcePermissionsForTeamMutation, + useSetResourcePermissionsForUserMutation, + useGetSyncStatusQuery, + useReloadLdapCfgMutation, + useGetLdapStatusQuery, + usePostSyncUserWithLdapMutation, + useGetUserFromLdapQuery, + useAdminProvisioningReloadAccessControlMutation, + useAdminProvisioningReloadDashboardsMutation, + useAdminProvisioningReloadDatasourcesMutation, + useAdminProvisioningReloadPluginsMutation, + useAdminGetSettingsQuery, + useAdminGetStatsQuery, + useAdminCreateUserMutation, + useAdminDeleteUserMutation, + useAdminGetUserAuthTokensQuery, + useAdminDisableUserMutation, + useAdminEnableUserMutation, + useAdminLogoutUserMutation, + useAdminUpdateUserPasswordMutation, + useAdminUpdateUserPermissionsMutation, + useGetUserQuotaQuery, + useUpdateUserQuotaMutation, + useAdminRevokeUserAuthTokenMutation, + useGetAnnotationsQuery, + usePostAnnotationMutation, + usePostGraphiteAnnotationMutation, + useMassDeleteAnnotationsMutation, + useGetAnnotationTagsQuery, + useDeleteAnnotationByIdMutation, + useGetAnnotationByIdQuery, + usePatchAnnotationMutation, + useUpdateAnnotationMutation, + useListDevicesQuery, + useSearchDevicesQuery, + useGetSessionListQuery, + useCreateSessionMutation, + useDeleteSessionMutation, + useGetSessionQuery, + useCreateSnapshotMutation, + useGetSnapshotQuery, + useCancelSnapshotMutation, + useUploadSnapshotMutation, + useGetShapshotListQuery, + useGetResourceDependenciesQuery, + useGetCloudMigrationTokenQuery, + useCreateCloudMigrationTokenMutation, + useDeleteCloudMigrationTokenMutation, + useRouteConvertPrometheusCortexGetRulesQuery, + useRouteConvertPrometheusCortexPostRuleGroupsMutation, + useRouteConvertPrometheusCortexDeleteNamespaceMutation, + useRouteConvertPrometheusCortexGetNamespaceQuery, + useRouteConvertPrometheusCortexPostRuleGroupMutation, + useRouteConvertPrometheusCortexDeleteRuleGroupMutation, + useRouteConvertPrometheusCortexGetRuleGroupQuery, + useRouteConvertPrometheusGetRulesQuery, + useRouteConvertPrometheusPostRuleGroupsMutation, + useRouteConvertPrometheusDeleteNamespaceMutation, + useRouteConvertPrometheusGetNamespaceQuery, + useRouteConvertPrometheusPostRuleGroupMutation, + useRouteConvertPrometheusDeleteRuleGroupMutation, + useRouteConvertPrometheusGetRuleGroupQuery, + useSearchDashboardSnapshotsQuery, + useCalculateDashboardDiffMutation, + usePostDashboardMutation, + useGetHomeDashboardQuery, + useImportDashboardMutation, + useInterpolateDashboardMutation, + useListPublicDashboardsQuery, + useGetDashboardTagsQuery, + useGetPublicDashboardQuery, + useCreatePublicDashboardMutation, + useDeletePublicDashboardMutation, + useUpdatePublicDashboardMutation, + useDeleteDashboardByUidMutation, + useGetDashboardByUidQuery, + useGetDashboardPermissionsListByUidQuery, + useUpdateDashboardPermissionsByUidMutation, + useRestoreDashboardVersionByUidMutation, + useGetDashboardVersionsByUidQuery, + useGetDashboardVersionByUidQuery, + useGetDataSourcesQuery, + useAddDataSourceMutation, + useGetCorrelationsQuery, + useGetDataSourceIdByNameQuery, + useDeleteDataSourceByNameMutation, + useGetDataSourceByNameQuery, + useDatasourceProxyDeleteByUiDcallsMutation, + useDatasourceProxyGetByUiDcallsQuery, + useDatasourceProxyPostByUiDcallsMutation, + useGetCorrelationsBySourceUidQuery, + useCreateCorrelationMutation, + useGetCorrelationQuery, + useUpdateCorrelationMutation, + useDeleteDataSourceByUidMutation, + useGetDataSourceByUidQuery, + useUpdateDataSourceByUidMutation, + useDeleteCorrelationMutation, + useCheckDatasourceHealthWithUidQuery, + useGetTeamLbacRulesApiQuery, + useUpdateTeamLbacRulesApiMutation, + useCallDatasourceResourceWithUidQuery, + useGetDataSourceCacheConfigQuery, + useSetDataSourceCacheConfigMutation, + useCleanDataSourceCacheMutation, + useDisableDataSourceCacheMutation, + useEnableDataSourceCacheMutation, + useQueryMetricsWithExpressionsMutation, + useGetFoldersQuery, + useCreateFolderMutation, + useDeleteFolderMutation, + useGetFolderByUidQuery, + useUpdateFolderMutation, + useGetFolderDescendantCountsQuery, + useMoveFolderMutation, + useGetFolderPermissionListQuery, + useUpdateFolderPermissionsMutation, + useGetMappedGroupsQuery, + useDeleteGroupMappingsMutation, + useCreateGroupMappingsMutation, + useUpdateGroupMappingsMutation, + useGetGroupRolesQuery, + useGetHealthQuery, + useGetLibraryElementsQuery, + useCreateLibraryElementMutation, + useGetLibraryElementByNameQuery, + useDeleteLibraryElementByUidMutation, + useGetLibraryElementByUidQuery, + useUpdateLibraryElementMutation, + useGetLibraryElementConnectionsQuery, + useGetStatusQuery, + useRefreshLicenseStatsQuery, + useDeleteLicenseTokenMutation, + useGetLicenseTokenQuery, + usePostLicenseTokenMutation, + usePostRenewLicenseTokenMutation, + useGetSamlLogoutQuery, + useGetCurrentOrgQuery, + useUpdateCurrentOrgMutation, + useUpdateCurrentOrgAddressMutation, + useGetPendingOrgInvitesQuery, + useAddOrgInviteMutation, + useRevokeInviteMutation, + useGetOrgPreferencesQuery, + usePatchOrgPreferencesMutation, + useUpdateOrgPreferencesMutation, + useGetCurrentOrgQuotaQuery, + useGetOrgUsersForCurrentOrgQuery, + useAddOrgUserToCurrentOrgMutation, + useGetOrgUsersForCurrentOrgLookupQuery, + useRemoveOrgUserForCurrentOrgMutation, + useUpdateOrgUserForCurrentOrgMutation, + useSearchOrgsQuery, + useCreateOrgMutation, + useGetOrgByNameQuery, + useDeleteOrgByIdMutation, + useGetOrgByIdQuery, + useUpdateOrgMutation, + useUpdateOrgAddressMutation, + useGetOrgQuotaQuery, + useUpdateOrgQuotaMutation, + useGetOrgUsersQuery, + useAddOrgUserMutation, + useSearchOrgUsersQuery, + useRemoveOrgUserMutation, + useUpdateOrgUserMutation, + useSearchPlaylistsQuery, + useCreatePlaylistMutation, + useDeletePlaylistMutation, + useGetPlaylistQuery, + useUpdatePlaylistMutation, + useGetPlaylistItemsQuery, + useViewPublicDashboardQuery, + useGetPublicAnnotationsQuery, + useQueryPublicDashboardMutation, + useSearchQueriesQuery, + useCreateQueryMutation, + useUnstarQueryMutation, + useStarQueryMutation, + useDeleteQueryMutation, + usePatchQueryCommentMutation, + useListRecordingRulesQuery, + useCreateRecordingRuleMutation, + useUpdateRecordingRuleMutation, + useTestCreateRecordingRuleMutation, + useDeleteRecordingRuleWriteTargetMutation, + useGetRecordingRuleWriteTargetQuery, + useCreateRecordingRuleWriteTargetMutation, + useDeleteRecordingRuleMutation, + useGetReportsQuery, + useCreateReportMutation, + useGetReportsByDashboardUidQuery, + useSendReportMutation, + useGetSettingsImageQuery, + useRenderReportCsVsQuery, + useRenderReportPdFsQuery, + useGetReportSettingsQuery, + useSaveReportSettingsMutation, + useSendTestEmailMutation, + usePostAcsMutation, + useGetMetadataQuery, + useGetSloQuery, + usePostSloMutation, + useSearchQuery, + useListSortOptionsQuery, + useCreateServiceAccountMutation, + useSearchOrgServiceAccountsWithPagingQuery, + useDeleteServiceAccountMutation, + useRetrieveServiceAccountQuery, + useUpdateServiceAccountMutation, + useListTokensQuery, + useCreateTokenMutation, + useDeleteTokenMutation, + useRetrieveJwksQuery, + useGetSharingOptionsQuery, + useCreateDashboardSnapshotMutation, + useDeleteDashboardSnapshotByDeleteKeyQuery, + useDeleteDashboardSnapshotMutation, + useGetDashboardSnapshotQuery, + useCreateTeamMutation, + useSearchTeamsQuery, + useRemoveTeamGroupApiQueryMutation, + useGetTeamGroupsApiQuery, + useAddTeamGroupApiMutation, + useSearchTeamGroupsQuery, + useDeleteTeamByIdMutation, + useGetTeamByIdQuery, + useUpdateTeamMutation, + useGetTeamMembersQuery, + useAddTeamMemberMutation, + useSetTeamMembershipsMutation, + useRemoveTeamMemberMutation, + useUpdateTeamMemberMutation, + useGetTeamPreferencesQuery, + useUpdateTeamPreferencesMutation, + useGetSignedInUserQuery, + useUpdateSignedInUserMutation, + useGetUserAuthTokensQuery, + useUpdateUserEmailQuery, + useClearHelpFlagsQuery, + useSetHelpFlagMutation, + useGetSignedInUserOrgListQuery, + useChangeUserPasswordMutation, + useGetUserPreferencesQuery, + usePatchUserPreferencesMutation, + useUpdateUserPreferencesMutation, + useGetUserQuotasQuery, + useRevokeUserAuthTokenMutation, + useUnstarDashboardByUidMutation, + useStarDashboardByUidMutation, + useGetSignedInUserTeamListQuery, + useUserSetUsingOrgMutation, + useSearchUsersQuery, + useGetUserByLoginOrEmailQuery, + useSearchUsersWithPagingQuery, + useGetUserByIdQuery, + useUpdateUserMutation, + useGetUserOrgListQuery, + useGetUserTeamsQuery, + useRouteGetAlertRulesQuery, + useRoutePostAlertRuleMutation, + useRouteGetAlertRulesExportQuery, + useRouteDeleteAlertRuleMutation, + useRouteGetAlertRuleQuery, + useRoutePutAlertRuleMutation, + useRouteGetAlertRuleExportQuery, + useRouteGetContactpointsQuery, + useRoutePostContactpointsMutation, + useRouteGetContactpointsExportQuery, + useRouteDeleteContactpointsMutation, + useRoutePutContactpointMutation, + useRouteDeleteAlertRuleGroupMutation, + useRouteGetAlertRuleGroupQuery, + useRoutePutAlertRuleGroupMutation, + useRouteGetAlertRuleGroupExportQuery, + useRouteGetMuteTimingsQuery, + useRoutePostMuteTimingMutation, + useRouteExportMuteTimingsQuery, + useRouteDeleteMuteTimingMutation, + useRouteGetMuteTimingQuery, + useRoutePutMuteTimingMutation, + useRouteExportMuteTimingQuery, + useRouteResetPolicyTreeMutation, + useRouteGetPolicyTreeQuery, + useRoutePutPolicyTreeMutation, + useRouteGetPolicyTreeExportQuery, + useRouteGetTemplatesQuery, + useRouteDeleteTemplateMutation, + useRouteGetTemplateQuery, + useRoutePutTemplateMutation, + useListAllProvidersSettingsQuery, + useRemoveProviderSettingsMutation, + useGetProviderSettingsQuery, + useUpdateProviderSettingsMutation, +} = injectedRtkApi; diff --git a/packages/grafana-api-clients/src/clients/rtkq/legacy/index.ts b/packages/grafana-api-clients/src/clients/rtkq/legacy/index.ts new file mode 100644 index 00000000000..722532483b6 --- /dev/null +++ b/packages/grafana-api-clients/src/clients/rtkq/legacy/index.ts @@ -0,0 +1,5 @@ +import { generatedAPI as rawAPI } from './endpoints.gen'; + +export const legacyAPI = rawAPI.enhanceEndpoints({}); + +export * from './endpoints.gen'; diff --git a/packages/grafana-api-clients/src/clients/rtkq/playlist/v0alpha1/endpoints.gen.ts b/packages/grafana-api-clients/src/clients/rtkq/playlist/v0alpha1/endpoints.gen.ts index 7a42a89de07..51bf82c23c6 100644 --- a/packages/grafana-api-clients/src/clients/rtkq/playlist/v0alpha1/endpoints.gen.ts +++ b/packages/grafana-api-clients/src/clients/rtkq/playlist/v0alpha1/endpoints.gen.ts @@ -1,11 +1,15 @@ import { api } from './baseAPI'; -export const addTagTypes = ['Playlist'] as const; +export const addTagTypes = ['API Discovery', 'Playlist'] as const; const injectedRtkApi = api .enhanceEndpoints({ addTagTypes, }) .injectEndpoints({ endpoints: (build) => ({ + getApiResources: build.query({ + query: () => ({ url: `/apis/playlist.grafana.app/v0alpha1/` }), + providesTags: ['API Discovery'], + }), listPlaylist: build.query({ query: (queryArg) => ({ url: `/playlists`, @@ -39,6 +43,29 @@ const injectedRtkApi = api }), invalidatesTags: ['Playlist'], }), + deletecollectionPlaylist: build.mutation({ + query: (queryArg) => ({ + url: `/playlists`, + method: 'DELETE', + params: { + pretty: queryArg.pretty, + continue: queryArg['continue'], + dryRun: queryArg.dryRun, + fieldSelector: queryArg.fieldSelector, + gracePeriodSeconds: queryArg.gracePeriodSeconds, + ignoreStoreReadErrorWithClusterBreakingPotential: queryArg.ignoreStoreReadErrorWithClusterBreakingPotential, + labelSelector: queryArg.labelSelector, + limit: queryArg.limit, + orphanDependents: queryArg.orphanDependents, + propagationPolicy: queryArg.propagationPolicy, + resourceVersion: queryArg.resourceVersion, + resourceVersionMatch: queryArg.resourceVersionMatch, + sendInitialEvents: queryArg.sendInitialEvents, + timeoutSeconds: queryArg.timeoutSeconds, + }, + }), + invalidatesTags: ['Playlist'], + }), getPlaylist: build.query({ query: (queryArg) => ({ url: `/playlists/${queryArg.name}`, @@ -77,10 +104,65 @@ const injectedRtkApi = api }), invalidatesTags: ['Playlist'], }), + updatePlaylist: build.mutation({ + query: (queryArg) => ({ + url: `/playlists/${queryArg.name}`, + method: 'PATCH', + body: queryArg.patch, + params: { + pretty: queryArg.pretty, + dryRun: queryArg.dryRun, + fieldManager: queryArg.fieldManager, + fieldValidation: queryArg.fieldValidation, + force: queryArg.force, + }, + }), + invalidatesTags: ['Playlist'], + }), + getPlaylistStatus: build.query({ + query: (queryArg) => ({ + url: `/playlists/${queryArg.name}/status`, + params: { + pretty: queryArg.pretty, + }, + }), + providesTags: ['Playlist'], + }), + replacePlaylistStatus: build.mutation({ + query: (queryArg) => ({ + url: `/playlists/${queryArg.name}/status`, + method: 'PUT', + body: queryArg.playlist, + params: { + pretty: queryArg.pretty, + dryRun: queryArg.dryRun, + fieldManager: queryArg.fieldManager, + fieldValidation: queryArg.fieldValidation, + }, + }), + invalidatesTags: ['Playlist'], + }), + updatePlaylistStatus: build.mutation({ + query: (queryArg) => ({ + url: `/playlists/${queryArg.name}/status`, + method: 'PATCH', + body: queryArg.patch, + params: { + pretty: queryArg.pretty, + dryRun: queryArg.dryRun, + fieldManager: queryArg.fieldManager, + fieldValidation: queryArg.fieldValidation, + force: queryArg.force, + }, + }), + invalidatesTags: ['Playlist'], + }), }), overrideExisting: false, }); export { injectedRtkApi as generatedAPI }; +export type GetApiResourcesApiResponse = /** status 200 OK */ ApiResourceList; +export type GetApiResourcesApiArg = void; export type ListPlaylistApiResponse = /** status 200 OK */ PlaylistList; export type ListPlaylistApiArg = { /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ @@ -141,6 +223,57 @@ export type CreatePlaylistApiArg = { fieldValidation?: string; playlist: Playlist; }; +export type DeletecollectionPlaylistApiResponse = /** status 200 OK */ Status; +export type DeletecollectionPlaylistApiArg = { + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; + /** The continue option should be set when retrieving more results from the server. Since this value is server defined, clients may only use the continue value from a previous query result with identical query parameters (except for the value of continue) and the server may reject a continue value it does not recognize. If the specified continue value is no longer valid whether due to expiration (generally five to fifteen minutes) or a configuration change on the server, the server will respond with a 410 ResourceExpired error together with a continue token. If the client needs a consistent list, it must restart their list without the continue field. Otherwise, the client may send another list request with the token received with the 410 error, the server will respond with a list starting from the next key, but from the latest snapshot, which is inconsistent from the previous list results - objects that are created, modified, or deleted after the first list request will be included in the response, as long as their keys are after the "next key". + + This field is not supported when watch is true. Clients may start a watch from the last resourceVersion value returned by the server and not miss any modifications. */ + continue?: string; + /** When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed */ + dryRun?: string; + /** A selector to restrict the list of returned objects by their fields. Defaults to everything. */ + fieldSelector?: string; + /** The duration in seconds before the object should be deleted. Value must be non-negative integer. The value zero indicates delete immediately. If this value is nil, the default grace period for the specified type will be used. Defaults to a per object value if not specified. zero means delete immediately. */ + gracePeriodSeconds?: number; + /** if set to true, it will trigger an unsafe deletion of the resource in case the normal deletion flow fails with a corrupt object error. A resource is considered corrupt if it can not be retrieved from the underlying storage successfully because of a) its data can not be transformed e.g. decryption failure, or b) it fails to decode into an object. NOTE: unsafe deletion ignores finalizer constraints, skips precondition checks, and removes the object from the storage. WARNING: This may potentially break the cluster if the workload associated with the resource being unsafe-deleted relies on normal deletion flow. Use only if you REALLY know what you are doing. The default value is false, and the user must opt in to enable it */ + ignoreStoreReadErrorWithClusterBreakingPotential?: boolean; + /** A selector to restrict the list of returned objects by their labels. Defaults to everything. */ + labelSelector?: string; + /** limit is a maximum number of responses to return for a list call. If more items exist, the server will set the `continue` field on the list metadata to a value that can be used with the same initial query to retrieve the next set of results. Setting a limit may return fewer than the requested amount of items (up to zero items) in the event all requested objects are filtered out and clients should only use the presence of the continue field to determine whether more results are available. Servers may choose not to support the limit argument and will return all of the available results. If limit is specified and the continue field is empty, clients may assume that no more results are available. This field is not supported if watch is true. + + The server guarantees that the objects returned when using continue will be identical to issuing a single list call without a limit - that is, no objects created, modified, or deleted after the first request is issued will be included in any subsequent continued requests. This is sometimes referred to as a consistent snapshot, and ensures that a client that is using limit to receive smaller chunks of a very large result can ensure they see all possible objects. If objects are updated during a chunked list the version of the object that was present at the time the first list result was calculated is returned. */ + limit?: number; + /** Deprecated: please use the PropagationPolicy, this field will be deprecated in 1.7. Should the dependent objects be orphaned. If true/false, the "orphan" finalizer will be added to/removed from the object's finalizers list. Either this field or PropagationPolicy may be set, but not both. */ + orphanDependents?: boolean; + /** Whether and how garbage collection will be performed. Either this field or OrphanDependents may be set, but not both. The default policy is decided by the existing finalizer set in the metadata.finalizers and the resource-specific default policy. Acceptable values are: 'Orphan' - orphan the dependents; 'Background' - allow the garbage collector to delete the dependents in the background; 'Foreground' - a cascading policy that deletes all dependents in the foreground. */ + propagationPolicy?: string; + /** resourceVersion sets a constraint on what resource versions a request may be served from. See https://kubernetes.io/docs/reference/using-api/api-concepts/#resource-versions for details. + + Defaults to unset */ + resourceVersion?: string; + /** resourceVersionMatch determines how resourceVersion is applied to list calls. It is highly recommended that resourceVersionMatch be set for list calls where resourceVersion is set See https://kubernetes.io/docs/reference/using-api/api-concepts/#resource-versions for details. + + Defaults to unset */ + resourceVersionMatch?: string; + /** `sendInitialEvents=true` may be set together with `watch=true`. In that case, the watch stream will begin with synthetic events to produce the current state of objects in the collection. Once all such events have been sent, a synthetic "Bookmark" event will be sent. The bookmark will report the ResourceVersion (RV) corresponding to the set of objects, and be marked with `"k8s.io/initial-events-end": "true"` annotation. Afterwards, the watch stream will proceed as usual, sending watch events corresponding to changes (subsequent to the RV) to objects watched. + + When `sendInitialEvents` option is set, we require `resourceVersionMatch` option to also be set. The semantic of the watch request is as following: - `resourceVersionMatch` = NotOlderThan + is interpreted as "data at least as new as the provided `resourceVersion`" + and the bookmark event is send when the state is synced + to a `resourceVersion` at least as fresh as the one provided by the ListOptions. + If `resourceVersion` is unset, this is interpreted as "consistent read" and the + bookmark event is send when the state is synced at least to the moment + when request started being processed. + - `resourceVersionMatch` set to any other value or unset + Invalid error is returned. + + Defaults to true if `resourceVersion=""` or `resourceVersion="0"` (for backward compatibility reasons) and to false otherwise. */ + sendInitialEvents?: boolean; + /** Timeout for the list/watch call. This limits the duration of the call, regardless of any activity or inactivity. */ + timeoutSeconds?: number; +}; export type GetPlaylistApiResponse = /** status 200 OK */ Playlist; export type GetPlaylistApiArg = { /** name of the Playlist */ @@ -179,6 +312,91 @@ export type DeletePlaylistApiArg = { /** Whether and how garbage collection will be performed. Either this field or OrphanDependents may be set, but not both. The default policy is decided by the existing finalizer set in the metadata.finalizers and the resource-specific default policy. Acceptable values are: 'Orphan' - orphan the dependents; 'Background' - allow the garbage collector to delete the dependents in the background; 'Foreground' - a cascading policy that deletes all dependents in the foreground. */ propagationPolicy?: string; }; +export type UpdatePlaylistApiResponse = /** status 200 OK */ Playlist | /** status 201 Created */ Playlist; +export type UpdatePlaylistApiArg = { + /** name of the Playlist */ + name: string; + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; + /** When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed */ + dryRun?: string; + /** fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint. This field is required for apply requests (application/apply-patch) but optional for non-apply patch types (JsonPatch, MergePatch, StrategicMergePatch). */ + fieldManager?: string; + /** fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields. Valid values are: - Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23. - Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default in v1.23+ - Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered. */ + fieldValidation?: string; + /** Force is going to "force" Apply requests. It means user will re-acquire conflicting fields owned by other people. Force flag must be unset for non-apply patch requests. */ + force?: boolean; + patch: Patch; +}; +export type GetPlaylistStatusApiResponse = /** status 200 OK */ Playlist; +export type GetPlaylistStatusApiArg = { + /** name of the Playlist */ + name: string; + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; +}; +export type ReplacePlaylistStatusApiResponse = /** status 200 OK */ Playlist | /** status 201 Created */ Playlist; +export type ReplacePlaylistStatusApiArg = { + /** name of the Playlist */ + name: string; + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; + /** When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed */ + dryRun?: string; + /** fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint. */ + fieldManager?: string; + /** fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields. Valid values are: - Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23. - Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default in v1.23+ - Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered. */ + fieldValidation?: string; + playlist: Playlist; +}; +export type UpdatePlaylistStatusApiResponse = /** status 200 OK */ Playlist | /** status 201 Created */ Playlist; +export type UpdatePlaylistStatusApiArg = { + /** name of the Playlist */ + name: string; + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; + /** When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed */ + dryRun?: string; + /** fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint. This field is required for apply requests (application/apply-patch) but optional for non-apply patch types (JsonPatch, MergePatch, StrategicMergePatch). */ + fieldManager?: string; + /** fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields. Valid values are: - Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23. - Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default in v1.23+ - Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered. */ + fieldValidation?: string; + /** Force is going to "force" Apply requests. It means user will re-acquire conflicting fields owned by other people. Force flag must be unset for non-apply patch requests. */ + force?: boolean; + patch: Patch; +}; +export type ApiResource = { + /** categories is a list of the grouped resources this resource belongs to (e.g. 'all') */ + categories?: string[]; + /** group is the preferred group of the resource. Empty implies the group of the containing resource list. For subresources, this may have a different value, for example: Scale". */ + group?: string; + /** kind is the kind for the resource (e.g. 'Foo' is the kind for a resource 'foo') */ + kind: string; + /** name is the plural name of the resource. */ + name: string; + /** namespaced indicates if a resource is namespaced or not. */ + namespaced: boolean; + /** shortNames is a list of suggested short names of the resource. */ + shortNames?: string[]; + /** singularName is the singular name of the resource. This allows clients to handle plural and singular opaquely. The singularName is more correct for reporting status on a single item and both singular and plural are allowed from the kubectl CLI interface. */ + singularName: string; + /** The hash value of the storage version, the version this resource is converted to when written to the data store. Value must be treated as opaque by clients. Only equality comparison on the value is valid. This is an alpha feature and may change or be removed in the future. The field is populated by the apiserver only if the StorageVersionHash feature gate is enabled. This field will remain optional even if it graduates. */ + storageVersionHash?: string; + /** verbs is a list of supported kube verbs (this includes get, list, watch, create, update, patch, delete, deletecollection, and proxy) */ + verbs: string[]; + /** version is the preferred version of the resource. Empty implies the version of the containing resource list For subresources, this may have a different value, for example: v1 (while inside a v1beta1 version of the core resource's group)". */ + version?: string; +}; +export type ApiResourceList = { + /** APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources */ + apiVersion?: string; + /** groupVersion is the group and version this APIResourceList is for. */ + groupVersion: string; + /** Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds */ + kind?: string; + /** resources contains the name of the resources and if they are namespaced. */ + resources: ApiResource[]; +}; export type Time = string; export type FieldsV1 = object; export type ManagedFieldsEntry = { @@ -377,3 +595,17 @@ export type Status = { /** Status of the operation. One of: "Success" or "Failure". More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status */ status?: string; }; +export type Patch = object; +export const { + useGetApiResourcesQuery, + useListPlaylistQuery, + useCreatePlaylistMutation, + useDeletecollectionPlaylistMutation, + useGetPlaylistQuery, + useReplacePlaylistMutation, + useDeletePlaylistMutation, + useUpdatePlaylistMutation, + useGetPlaylistStatusQuery, + useReplacePlaylistStatusMutation, + useUpdatePlaylistStatusMutation, +} = injectedRtkApi; diff --git a/packages/grafana-api-clients/src/clients/rtkq/provisioning/v0alpha1/endpoints.gen.ts b/packages/grafana-api-clients/src/clients/rtkq/provisioning/v0alpha1/endpoints.gen.ts index 41e4cac3c01..7d566227d1a 100644 --- a/packages/grafana-api-clients/src/clients/rtkq/provisioning/v0alpha1/endpoints.gen.ts +++ b/packages/grafana-api-clients/src/clients/rtkq/provisioning/v0alpha1/endpoints.gen.ts @@ -1,11 +1,15 @@ import { api } from './baseAPI'; -export const addTagTypes = ['Job', 'Repository', 'Provisioning'] as const; +export const addTagTypes = ['API Discovery', 'Job', 'Repository', 'Provisioning'] as const; const injectedRtkApi = api .enhanceEndpoints({ addTagTypes, }) .injectEndpoints({ endpoints: (build) => ({ + getApiResources: build.query({ + query: () => ({ url: `/apis/provisioning.grafana.app/v0alpha1/` }), + providesTags: ['API Discovery'], + }), listJob: build.query({ query: (queryArg) => ({ url: `/jobs`, @@ -100,6 +104,21 @@ const injectedRtkApi = api }), invalidatesTags: ['Job'], }), + updateJob: build.mutation({ + query: (queryArg) => ({ + url: `/jobs/${queryArg.name}`, + method: 'PATCH', + body: queryArg.patch, + params: { + pretty: queryArg.pretty, + dryRun: queryArg.dryRun, + fieldManager: queryArg.fieldManager, + fieldValidation: queryArg.fieldValidation, + force: queryArg.force, + }, + }), + invalidatesTags: ['Job'], + }), listRepository: build.query({ query: (queryArg) => ({ url: `/repositories`, @@ -197,6 +216,21 @@ const injectedRtkApi = api }), invalidatesTags: ['Repository'], }), + updateRepository: build.mutation({ + query: (queryArg) => ({ + url: `/repositories/${queryArg.name}`, + method: 'PATCH', + body: queryArg.patch, + params: { + pretty: queryArg.pretty, + dryRun: queryArg.dryRun, + fieldManager: queryArg.fieldManager, + fieldValidation: queryArg.fieldValidation, + force: queryArg.force, + }, + }), + invalidatesTags: ['Repository'], + }), getRepositoryFiles: build.query({ query: (queryArg) => ({ url: `/repositories/${queryArg.name}/files/`, @@ -336,6 +370,21 @@ const injectedRtkApi = api }), invalidatesTags: ['Repository'], }), + updateRepositoryStatus: build.mutation({ + query: (queryArg) => ({ + url: `/repositories/${queryArg.name}/status`, + method: 'PATCH', + body: queryArg.patch, + params: { + pretty: queryArg.pretty, + dryRun: queryArg.dryRun, + fieldManager: queryArg.fieldManager, + fieldValidation: queryArg.fieldValidation, + force: queryArg.force, + }, + }), + invalidatesTags: ['Repository'], + }), createRepositoryTest: build.mutation({ query: (queryArg) => ({ url: `/repositories/${queryArg.name}/test`, method: 'POST', body: queryArg.body }), invalidatesTags: ['Repository'], @@ -360,6 +409,8 @@ const injectedRtkApi = api overrideExisting: false, }); export { injectedRtkApi as generatedAPI }; +export type GetApiResourcesApiResponse = /** status 200 OK */ ApiResourceList; +export type GetApiResourcesApiArg = void; export type ListJobApiResponse = /** status 200 OK */ JobList; export type ListJobApiArg = { /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ @@ -509,6 +560,22 @@ export type DeleteJobApiArg = { /** Whether and how garbage collection will be performed. Either this field or OrphanDependents may be set, but not both. The default policy is decided by the existing finalizer set in the metadata.finalizers and the resource-specific default policy. Acceptable values are: 'Orphan' - orphan the dependents; 'Background' - allow the garbage collector to delete the dependents in the background; 'Foreground' - a cascading policy that deletes all dependents in the foreground. */ propagationPolicy?: string; }; +export type UpdateJobApiResponse = /** status 200 OK */ Job | /** status 201 Created */ Job; +export type UpdateJobApiArg = { + /** name of the Job */ + name: string; + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; + /** When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed */ + dryRun?: string; + /** fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint. This field is required for apply requests (application/apply-patch) but optional for non-apply patch types (JsonPatch, MergePatch, StrategicMergePatch). */ + fieldManager?: string; + /** fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields. Valid values are: - Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23. - Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default in v1.23+ - Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered. */ + fieldValidation?: string; + /** Force is going to "force" Apply requests. It means user will re-acquire conflicting fields owned by other people. Force flag must be unset for non-apply patch requests. */ + force?: boolean; + patch: Patch; +}; export type ListRepositoryApiResponse = /** status 200 OK */ RepositoryList; export type ListRepositoryApiArg = { /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ @@ -658,6 +725,22 @@ export type DeleteRepositoryApiArg = { /** Whether and how garbage collection will be performed. Either this field or OrphanDependents may be set, but not both. The default policy is decided by the existing finalizer set in the metadata.finalizers and the resource-specific default policy. Acceptable values are: 'Orphan' - orphan the dependents; 'Background' - allow the garbage collector to delete the dependents in the background; 'Foreground' - a cascading policy that deletes all dependents in the foreground. */ propagationPolicy?: string; }; +export type UpdateRepositoryApiResponse = /** status 200 OK */ Repository | /** status 201 Created */ Repository; +export type UpdateRepositoryApiArg = { + /** name of the Repository */ + name: string; + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; + /** When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed */ + dryRun?: string; + /** fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint. This field is required for apply requests (application/apply-patch) but optional for non-apply patch types (JsonPatch, MergePatch, StrategicMergePatch). */ + fieldManager?: string; + /** fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields. Valid values are: - Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23. - Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default in v1.23+ - Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered. */ + fieldValidation?: string; + /** Force is going to "force" Apply requests. It means user will re-acquire conflicting fields owned by other people. Force flag must be unset for non-apply patch requests. */ + force?: boolean; + patch: Patch; +}; export type GetRepositoryFilesApiResponse = /** status 200 OK */ { /** APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources */ apiVersion?: string; @@ -811,6 +894,22 @@ export type ReplaceRepositoryStatusApiArg = { fieldValidation?: string; repository: Repository; }; +export type UpdateRepositoryStatusApiResponse = /** status 200 OK */ Repository | /** status 201 Created */ Repository; +export type UpdateRepositoryStatusApiArg = { + /** name of the Repository */ + name: string; + /** If 'true', then the output is pretty printed. Defaults to 'false' unless the user-agent indicates a browser or command-line HTTP tool (curl and wget). */ + pretty?: string; + /** When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed */ + dryRun?: string; + /** fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint. This field is required for apply requests (application/apply-patch) but optional for non-apply patch types (JsonPatch, MergePatch, StrategicMergePatch). */ + fieldManager?: string; + /** fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields. Valid values are: - Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23. - Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default in v1.23+ - Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered. */ + fieldValidation?: string; + /** Force is going to "force" Apply requests. It means user will re-acquire conflicting fields owned by other people. Force flag must be unset for non-apply patch requests. */ + force?: boolean; + patch: Patch; +}; export type CreateRepositoryTestApiResponse = /** status 200 OK */ TestResults; export type CreateRepositoryTestApiArg = { /** name of the TestResults */ @@ -840,6 +939,38 @@ export type GetFrontendSettingsApiResponse = /** status 200 undefined */ Reposit export type GetFrontendSettingsApiArg = void; export type GetResourceStatsApiResponse = /** status 200 undefined */ ResourceStats; export type GetResourceStatsApiArg = void; +export type ApiResource = { + /** categories is a list of the grouped resources this resource belongs to (e.g. 'all') */ + categories?: string[]; + /** group is the preferred group of the resource. Empty implies the group of the containing resource list. For subresources, this may have a different value, for example: Scale". */ + group?: string; + /** kind is the kind for the resource (e.g. 'Foo' is the kind for a resource 'foo') */ + kind: string; + /** name is the plural name of the resource. */ + name: string; + /** namespaced indicates if a resource is namespaced or not. */ + namespaced: boolean; + /** shortNames is a list of suggested short names of the resource. */ + shortNames?: string[]; + /** singularName is the singular name of the resource. This allows clients to handle plural and singular opaquely. The singularName is more correct for reporting status on a single item and both singular and plural are allowed from the kubectl CLI interface. */ + singularName: string; + /** The hash value of the storage version, the version this resource is converted to when written to the data store. Value must be treated as opaque by clients. Only equality comparison on the value is valid. This is an alpha feature and may change or be removed in the future. The field is populated by the apiserver only if the StorageVersionHash feature gate is enabled. This field will remain optional even if it graduates. */ + storageVersionHash?: string; + /** verbs is a list of supported kube verbs (this includes get, list, watch, create, update, patch, delete, deletecollection, and proxy) */ + verbs: string[]; + /** version is the preferred version of the resource. Empty implies the version of the containing resource list For subresources, this may have a different value, for example: v1 (while inside a v1beta1 version of the core resource's group)". */ + version?: string; +}; +export type ApiResourceList = { + /** APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources */ + apiVersion?: string; + /** groupVersion is the group and version this APIResourceList is for. */ + groupVersion: string; + /** Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds */ + kind?: string; + /** resources contains the name of the resources and if they are namespaced. */ + resources: ApiResource[]; +}; export type Time = string; export type FieldsV1 = object; export type ManagedFieldsEntry = { @@ -1117,6 +1248,7 @@ export type Status = { /** Status of the operation. One of: "Success" or "Failure". More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status */ status?: string; }; +export type Patch = object; export type InlineSecureValue = | { /** Create a secure value -- this is only used for POST/PUT */ @@ -1506,18 +1638,21 @@ export type ResourceStats = { unmanaged?: ResourceCount[]; }; export const { + useGetApiResourcesQuery, useListJobQuery, useCreateJobMutation, useDeletecollectionJobMutation, useGetJobQuery, useReplaceJobMutation, useDeleteJobMutation, + useUpdateJobMutation, useListRepositoryQuery, useCreateRepositoryMutation, useDeletecollectionRepositoryMutation, useGetRepositoryQuery, useReplaceRepositoryMutation, useDeleteRepositoryMutation, + useUpdateRepositoryMutation, useGetRepositoryFilesQuery, useGetRepositoryFilesWithPathQuery, useReplaceRepositoryFilesWithPathMutation, @@ -1533,6 +1668,7 @@ export const { useGetRepositoryResourcesQuery, useGetRepositoryStatusQuery, useReplaceRepositoryStatusMutation, + useUpdateRepositoryStatusMutation, useCreateRepositoryTestMutation, useGetRepositoryWebhookQuery, useCreateRepositoryWebhookMutation, diff --git a/packages/grafana-api-clients/src/clients/rtkq/shorturl/v1alpha1/endpoints.gen.ts b/packages/grafana-api-clients/src/clients/rtkq/shorturl/v1alpha1/endpoints.gen.ts index 9cabcb8ab7b..374c96482a4 100644 --- a/packages/grafana-api-clients/src/clients/rtkq/shorturl/v1alpha1/endpoints.gen.ts +++ b/packages/grafana-api-clients/src/clients/rtkq/shorturl/v1alpha1/endpoints.gen.ts @@ -597,3 +597,17 @@ export type Patch = object; export type GetGoto = { url: string; }; +export const { + useGetApiResourcesQuery, + useListShortUrlQuery, + useCreateShortUrlMutation, + useDeletecollectionShortUrlMutation, + useGetShortUrlQuery, + useReplaceShortUrlMutation, + useDeleteShortUrlMutation, + useUpdateShortUrlMutation, + useGetShortUrlGotoQuery, + useGetShortUrlStatusQuery, + useReplaceShortUrlStatusMutation, + useUpdateShortUrlStatusMutation, +} = injectedRtkApi; diff --git a/packages/grafana-api-clients/src/scripts/generate-rtk-apis.ts b/packages/grafana-api-clients/src/scripts/generate-rtk-apis.ts index 82e1339f9bd..18fd3cbee59 100644 --- a/packages/grafana-api-clients/src/scripts/generate-rtk-apis.ts +++ b/packages/grafana-api-clients/src/scripts/generate-rtk-apis.ts @@ -28,6 +28,7 @@ const createAPIConfig = (app: string, version: string, filterEndpoints?: Endpoin apiFile: `../clients/rtkq/${app}/${version}/baseAPI.ts`, filterEndpoints, tag: true, + hooks: true, ...additional, }, }; @@ -39,6 +40,14 @@ const config: ConfigFile = { exportName: 'generatedAPI', outputFiles: { + // OpenAPI3 client with all endpoints + '../clients/rtkq/legacy/endpoints.gen.ts': { + schemaFile: path.join(basePath, 'public/openapi3.json'), + hooks: true, + tag: true, + apiFile: '../clients/rtkq/legacy/baseAPI.ts', + filterEndpoints: (_name, operation) => !operation.operation.deprecated, + }, '../clients/rtkq/migrate-to-cloud/endpoints.gen.ts': { schemaFile: path.join(basePath, 'public/openapi3.json'), apiFile: '../clients/rtkq/migrate-to-cloud/baseAPI.ts', @@ -77,35 +86,17 @@ const config: ConfigFile = { apiFile: '../clients/rtkq/user/baseAPI.ts', filterEndpoints: ['starDashboardByUid', 'unstarDashboardByUid'], }, - ...createAPIConfig('iam', 'v0alpha1', ['getDisplayMapping']), - ...createAPIConfig('provisioning', 'v0alpha1', filterEndpoints, { hooks: true }), - ...createAPIConfig('folder', 'v1beta1', undefined), - ...createAPIConfig('advisor', 'v0alpha1', [ - 'createCheck', - 'getCheck', - 'listCheck', - 'deleteCheck', - 'updateCheck', - 'listCheckType', - 'updateCheckType', - ]), - ...createAPIConfig('playlist', 'v0alpha1', [ - 'listPlaylist', - 'getPlaylist', - 'createPlaylist', - 'deletePlaylist', - 'replacePlaylist', - ]), - ...createAPIConfig('shorturl', 'v1alpha1'), - ...createAPIConfig('preferences', 'v1alpha1', undefined, { hooks: true }), - ...createAPIConfig('dashboard', 'v0alpha1', ['getSearch']), + ...createAPIConfig('advisor', 'v0alpha1'), ...createAPIConfig('correlations', 'v0alpha1'), + ...createAPIConfig('dashboard', 'v0alpha1'), + ...createAPIConfig('folder', 'v1beta1'), + ...createAPIConfig('iam', 'v0alpha1'), + ...createAPIConfig('playlist', 'v0alpha1'), + ...createAPIConfig('preferences', 'v1alpha1'), + ...createAPIConfig('provisioning', 'v0alpha1'), + ...createAPIConfig('shorturl', 'v1alpha1'), // PLOP_INJECT_API_CLIENT - Used by the API client generator }, }; -function filterEndpoints(name: string) { - return !name.toLowerCase().includes('getapiresources') && !name.toLowerCase().includes('update'); -} - export default config; diff --git a/public/app/api/clients/legacy/index.ts b/public/app/api/clients/legacy/index.ts new file mode 100644 index 00000000000..6a6abcf4054 --- /dev/null +++ b/public/app/api/clients/legacy/index.ts @@ -0,0 +1,6 @@ +import { generatedAPI } from '@grafana/api-clients/rtkq/legacy'; + +export const legacyAPI = generatedAPI.enhanceEndpoints({}); + +// eslint-disable-next-line no-barrel-files/no-barrel-files +export * from '@grafana/api-clients/rtkq/legacy'; diff --git a/public/app/core/reducers/root.ts b/public/app/core/reducers/root.ts index 890879ca7a2..4d26d7bc153 100644 --- a/public/app/core/reducers/root.ts +++ b/public/app/core/reducers/root.ts @@ -3,6 +3,7 @@ import { AnyAction, combineReducers } from 'redux'; import { notificationsAPIv0alpha1, rulesAPIv0alpha1 } from '@grafana/alerting/unstable'; import { allReducers as allApiClientReducers } from '@grafana/api-clients/rtkq'; +import { generatedAPI as legacyAPI } from '@grafana/api-clients/rtkq/legacy'; import sharedReducers from 'app/core/reducers'; import ldapReducers from 'app/features/admin/state/reducers'; import alertingReducers from 'app/features/alerting/state/reducers'; @@ -51,6 +52,7 @@ const rootReducers = { ...templatingReducers, ...supportBundlesReducer, ...authConfigReducers, + [legacyAPI.reducerPath]: legacyAPI.reducer, plugins: pluginsReducer, [alertingApi.reducerPath]: alertingApi.reducer, [notificationsAPIv0alpha1.reducerPath]: notificationsAPIv0alpha1.reducer, diff --git a/public/app/store/configureStore.ts b/public/app/store/configureStore.ts index 5b2771c879a..34a5500268e 100644 --- a/public/app/store/configureStore.ts +++ b/public/app/store/configureStore.ts @@ -4,6 +4,7 @@ import { Middleware } from 'redux'; import { notificationsAPIv0alpha1, rulesAPIv0alpha1 } from '@grafana/alerting/unstable'; import { allMiddleware as allApiClientMiddleware } from '@grafana/api-clients/rtkq'; +import { legacyAPI } from 'app/api/clients/legacy'; import { browseDashboardsAPI } from 'app/features/browse-dashboards/api/browseDashboardsAPI'; import { publicDashboardApi } from 'app/features/dashboard/api/publicDashboardApi'; import { StoreState } from 'app/types/store'; @@ -42,6 +43,7 @@ export function configureStore(initialState?: Partial) { // other Grafana core APIs publicDashboardApi.middleware, browseDashboardsAPI.middleware, + legacyAPI.middleware, ...allApiClientMiddleware, ...extraMiddleware ), From edc7302c2ff51c273decc0de9a02f9e9d561c04e Mon Sep 17 00:00:00 2001 From: Isabel Matwawana <76437239+imatwawana@users.noreply.github.com> Date: Wed, 29 Oct 2025 09:35:53 -0400 Subject: [PATCH 087/378] Docs: Add query variable static options (#113058) --- .../variables/add-template-variables/index.md | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/docs/sources/visualizations/dashboards/variables/add-template-variables/index.md b/docs/sources/visualizations/dashboards/variables/add-template-variables/index.md index 42cea78cf57..69dbf4a2547 100644 --- a/docs/sources/visualizations/dashboards/variables/add-template-variables/index.md +++ b/docs/sources/visualizations/dashboards/variables/add-template-variables/index.md @@ -161,19 +161,10 @@ Query expressions are different for each data source. For more information, refe 1. [Enter general options](#enter-general-options). 1. Under the **Query options** section of the page, select a target data source in the **Data source** drop-down list. - You can also click **Open advanced data source picker** to see more options, including adding a data source (Admins only). For more information about data sources, refer to [Add a data source](ref:add-a-data-source). -1. In the **Query type** drop-down list, select one of the following options: - - **Label names** - - **Label values** - - **Metrics** - - **Query result** - - **Series query** - - **Classic query** - -1. In the **Query** field, enter a query. +1. In the **Query type** drop-down list, select an option and fill in the query fields accordingly. - The query field varies according to your data source. Some data sources have custom query editors. - Each data source defines how the variable values are extracted. The typical implementation uses every string value returned from the data source response as a variable value. Make sure to double-check the documentation for the data source. - Some data sources let you provide custom "display names" for the values. For instance, the PostgreSQL, MySQL, and Microsoft SQL Server plugins handle this by looking for fields named `__text` and `__value` in the result. Other data sources may look for `text` and `value` or use a different approach. Always remember to double-check the documentation for the data source. @@ -185,9 +176,15 @@ Query expressions are different for each data source. For more information, refe - **On dashboard load** - Queries the data source every time the dashboard loads. This slows down dashboard loading, because the variable query needs to be completed before dashboard can be initialized. - **On time range change** - Queries the data source every time the dashboard loads and when the dashboard time range changes. Use this option if your variable options query contains a time range filter or is dependent on the dashboard time range. +1. (Optional) In the **Static options** section of the page, toggle on the **Use static options** switch to add custom options in addition to the query results: + - Make entries in the **Value** and **Display text** fields. + - Click **+ Add new option** to add another static option. + - Repeat these steps as many times as needed. + 1. (Optional) Configure the settings in the [Selection Options](#configure-variable-selection-options) section: - **Multi-value** - Enables multiple values to be selected at the same time. - - **Include All option** - Enables an option to include all variables. + - **Allow custom values** - Enables users to add custom values to the list. + - **Include All option** - Enables an option to include all variables. Enter a value in the **Custom all value** field to set your own "all" option. 1. In the **Preview of values** section, Grafana displays a list of the current variable values. Review them to ensure they match what you expect. 1. Click **Save dashboard**. From c1808a00c2f3741224a8472789b4e6e139b6366a Mon Sep 17 00:00:00 2001 From: Janos Gub Date: Wed, 29 Oct 2025 15:07:56 +0100 Subject: [PATCH 088/378] Adding adaptive telemetry's own weight (#113167) --- pkg/services/navtree/models.go | 1 + pkg/services/navtree/navtreeimpl/applinks.go | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/services/navtree/models.go b/pkg/services/navtree/models.go index 50ccfcb4cdd..8206a45d5ea 100644 --- a/pkg/services/navtree/models.go +++ b/pkg/services/navtree/models.go @@ -21,6 +21,7 @@ const ( WeightAlerting WeightAlertsAndIncidents WeightAIAndML + WeightAdaptiveTelemetry WeightTestingAndSynthetics WeightObservability WeightCloudServiceProviders diff --git a/pkg/services/navtree/navtreeimpl/applinks.go b/pkg/services/navtree/navtreeimpl/applinks.go index 7a2f15206dc..e3fea6da25e 100644 --- a/pkg/services/navtree/navtreeimpl/applinks.go +++ b/pkg/services/navtree/navtreeimpl/applinks.go @@ -344,7 +344,7 @@ func (s *ServiceImpl) addPluginToSection(c *contextmodel.ReqContext, treeRoot *n Id: navtree.NavIDAdaptiveTelemetry, SubTitle: "Reduce noise, cut costs, and accelerate troubleshooting by intelligently ingesting only the telemetry data that matters most.", Icon: "adaptive-telemetry", - SortWeight: navtree.WeightAIAndML + 1, // Place under "AI & Machine Learning" + SortWeight: navtree.WeightAdaptiveTelemetry, Children: sectionChildren, Url: "adaptive-telemetry", // Use the icon URL from the first "Adaptive Telemetry" plugin in the list (they will all be the same) From 7dbacddb180c11e518c046886840b3977ff7cc09 Mon Sep 17 00:00:00 2001 From: Matheus Macabu Date: Wed, 29 Oct 2025 15:08:43 +0100 Subject: [PATCH 089/378] CloudMigrations: Check contact point permissions before fetching it (#113159) --- .../cloudmigrationimpl/cloudmigration_test.go | 13 +++++++++++-- .../cloudmigrationimpl/snapshot_mgmt_alerts.go | 10 ++++++++++ .../cloudmigrationimpl/snapshot_mgmt_alerts_test.go | 7 +------ .../cloudmigrationimpl/xorm_store_test.go | 2 +- 4 files changed, 23 insertions(+), 9 deletions(-) diff --git a/pkg/services/cloudmigration/cloudmigrationimpl/cloudmigration_test.go b/pkg/services/cloudmigration/cloudmigrationimpl/cloudmigration_test.go index 449a0ee0817..2d393236801 100644 --- a/pkg/services/cloudmigration/cloudmigrationimpl/cloudmigration_test.go +++ b/pkg/services/cloudmigration/cloudmigrationimpl/cloudmigration_test.go @@ -40,6 +40,7 @@ import ( "github.com/grafana/grafana/pkg/services/ngalert/models" ngalertstore "github.com/grafana/grafana/pkg/services/ngalert/store" ngalertfakes "github.com/grafana/grafana/pkg/services/ngalert/tests/fakes" + "github.com/grafana/grafana/pkg/services/pluginsintegration/pluginaccesscontrol" "github.com/grafana/grafana/pkg/services/pluginsintegration/pluginsettings" "github.com/grafana/grafana/pkg/services/pluginsintegration/pluginstore" "github.com/grafana/grafana/pkg/services/quota/quotatest" @@ -790,7 +791,15 @@ func TestGetPlugins(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) t.Cleanup(cancel) - user := &user.SignedInUser{OrgID: 1} + user := &user.SignedInUser{ + OrgID: 1, + Permissions: map[int64]map[string][]string{ + 1: { + pluginaccesscontrol.ActionInstall: {pluginaccesscontrol.ScopeProvider.GetResourceAllScope()}, + pluginaccesscontrol.ActionWrite: {pluginaccesscontrol.ScopeProvider.GetResourceAllScope()}, + }, + }, + } s.pluginStore = pluginstore.NewFakePluginStore([]pluginstore.Plugin{ { @@ -1001,7 +1010,7 @@ func setUpServiceTest(t *testing.T, cfgOverrides ...configOverrides) cloudmigrat mockFolder, &pluginstore.FakePluginStore{}, &pluginsettings.FakePluginSettings{}, - actest.FakeAccessControl{ExpectedEvaluate: true}, + accessControl, fakeAccessControlService, kvstore.ProvideService(sqlStore), &libraryelementsfake.LibraryElementService{}, diff --git a/pkg/services/cloudmigration/cloudmigrationimpl/snapshot_mgmt_alerts.go b/pkg/services/cloudmigration/cloudmigrationimpl/snapshot_mgmt_alerts.go index a279c09d9db..ae9a1ef52ed 100644 --- a/pkg/services/cloudmigration/cloudmigrationimpl/snapshot_mgmt_alerts.go +++ b/pkg/services/cloudmigration/cloudmigrationimpl/snapshot_mgmt_alerts.go @@ -9,9 +9,12 @@ import ( "github.com/prometheus/common/model" "github.com/grafana/grafana/pkg/components/simplejson" + ac "github.com/grafana/grafana/pkg/services/accesscontrol" ngalertapi "github.com/grafana/grafana/pkg/services/ngalert/api/compat" "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions" + "github.com/grafana/grafana/pkg/services/ngalert/models" "github.com/grafana/grafana/pkg/services/ngalert/provisioning" + "github.com/grafana/grafana/pkg/services/org" "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/setting" ) @@ -79,6 +82,13 @@ type contactPoint struct { } func (s *Service) getContactPoints(ctx context.Context, signedInUser *user.SignedInUser) ([]contactPoint, error) { + userIsOrgAdmin := signedInUser.HasRole(org.RoleAdmin) + hasAccess, _ := s.accessControl.Evaluate(ctx, signedInUser, ac.EvalPermission(ac.ActionAlertingReceiversReadSecrets, models.ScopeReceiversAll)) + if !userIsOrgAdmin && !hasAccess { + msg := "user '%s' is not allowed to read contact point secrets, missing 'alert.notifications.receivers.secrets:read' permission, which can be granted through the 'Admin' or 'Alerting > Full admin access' roles" + return nil, fmt.Errorf(msg, signedInUser.UserUID) + } + query := provisioning.ContactPointQuery{ OrgID: signedInUser.GetOrgID(), Decrypt: true, // needed to recreate the settings in the target instance. diff --git a/pkg/services/cloudmigration/cloudmigrationimpl/snapshot_mgmt_alerts_test.go b/pkg/services/cloudmigration/cloudmigrationimpl/snapshot_mgmt_alerts_test.go index ec50629c24b..611b10c317b 100644 --- a/pkg/services/cloudmigration/cloudmigrationimpl/snapshot_mgmt_alerts_test.go +++ b/pkg/services/cloudmigration/cloudmigrationimpl/snapshot_mgmt_alerts_test.go @@ -5,7 +5,6 @@ import ( "encoding/json" "errors" "fmt" - "net/http" "testing" "time" @@ -13,7 +12,6 @@ import ( "github.com/prometheus/alertmanager/pkg/labels" "github.com/stretchr/testify/require" - "github.com/grafana/grafana/pkg/apimachinery/errutil" "github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/dashboards" @@ -127,10 +125,7 @@ func TestGetContactPoints(t *testing.T) { contactPoints, err := s.getContactPoints(ctx, user) require.Nil(t, contactPoints) - - gfErr := errutil.Error{} - require.ErrorAs(t, err, &gfErr) - require.Equal(t, http.StatusForbidden, gfErr.Reason.Status().HTTPStatus()) + require.Contains(t, err.Error(), "alert.notifications.receivers.secrets:read") }) } diff --git a/pkg/services/cloudmigration/cloudmigrationimpl/xorm_store_test.go b/pkg/services/cloudmigration/cloudmigrationimpl/xorm_store_test.go index 2d84b257a5a..6abb63ce54e 100644 --- a/pkg/services/cloudmigration/cloudmigrationimpl/xorm_store_test.go +++ b/pkg/services/cloudmigration/cloudmigrationimpl/xorm_store_test.go @@ -822,7 +822,7 @@ func TestEncodeDecode(t *testing.T) { Private: grafanaPrivateKey[:], }, crypto.NewNacl(), - "", + t.TempDir(), ) require.NoError(t, err) From 2472555af0d7e488c424478e08131d4badbdfaa4 Mon Sep 17 00:00:00 2001 From: Brendan O'Handley Date: Wed, 29 Oct 2025 10:15:20 -0400 Subject: [PATCH 090/378] Add to dashboard: expose add to dashboard form component for external apps (#112609) * add extension for drilldown to add to dashboard * reuse configure add to dashboard function callback * structure for drilldown add to dashboard * fix imports * fix tests * expose as a component * remove extension link * get component ready to extend * lazy load component * add component to exposed component registry * update folder structure to not work in explore folder * keep dependencies clean * nice structure to let folks know this is a drilldown integration * update code owners for new file * make exposed component more generic, step one, update component id * step 2, expose add to dashboard form component * add more explicit useAbsolutePath option to form * remove old implementation code for drilldown specific component * commit translation * add comments to avoid breaking changes * add e2e test for add to dashboard form component * fix flaky test * add exposed component id to e2e test app * remove gridPos in buildPanel fallback fn * add code comment for useAbsolutePath's purpose * remove gridPos from e2e test --- .../pages/ExposedComponents.tsx | 17 ++++++++ .../grafana-extensionstest-app/plugin.json | 2 +- .../tests/useExposedComponent.spec.ts | 30 ++++++++++++++ .../src/types/pluginExtensions.ts | 1 + .../addToDashboard/AddToDashboardForm.tsx | 14 ++++++- .../AddToDashboardFormExposedComponent.tsx | 41 +++++++++++++++++++ .../addToDashboard/addToDashboard.ts | 17 +++++++- .../plugins/extensions/registry/setup.ts | 7 ++++ public/locales/en-US/grafana.json | 5 +++ 9 files changed, 130 insertions(+), 4 deletions(-) create mode 100644 public/app/features/dashboard-scene/addToDashboard/AddToDashboardFormExposedComponent.tsx diff --git a/e2e-playwright/test-plugins/grafana-extensionstest-app/pages/ExposedComponents.tsx b/e2e-playwright/test-plugins/grafana-extensionstest-app/pages/ExposedComponents.tsx index 28775391881..6b284e171bc 100644 --- a/e2e-playwright/test-plugins/grafana-extensionstest-app/pages/ExposedComponents.tsx +++ b/e2e-playwright/test-plugins/grafana-extensionstest-app/pages/ExposedComponents.tsx @@ -10,6 +10,7 @@ export function ExposedComponents() { const { component: ReusableComponent } = usePluginComponent( 'grafana-extensionexample1-app/reusable-component/v1' ); + const { component: AddToDashboardForm } = usePluginComponent('grafana/add-to-dashboard-form/v1'); if (!ReusableComponent) { return null; @@ -20,6 +21,22 @@ export function ExposedComponents() {
+ {AddToDashboardForm && ( +
+

Save to dashboard (exposed form)

+ ({ + type: 'timeseries', + title: 'E2E Add to Dashboard Panel', + targets: [], + })} + // Ensure navigation works correctly from plugin page + options={{ useAbsolutePath: true }} + onClose={() => {}} + /> +
+ )} ); } diff --git a/e2e-playwright/test-plugins/grafana-extensionstest-app/plugin.json b/e2e-playwright/test-plugins/grafana-extensionstest-app/plugin.json index 90978c2c8a2..57fa87dcde5 100644 --- a/e2e-playwright/test-plugins/grafana-extensionstest-app/plugin.json +++ b/e2e-playwright/test-plugins/grafana-extensionstest-app/plugin.json @@ -80,7 +80,7 @@ "grafanaDependency": ">=10.4.0", "plugins": [], "extensions": { - "exposedComponents": ["grafana-extensionexample1-app/reusable-component/v1"] + "exposedComponents": ["grafana-extensionexample1-app/reusable-component/v1", "grafana/add-to-dashboard-form/v1"] } } } diff --git a/e2e-playwright/test-plugins/grafana-extensionstest-app/tests/useExposedComponent.spec.ts b/e2e-playwright/test-plugins/grafana-extensionstest-app/tests/useExposedComponent.spec.ts index 9f3d3f0bf35..501c929b612 100644 --- a/e2e-playwright/test-plugins/grafana-extensionstest-app/tests/useExposedComponent.spec.ts +++ b/e2e-playwright/test-plugins/grafana-extensionstest-app/tests/useExposedComponent.spec.ts @@ -1,6 +1,7 @@ import { test, expect } from '@grafana/plugin-e2e'; import { testIds } from '../testIds'; import pluginJson from '../plugin.json'; +import { ensureExtensionRegistryIsPopulated } from './utils'; test.describe( 'grafana-extensionstest-app', @@ -12,5 +13,34 @@ test.describe( await page.goto(`/a/${pluginJson.id}/exposed-components`); await expect(page.getByTestId(testIds.appB.exposedComponent)).toHaveText('Hello World!'); }); + + test('exposed add-to-dashboard form saves to a new dashboard', async ({ page }) => { + await page.goto(`/a/${pluginJson.id}/exposed-components`); + await ensureExtensionRegistryIsPopulated(page); + + // Wait for the exposed form section to be ready + await expect(page.getByRole('heading', { name: 'Save to dashboard (exposed form)' })).toBeVisible(); + + // Wait for any of the form buttons to render (lazy load) before clicking + const openInNewTab = page.getByRole('button', { name: 'Open in new tab' }); + const cancelBtn = page.getByRole('button', { name: 'Cancel' }); + await Promise.race([expect(openInNewTab).toBeVisible(), expect(cancelBtn).toBeVisible()]); + + // Now wait for the submit button to be visible, then click (role or text) + const openDashboardByRole = page.getByRole('button', { name: 'Open dashboard' }); + const openDashboardByText = page.getByText('Open dashboard'); + if (await openDashboardByRole.isVisible().catch(() => false)) { + await openDashboardByRole.click(); + } else { + await expect(openDashboardByText.first()).toBeVisible(); + await openDashboardByText.first().click(); + } + + // Navigates to /dashboard/new and prepopulates a panel from local storage + await expect(page).toHaveURL(/\/dashboard\/new/); + + // Panel should be created with our custom title + await expect(page.getByText('E2E Add to Dashboard Panel').first()).toBeVisible(); + }); } ); diff --git a/packages/grafana-data/src/types/pluginExtensions.ts b/packages/grafana-data/src/types/pluginExtensions.ts index 47e130afcce..4b988c49a0a 100644 --- a/packages/grafana-data/src/types/pluginExtensions.ts +++ b/packages/grafana-data/src/types/pluginExtensions.ts @@ -230,6 +230,7 @@ export enum PluginExtensionPointPatterns { // Extension Points available in plugins export enum PluginExtensionExposedComponents { CentralAlertHistorySceneV1 = 'grafana/central-alert-history-scene/v1', + AddToDashboardFormV1 = 'grafana/add-to-dashboard-form/v1', } export type PluginExtensionPanelContext = { diff --git a/public/app/features/dashboard-scene/addToDashboard/AddToDashboardForm.tsx b/public/app/features/dashboard-scene/addToDashboard/AddToDashboardForm.tsx index 17ecf87eb8f..85f3e47ae03 100644 --- a/public/app/features/dashboard-scene/addToDashboard/AddToDashboardForm.tsx +++ b/public/app/features/dashboard-scene/addToDashboard/AddToDashboardForm.tsx @@ -41,7 +41,11 @@ export interface Props { children?: React.ReactNode; } -export function AddToDashboardForm({ +/** + * Internal implementation used by the exposed versioned wrapper. + * For stability/versioning guidance, refer to AddToDashboardFormExposedComponent. + */ +export function AddToDashboardForm({ onClose, buildPanel, timeRange, @@ -91,7 +95,7 @@ export function AddToDashboardForm({ queries: panel.targets, }); - const error = addToDashboard({ dashboardUid, panel, openInNewTab, timeRange }); + const error = addToDashboard({ dashboardUid, panel, openInNewTab, timeRange, options }); if (error) { setSubmissionError(error); return; @@ -202,3 +206,9 @@ function assertIsSaveToExistingDashboardError( // explicitly assert its type so that TS can narrow down FormDTO to SaveToExistingDashboard // when we use it in the form. } + +export interface AbsolutePathOptions { + useAbsolutePath: boolean; +} + +export default AddToDashboardForm; diff --git a/public/app/features/dashboard-scene/addToDashboard/AddToDashboardFormExposedComponent.tsx b/public/app/features/dashboard-scene/addToDashboard/AddToDashboardFormExposedComponent.tsx new file mode 100644 index 00000000000..3111700e1ee --- /dev/null +++ b/public/app/features/dashboard-scene/addToDashboard/AddToDashboardFormExposedComponent.tsx @@ -0,0 +1,41 @@ +import { lazy, Suspense } from 'react'; + +import { t } from '@grafana/i18n'; + +import { AbsolutePathOptions, Props } from './AddToDashboardForm'; + +// Lazy load the component +const AddToDashboardFormLazy = lazy(() => import('./AddToDashboardForm')); + +/** + * EXPOSED COMPONENT (stable): grafana/add-to-dashboard-form/v1 + * + * This component is exposed to plugins via the Plugin Extensions system. + * Treat its props and user-visible behavior as a stable contract. Do not make + * breaking changes in-place. If you need to change the API or behavior in a + * breaking way, create a new versioned component (e.g. AddToDashboardFormV2) + * and register it under a new ID: "grafana/add-to-dashboard-form/v2". + * + * Consumers should import it using the exposed component ID and pass only the + * supported props. The default buildPanel creates a time series panel; callers + * can supply a custom builder via "buildPanel". + */ +export const AddToDashboardFormExposedComponent = (props: Partial>) => ( + + {})} + buildPanel={ + props.buildPanel ?? + (() => ({ + type: 'timeseries', + title: t('dashboard-scene.add-to-dashboard-form-exposed.title.new-panel', 'New panel'), + targets: [], + })) + } + timeRange={props.timeRange} + options={props.options} + > + {props.children} + + +); diff --git a/public/app/features/dashboard-scene/addToDashboard/addToDashboard.ts b/public/app/features/dashboard-scene/addToDashboard/addToDashboard.ts index e22feb9a502..dfb375fced0 100644 --- a/public/app/features/dashboard-scene/addToDashboard/addToDashboard.ts +++ b/public/app/features/dashboard-scene/addToDashboard/addToDashboard.ts @@ -26,6 +26,9 @@ interface AddPanelToDashboardOptions { dashboardUid?: string; openInNewTab?: boolean; timeRange?: TimeRange; + options?: { + useAbsolutePath?: boolean; + }; } export function addToDashboard({ @@ -33,6 +36,7 @@ export function addToDashboard({ dashboardUid, openInNewTab, timeRange, + options, }: AddPanelToDashboardOptions): SubmissionError | undefined { let dto: DashboardDTO = { meta: {}, @@ -83,7 +87,18 @@ export function addToDashboard({ return; } - locationService.push(locationUtil.stripBaseFromUrl(dashboardURL)); + let navigateToDashboardUrl = locationUtil.stripBaseFromUrl(dashboardURL); + + // External apps need absolute paths to navigate to dashboards correctly. + // Without the leading '/', paths like "dashboard/new" are treated as relative to the current location. + // For example, from "/a/grafana-metricsdrilldown-app", this would incorrectly navigate to + // "/a/grafana-metricsdrilldown-app/dashboard/new" instead of "/dashboard/new". + if (options?.useAbsolutePath) { + navigateToDashboardUrl = '/' + navigateToDashboardUrl; + } + + locationService.push(navigateToDashboardUrl); + return; } diff --git a/public/app/features/plugins/extensions/registry/setup.ts b/public/app/features/plugins/extensions/registry/setup.ts index c4057e22c4b..bb25c487dc3 100644 --- a/public/app/features/plugins/extensions/registry/setup.ts +++ b/public/app/features/plugins/extensions/registry/setup.ts @@ -1,5 +1,6 @@ import { PluginExtensionExposedComponents } from '@grafana/data'; import CentralAlertHistorySceneExposedComponent from 'app/features/alerting/unified/components/rules/central-state-history/CentralAlertHistorySceneExposedComponent'; +import { AddToDashboardFormExposedComponent } from 'app/features/dashboard-scene/addToDashboard/AddToDashboardFormExposedComponent'; import { getCoreExtensionConfigurations } from '../getCoreExtensionConfigurations'; @@ -36,5 +37,11 @@ exposedComponentsRegistry.register({ description: 'Central alert history scene', component: CentralAlertHistorySceneExposedComponent, }, + { + id: PluginExtensionExposedComponents.AddToDashboardFormV1, + title: 'Add to dashboard form', + description: 'Add to dashboard form', + component: AddToDashboardFormExposedComponent, + }, ], }); diff --git a/public/locales/en-US/grafana.json b/public/locales/en-US/grafana.json index e8c29e9ffe7..3c0c17c7af2 100644 --- a/public/locales/en-US/grafana.json +++ b/public/locales/en-US/grafana.json @@ -5702,6 +5702,11 @@ "open-in-new-tab": "Open in new tab", "title-error-adding-the-panel": "Error adding the panel" }, + "add-to-dashboard-form-exposed": { + "title": { + "new-panel": "New panel" + } + }, "annotation-settings-edit": { "back-to-list": "Back to list", "delete": "Delete", From 19826b5b2616f9aef013893f97086bc88b4ffe69 Mon Sep 17 00:00:00 2001 From: Haris Rozajac <58232930+harisrozajac@users.noreply.github.com> Date: Wed, 29 Oct 2025 08:15:43 -0600 Subject: [PATCH 091/378] Dashboard Save: Fix the issue of clicking Save button that wouldn't trigger save (#113134) * fix the issue of clicking Save button that wouldn't trigger save * clean up --- eslint-suppressions.json | 5 -- .../saving/SaveDashboardAsForm.tsx | 61 +++++++++++++------ 2 files changed, 42 insertions(+), 24 deletions(-) diff --git a/eslint-suppressions.json b/eslint-suppressions.json index fdcf848a354..c704beaefc3 100644 --- a/eslint-suppressions.json +++ b/eslint-suppressions.json @@ -2110,11 +2110,6 @@ "count": 1 } }, - "public/app/features/dashboard-scene/saving/SaveDashboardAsForm.tsx": { - "no-restricted-syntax": { - "count": 4 - } - }, "public/app/features/dashboard-scene/saving/SaveDashboardForm.tsx": { "no-restricted-syntax": { "count": 1 diff --git a/public/app/features/dashboard-scene/saving/SaveDashboardAsForm.tsx b/public/app/features/dashboard-scene/saving/SaveDashboardAsForm.tsx index 8f0a383d80f..896c2fa3474 100644 --- a/public/app/features/dashboard-scene/saving/SaveDashboardAsForm.tsx +++ b/public/app/features/dashboard-scene/saving/SaveDashboardAsForm.tsx @@ -1,5 +1,4 @@ -import debounce from 'debounce-promise'; -import { ChangeEvent, useState, useEffect } from 'react'; +import { ChangeEvent, useCallback, useEffect, useRef, useState } from 'react'; import { UseFormSetValue, useForm } from 'react-hook-form'; import { selectors } from '@grafana/e2e-selectors'; @@ -43,19 +42,48 @@ export function SaveDashboardAsForm({ dashboard, changeInfo }: Props) { }, }); - const { errors, isValid, validatingFields } = formState; + const { errors, isValid } = formState; const formValues = watch(); const { state, onSaveDashboard } = useSaveDashboard(false); const [contentSent, setContentSent] = useState<{ title?: string; folderUid?: string }>({}); + const validationTimeoutRef = useRef(); + // Validate title on form mount to catch invalid default values useEffect(() => { trigger('title'); }, [trigger]); + // Cleanup timeout on unmount + useEffect(() => { + return () => { + clearTimeout(validationTimeoutRef.current); + }; + }, []); + + const handleTitleChange = useCallback( + (e: ChangeEvent) => { + setValue('title', e.target.value, { shouldDirty: true }); + clearTimeout(validationTimeoutRef.current); + validationTimeoutRef.current = setTimeout(() => { + trigger('title'); + }, 400); + }, + [setValue, trigger] + ); + const onSave = async (overwrite: boolean) => { + clearTimeout(validationTimeoutRef.current); + + const isTitleValid = await trigger('title'); + + // This prevents the race between the new input and old validation state + if (!isTitleValid) { + return; + } + const data = getValues(); const result = await onSaveDashboard(dashboard, { @@ -88,16 +116,7 @@ export function SaveDashboardAsForm({ dashboard, changeInfo }: Props) { ); const saveButton = (overwrite: boolean) => { - const isTitleValidating = !!validatingFields.title; - - return ( - - ); + return ; }; function renderFooter(error?: Error) { const formValuesMatchContentSent = @@ -128,23 +147,27 @@ export function SaveDashboardAsForm({ dashboard, changeInfo }: Props) { return (
onSave(false))}> - } invalid={!!errors.title} error={errors.title?.message}> + } + invalid={!!errors.title} + error={errors.title?.message} + > ) => { - setValue('title', e.target.value, { shouldValidate: true }); - }, 400)} /> } invalid={!!errors.description} error={errors.description?.message} @@ -159,7 +182,7 @@ export function SaveDashboardAsForm({ dashboard, changeInfo }: Props) { /> - + { setValue('folder', { uid, title }); @@ -177,7 +200,7 @@ export function SaveDashboardAsForm({ dashboard, changeInfo }: Props) { /> {!changeInfo.isNew && ( - + )} From 87794bec12ec660e9805edccbf59944230da16f8 Mon Sep 17 00:00:00 2001 From: Gilles De Mey Date: Wed, 29 Oct 2025 15:21:05 +0100 Subject: [PATCH 092/378] Alerting: Add instances with no label value to an ungrouped group (#113170) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit add instances with no label value to an ungrouped group in alerting triage – these will be collapsed by default --- .../unified/triage/rows/FolderGroupRow.tsx | 3 +- .../alerting/unified/triage/rows/GroupRow.tsx | 15 +++++++-- .../alerting/unified/triage/rows/utils.ts | 6 ++-- .../unified/triage/scene/Workbench.tsx | 32 +++++++++++++------ .../alerting/unified/triage/scene/utils.ts | 9 ++---- .../features/alerting/unified/triage/types.ts | 5 ++- 6 files changed, 46 insertions(+), 24 deletions(-) diff --git a/public/app/features/alerting/unified/triage/rows/FolderGroupRow.tsx b/public/app/features/alerting/unified/triage/rows/FolderGroupRow.tsx index 4809a44573a..1e5e1156452 100644 --- a/public/app/features/alerting/unified/triage/rows/FolderGroupRow.tsx +++ b/public/app/features/alerting/unified/triage/rows/FolderGroupRow.tsx @@ -1,4 +1,5 @@ import { css } from '@emotion/css'; +import { isString } from 'lodash'; import React from 'react'; import { GrafanaTheme2 } from '@grafana/data'; @@ -27,7 +28,7 @@ export const FolderGroupRow = ({ row, leftColumnWidth, rowKey, depth = 0, childr title={ - {row.metadata.value} + {isString(row.metadata.value) && {row.metadata.value}} } isOpenByDefault={true} diff --git a/public/app/features/alerting/unified/triage/rows/GroupRow.tsx b/public/app/features/alerting/unified/triage/rows/GroupRow.tsx index 4499672dd6e..1bb73674165 100644 --- a/public/app/features/alerting/unified/triage/rows/GroupRow.tsx +++ b/public/app/features/alerting/unified/triage/rows/GroupRow.tsx @@ -5,9 +5,10 @@ import { AlertLabel } from '@grafana/alerting/unstable'; import { GrafanaTheme2 } from '@grafana/data'; import { useStyles2 } from '@grafana/ui'; -import { GenericGroupedRow } from '../types'; +import { EmptyLabelValue, GenericGroupedRow } from '../types'; import { GenericRow } from './GenericRow'; +import { formatLabelValue } from './utils'; interface GroupRowProps { row: GenericGroupedRow; @@ -19,13 +20,21 @@ interface GroupRowProps { export const GroupRow = ({ row, leftColumnWidth, rowKey, depth = 0, children }: GroupRowProps) => { const styles = useStyles2(getStyles); + const isEmptyValue = row.metadata.value === EmptyLabelValue; return ( } - isOpenByDefault={true} + title={ + + } + isOpenByDefault={!isEmptyValue} leftColumnClassName={styles.groupRow} rightColumnClassName={styles.groupRow} depth={depth} diff --git a/public/app/features/alerting/unified/triage/rows/utils.ts b/public/app/features/alerting/unified/triage/rows/utils.ts index 6a4d0731643..d5b193ee755 100644 --- a/public/app/features/alerting/unified/triage/rows/utils.ts +++ b/public/app/features/alerting/unified/triage/rows/utils.ts @@ -1,4 +1,4 @@ -import { WorkbenchRow } from '../types'; +import { EmptyLabelValue, LabelValue, WorkbenchRow } from '../types'; // Generate unique keys for WorkbenchRow items export function generateRowKey(row: WorkbenchRow, fallbackIndex: number): string { @@ -8,6 +8,8 @@ export function generateRowKey(row: WorkbenchRow, fallbackIndex: number): string } else { // For GenericGroupedRow, create key from label and value const groupedRow = row; - return `group-${groupedRow.metadata.label}-${groupedRow.metadata.value}`; + return `group-${groupedRow.metadata.label}-${formatLabelValue(groupedRow.metadata.value)}`; } } + +export const formatLabelValue = (value: LabelValue): string => (value === EmptyLabelValue ? '' : value); diff --git a/public/app/features/alerting/unified/triage/scene/Workbench.tsx b/public/app/features/alerting/unified/triage/scene/Workbench.tsx index 356a2924461..f202a5cd0a0 100644 --- a/public/app/features/alerting/unified/triage/scene/Workbench.tsx +++ b/public/app/features/alerting/unified/triage/scene/Workbench.tsx @@ -1,3 +1,4 @@ +import { isEmpty } from 'lodash'; import { ArrayValues } from 'type-fest'; import { DataFrame, PanelData } from '@grafana/data'; @@ -6,7 +7,7 @@ import { useQueryRunner, useTimeRange, useVariableValues } from '@grafana/scenes import { Workbench } from '../Workbench'; import { DEFAULT_FIELDS, METRIC_NAME, VARIABLES } from '../constants'; -import { AlertRuleRow, GenericGroupedRow, WorkbenchRow } from '../types'; +import { AlertRuleRow, EmptyLabelValue, GenericGroupedRow, WorkbenchRow } from '../types'; import { convertTimeRangeToDomain, getDataQuery, useQueryFilter } from './utils'; @@ -79,29 +80,40 @@ function groupData(dataPoints: DataPoint[], groupBy: string[], depth: number): W } const groupByKey = groupBy[depth]; - const grouped = new Map(); + const grouped = new Map(); for (const dp of dataPoints) { - const key = String(dp[groupByKey] ?? 'undefined'); - if (!grouped.has(key)) { - grouped.set(key, []); + const mapKey = dp[groupByKey] ?? EmptyLabelValue; + if (!grouped.has(mapKey)) { + grouped.set(mapKey, []); } - grouped.get(key)?.push(dp); + grouped.get(mapKey)?.push(dp); } const result: GenericGroupedRow[] = []; + const emptyGroups: GenericGroupedRow[] = []; + for (const [value, rows] of grouped.entries()) { - result.push({ + const labelValue = isEmpty(value) ? EmptyLabelValue : value; + + const group: GenericGroupedRow = { type: 'group', metadata: { label: groupByKey, - value: value, + value: labelValue, }, rows: groupData(rows, groupBy, depth + 1), - }); + }; + + // Separate empty label groups to append at the end + if (group.metadata.value === EmptyLabelValue) { + emptyGroups.push(group); + } else { + result.push(group); + } } - return result; + return [...result, ...emptyGroups]; } // @TODO narrower types for PanelData! (if possible) diff --git a/public/app/features/alerting/unified/triage/scene/utils.ts b/public/app/features/alerting/unified/triage/scene/utils.ts index 19886a760e0..456e3f3c7bf 100644 --- a/public/app/features/alerting/unified/triage/scene/utils.ts +++ b/public/app/features/alerting/unified/triage/scene/utils.ts @@ -1,6 +1,6 @@ import { TimeRange } from '@grafana/data'; import { SceneDataQuery } from '@grafana/scenes'; -import { useVariableValue, useVariableValues } from '@grafana/scenes-react'; +import { useVariableValue } from '@grafana/scenes-react'; import { DataSourceRef } from '@grafana/schema'; import { DATASOURCE_UID, VARIABLES } from '../constants'; @@ -44,11 +44,6 @@ export function convertTimeRangeToDomain(timeRange: TimeRange): Domain { * This hook will create a Prometheus label matcher string from the "groupBy" and "filters" variables */ export function useQueryFilter(): string { - const [groupBy = []] = useVariableValues(VARIABLES.groupBy); const [filters = ''] = useVariableValue(VARIABLES.filters); - - const groupByFilter = stringifyGroupFilter(groupBy); - const queryFilter = [groupByFilter, filters].filter((s) => Boolean(s)).join(','); - - return queryFilter; + return filters; } diff --git a/public/app/features/alerting/unified/triage/types.ts b/public/app/features/alerting/unified/triage/types.ts index b599f46cb33..c878f8f303c 100644 --- a/public/app/features/alerting/unified/triage/types.ts +++ b/public/app/features/alerting/unified/triage/types.ts @@ -18,7 +18,10 @@ export interface GenericGroupedRow { type: 'group'; metadata: { label: string; - value: string; + value: LabelValue; }; rows: WorkbenchRow[]; } + +export type LabelValue = string | typeof EmptyLabelValue; +export const EmptyLabelValue = Symbol('empty label value'); From 04ab5529509e438b5fa52a611ea1abf5d84548b9 Mon Sep 17 00:00:00 2001 From: Tobias Skarhed <1438972+tskarhed@users.noreply.github.com> Date: Wed, 29 Oct 2025 15:33:48 +0100 Subject: [PATCH 093/378] DashboardControls: Render UNSAFE hidden dashboard controls (#113046) * Render UNSAFE hidden dashboard controls * Remove unused imports * Extract to function and write test * Remove unnecessary context from test * Remove exclamation --- .../scene/DashboardControls.test.tsx | 43 ++++++++++++++++++- .../scene/DashboardControls.tsx | 18 +++++++- 2 files changed, 59 insertions(+), 2 deletions(-) diff --git a/public/app/features/dashboard-scene/scene/DashboardControls.test.tsx b/public/app/features/dashboard-scene/scene/DashboardControls.test.tsx index c01808f411e..c13e65574be 100644 --- a/public/app/features/dashboard-scene/scene/DashboardControls.test.tsx +++ b/public/app/features/dashboard-scene/scene/DashboardControls.test.tsx @@ -1,7 +1,7 @@ import { render } from '@testing-library/react'; import { selectors } from '@grafana/e2e-selectors'; -import { SceneVariableSet, TextBoxVariable } from '@grafana/scenes'; +import { SceneVariableSet, ScopesVariable, TextBoxVariable } from '@grafana/scenes'; import { DashboardControls, DashboardControlsState } from './DashboardControls'; import { DashboardScene } from './DashboardScene'; @@ -97,6 +97,47 @@ describe('DashboardControls', () => { expect(renderer.queryByTestId(selectors.pages.Dashboard.Controls)).not.toBeInTheDocument(); }); + + it('should render ScopesVariable Component even when hidden', () => { + const scopeVariable = new ScopesVariable({ + enable: true, + }); + + const dashboard = new DashboardScene({ + uid: 'test-dashboard', + $variables: new SceneVariableSet({ + variables: [scopeVariable], + }), + controls: new DashboardControls({ + hideTimeControls: true, + hideVariableControls: true, + hideLinksControls: true, + hideDashboardControls: true, + }), + }); + + dashboard.activate(); + + const controls = dashboard.state.controls as DashboardControls; + + // Mock the Component getter - use 'as any' to bypass TypeScript's getter checking + // Return a component function (not JSX directly) that renders our test element + // eslint-disable-next-line @typescript-eslint/no-explicit-any + jest.spyOn(scopeVariable as any, 'Component', 'get').mockReturnValue(() => { + return
Mocked Component
; + }); + + const renderer = render(); + + // Verify UNSAFE_renderAsHidden is set (required for renderHiddenVariables to include it) + expect(scopeVariable.UNSAFE_renderAsHidden).toBe(true); + + // Check that the mocked component is rendered - this proves renderHiddenVariables + // accessed the Component getter and rendered it + expect(renderer.getByText('Mocked Component')).toBeInTheDocument(); + + jest.restoreAllMocks(); + }); }); describe('UrlSync', () => { diff --git a/public/app/features/dashboard-scene/scene/DashboardControls.tsx b/public/app/features/dashboard-scene/scene/DashboardControls.tsx index e6a8e7ab8a0..921874732eb 100644 --- a/public/app/features/dashboard-scene/scene/DashboardControls.tsx +++ b/public/app/features/dashboard-scene/scene/DashboardControls.tsx @@ -153,7 +153,8 @@ function DashboardControlsRenderer({ model }: SceneComponentProps; + + return {renderHiddenVariables(dashboard)}; } return ( @@ -200,6 +201,21 @@ function DataLayerControls({ dashboard }: { dashboard: DashboardScene }) { ); } +function renderHiddenVariables(dashboard: DashboardScene) { + const { variables } = sceneGraph.getVariables(dashboard).useState(); + const renderAsHiddenVariables = variables.filter((v) => v.UNSAFE_renderAsHidden); + if (renderAsHiddenVariables && renderAsHiddenVariables.length > 0) { + return ( + <> + {renderAsHiddenVariables.map((v) => ( + + ))} + + ); + } + return null; +} + function getStyles(theme: GrafanaTheme2) { return { controls: css({ From 284648df9e5d40a4c9d2d6066835c77d6779d108 Mon Sep 17 00:00:00 2001 From: Kyle Brandt Date: Wed, 29 Oct 2025 11:06:56 -0400 Subject: [PATCH 094/378] SQL Expressions: Point to grafana GMS fork (#113104) Use fork that does not have cgo as default, had to revert build tag method attempt since it broke things like running go test on macs (without the tag) #112289. --- apps/advisor/go.mod | 2 +- apps/advisor/go.sum | 4 ++-- apps/iam/go.mod | 2 +- apps/iam/go.sum | 4 ++-- go.mod | 8 +++++--- go.sum | 12 ++++-------- go.work.sum | 6 ++++-- pkg/expr/sql/db_test.go | 12 ------------ 8 files changed, 19 insertions(+), 31 deletions(-) diff --git a/apps/advisor/go.mod b/apps/advisor/go.mod index da70ceca234..1bfc3c9671a 100644 --- a/apps/advisor/go.mod +++ b/apps/advisor/go.mod @@ -96,7 +96,7 @@ require ( github.com/dolthub/go-icu-regex v0.0.0-20250327004329-6799764f2dad // indirect github.com/dolthub/go-mysql-server v0.19.1-0.20250410182021-5632d67cd46e // indirect github.com/dolthub/jsonpath v0.0.2-0.20240227200619-19675ab05c71 // indirect - github.com/dolthub/vitess v0.0.0-20250410090211-143e6b272ad4 // indirect + github.com/dolthub/vitess v0.0.0-20250930230441-70c2c6a98e33 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/emicklei/go-restful/v3 v3.13.0 // indirect github.com/fatih/color v1.18.0 // indirect diff --git a/apps/advisor/go.sum b/apps/advisor/go.sum index 89d9baaa4b4..8594bd52e94 100644 --- a/apps/advisor/go.sum +++ b/apps/advisor/go.sum @@ -383,8 +383,8 @@ github.com/dolthub/go-mysql-server v0.19.1-0.20250410182021-5632d67cd46e h1:7pAt github.com/dolthub/go-mysql-server v0.19.1-0.20250410182021-5632d67cd46e/go.mod h1:KZyoO3jngyZCLyCf100FEQTrwAHj33AIMj4Zv4u3MNE= github.com/dolthub/jsonpath v0.0.2-0.20240227200619-19675ab05c71 h1:bMGS25NWAGTEtT5tOBsCuCrlYnLRKpbJVJkDbrTRhwQ= github.com/dolthub/jsonpath v0.0.2-0.20240227200619-19675ab05c71/go.mod h1:2/2zjLQ/JOOSbbSboojeg+cAwcRV0fDLzIiWch/lhqI= -github.com/dolthub/vitess v0.0.0-20250410090211-143e6b272ad4 h1:LGTt2LtYX8vaai32d+c9L0sMcP+Dg9w1kO6+lbsxxYg= -github.com/dolthub/vitess v0.0.0-20250410090211-143e6b272ad4/go.mod h1:1gQZs/byeHLMSul3Lvl3MzioMtOW1je79QYGyi2fd70= +github.com/dolthub/vitess v0.0.0-20250930230441-70c2c6a98e33 h1:ScHTwNbcVC6JH1OSyXzj8S4w67BIpRXwTSjrac3/PSw= +github.com/dolthub/vitess v0.0.0-20250930230441-70c2c6a98e33/go.mod h1:8pvvk5OLaLN9LLxghyczUapn/97l+mBgIb10qC1LG84= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= 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= diff --git a/apps/iam/go.mod b/apps/iam/go.mod index 154a6bb0632..b98eea39b77 100644 --- a/apps/iam/go.mod +++ b/apps/iam/go.mod @@ -165,7 +165,7 @@ require ( github.com/dolthub/go-icu-regex v0.0.0-20250327004329-6799764f2dad // indirect github.com/dolthub/go-mysql-server v0.19.1-0.20250410182021-5632d67cd46e // indirect github.com/dolthub/jsonpath v0.0.2-0.20240227200619-19675ab05c71 // indirect - github.com/dolthub/vitess v0.0.0-20250410090211-143e6b272ad4 // indirect + github.com/dolthub/vitess v0.0.0-20250930230441-70c2c6a98e33 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/emicklei/go-restful/v3 v3.13.0 // indirect github.com/emirpasic/gods v1.18.1 // indirect diff --git a/apps/iam/go.sum b/apps/iam/go.sum index ad77e3a1a30..8a7ec4477df 100644 --- a/apps/iam/go.sum +++ b/apps/iam/go.sum @@ -499,8 +499,8 @@ github.com/dolthub/jsonpath v0.0.2-0.20240227200619-19675ab05c71 h1:bMGS25NWAGTE github.com/dolthub/jsonpath v0.0.2-0.20240227200619-19675ab05c71/go.mod h1:2/2zjLQ/JOOSbbSboojeg+cAwcRV0fDLzIiWch/lhqI= github.com/dolthub/maphash v0.1.0 h1:bsQ7JsF4FkkWyrP3oCnFJgrCUAFbFf3kOl4L/QxPDyQ= github.com/dolthub/maphash v0.1.0/go.mod h1:gkg4Ch4CdCDu5h6PMriVLawB7koZ+5ijb9puGMV50a4= -github.com/dolthub/vitess v0.0.0-20250410090211-143e6b272ad4 h1:LGTt2LtYX8vaai32d+c9L0sMcP+Dg9w1kO6+lbsxxYg= -github.com/dolthub/vitess v0.0.0-20250410090211-143e6b272ad4/go.mod h1:1gQZs/byeHLMSul3Lvl3MzioMtOW1je79QYGyi2fd70= +github.com/dolthub/vitess v0.0.0-20250930230441-70c2c6a98e33 h1:ScHTwNbcVC6JH1OSyXzj8S4w67BIpRXwTSjrac3/PSw= +github.com/dolthub/vitess v0.0.0-20250930230441-70c2c6a98e33/go.mod h1:8pvvk5OLaLN9LLxghyczUapn/97l+mBgIb10qC1LG84= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= 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= diff --git a/go.mod b/go.mod index 6c3cf08f214..3b1a8ff4dd5 100644 --- a/go.mod +++ b/go.mod @@ -53,7 +53,7 @@ require ( github.com/dgraph-io/badger/v4 v4.7.0 // @grafana/grafana-search-and-storage github.com/dlmiddlecote/sqlstats v1.0.2 // @grafana/grafana-backend-group github.com/dolthub/go-mysql-server v0.19.1-0.20250410182021-5632d67cd46e // @grafana/grafana-datasources-core-services - github.com/dolthub/vitess v0.0.0-20250410090211-143e6b272ad4 // @grafana/grafana-datasources-core-services + github.com/dolthub/vitess v0.0.0-20250930230441-70c2c6a98e33 // @grafana/grafana-datasources-core-services github.com/dustin/go-humanize v1.0.1 // @grafana/observability-traces-and-profiling github.com/emicklei/go-restful/v3 v3.13.0 // @grafana/grafana-app-platform-squad github.com/fatih/color v1.18.0 // @grafana/grafana-backend-group @@ -404,7 +404,6 @@ require ( github.com/docker/go-connections v0.6.0 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/dolthub/flatbuffers/v23 v23.3.3-dh.2 // indirect - github.com/dolthub/go-icu-regex v0.0.0-20250327004329-6799764f2dad // indirect github.com/dolthub/jsonpath v0.0.2-0.20240227200619-19675ab05c71 // indirect github.com/dolthub/maphash v0.1.0 // indirect github.com/edsrzf/mmap-go v1.2.0 // indirect @@ -583,7 +582,6 @@ require ( github.com/stoewer/go-strcase v1.3.1 // indirect github.com/stretchr/objx v0.5.2 // indirect github.com/subosito/gotenv v1.6.0 // indirect - github.com/tetratelabs/wazero v1.8.2 // indirect github.com/uber/jaeger-client-go v2.30.0+incompatible // indirect github.com/uber/jaeger-lib v2.4.1+incompatible // indirect github.com/unknwon/bra v0.0.0-20200517080246-1e3013ecaff8 // indirect @@ -678,6 +676,10 @@ exclude github.com/mattn/go-sqlite3 v2.0.3+incompatible // lock for mysql tsdb compat replace github.com/go-sql-driver/mysql => github.com/go-sql-driver/mysql v1.7.1 +// Use our fork of dolthub/go-mysql-server which makes non-cgo the default +// since using a build tag is not sufficient for some use cases (e.g. developers tests in IDE). +replace github.com/dolthub/go-mysql-server => github.com/grafana/go-mysql-server v0.20.1-grafana1 + // v1.* versions were retracted, we need to stick with v0.*. This should work // without the exclude, but this otherwise gets pulled in as a transitive // dependency. diff --git a/go.sum b/go.sum index 799c4a97b4a..a6d4d890765 100644 --- a/go.sum +++ b/go.sum @@ -1120,16 +1120,12 @@ github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZ github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/dolthub/flatbuffers/v23 v23.3.3-dh.2 h1:u3PMzfF8RkKd3lB9pZ2bfn0qEG+1Gms9599cr0REMww= github.com/dolthub/flatbuffers/v23 v23.3.3-dh.2/go.mod h1:mIEZOHnFx4ZMQeawhw9rhsj+0zwQj7adVsnBX7t+eKY= -github.com/dolthub/go-icu-regex v0.0.0-20250327004329-6799764f2dad h1:66ZPawHszNu37VPQckdhX1BPPVzREsGgNxQeefnlm3g= -github.com/dolthub/go-icu-regex v0.0.0-20250327004329-6799764f2dad/go.mod h1:ylU4XjUpsMcvl/BKeRRMXSH7e7WBrPXdSLvnRJYrxEA= -github.com/dolthub/go-mysql-server v0.19.1-0.20250410182021-5632d67cd46e h1:7pAttAqWaudUAsM9iHASi/4eFBK+qn4qeaNto7g8bK4= -github.com/dolthub/go-mysql-server v0.19.1-0.20250410182021-5632d67cd46e/go.mod h1:KZyoO3jngyZCLyCf100FEQTrwAHj33AIMj4Zv4u3MNE= github.com/dolthub/jsonpath v0.0.2-0.20240227200619-19675ab05c71 h1:bMGS25NWAGTEtT5tOBsCuCrlYnLRKpbJVJkDbrTRhwQ= github.com/dolthub/jsonpath v0.0.2-0.20240227200619-19675ab05c71/go.mod h1:2/2zjLQ/JOOSbbSboojeg+cAwcRV0fDLzIiWch/lhqI= github.com/dolthub/maphash v0.1.0 h1:bsQ7JsF4FkkWyrP3oCnFJgrCUAFbFf3kOl4L/QxPDyQ= github.com/dolthub/maphash v0.1.0/go.mod h1:gkg4Ch4CdCDu5h6PMriVLawB7koZ+5ijb9puGMV50a4= -github.com/dolthub/vitess v0.0.0-20250410090211-143e6b272ad4 h1:LGTt2LtYX8vaai32d+c9L0sMcP+Dg9w1kO6+lbsxxYg= -github.com/dolthub/vitess v0.0.0-20250410090211-143e6b272ad4/go.mod h1:1gQZs/byeHLMSul3Lvl3MzioMtOW1je79QYGyi2fd70= +github.com/dolthub/vitess v0.0.0-20250930230441-70c2c6a98e33 h1:ScHTwNbcVC6JH1OSyXzj8S4w67BIpRXwTSjrac3/PSw= +github.com/dolthub/vitess v0.0.0-20250930230441-70c2c6a98e33/go.mod h1:8pvvk5OLaLN9LLxghyczUapn/97l+mBgIb10qC1LG84= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= 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= @@ -1617,6 +1613,8 @@ github.com/grafana/dskit v0.0.0-20250908063411-6b6da59b5cc4 h1:jSojuc7njleS3UOz2 github.com/grafana/dskit v0.0.0-20250908063411-6b6da59b5cc4/go.mod h1:VahT+GtfQIM+o8ht2StR6J9g+Ef+C2Vokh5uuSmOD/4= github.com/grafana/e2e v0.1.1 h1:/b6xcv5BtoBnx8cZnCiey9DbjEc8z7gXHO5edoeRYxc= github.com/grafana/e2e v0.1.1/go.mod h1:RpNLgae5VT+BUHvPE+/zSypmOXKwEu4t+tnEMS1ATaE= +github.com/grafana/go-mysql-server v0.20.1-grafana1 h1:yA4Mzt+tTdIlQutBUaiPnepULPQ7CS4hMu2GOpHqT6s= +github.com/grafana/go-mysql-server v0.20.1-grafana1/go.mod h1:EeYR0apo+8j2Dyxmn2ghkPlirO2S5mT1xHBrA+Efys8= github.com/grafana/gofpdf v0.0.0-20250307124105-3b9c5d35577f h1:5xkjl5Y/j2QefJKOtTfyD1wXlVsQ2yEXmd0u82h5obs= github.com/grafana/gofpdf v0.0.0-20250307124105-3b9c5d35577f/go.mod h1:+O5QxOwwgP10jedZHapzXY+IPKTnzHBtIs5UUb9G+kI= github.com/grafana/gomemcache v0.0.0-20250318131618-74242eea118d h1:oXRJlb9UjVsl6LhqBdbyAQ9YFhExwsj4bjh5vwMNRZY= @@ -2463,8 +2461,6 @@ github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= -github.com/tetratelabs/wazero v1.8.2 h1:yIgLR/b2bN31bjxwXHD8a3d+BogigR952csSDdLYEv4= -github.com/tetratelabs/wazero v1.8.2/go.mod h1:yAI0XTsMBhREkM/YDAK/zNou3GoiAce1P6+rp/wQhjs= github.com/thanos-io/objstore v0.0.0-20240818203309-0363dadfdfb1 h1:z0v9BB/p7s4J6R//+0a5M3wCld8KzNjrGRLIwXfrAZk= github.com/thanos-io/objstore v0.0.0-20240818203309-0363dadfdfb1/go.mod h1:3ukSkG4rIRUGkKM4oIz+BSuUx2e3RlQVVv3Cc3W+Tv4= github.com/thejerf/slogassert v0.3.4 h1:VoTsXixRbXMrRSSxDjYTiEDCM4VWbsYPW5rB/hX24kM= diff --git a/go.work.sum b/go.work.sum index d78d14d4bb1..8406037217a 100644 --- a/go.work.sum +++ b/go.work.sum @@ -576,8 +576,7 @@ github.com/dolthub/sqllogictest/go v0.0.0-20201107003712-816f3ae12d81 h1:7/v8q9X github.com/dolthub/sqllogictest/go v0.0.0-20201107003712-816f3ae12d81/go.mod h1:siLfyv2c92W1eN/R4QqG/+RjjX5W2+gCTRjZxBjI3TY= github.com/dolthub/swiss v0.2.1 h1:gs2osYs5SJkAaH5/ggVJqXQxRXtWshF6uE0lgR/Y3Gw= github.com/dolthub/swiss v0.2.1/go.mod h1:8AhKZZ1HK7g18j7v7k6c5cYIGEZJcPn0ARsai8cUrh0= -github.com/dolthub/vitess v0.0.0-20250930230441-70c2c6a98e33 h1:ScHTwNbcVC6JH1OSyXzj8S4w67BIpRXwTSjrac3/PSw= -github.com/dolthub/vitess v0.0.0-20250930230441-70c2c6a98e33/go.mod h1:8pvvk5OLaLN9LLxghyczUapn/97l+mBgIb10qC1LG84= +github.com/dolthub/vitess v0.0.0-20250410090211-143e6b272ad4/go.mod h1:1gQZs/byeHLMSul3Lvl3MzioMtOW1je79QYGyi2fd70= github.com/drone/envsubst v1.0.3 h1:PCIBwNDYjs50AsLZPYdfhSATKaRg/FJmDc2D6+C2x8g= github.com/drone/envsubst v1.0.3/go.mod h1:N2jZmlMufstn1KEqvbHjw40h1KyTmnVzHcSc9bFiJ2g= github.com/dvyukov/go-fuzz v0.0.0-20210103155950-6a8e9d1f2415 h1:q1oJaUPdmpDm/VyXosjgPgr6wS7c5iV2p0PwJD73bUI= @@ -750,6 +749,9 @@ github.com/grafana/dskit v0.0.0-20250611075409-46f51e1ce914/go.mod h1:OiN4P4aC6L github.com/grafana/dskit v0.0.0-20250818234656-8ff9c6532e85/go.mod h1:kImsvJ1xnmeT9Z6StK+RdEKLzlpzBsKwJbEQfmBJdFs= github.com/grafana/go-gelf/v2 v2.0.1 h1:BOChP0h/jLeD+7F9mL7tq10xVkDG15he3T1zHuQaWak= github.com/grafana/go-gelf/v2 v2.0.1/go.mod h1:lexHie0xzYGwCgiRGcvZ723bSNyNI8ZRD4s0CLobh90= +github.com/grafana/go-mysql-server v0.20.1-0.20251027172658-317a8d46ffa4/go.mod h1:EeYR0apo+8j2Dyxmn2ghkPlirO2S5mT1xHBrA+Efys8= +github.com/grafana/go-mysql-server v0.20.1-grafana1 h1:yA4Mzt+tTdIlQutBUaiPnepULPQ7CS4hMu2GOpHqT6s= +github.com/grafana/go-mysql-server v0.20.1-grafana1/go.mod h1:EeYR0apo+8j2Dyxmn2ghkPlirO2S5mT1xHBrA+Efys8= github.com/grafana/grafana-app-sdk v0.40.2/go.mod h1:BbNXPNki3mtbkWxYqJsyA1Cj9AShSyaY33z8WkyfVv0= github.com/grafana/grafana-app-sdk/logging v0.40.2/go.mod h1:otUD9XpJD7A5sCLb8mcs9hIXGdeV6lnhzVwe747g4RU= github.com/grafana/grafana-app-sdk/logging v0.48.0/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA= diff --git a/pkg/expr/sql/db_test.go b/pkg/expr/sql/db_test.go index ff5ecac022f..c67c23b32b9 100644 --- a/pkg/expr/sql/db_test.go +++ b/pkg/expr/sql/db_test.go @@ -278,18 +278,6 @@ func TestNaNBecomesNull(t *testing.T) { require.NoError(t, err) } -func TestErrorsFromGoMySQLServerAreFlagged(t *testing.T) { - const GmsNotImplemented = "TRUNCATE" // not implemented in go-mysql-server as of 2025-04-11 - - db := DB{} - - query := `SELECT ` + GmsNotImplemented + `(123.456, 2);` - - _, err := db.QueryFrames(context.Background(), &testTracer{}, "sqlExpressionRefId", query, nil) - require.Error(t, err) - require.Contains(t, err.Error(), "error from the sql expression engine") -} - func TestFrameToSQLAndBack_JSONRoundtrip(t *testing.T) { expectedFrame := &data.Frame{ RefID: "json_test", From 51b39d8c6ec715d9b4eaa9bf2757b88a2c0368df Mon Sep 17 00:00:00 2001 From: Sergej-Vlasov <37613182+Sergej-Vlasov@users.noreply.github.com> Date: Wed, 29 Oct 2025 15:07:55 +0000 Subject: [PATCH 095/378] DashboardScene: Ignore defaults changes when exiting edit mode (#112796) * exit dashboard without confirmation with only optional changes * centralise * clean up logic * export to util --- .../features/dashboard-scene/saving/DashboardPrompt.tsx | 4 ++-- .../app/features/dashboard-scene/scene/DashboardScene.tsx | 3 ++- public/app/features/dashboard-scene/utils/utils.ts | 8 ++++++++ 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/public/app/features/dashboard-scene/saving/DashboardPrompt.tsx b/public/app/features/dashboard-scene/saving/DashboardPrompt.tsx index 134e2cedbab..fb44176788f 100644 --- a/public/app/features/dashboard-scene/saving/DashboardPrompt.tsx +++ b/public/app/features/dashboard-scene/saving/DashboardPrompt.tsx @@ -16,7 +16,7 @@ import { DashboardMeta } from 'app/types/dashboard'; import { SaveLibraryVizPanelModal } from '../panel-edit/SaveLibraryVizPanelModal'; import { DashboardScene } from '../scene/DashboardScene'; -import { getLibraryPanelBehavior, isLibraryPanel } from '../utils/utils'; +import { getLibraryPanelBehavior, hasActualSaveChanges, isLibraryPanel } from '../utils/utils'; interface DashboardPromptProps { dashboard: DashboardScene; @@ -200,7 +200,7 @@ export function ignoreChanges(scene: DashboardScene | null) { return true; } - return !canSave || fromScript || fromFile; + return !canSave || fromScript || fromFile || (scene.state.isEditing && !hasActualSaveChanges(scene)); } export function isEmptyDashboard( diff --git a/public/app/features/dashboard-scene/scene/DashboardScene.tsx b/public/app/features/dashboard-scene/scene/DashboardScene.tsx index 0cabdf459a2..748d3e7986e 100644 --- a/public/app/features/dashboard-scene/scene/DashboardScene.tsx +++ b/public/app/features/dashboard-scene/scene/DashboardScene.tsx @@ -72,6 +72,7 @@ import { getDefaultVizPanel, getLayoutManagerFor, getPanelIdForVizPanel, + hasActualSaveChanges, } from '../utils/utils'; import { SchemaV2EditorDrawer } from '../v2schema/SchemaV2EditorDrawer'; @@ -316,7 +317,7 @@ export class DashboardScene extends SceneObjectBase impleme return; } - if (!this.state.isDirty || skipConfirm || this.managedResourceCannotBeEdited()) { + if (!this.state.isDirty || skipConfirm || !hasActualSaveChanges(this) || this.managedResourceCannotBeEdited()) { this.exitEditModeConfirmed(restoreInitialState || this.state.isDirty); return; } diff --git a/public/app/features/dashboard-scene/utils/utils.ts b/public/app/features/dashboard-scene/utils/utils.ts index 12dba08eda4..419ce760b21 100644 --- a/public/app/features/dashboard-scene/utils/utils.ts +++ b/public/app/features/dashboard-scene/utils/utils.ts @@ -427,3 +427,11 @@ export function hasLibraryPanelsInV1Dashboard(dashboard: Dashboard | undefined): } export const dashboardLog = createLogger('Dashboard'); + +/** + * Checks if there are save changes but not counting time range, refresh rate and default variable value change + */ +export function hasActualSaveChanges(dashboard: DashboardScene) { + const changes = dashboard.getDashboardChanges(); + return !!changes.diffCount; +} From 7eb8a9af99c74294525c84f2188e1610c81f2d49 Mon Sep 17 00:00:00 2001 From: Pepe Cano <825430+ppcano@users.noreply.github.com> Date: Wed, 29 Oct 2025 16:08:08 +0100 Subject: [PATCH 096/378] docs(alerting): clarify notification group deletion after group interval elapses (#113160) --- .../fundamentals/notifications/group-alert-notifications.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/sources/alerting/fundamentals/notifications/group-alert-notifications.md b/docs/sources/alerting/fundamentals/notifications/group-alert-notifications.md index 64b1e83ef54..91b5f217315 100644 --- a/docs/sources/alerting/fundamentals/notifications/group-alert-notifications.md +++ b/docs/sources/alerting/fundamentals/notifications/group-alert-notifications.md @@ -159,7 +159,9 @@ Once the first notification has been sent for a new group of alerts, the group i When the group interval timer elapses, the system resets the group interval timer and sends a notification only if there were group changes. This process repeats until there are no more alerts. -It's important to note that an alert instance exits the group after being resolved and notified of its state change. When no alerts remain, the group is deleted, and then the group wait timer handles the first notification for the next incoming alert once again. +It's important to note that an alert instance exits the group after being resolved and notified of its state change. + +When the group interval timer elapses and no alerts remain, the group is deleted. The [group wait timer](#group-wait) will then start again the next time a new alert arrives. ### Repeat interval From 3bfbbb1961e761ef3a2cdc293d07f6eb101fa742 Mon Sep 17 00:00:00 2001 From: Todd Treece <360020+toddtreece@users.noreply.github.com> Date: Wed, 29 Oct 2025 11:33:43 -0400 Subject: [PATCH 097/378] Plugins: Skip angular check for CDN source (#113163) --- .../angularinspector/angularinspector.go | 5 +++ .../angularinspector/angularinspector_test.go | 32 +++++++++++++++---- 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/pkg/plugins/manager/loader/angular/angularinspector/angularinspector.go b/pkg/plugins/manager/loader/angular/angularinspector/angularinspector.go index e67b04b69f2..98840189389 100644 --- a/pkg/plugins/manager/loader/angular/angularinspector/angularinspector.go +++ b/pkg/plugins/manager/loader/angular/angularinspector/angularinspector.go @@ -35,6 +35,11 @@ func NewPatternListInspector(detectorsProvider angulardetector.DetectorsProvider } func (i *PatternsListInspector) Inspect(ctx context.Context, p *plugins.Plugin) (isAngular bool, err error) { + // CDN plugins are ignored because they should not be using Angular + if p.Class == plugins.ClassCDN { + return false, nil + } + f, err := p.FS.Open("module.js") if err != nil { if errors.Is(err, plugins.ErrFileNotExist) { diff --git a/pkg/plugins/manager/loader/angular/angularinspector/angularinspector_test.go b/pkg/plugins/manager/loader/angular/angularinspector/angularinspector_test.go index f45ae982d09..47c5af990b9 100644 --- a/pkg/plugins/manager/loader/angular/angularinspector/angularinspector_test.go +++ b/pkg/plugins/manager/loader/angular/angularinspector/angularinspector_test.go @@ -27,17 +27,17 @@ func (d *fakeDetector) String() string { } func TestPatternsListInspector(t *testing.T) { - plugin := &plugins.Plugin{ - FS: plugins.NewInMemoryFS(map[string][]byte{"module.js": nil}), - } - for _, tc := range []struct { name string + plugin *plugins.Plugin fakeDetectors []*fakeDetector exp func(t *testing.T, r bool, err error, fakeDetectors []*fakeDetector) }{ { name: "calls the detectors in sequence until true is returned", + plugin: &plugins.Plugin{ + FS: plugins.NewInMemoryFS(map[string][]byte{"module.js": nil}), + }, fakeDetectors: []*fakeDetector{ {returns: false}, {returns: true}, @@ -53,6 +53,9 @@ func TestPatternsListInspector(t *testing.T) { }, { name: "calls the detectors in sequence and returns false as default", + plugin: &plugins.Plugin{ + FS: plugins.NewInMemoryFS(map[string][]byte{"module.js": nil}), + }, fakeDetectors: []*fakeDetector{ {returns: false}, {returns: false}, @@ -65,13 +68,30 @@ func TestPatternsListInspector(t *testing.T) { }, }, { - name: "empty detectors should return false", + name: "empty detectors should return false", + plugin: &plugins.Plugin{ + FS: plugins.NewInMemoryFS(map[string][]byte{"module.js": nil}), + }, fakeDetectors: nil, exp: func(t *testing.T, r bool, err error, fakeDetectors []*fakeDetector) { require.NoError(t, err) require.False(t, r, "inspector should return false") }, }, + { + name: "CDN plugins return false without calling detectors", + plugin: &plugins.Plugin{ + Class: plugins.ClassCDN, + }, + fakeDetectors: []*fakeDetector{ + {returns: true}, + }, + exp: func(t *testing.T, r bool, err error, fakeDetectors []*fakeDetector) { + require.NoError(t, err) + require.False(t, r, "inspector should return false for CDN plugins") + require.Equal(t, 0, fakeDetectors[0].calls, "detectors should not be called for CDN plugins") + }, + }, } { t.Run(tc.name, func(t *testing.T) { detectors := make([]angulardetector.AngularDetector, 0, len(tc.fakeDetectors)) @@ -79,7 +99,7 @@ func TestPatternsListInspector(t *testing.T) { detectors = append(detectors, angulardetector.AngularDetector(d)) } inspector := NewPatternListInspector(&angulardetector.StaticDetectorsProvider{Detectors: detectors}) - r, err := inspector.Inspect(context.Background(), plugin) + r, err := inspector.Inspect(context.Background(), tc.plugin) tc.exp(t, r, err, tc.fakeDetectors) }) } From 269c145051eed3f235896b653e62e440b866da1b Mon Sep 17 00:00:00 2001 From: Yunwen Zheng Date: Wed, 29 Oct 2025 12:14:12 -0400 Subject: [PATCH 098/378] SaveProvisionedDashboardForm: Bug fix repo type incorrectly showing in preview banner (#113120) * SaveProvisionedDashboardForm: fix repo type incorrectly showing in preview banner --- .../Dashboards/SaveProvisionedDashboardForm.tsx | 9 +++++---- .../components/Folders/NewProvisionedFolderForm.tsx | 2 +- .../hooks/useProvisionedRequestHandler.test.ts | 7 +------ .../provisioning/hooks/useProvisionedRequestHandler.ts | 4 ++-- 4 files changed, 9 insertions(+), 13 deletions(-) diff --git a/public/app/features/provisioning/components/Dashboards/SaveProvisionedDashboardForm.tsx b/public/app/features/provisioning/components/Dashboards/SaveProvisionedDashboardForm.tsx index 6af33a5cbea..bffaab79a73 100644 --- a/public/app/features/provisioning/components/Dashboards/SaveProvisionedDashboardForm.tsx +++ b/public/app/features/provisioning/components/Dashboards/SaveProvisionedDashboardForm.tsx @@ -86,7 +86,7 @@ export function SaveProvisionedDashboardForm({ ); const navigateToPreview = useCallback( - (ref: string, path: string, repoType: string) => { + (ref: string, path: string, repoType?: string) => { const url = buildResourceBranchRedirectUrl({ baseUrl: `${PROVISIONING_URL}/${defaultValues.repo}/dashboard/preview/${path}`, paramName: 'ref', @@ -110,7 +110,7 @@ export function SaveProvisionedDashboardForm({ }, [dashboard, defaultValues.folder?.uid, drawer, panelEditor, request?.data?.resource]); const onWriteSuccess = useCallback( - ({ repoType }: ProvisionedOperationInfo, upsert: Resource) => { + (upsert: Resource) => { handleDismiss(); if (isNew && upsert?.metadata.name) { handleNewDashboard(upsert); @@ -118,7 +118,7 @@ export function SaveProvisionedDashboardForm({ // if pushed to an existing but non-configured branch, navigate to preview page if (ref !== repository?.branch && ref) { - navigateToPreview(ref, path, repoType); + navigateToPreview(ref, path, repository?.type); return; } @@ -127,7 +127,7 @@ export function SaveProvisionedDashboardForm({ editPanel: null, }); }, - [isNew, path, ref, repository?.branch, handleDismiss, handleNewDashboard, navigateToPreview] + [isNew, path, ref, repository?.branch, repository?.type, handleDismiss, handleNewDashboard, navigateToPreview] ); const onBranchSuccess = useCallback( @@ -147,6 +147,7 @@ export function SaveProvisionedDashboardForm({ request, workflow, resourceType: 'dashboard', + repository, handlers: { onBranchSuccess: ({ ref, path }, info, resource) => onBranchSuccess(ref, path, info, resource), onWriteSuccess, diff --git a/public/app/features/provisioning/components/Folders/NewProvisionedFolderForm.tsx b/public/app/features/provisioning/components/Folders/NewProvisionedFolderForm.tsx index 3b9d62916a4..109277d38a7 100644 --- a/public/app/features/provisioning/components/Folders/NewProvisionedFolderForm.tsx +++ b/public/app/features/provisioning/components/Folders/NewProvisionedFolderForm.tsx @@ -92,7 +92,7 @@ function FormContent({ initialValues, repository, workflowOptions, folder, onDis handlers: { onDismiss, onBranchSuccess, - onWriteSuccess: (_, resource) => onWriteSuccess(resource), + onWriteSuccess, onError, }, }); diff --git a/public/app/features/provisioning/hooks/useProvisionedRequestHandler.test.ts b/public/app/features/provisioning/hooks/useProvisionedRequestHandler.test.ts index 0a0e48cf498..7e06b38eff1 100644 --- a/public/app/features/provisioning/hooks/useProvisionedRequestHandler.test.ts +++ b/public/app/features/provisioning/hooks/useProvisionedRequestHandler.test.ts @@ -153,12 +153,7 @@ describe('useProvisionedRequestHandler', () => { ); expect(handlers.onWriteSuccess).toHaveBeenCalledWith( - expect.objectContaining({ - resourceType: 'dashboard', - repoType: 'git', - workflow: 'write', - }), - expect.any(Object) + expect.objectContaining({ kind: 'Dashboard', metadata: expect.objectContaining({ name: 'test-dashboard' }) }) ); expect(handlers.onDismiss).toHaveBeenCalled(); }); diff --git a/public/app/features/provisioning/hooks/useProvisionedRequestHandler.ts b/public/app/features/provisioning/hooks/useProvisionedRequestHandler.ts index 7fc3bb052fe..188f6218950 100644 --- a/public/app/features/provisioning/hooks/useProvisionedRequestHandler.ts +++ b/public/app/features/provisioning/hooks/useProvisionedRequestHandler.ts @@ -29,7 +29,7 @@ interface RequestHandlers { info: ProvisionedOperationInfo, resource: Resource ) => void; - onWriteSuccess?: (info: ProvisionedOperationInfo, resource: Resource) => void; + onWriteSuccess?: (resource: Resource) => void; onError?: (error: unknown, info: ProvisionedOperationInfo) => void; onDismiss?: () => void; } @@ -116,7 +116,7 @@ export function useProvisionedRequestHandler({ // refetch folder items after success if folderUID is passed in dispatch(refetchChildren({ parentUID: folderUID || repository?.name, pageSize: PAGE_SIZE })); } - handlers.onWriteSuccess(info, resourceData); + handlers.onWriteSuccess(resourceData); } handlers.onDismiss?.(); From ec6e516e28a8bf4a25b9e1d835e369e06075c2c0 Mon Sep 17 00:00:00 2001 From: Yunwen Zheng Date: Wed, 29 Oct 2025 12:14:57 -0400 Subject: [PATCH 099/378] DashboardEmpty: Disable import dashboard function when a new dashboard is git provisioned (#113122) DashboardEmpty: Disable import dashboard function when a new dashboar is git provisioned --- .../dashboard/dashgrid/DashboardEmpty/DashboardEmptyHooks.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/public/app/features/dashboard/dashgrid/DashboardEmpty/DashboardEmptyHooks.ts b/public/app/features/dashboard/dashgrid/DashboardEmpty/DashboardEmptyHooks.ts index 7340226a7a2..d0432f5e606 100644 --- a/public/app/features/dashboard/dashgrid/DashboardEmpty/DashboardEmptyHooks.ts +++ b/public/app/features/dashboard/dashgrid/DashboardEmpty/DashboardEmptyHooks.ts @@ -73,8 +73,9 @@ export const useOnAddLibraryPanel = ({ dashboard, canCreate, isReadOnlyRepo }: H }; export const useOnImportDashboard = ({ dashboard, canCreate, isReadOnlyRepo }: HookProps) => { + const isProvisioned = dashboard instanceof DashboardScene && dashboard.isManagedRepository(); return useMemo(() => { - if (!canCreate || isReadOnlyRepo) { + if (!canCreate || isProvisioned || isReadOnlyRepo) { return undefined; } @@ -82,5 +83,5 @@ export const useOnImportDashboard = ({ dashboard, canCreate, isReadOnlyRepo }: H DashboardInteractions.emptyDashboardButtonClicked({ item: 'import_dashboard' }); onImportDashboardImpl(); }; - }, [canCreate, isReadOnlyRepo]); + }, [canCreate, isReadOnlyRepo, isProvisioned]); }; From af8d166b909c941884c3c28188ed8d780596f006 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laura=20Fern=C3=A1ndez?= Date: Wed, 29 Oct 2025 17:17:07 +0100 Subject: [PATCH 100/378] Chore: Update `node` to v24 (#112649) --- .nvmrc | 2 +- Dockerfile | 2 +- contribute/developer-guide.md | 2 +- .../grafana-extensionstest-app/package.json | 2 +- .../grafana-test-datasource/package.json | 2 +- package.json | 2 +- packages/grafana-data/package.json | 2 +- .../src/vector/FunctionalVector.ts | 6 +- packages/grafana-e2e-selectors/package.json | 2 +- packages/grafana-flamegraph/package.json | 2 +- .../grafana-o11y-ds-frontend/package.json | 2 +- packages/grafana-prometheus/package.json | 2 +- packages/grafana-sql/package.json | 2 +- packages/grafana-test-utils/package.json | 2 +- packages/grafana-ui/package.json | 2 +- .../datasource/azuremonitor/package.json | 2 +- .../datasource/cloud-monitoring/package.json | 2 +- .../package.json | 2 +- .../grafana-pyroscope-datasource/package.json | 2 +- .../grafana-testdata-datasource/package.json | 2 +- .../plugins/datasource/graphite/package.json | 2 +- .../plugins/datasource/jaeger/package.json | 2 +- .../app/plugins/datasource/loki/package.json | 2 +- .../app/plugins/datasource/mssql/package.json | 2 +- .../app/plugins/datasource/mysql/package.json | 2 +- .../app/plugins/datasource/parca/package.json | 2 +- .../app/plugins/datasource/tempo/package.json | 2 +- .../plugins/datasource/zipkin/package.json | 2 +- yarn.lock | 124 +++++++++++------- 29 files changed, 106 insertions(+), 78 deletions(-) diff --git a/.nvmrc b/.nvmrc index aebd91c521b..c519bf5baaa 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -v22.16.0 +v24.11.0 diff --git a/Dockerfile b/Dockerfile index 0edb989ac76..909281146e7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -17,7 +17,7 @@ ARG JS_SRC=js-builder FROM alpine:3.22.2 AS alpine-base FROM ubuntu:22.04 AS ubuntu-base FROM golang:1.25.3-alpine AS go-builder-base -FROM --platform=${JS_PLATFORM} node:22-alpine AS js-builder-base +FROM --platform=${JS_PLATFORM} node:24-alpine AS js-builder-base # Javascript build stage FROM --platform=${JS_PLATFORM} ${JS_IMAGE} AS js-builder ARG JS_NODE_ENV=production diff --git a/contribute/developer-guide.md b/contribute/developer-guide.md index eaa8334926c..65dadfae463 100644 --- a/contribute/developer-guide.md +++ b/contribute/developer-guide.md @@ -18,7 +18,7 @@ We recommend using [Homebrew](https://brew.sh/) for installing any missing depen ``` brew install git brew install go -brew install node@22 +brew install node@24 ``` ### Windows diff --git a/e2e-playwright/test-plugins/grafana-extensionstest-app/package.json b/e2e-playwright/test-plugins/grafana-extensionstest-app/package.json index e1960c9515e..12829268e71 100644 --- a/e2e-playwright/test-plugins/grafana-extensionstest-app/package.json +++ b/e2e-playwright/test-plugins/grafana-extensionstest-app/package.json @@ -13,7 +13,7 @@ "devDependencies": { "@grafana/plugin-configs": "workspace:*", "@types/lodash": "4.17.7", - "@types/node": "22.15.0", + "@types/node": "24.9.2", "@types/prismjs": "1.26.4", "@types/react": "18.3.18", "@types/react-dom": "18.3.5", diff --git a/e2e-playwright/test-plugins/grafana-test-datasource/package.json b/e2e-playwright/test-plugins/grafana-test-datasource/package.json index 71b032b1d88..e62edcbaad6 100644 --- a/e2e-playwright/test-plugins/grafana-test-datasource/package.json +++ b/e2e-playwright/test-plugins/grafana-test-datasource/package.json @@ -13,7 +13,7 @@ "devDependencies": { "@grafana/plugin-configs": "workspace:*", "@types/lodash": "4.17.7", - "@types/node": "22.15.0", + "@types/node": "24.9.2", "@types/prismjs": "1.26.4", "@types/react": "18.3.18", "@types/react-dom": "18.3.5", diff --git a/package.json b/package.json index 503049f3ed2..f0f0e411591 100644 --- a/package.json +++ b/package.json @@ -136,7 +136,7 @@ "@types/lodash": "4.17.20", "@types/logfmt": "^1.2.3", "@types/lucene": "^2", - "@types/node": "22.17.0", + "@types/node": "24.9.2", "@types/node-forge": "^1", "@types/ol-ext": "npm:@siedlerchr/types-ol-ext@3.3.0", "@types/pluralize": "^0.0.33", diff --git a/packages/grafana-data/package.json b/packages/grafana-data/package.json index 950d5122932..c990c304caf 100644 --- a/packages/grafana-data/package.json +++ b/packages/grafana-data/package.json @@ -89,7 +89,7 @@ "@testing-library/react": "16.3.0", "@types/history": "4.7.11", "@types/lodash": "4.17.20", - "@types/node": "22.17.0", + "@types/node": "24.9.2", "@types/papaparse": "5.3.16", "@types/react": "18.3.18", "@types/react-dom": "18.3.5", diff --git a/packages/grafana-data/src/vector/FunctionalVector.ts b/packages/grafana-data/src/vector/FunctionalVector.ts index f5ccfc7be8a..a84b6122232 100644 --- a/packages/grafana-data/src/vector/FunctionalVector.ts +++ b/packages/grafana-data/src/vector/FunctionalVector.ts @@ -153,13 +153,13 @@ export abstract class FunctionalVector { findIndex(predicate: (value: T, index: number, obj: T[]) => unknown, thisArg?: any): number { return this.toArray().findIndex(predicate, thisArg); } - entries(): IterableIterator<[number, T]> { + entries(): ArrayIterator<[number, T]> { return this.toArray().entries(); } - keys(): IterableIterator { + keys(): ArrayIterator { return this.toArray().keys(); } - values(): IterableIterator { + values(): ArrayIterator { return this.toArray().values(); } includes(searchElement: T, fromIndex?: number | undefined): boolean { diff --git a/packages/grafana-e2e-selectors/package.json b/packages/grafana-e2e-selectors/package.json index 008f555cc3b..9a50bc2ee5c 100644 --- a/packages/grafana-e2e-selectors/package.json +++ b/packages/grafana-e2e-selectors/package.json @@ -40,7 +40,7 @@ }, "devDependencies": { "@rollup/plugin-node-resolve": "16.0.1", - "@types/node": "22.17.0", + "@types/node": "24.9.2", "@types/semver": "7.7.1", "esbuild": "0.25.8", "rimraf": "6.0.1", diff --git a/packages/grafana-flamegraph/package.json b/packages/grafana-flamegraph/package.json index 3185d65d5c1..98cb22e9fb2 100644 --- a/packages/grafana-flamegraph/package.json +++ b/packages/grafana-flamegraph/package.json @@ -67,7 +67,7 @@ "@types/d3": "^7", "@types/jest": "^29.5.4", "@types/lodash": "4.17.20", - "@types/node": "22.17.0", + "@types/node": "24.9.2", "@types/react": "18.3.18", "@types/react-virtualized-auto-sizer": "1.0.8", "@types/tinycolor2": "1.4.6", diff --git a/packages/grafana-o11y-ds-frontend/package.json b/packages/grafana-o11y-ds-frontend/package.json index 5694659ab70..b79a584715f 100644 --- a/packages/grafana-o11y-ds-frontend/package.json +++ b/packages/grafana-o11y-ds-frontend/package.json @@ -35,7 +35,7 @@ "@testing-library/react": "16.3.0", "@testing-library/user-event": "14.6.1", "@types/jest": "^29.5.4", - "@types/node": "22.17.0", + "@types/node": "24.9.2", "@types/react": "18.3.18", "@types/systemjs": "6.15.3", "jest": "^29.6.4", diff --git a/packages/grafana-prometheus/package.json b/packages/grafana-prometheus/package.json index c7413cdd517..4c8f16ac688 100644 --- a/packages/grafana-prometheus/package.json +++ b/packages/grafana-prometheus/package.json @@ -87,7 +87,7 @@ "@testing-library/react": "16.3.0", "@testing-library/user-event": "14.6.1", "@types/jest": "29.5.14", - "@types/node": "22.17.0", + "@types/node": "24.9.2", "@types/pluralize": "^0.0.33", "@types/prismjs": "1.26.5", "esbuild": "0.25.8", diff --git a/packages/grafana-sql/package.json b/packages/grafana-sql/package.json index 2ea7c0f82c7..db36dfec348 100644 --- a/packages/grafana-sql/package.json +++ b/packages/grafana-sql/package.json @@ -42,7 +42,7 @@ "@testing-library/user-event": "14.6.1", "@types/jest": "^29.5.4", "@types/lodash": "4.17.20", - "@types/node": "22.17.0", + "@types/node": "24.9.2", "@types/react": "18.3.18", "@types/react-dom": "18.3.5", "@types/react-virtualized-auto-sizer": "1.0.8", diff --git a/packages/grafana-test-utils/package.json b/packages/grafana-test-utils/package.json index 70bf836f843..ecd8980173a 100644 --- a/packages/grafana-test-utils/package.json +++ b/packages/grafana-test-utils/package.json @@ -65,7 +65,7 @@ "@types/chance": "^1.1.7", "@types/jest": "29.5.14", "@types/lodash": "4.17.20", - "@types/node": "22.17.0", + "@types/node": "24.9.2", "jest": "29.7.0", "typescript": "5.9.2" } diff --git a/packages/grafana-ui/package.json b/packages/grafana-ui/package.json index 91dc005eadc..6c96682758b 100644 --- a/packages/grafana-ui/package.json +++ b/packages/grafana-ui/package.json @@ -165,7 +165,7 @@ "@types/is-hotkey": "0.1.10", "@types/jest": "29.5.14", "@types/mock-raf": "1.0.6", - "@types/node": "22.17.0", + "@types/node": "24.9.2", "@types/prismjs": "1.26.5", "@types/react": "18.3.18", "@types/react-color": "3.0.13", diff --git a/public/app/plugins/datasource/azuremonitor/package.json b/public/app/plugins/datasource/azuremonitor/package.json index 363460331ab..778de26d31d 100644 --- a/public/app/plugins/datasource/azuremonitor/package.json +++ b/public/app/plugins/datasource/azuremonitor/package.json @@ -34,7 +34,7 @@ "@testing-library/user-event": "14.6.1", "@types/jest": "29.5.14", "@types/lodash": "4.17.20", - "@types/node": "22.17.0", + "@types/node": "24.9.2", "@types/prismjs": "1.26.5", "@types/react": "18.3.18", "@types/react-dom": "18.3.5", diff --git a/public/app/plugins/datasource/cloud-monitoring/package.json b/public/app/plugins/datasource/cloud-monitoring/package.json index 6671d62b3be..19ce293b786 100644 --- a/public/app/plugins/datasource/cloud-monitoring/package.json +++ b/public/app/plugins/datasource/cloud-monitoring/package.json @@ -35,7 +35,7 @@ "@types/debounce-promise": "3.1.9", "@types/jest": "29.5.14", "@types/lodash": "4.17.20", - "@types/node": "22.17.0", + "@types/node": "24.9.2", "@types/prismjs": "1.26.5", "@types/react": "18.3.18", "@types/react-dom": "18.3.5", diff --git a/public/app/plugins/datasource/grafana-postgresql-datasource/package.json b/public/app/plugins/datasource/grafana-postgresql-datasource/package.json index 78dd4ab395d..b1106f0202c 100644 --- a/public/app/plugins/datasource/grafana-postgresql-datasource/package.json +++ b/public/app/plugins/datasource/grafana-postgresql-datasource/package.json @@ -23,7 +23,7 @@ "@testing-library/user-event": "14.6.1", "@types/jest": "29.5.14", "@types/lodash": "4.17.20", - "@types/node": "22.17.0", + "@types/node": "24.9.2", "@types/react": "18.3.18", "jest": "29.7.0", "ts-node": "10.9.2", diff --git a/public/app/plugins/datasource/grafana-pyroscope-datasource/package.json b/public/app/plugins/datasource/grafana-pyroscope-datasource/package.json index f5a2792f57c..8f4756784f8 100644 --- a/public/app/plugins/datasource/grafana-pyroscope-datasource/package.json +++ b/public/app/plugins/datasource/grafana-pyroscope-datasource/package.json @@ -27,7 +27,7 @@ "@testing-library/user-event": "14.6.1", "@types/jest": "29.5.14", "@types/lodash": "4.17.20", - "@types/node": "22.17.0", + "@types/node": "24.9.2", "@types/prismjs": "1.26.5", "@types/react": "18.3.18", "@types/react-dom": "18.3.5", diff --git a/public/app/plugins/datasource/grafana-testdata-datasource/package.json b/public/app/plugins/datasource/grafana-testdata-datasource/package.json index b4b36bb2a68..d738f47d24d 100644 --- a/public/app/plugins/datasource/grafana-testdata-datasource/package.json +++ b/public/app/plugins/datasource/grafana-testdata-datasource/package.json @@ -30,7 +30,7 @@ "@types/d3-random": "^3.0.2", "@types/jest": "29.5.14", "@types/lodash": "4.17.20", - "@types/node": "22.17.0", + "@types/node": "24.9.2", "@types/react": "18.3.18", "@types/react-dom": "18.3.5", "@types/uuid": "10.0.0", diff --git a/public/app/plugins/datasource/graphite/package.json b/public/app/plugins/datasource/graphite/package.json index 49df565f4fc..5804b4b1b48 100644 --- a/public/app/plugins/datasource/graphite/package.json +++ b/public/app/plugins/datasource/graphite/package.json @@ -31,7 +31,7 @@ "@testing-library/user-event": "14.6.1", "@types/jest": "29.5.14", "@types/lodash": "4.17.20", - "@types/node": "22.17.0", + "@types/node": "24.9.2", "@types/react": "18.3.18", "@types/react-dom": "18.3.5", "@types/semver": "7.7.1", diff --git a/public/app/plugins/datasource/jaeger/package.json b/public/app/plugins/datasource/jaeger/package.json index a1ccd2a32bc..3fe1880cc50 100644 --- a/public/app/plugins/datasource/jaeger/package.json +++ b/public/app/plugins/datasource/jaeger/package.json @@ -31,7 +31,7 @@ "@types/jest": "29.5.14", "@types/lodash": "4.17.20", "@types/logfmt": "^1.2.3", - "@types/node": "22.17.0", + "@types/node": "24.9.2", "@types/react": "18.3.18", "@types/react-dom": "18.3.5", "@types/react-window": "1.8.8", diff --git a/public/app/plugins/datasource/loki/package.json b/public/app/plugins/datasource/loki/package.json index 41c78cae48e..36f40009094 100644 --- a/public/app/plugins/datasource/loki/package.json +++ b/public/app/plugins/datasource/loki/package.json @@ -33,7 +33,7 @@ "@types/d3-random": "^3.0.2", "@types/jest": "29.5.14", "@types/lodash": "4.17.20", - "@types/node": "22.17.0", + "@types/node": "24.9.2", "@types/react": "18.3.18", "@types/react-dom": "18.3.5", "@types/uuid": "10.0.0", diff --git a/public/app/plugins/datasource/mssql/package.json b/public/app/plugins/datasource/mssql/package.json index d69d7c10eb0..9f3da85359b 100644 --- a/public/app/plugins/datasource/mssql/package.json +++ b/public/app/plugins/datasource/mssql/package.json @@ -24,7 +24,7 @@ "@testing-library/user-event": "14.6.1", "@types/jest": "29.5.14", "@types/lodash": "4.17.20", - "@types/node": "22.17.0", + "@types/node": "24.9.2", "@types/react": "18.3.18", "i18next-cli": "1.11.12", "ts-node": "10.9.2", diff --git a/public/app/plugins/datasource/mysql/package.json b/public/app/plugins/datasource/mysql/package.json index f7325cdd3d1..b541a1506be 100644 --- a/public/app/plugins/datasource/mysql/package.json +++ b/public/app/plugins/datasource/mysql/package.json @@ -23,7 +23,7 @@ "@testing-library/user-event": "14.6.1", "@types/jest": "29.5.14", "@types/lodash": "4.17.20", - "@types/node": "22.17.0", + "@types/node": "24.9.2", "@types/react": "18.3.18", "jest": "29.7.0", "ts-node": "10.9.2", diff --git a/public/app/plugins/datasource/parca/package.json b/public/app/plugins/datasource/parca/package.json index 09e627a75eb..b4b6041c348 100644 --- a/public/app/plugins/datasource/parca/package.json +++ b/public/app/plugins/datasource/parca/package.json @@ -23,7 +23,7 @@ "@testing-library/react": "16.3.0", "@testing-library/user-event": "14.6.1", "@types/lodash": "4.17.20", - "@types/node": "22.17.0", + "@types/node": "24.9.2", "@types/react": "18.3.18", "@types/react-dom": "18.3.5", "jest": "29.7.0", diff --git a/public/app/plugins/datasource/tempo/package.json b/public/app/plugins/datasource/tempo/package.json index b3147dfd7b9..1a089ff5590 100644 --- a/public/app/plugins/datasource/tempo/package.json +++ b/public/app/plugins/datasource/tempo/package.json @@ -45,7 +45,7 @@ "@testing-library/user-event": "14.6.1", "@types/jest": "29.5.14", "@types/lodash": "4.17.20", - "@types/node": "22.17.0", + "@types/node": "24.9.2", "@types/prismjs": "1.26.5", "@types/react": "18.3.18", "@types/react-dom": "18.3.5", diff --git a/public/app/plugins/datasource/zipkin/package.json b/public/app/plugins/datasource/zipkin/package.json index c37f7d8d140..f7a8a8ad869 100644 --- a/public/app/plugins/datasource/zipkin/package.json +++ b/public/app/plugins/datasource/zipkin/package.json @@ -26,7 +26,7 @@ "@testing-library/react": "16.3.0", "@types/jest": "29.5.14", "@types/lodash": "4.17.20", - "@types/node": "22.17.0", + "@types/node": "24.9.2", "@types/react": "18.3.18", "@types/react-dom": "18.3.5", "jest": "29.7.0", diff --git a/yarn.lock b/yarn.lock index 9c9e587d570..6479a1bc630 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2448,7 +2448,7 @@ __metadata: "@testing-library/user-event": "npm:14.6.1" "@types/jest": "npm:29.5.14" "@types/lodash": "npm:4.17.20" - "@types/node": "npm:22.17.0" + "@types/node": "npm:24.9.2" "@types/prismjs": "npm:1.26.5" "@types/react": "npm:18.3.18" "@types/react-dom": "npm:18.3.5" @@ -2492,7 +2492,7 @@ __metadata: "@testing-library/user-event": "npm:14.6.1" "@types/jest": "npm:29.5.14" "@types/lodash": "npm:4.17.20" - "@types/node": "npm:22.17.0" + "@types/node": "npm:24.9.2" "@types/react": "npm:18.3.18" jest: "npm:29.7.0" lodash: "npm:4.17.21" @@ -2523,7 +2523,7 @@ __metadata: "@testing-library/user-event": "npm:14.6.1" "@types/jest": "npm:29.5.14" "@types/lodash": "npm:4.17.20" - "@types/node": "npm:22.17.0" + "@types/node": "npm:24.9.2" "@types/prismjs": "npm:1.26.5" "@types/react": "npm:18.3.18" "@types/react-dom": "npm:18.3.5" @@ -2566,7 +2566,7 @@ __metadata: "@types/d3-random": "npm:^3.0.2" "@types/jest": "npm:29.5.14" "@types/lodash": "npm:4.17.20" - "@types/node": "npm:22.17.0" + "@types/node": "npm:24.9.2" "@types/react": "npm:18.3.18" "@types/react-dom": "npm:18.3.5" "@types/uuid": "npm:10.0.0" @@ -2608,7 +2608,7 @@ __metadata: "@testing-library/user-event": "npm:14.6.1" "@types/jest": "npm:29.5.14" "@types/lodash": "npm:4.17.20" - "@types/node": "npm:22.17.0" + "@types/node": "npm:24.9.2" "@types/react": "npm:18.3.18" "@types/react-dom": "npm:18.3.5" "@types/semver": "npm:7.7.1" @@ -2651,7 +2651,7 @@ __metadata: "@types/jest": "npm:29.5.14" "@types/lodash": "npm:4.17.20" "@types/logfmt": "npm:^1.2.3" - "@types/node": "npm:22.17.0" + "@types/node": "npm:24.9.2" "@types/react": "npm:18.3.18" "@types/react-dom": "npm:18.3.5" "@types/react-window": "npm:1.8.8" @@ -2696,7 +2696,7 @@ __metadata: "@types/d3-random": "npm:^3.0.2" "@types/jest": "npm:29.5.14" "@types/lodash": "npm:4.17.20" - "@types/node": "npm:22.17.0" + "@types/node": "npm:24.9.2" "@types/react": "npm:18.3.18" "@types/react-dom": "npm:18.3.5" "@types/uuid": "npm:10.0.0" @@ -2737,7 +2737,7 @@ __metadata: "@testing-library/user-event": "npm:14.6.1" "@types/jest": "npm:29.5.14" "@types/lodash": "npm:4.17.20" - "@types/node": "npm:22.17.0" + "@types/node": "npm:24.9.2" "@types/react": "npm:18.3.18" i18next-cli: "npm:1.11.12" lodash: "npm:4.17.21" @@ -2769,7 +2769,7 @@ __metadata: "@testing-library/user-event": "npm:14.6.1" "@types/jest": "npm:29.5.14" "@types/lodash": "npm:4.17.20" - "@types/node": "npm:22.17.0" + "@types/node": "npm:24.9.2" "@types/react": "npm:18.3.18" jest: "npm:29.7.0" lodash: "npm:4.17.21" @@ -2798,7 +2798,7 @@ __metadata: "@testing-library/react": "npm:16.3.0" "@testing-library/user-event": "npm:14.6.1" "@types/lodash": "npm:4.17.20" - "@types/node": "npm:22.17.0" + "@types/node": "npm:24.9.2" "@types/react": "npm:18.3.18" "@types/react-dom": "npm:18.3.5" jest: "npm:29.7.0" @@ -2837,7 +2837,7 @@ __metadata: "@types/debounce-promise": "npm:3.1.9" "@types/jest": "npm:29.5.14" "@types/lodash": "npm:4.17.20" - "@types/node": "npm:22.17.0" + "@types/node": "npm:24.9.2" "@types/prismjs": "npm:1.26.5" "@types/react": "npm:18.3.18" "@types/react-dom": "npm:18.3.5" @@ -2890,7 +2890,7 @@ __metadata: "@testing-library/user-event": "npm:14.6.1" "@types/jest": "npm:29.5.14" "@types/lodash": "npm:4.17.20" - "@types/node": "npm:22.17.0" + "@types/node": "npm:24.9.2" "@types/prismjs": "npm:1.26.5" "@types/react": "npm:18.3.18" "@types/react-dom": "npm:18.3.5" @@ -2941,7 +2941,7 @@ __metadata: "@testing-library/react": "npm:16.3.0" "@types/jest": "npm:29.5.14" "@types/lodash": "npm:4.17.20" - "@types/node": "npm:22.17.0" + "@types/node": "npm:24.9.2" "@types/react": "npm:18.3.18" "@types/react-dom": "npm:18.3.5" jest: "npm:29.7.0" @@ -3074,7 +3074,7 @@ __metadata: "@types/d3-interpolate": "npm:^3.0.0" "@types/history": "npm:4.7.11" "@types/lodash": "npm:4.17.20" - "@types/node": "npm:22.17.0" + "@types/node": "npm:24.9.2" "@types/papaparse": "npm:5.3.16" "@types/react": "npm:18.3.18" "@types/react-dom": "npm:18.3.5" @@ -3120,7 +3120,7 @@ __metadata: resolution: "@grafana/e2e-selectors@workspace:packages/grafana-e2e-selectors" dependencies: "@rollup/plugin-node-resolve": "npm:16.0.1" - "@types/node": "npm:22.17.0" + "@types/node": "npm:24.9.2" "@types/semver": "npm:7.7.1" esbuild: "npm:0.25.8" rimraf: "npm:6.0.1" @@ -3226,7 +3226,7 @@ __metadata: "@types/d3": "npm:^7" "@types/jest": "npm:^29.5.4" "@types/lodash": "npm:4.17.20" - "@types/node": "npm:22.17.0" + "@types/node": "npm:24.9.2" "@types/react": "npm:18.3.18" "@types/react-virtualized-auto-sizer": "npm:1.0.8" "@types/tinycolor2": "npm:1.4.6" @@ -3347,7 +3347,7 @@ __metadata: "@testing-library/react": "npm:16.3.0" "@testing-library/user-event": "npm:14.6.1" "@types/jest": "npm:^29.5.4" - "@types/node": "npm:22.17.0" + "@types/node": "npm:24.9.2" "@types/react": "npm:18.3.18" "@types/systemjs": "npm:6.15.3" jest: "npm:^29.6.4" @@ -3469,7 +3469,7 @@ __metadata: "@types/debounce-promise": "npm:3.1.9" "@types/jest": "npm:29.5.14" "@types/lodash": "npm:4.17.20" - "@types/node": "npm:22.17.0" + "@types/node": "npm:24.9.2" "@types/pluralize": "npm:^0.0.33" "@types/prismjs": "npm:1.26.5" "@types/react": "npm:18.3.18" @@ -3662,7 +3662,7 @@ __metadata: "@testing-library/user-event": "npm:14.6.1" "@types/jest": "npm:^29.5.4" "@types/lodash": "npm:4.17.20" - "@types/node": "npm:22.17.0" + "@types/node": "npm:24.9.2" "@types/react": "npm:18.3.18" "@types/react-dom": "npm:18.3.5" "@types/react-virtualized-auto-sizer": "npm:1.0.8" @@ -3698,7 +3698,7 @@ __metadata: "@types/chance": "npm:^1.1.7" "@types/jest": "npm:29.5.14" "@types/lodash": "npm:4.17.20" - "@types/node": "npm:22.17.0" + "@types/node": "npm:24.9.2" chance: "npm:^1.1.13" jest: "npm:29.7.0" jest-matcher-utils: "npm:29.7.0" @@ -3770,7 +3770,7 @@ __metadata: "@types/jquery": "npm:3.5.33" "@types/lodash": "npm:4.17.20" "@types/mock-raf": "npm:1.0.6" - "@types/node": "npm:22.17.0" + "@types/node": "npm:24.9.2" "@types/prismjs": "npm:1.26.5" "@types/react": "npm:18.3.18" "@types/react-color": "npm:3.0.13" @@ -4077,13 +4077,20 @@ __metadata: languageName: node linkType: hard -"@inquirer/figures@npm:^1.0.14, @inquirer/figures@npm:^1.0.3": +"@inquirer/figures@npm:^1.0.14": version: 1.0.14 resolution: "@inquirer/figures@npm:1.0.14" checksum: 10/39df361eb607cea5a020d457e25f9c6aee3a1de8975c6295a4b3bfe86ba7e7f7bfbefa6a52b145b1790f2690e5c8f10eb822e5bc764aff7ba00a6cd24eec5a25 languageName: node linkType: hard +"@inquirer/figures@npm:^1.0.3": + version: 1.0.11 + resolution: "@inquirer/figures@npm:1.0.11" + checksum: 10/357ddd2e83718bc3c9189d518b93fd69099af9c860354df9a5ac0ec024cb5df1228ae4608d2de7625624d2adcd047db813f29426a610eaae7b9e449f8c753c6b + languageName: node + linkType: hard + "@inquirer/input@npm:^4.2.5": version: 4.2.5 resolution: "@inquirer/input@npm:4.2.5" @@ -6049,11 +6056,11 @@ __metadata: linkType: hard "@openfeature/web-sdk@npm:^1.6.1": - version: 1.7.0 - resolution: "@openfeature/web-sdk@npm:1.7.0" + version: 1.6.2 + resolution: "@openfeature/web-sdk@npm:1.6.2" peerDependencies: "@openfeature/core": ^1.9.0 - checksum: 10/8b9f5ec5bb0e618b439b2e18b73d5c1aecdeea98da28588dc949da2fa0bd8258d27a8329f2371b527410bbeb858af4a8b01254fda59df9d10b26fb23e9217c22 + checksum: 10/0fcc0ef76ff51d4725a00ff07755b21941b647f775d1ff04fc3d973143e78c909ccba485f582fcbc7f6201f42c795c85bcb103c43d64924fedf13ea517f625ac languageName: node linkType: hard @@ -8956,7 +8963,7 @@ __metadata: languageName: node linkType: hard -"@swc/core@npm:1.13.19, @swc/core@npm:^1.10.8, @swc/core@npm:^1.5.22": +"@swc/core@npm:1.13.19": version: 1.13.19 resolution: "@swc/core@npm:1.13.19" dependencies: @@ -9002,7 +9009,7 @@ __metadata: languageName: node linkType: hard -"@swc/core@npm:1.13.3": +"@swc/core@npm:1.13.3, @swc/core@npm:^1.10.8, @swc/core@npm:^1.5.22": version: 1.13.3 resolution: "@swc/core@npm:1.13.3" dependencies: @@ -9116,7 +9123,7 @@ __metadata: "@grafana/schema": "workspace:*" "@grafana/ui": "workspace:*" "@types/lodash": "npm:4.17.7" - "@types/node": "npm:22.15.0" + "@types/node": "npm:24.9.2" "@types/prismjs": "npm:1.26.4" "@types/react": "npm:18.3.18" "@types/react-dom": "npm:18.3.5" @@ -9148,7 +9155,7 @@ __metadata: "@grafana/schema": "workspace:*" "@grafana/ui": "workspace:*" "@types/lodash": "npm:4.17.7" - "@types/node": "npm:22.15.0" + "@types/node": "npm:24.9.2" "@types/prismjs": "npm:1.26.4" "@types/react": "npm:18.3.18" "@types/react-dom": "npm:18.3.5" @@ -10193,7 +10200,7 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:*, @types/node@npm:22.17.0, @types/node@npm:>=10.0.0, @types/node@npm:>=13.7.0, @types/node@npm:>=13.7.4": +"@types/node@npm:*, @types/node@npm:>=10.0.0, @types/node@npm:>=13.7.0, @types/node@npm:>=13.7.4": version: 22.17.0 resolution: "@types/node@npm:22.17.0" dependencies: @@ -10209,12 +10216,12 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:22.15.0": - version: 22.15.0 - resolution: "@types/node@npm:22.15.0" +"@types/node@npm:24.9.2": + version: 24.9.2 + resolution: "@types/node@npm:24.9.2" dependencies: - undici-types: "npm:~6.21.0" - checksum: 10/96911bc8bcebd32e96d0d6b46214f5b935e47ff3dac1fc6cf6a5256ebdd01dfecf689a41b3e3a1f35385c3341e0b79e0cf42a6409ce81e6b5fb9b3d7317fedbb + undici-types: "npm:~7.16.0" + checksum: 10/3e76ad89cca317c0886deedab0245b6b2a04ef6c47362bd3918020296f3e9630334795af9cee8c6633eae774c85d848ff2e6bed5a7c3133fc94968364fc3ee36 languageName: node linkType: hard @@ -13153,7 +13160,7 @@ __metadata: languageName: node linkType: hard -"chalk@npm:5.6.2, chalk@npm:^5.2.0, chalk@npm:^5.3.0, chalk@npm:^5.4.1, chalk@npm:^5.6.2": +"chalk@npm:5.6.2, chalk@npm:^5.6.2": version: 5.6.2 resolution: "chalk@npm:5.6.2" checksum: 10/1b2f48f6fba1370670d5610f9cd54c391d6ede28f4b7062dd38244ea5768777af72e5be6b74fb6c6d54cb84c4a2dff3f3afa9b7cb5948f7f022cfd3d087989e0 @@ -13191,6 +13198,13 @@ __metadata: languageName: node linkType: hard +"chalk@npm:^5.2.0, chalk@npm:^5.3.0, chalk@npm:^5.4.1": + version: 5.4.1 + resolution: "chalk@npm:5.4.1" + checksum: 10/29df3ffcdf25656fed6e95962e2ef86d14dfe03cd50e7074b06bad9ffbbf6089adbb40f75c00744d843685c8d008adaf3aed31476780312553caf07fa86e5bc7 + languageName: node + linkType: hard + "chance@npm:^1.1.13": version: 1.1.13 resolution: "chance@npm:1.1.13" @@ -13794,7 +13808,7 @@ __metadata: languageName: node linkType: hard -"commander@npm:14.0.1, commander@npm:~14.0.0": +"commander@npm:14.0.1": version: 14.0.1 resolution: "commander@npm:14.0.1" checksum: 10/783115e9403caeca29c0fcbd4e0358f70c67760e4e4933f3453fcdd5ddba2ec44173c8da5213d7ce5e404f51c7e71203a42c548164dbe27b668b32a8981577f1 @@ -13871,6 +13885,13 @@ __metadata: languageName: node linkType: hard +"commander@npm:~14.0.0": + version: 14.0.0 + resolution: "commander@npm:14.0.0" + checksum: 10/c05418bfc35a3e8b5c67bd9f75f5b773f386f9b85f83e70e7c926047f270929cb06cf13cd68f387dd6e7e23c6157de8171b28ba606abd3e6256028f1f789becf + languageName: node + linkType: hard + "comment-parser@npm:1.4.1": version: 1.4.1 resolution: "comment-parser@npm:1.4.1" @@ -16109,7 +16130,16 @@ __metadata: languageName: node linkType: hard -"enquirer@npm:^2.3.6, enquirer@npm:^2.4.1": +"enquirer@npm:^2.3.6, enquirer@npm:~2.3.6": + version: 2.3.6 + resolution: "enquirer@npm:2.3.6" + dependencies: + ansi-colors: "npm:^4.1.1" + checksum: 10/751d14f037eb7683997e696fb8d5fe2675e0b0cde91182c128cf598acf3f5bd9005f35f7c2a9109e291140af496ebec237b6dac86067d59a9b44f3688107f426 + languageName: node + linkType: hard + +"enquirer@npm:^2.4.1": version: 2.4.1 resolution: "enquirer@npm:2.4.1" dependencies: @@ -16119,15 +16149,6 @@ __metadata: languageName: node linkType: hard -"enquirer@npm:~2.3.6": - version: 2.3.6 - resolution: "enquirer@npm:2.3.6" - dependencies: - ansi-colors: "npm:^4.1.1" - checksum: 10/751d14f037eb7683997e696fb8d5fe2675e0b0cde91182c128cf598acf3f5bd9005f35f7c2a9109e291140af496ebec237b6dac86067d59a9b44f3688107f426 - languageName: node - linkType: hard - "ensure-posix-path@npm:^1.1.0": version: 1.1.1 resolution: "ensure-posix-path@npm:1.1.1" @@ -18882,7 +18903,7 @@ __metadata: "@types/lodash": "npm:4.17.20" "@types/logfmt": "npm:^1.2.3" "@types/lucene": "npm:^2" - "@types/node": "npm:22.17.0" + "@types/node": "npm:24.9.2" "@types/node-forge": "npm:^1" "@types/ol-ext": "npm:@siedlerchr/types-ol-ext@3.3.0" "@types/pluralize": "npm:^0.0.33" @@ -32578,6 +32599,13 @@ __metadata: languageName: node linkType: hard +"undici-types@npm:~7.16.0": + version: 7.16.0 + resolution: "undici-types@npm:7.16.0" + checksum: 10/db43439f69c2d94cc29f75cbfe9de86df87061d6b0c577ebe9bb3255f49b22c50162a7d7eb413b0458b6510b8ca299ac7cff38c3a29fbd31af9f504bcf7fbc0d + languageName: node + linkType: hard + "undici@npm:^7.12.0": version: 7.13.0 resolution: "undici@npm:7.13.0" From 0124aab8050011517674a765a587ae2d11d3bd8b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 29 Oct 2025 20:08:38 +0300 Subject: [PATCH 101/378] deps(actions): bump trufflesecurity/trufflehog from 3.90.11 to 3.90.12 (#113069) Bumps [trufflesecurity/trufflehog](https://github.com/trufflesecurity/trufflehog) from 3.90.11 to 3.90.12. - [Release notes](https://github.com/trufflesecurity/trufflehog/releases) - [Changelog](https://github.com/trufflesecurity/trufflehog/blob/main/.goreleaser.yml) - [Commits](https://github.com/trufflesecurity/trufflehog/compare/ad6fc8fb446b8fafbf7ea8193d2d6bfd42f45690...b84c3d14d189e16da175e2c27fa8136603783ffc) --- updated-dependencies: - dependency-name: trufflesecurity/trufflehog dependency-version: 3.90.12 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/trufflehog.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/trufflehog.yml b/.github/workflows/trufflehog.yml index 7278c8ad3ed..c5bc7fd095e 100644 --- a/.github/workflows/trufflehog.yml +++ b/.github/workflows/trufflehog.yml @@ -31,6 +31,6 @@ jobs: persist-credentials: false fetch-depth: ${{ steps.fetch_depth.outputs.fetch_depth }} - name: Trufflehog - uses: trufflesecurity/trufflehog@ad6fc8fb446b8fafbf7ea8193d2d6bfd42f45690 # v3.90.11 + uses: trufflesecurity/trufflehog@b84c3d14d189e16da175e2c27fa8136603783ffc # v3.90.12 with: extra_args: --results=verified From 6a3e95913ef091bf97492d98ee2db5a68df1fbb2 Mon Sep 17 00:00:00 2001 From: Ivan Ortega Alba Date: Wed, 29 Oct 2025 18:15:16 +0100 Subject: [PATCH 102/378] Scenes: Fix timezone not being preserved in links (#112879) * Scenes: Fix timezone not being preserved in links * Update E2E --- .../dashboard-templating.spec.ts | 9 ++------ package.json | 4 ++-- yarn.lock | 22 +++++++++---------- 3 files changed, 15 insertions(+), 20 deletions(-) diff --git a/e2e-playwright/dashboards-suite/dashboard-templating.spec.ts b/e2e-playwright/dashboards-suite/dashboard-templating.spec.ts index 1b3f8a326fa..ded0abd61ef 100644 --- a/e2e-playwright/dashboards-suite/dashboard-templating.spec.ts +++ b/e2e-playwright/dashboards-suite/dashboard-templating.spec.ts @@ -19,9 +19,7 @@ test.describe( // Open dashboard global variables and interpolation await gotoDashboardPage({ uid: DASHBOARD_UID }); - // Get the actual timezone from the browser context (should be Pacific/Easter due to test.use) - const timeZone = await page.evaluate(() => Intl.DateTimeFormat().resolvedOptions().timeZone); - const example = `Example: from=now-6h&to=now&timezone=${encodeURIComponent(timeZone)}`; + const example = `Example: from=now-6h&to=now&timezone=browser`; const expectedItems: string[] = [ '__dashboard = Templating - Global variables and interpolation', @@ -68,10 +66,7 @@ test.describe( // Check link interpolation is working correctly const exampleLink = page.locator(`a:has-text("${example}")`); - await expect(exampleLink).toHaveAttribute( - 'href', - `https://example.com/?from=now-6h&to=now&timezone=${encodeURIComponent(timeZone)}` - ); + await expect(exampleLink).toHaveAttribute('href', `https://example.com/?from=now-6h&to=now&timezone=browser`); }); } ); diff --git a/package.json b/package.json index f0f0e411591..d74e091448d 100644 --- a/package.json +++ b/package.json @@ -296,8 +296,8 @@ "@grafana/plugin-ui": "^0.10.10", "@grafana/prometheus": "workspace:*", "@grafana/runtime": "workspace:*", - "@grafana/scenes": "^6.39.8", - "@grafana/scenes-react": "^6.39.8", + "@grafana/scenes": "^6.40.1", + "@grafana/scenes-react": "^6.40.1", "@grafana/schema": "workspace:*", "@grafana/sql": "workspace:*", "@grafana/ui": "workspace:*", diff --git a/yarn.lock b/yarn.lock index 6479a1bc630..7480476abed 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3555,11 +3555,11 @@ __metadata: languageName: unknown linkType: soft -"@grafana/scenes-react@npm:^6.39.8": - version: 6.39.8 - resolution: "@grafana/scenes-react@npm:6.39.8" +"@grafana/scenes-react@npm:^6.40.1": + version: 6.40.1 + resolution: "@grafana/scenes-react@npm:6.40.1" dependencies: - "@grafana/scenes": "npm:6.39.8" + "@grafana/scenes": "npm:6.40.1" lru-cache: "npm:^10.2.2" react-use: "npm:^17.4.0" peerDependencies: @@ -3571,7 +3571,7 @@ __metadata: react: ^18.0.0 react-dom: ^18.0.0 react-router-dom: ^6.28.0 - checksum: 10/14f94437976890e5f9f2046be67796612273041f45ac76baace296249630e1189b28838ff6346c4463fa3fabf3e55d34ccbc4ff92a5ece83bf04566d52638c87 + checksum: 10/4515d53609d7b49e234bbc5c3da8131406c20b8ac0e54b1a5ca3ce3d1d42220ff08db65d31c83c9796188ef9d76e9a24fef170badb793a56b44bbabd31302575 languageName: node linkType: hard @@ -3601,9 +3601,9 @@ __metadata: languageName: node linkType: hard -"@grafana/scenes@npm:6.39.8, @grafana/scenes@npm:^6.39.8": - version: 6.39.8 - resolution: "@grafana/scenes@npm:6.39.8" +"@grafana/scenes@npm:6.40.1, @grafana/scenes@npm:^6.40.1": + version: 6.40.1 + resolution: "@grafana/scenes@npm:6.40.1" dependencies: "@floating-ui/react": "npm:^0.26.16" "@leeoniya/ufuzzy": "npm:^1.0.16" @@ -3623,7 +3623,7 @@ __metadata: react: ^18.0.0 react-dom: ^18.0.0 react-router-dom: ^6.28.0 - checksum: 10/0a9ce2dfae242c805463867d65f6dbd434490c764f791bb923af47b3042978ffceccbfe52e79d940b89c1e62f86a39992c10b505eb330dcf73005f69f2c2a444 + checksum: 10/f3f33d58bca9d05cf8d9527564e2f6bd9f164b44531382972c2b1ed0a54f54e29a6130fcab5797cd5dbba673e5d678ae5d1ef9c01ce6fe7895ee0f0c9408bc10 languageName: node linkType: hard @@ -18832,8 +18832,8 @@ __metadata: "@grafana/plugin-ui": "npm:^0.10.10" "@grafana/prometheus": "workspace:*" "@grafana/runtime": "workspace:*" - "@grafana/scenes": "npm:^6.39.8" - "@grafana/scenes-react": "npm:^6.39.8" + "@grafana/scenes": "npm:^6.40.1" + "@grafana/scenes-react": "npm:^6.40.1" "@grafana/schema": "workspace:*" "@grafana/sql": "workspace:*" "@grafana/test-utils": "workspace:*" From de88abafdd955d71d931b70c24dfe0c4b5a25b50 Mon Sep 17 00:00:00 2001 From: Todd Treece <360020+toddtreece@users.noreply.github.com> Date: Wed, 29 Oct 2025 13:32:31 -0400 Subject: [PATCH 103/378] Plugins API: Merge meta and installs (#112962) --- apps/plugins/go.mod | 6 +- apps/plugins/go.sum | 4 - apps/plugins/kinds/manifest.cue | 5 +- .../kinds/{pluginmeta.cue => plugin.cue} | 26 +- apps/plugins/kinds/plugininstall.cue | 15 - .../plugins/v0alpha1/plugin_client_gen.go | 123 ++++ ...nmeta_codec_gen.go => plugin_codec_gen.go} | 10 +- .../plugin_getmeta_response_types_gen.go | 463 +++++++++++++ ...metadata_gen.go => plugin_metadata_gen.go} | 8 +- ...eta_object_gen.go => plugin_object_gen.go} | 102 +-- .../plugins/v0alpha1/plugin_schema_gen.go | 34 + .../apis/plugins/v0alpha1/plugin_spec_gen.go | 25 + ...eta_status_gen.go => plugin_status_gen.go} | 28 +- .../v0alpha1/plugininstall_client_gen.go | 99 --- .../v0alpha1/plugininstall_codec_gen.go | 28 - .../v0alpha1/plugininstall_metadata_gen.go | 31 - .../v0alpha1/plugininstall_object_gen.go | 319 --------- .../v0alpha1/plugininstall_schema_gen.go | 34 - .../v0alpha1/plugininstall_spec_gen.go | 25 - .../v0alpha1/plugininstall_status_gen.go | 44 -- .../plugins/v0alpha1/pluginmeta_client_gen.go | 99 --- .../plugins/v0alpha1/pluginmeta_schema_gen.go | 34 - .../plugins/v0alpha1/pluginmeta_spec_gen.go | 477 -------------- apps/plugins/pkg/apis/plugins_manifest.go | 253 ++++++- apps/plugins/pkg/app/app.go | 43 +- apps/plugins/pkg/app/install/registrar.go | 16 +- apps/plugins/pkg/app/storage.go | 75 --- pkg/registry/apps/plugins/register.go | 25 +- .../pluginsintegration/installsync/syncer.go | 6 + .../installsync/syncer_test.go | 620 ++++++++---------- pkg/tests/apis/plugins/discovery_test.go | 48 +- pkg/tests/apis/plugins/plugininstalls_test.go | 185 +----- pkg/tests/apis/plugins/pluginsmeta_test.go | 47 -- 33 files changed, 1350 insertions(+), 2007 deletions(-) rename apps/plugins/kinds/{pluginmeta.cue => plugin.cue} (92%) delete mode 100644 apps/plugins/kinds/plugininstall.cue create mode 100644 apps/plugins/pkg/apis/plugins/v0alpha1/plugin_client_gen.go rename apps/plugins/pkg/apis/plugins/v0alpha1/{pluginmeta_codec_gen.go => plugin_codec_gen.go} (56%) create mode 100644 apps/plugins/pkg/apis/plugins/v0alpha1/plugin_getmeta_response_types_gen.go rename apps/plugins/pkg/apis/plugins/v0alpha1/{pluginmeta_metadata_gen.go => plugin_metadata_gen.go} (85%) rename apps/plugins/pkg/apis/plugins/v0alpha1/{pluginmeta_object_gen.go => plugin_object_gen.go} (69%) create mode 100644 apps/plugins/pkg/apis/plugins/v0alpha1/plugin_schema_gen.go create mode 100644 apps/plugins/pkg/apis/plugins/v0alpha1/plugin_spec_gen.go rename apps/plugins/pkg/apis/plugins/v0alpha1/{pluginmeta_status_gen.go => plugin_status_gen.go} (52%) delete mode 100644 apps/plugins/pkg/apis/plugins/v0alpha1/plugininstall_client_gen.go delete mode 100644 apps/plugins/pkg/apis/plugins/v0alpha1/plugininstall_codec_gen.go delete mode 100644 apps/plugins/pkg/apis/plugins/v0alpha1/plugininstall_metadata_gen.go delete mode 100644 apps/plugins/pkg/apis/plugins/v0alpha1/plugininstall_object_gen.go delete mode 100644 apps/plugins/pkg/apis/plugins/v0alpha1/plugininstall_schema_gen.go delete mode 100644 apps/plugins/pkg/apis/plugins/v0alpha1/plugininstall_spec_gen.go delete mode 100644 apps/plugins/pkg/apis/plugins/v0alpha1/plugininstall_status_gen.go delete mode 100644 apps/plugins/pkg/apis/plugins/v0alpha1/pluginmeta_client_gen.go delete mode 100644 apps/plugins/pkg/apis/plugins/v0alpha1/pluginmeta_schema_gen.go delete mode 100644 apps/plugins/pkg/apis/plugins/v0alpha1/pluginmeta_spec_gen.go delete mode 100644 apps/plugins/pkg/app/storage.go delete mode 100644 pkg/tests/apis/plugins/pluginsmeta_test.go diff --git a/apps/plugins/go.mod b/apps/plugins/go.mod index ab1de1b4186..f0ef53718bc 100644 --- a/apps/plugins/go.mod +++ b/apps/plugins/go.mod @@ -3,8 +3,8 @@ module github.com/grafana/grafana/apps/plugins go 1.25.3 require ( - github.com/grafana/authlib/types v0.0.0-20250926065801-df98203cff37 github.com/grafana/grafana-app-sdk v0.48.1 + github.com/grafana/grafana-app-sdk/logging v0.48.1 github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250428110029-a8ea72012bde k8s.io/apimachinery v0.34.1 k8s.io/apiserver v0.34.1 @@ -14,7 +14,6 @@ require ( require ( github.com/beorn7/perks v1.0.1 // indirect - github.com/blang/semver/v4 v4.0.0 // indirect github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874 // indirect github.com/cenkalti/backoff/v5 v5.0.3 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect @@ -37,8 +36,8 @@ require ( github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 // indirect github.com/google/uuid v1.6.0 // indirect github.com/grafana/authlib v0.0.0-20250930082137-a40e2c2b094f // indirect + github.com/grafana/authlib/types v0.0.0-20250926065801-df98203cff37 // indirect github.com/grafana/dskit v0.0.0-20250908063411-6b6da59b5cc4 // indirect - github.com/grafana/grafana-app-sdk/logging v0.48.1 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect @@ -93,7 +92,6 @@ require ( k8s.io/api v0.34.1 // indirect k8s.io/apiextensions-apiserver v0.34.1 // indirect k8s.io/client-go v0.34.1 // indirect - k8s.io/component-base v0.34.1 // indirect k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 // indirect sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect sigs.k8s.io/randfill v1.0.0 // indirect diff --git a/apps/plugins/go.sum b/apps/plugins/go.sum index 07264ead5aa..fb208331835 100644 --- a/apps/plugins/go.sum +++ b/apps/plugins/go.sum @@ -1,7 +1,5 @@ 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/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874 h1:N7oVaKyGp8bttX0bfZGmcGkjz7DLQXhAn3DNd3T0ous= github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874/go.mod h1:r5xuitiExdLAJ09PR7vBVENGvp4ZuTBeWTGtxuX3K+c= github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= @@ -242,8 +240,6 @@ k8s.io/apiserver v0.34.1 h1:U3JBGdgANK3dfFcyknWde1G6X1F4bg7PXuvlqt8lITA= k8s.io/apiserver v0.34.1/go.mod h1:eOOc9nrVqlBI1AFCvVzsob0OxtPZUCPiUJL45JOTBG0= k8s.io/client-go v0.34.1 h1:ZUPJKgXsnKwVwmKKdPfw4tB58+7/Ik3CrjOEhsiZ7mY= k8s.io/client-go v0.34.1/go.mod h1:kA8v0FP+tk6sZA0yKLRG67LWjqufAoSHA2xVGKw9Of8= -k8s.io/component-base v0.34.1 h1:v7xFgG+ONhytZNFpIz5/kecwD+sUhVE6HU7qQUiRM4A= -k8s.io/component-base v0.34.1/go.mod h1:mknCpLlTSKHzAQJJnnHVKqjxR7gBeHRv0rPXA7gdtQ0= 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-20250910181357-589584f1c912 h1:Y3gxNAuB0OBLImH611+UDZcmKS3g6CthxToOb37KgwE= diff --git a/apps/plugins/kinds/manifest.cue b/apps/plugins/kinds/manifest.cue index f16ba2d1a72..b3f5251432b 100644 --- a/apps/plugins/kinds/manifest.cue +++ b/apps/plugins/kinds/manifest.cue @@ -5,14 +5,13 @@ manifest: { groupOverride: "plugins.grafana.app" versions: { "v0alpha1": { - served: false + served: true codegen: { ts: {enabled: false} go: {enabled: true} } kinds: [ - pluginMetaV0Alpha1, - pluginInstallV0Alpha1, + pluginV0Alpha1, ] } } diff --git a/apps/plugins/kinds/pluginmeta.cue b/apps/plugins/kinds/plugin.cue similarity index 92% rename from apps/plugins/kinds/pluginmeta.cue rename to apps/plugins/kinds/plugin.cue index 93f41095707..4f381082969 100644 --- a/apps/plugins/kinds/pluginmeta.cue +++ b/apps/plugins/kinds/plugin.cue @@ -4,17 +4,33 @@ import ( "time" ) -pluginMetaV0Alpha1: { - kind: "PluginMeta" - plural: "pluginsmeta" +pluginV0Alpha1: { + kind: "Plugin" + plural: "plugins" scope: "Namespaced" schema: { spec: { - pluginJSON: #JSONData, + id: string + version: string + url?: string + class: "core" | "external" | "cdn" + } + } + routes: { + "/meta": { + "GET": { + request: {} + response: #JSONData, + responseMetadata: { + typeMeta: false + objectMeta: false + } + } } } } + // JSON configuration schema for Grafana plugins // Converted from: https://github.com/grafana/grafana/blob/main/docs/sources/developers/plugins/plugin.schema.json #JSONData: { @@ -217,4 +233,4 @@ pluginMetaV0Alpha1: { title?: string description?: string }] -} +} \ No newline at end of file diff --git a/apps/plugins/kinds/plugininstall.cue b/apps/plugins/kinds/plugininstall.cue deleted file mode 100644 index d72cfac7342..00000000000 --- a/apps/plugins/kinds/plugininstall.cue +++ /dev/null @@ -1,15 +0,0 @@ -package plugins - -pluginInstallV0Alpha1: { - kind: "PluginInstall" - plural: "plugininstalls" - scope: "Namespaced" - schema: { - spec: { - id: string - version: string - url?: string - class: "core" | "external" | "cdn" - } - } -} diff --git a/apps/plugins/pkg/apis/plugins/v0alpha1/plugin_client_gen.go b/apps/plugins/pkg/apis/plugins/v0alpha1/plugin_client_gen.go new file mode 100644 index 00000000000..3e9bcb3a2bb --- /dev/null +++ b/apps/plugins/pkg/apis/plugins/v0alpha1/plugin_client_gen.go @@ -0,0 +1,123 @@ +package v0alpha1 + +import ( + "context" + "encoding/json" + "fmt" + "net/http" + + "github.com/grafana/grafana-app-sdk/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +type PluginClient struct { + client *resource.TypedClient[*Plugin, *PluginList] +} + +func NewPluginClient(client resource.Client) *PluginClient { + return &PluginClient{ + client: resource.NewTypedClient[*Plugin, *PluginList](client, PluginKind()), + } +} + +func NewPluginClientFromGenerator(generator resource.ClientGenerator) (*PluginClient, error) { + c, err := generator.ClientFor(PluginKind()) + if err != nil { + return nil, err + } + return NewPluginClient(c), nil +} + +func (c *PluginClient) Get(ctx context.Context, identifier resource.Identifier) (*Plugin, error) { + return c.client.Get(ctx, identifier) +} + +func (c *PluginClient) List(ctx context.Context, namespace string, opts resource.ListOptions) (*PluginList, error) { + return c.client.List(ctx, namespace, opts) +} + +func (c *PluginClient) ListAll(ctx context.Context, namespace string, opts resource.ListOptions) (*PluginList, error) { + resp, err := c.client.List(ctx, namespace, resource.ListOptions{ + ResourceVersion: opts.ResourceVersion, + Limit: opts.Limit, + LabelFilters: opts.LabelFilters, + FieldSelectors: opts.FieldSelectors, + }) + if err != nil { + return nil, err + } + for resp.GetContinue() != "" { + page, err := c.client.List(ctx, namespace, resource.ListOptions{ + Continue: resp.GetContinue(), + ResourceVersion: opts.ResourceVersion, + Limit: opts.Limit, + LabelFilters: opts.LabelFilters, + FieldSelectors: opts.FieldSelectors, + }) + if err != nil { + return nil, err + } + resp.SetContinue(page.GetContinue()) + resp.SetResourceVersion(page.GetResourceVersion()) + resp.SetItems(append(resp.GetItems(), page.GetItems()...)) + } + return resp, nil +} + +func (c *PluginClient) Create(ctx context.Context, obj *Plugin, opts resource.CreateOptions) (*Plugin, error) { + // Make sure apiVersion and kind are set + obj.APIVersion = GroupVersion.Identifier() + obj.Kind = PluginKind().Kind() + return c.client.Create(ctx, obj, opts) +} + +func (c *PluginClient) Update(ctx context.Context, obj *Plugin, opts resource.UpdateOptions) (*Plugin, error) { + return c.client.Update(ctx, obj, opts) +} + +func (c *PluginClient) Patch(ctx context.Context, identifier resource.Identifier, req resource.PatchRequest, opts resource.PatchOptions) (*Plugin, error) { + return c.client.Patch(ctx, identifier, req, opts) +} + +func (c *PluginClient) UpdateStatus(ctx context.Context, identifier resource.Identifier, newStatus PluginStatus, opts resource.UpdateOptions) (*Plugin, error) { + return c.client.Update(ctx, &Plugin{ + TypeMeta: metav1.TypeMeta{ + Kind: PluginKind().Kind(), + APIVersion: GroupVersion.Identifier(), + }, + ObjectMeta: metav1.ObjectMeta{ + ResourceVersion: opts.ResourceVersion, + Namespace: identifier.Namespace, + Name: identifier.Name, + }, + Status: newStatus, + }, resource.UpdateOptions{ + Subresource: "status", + ResourceVersion: opts.ResourceVersion, + }) +} + +func (c *PluginClient) Delete(ctx context.Context, identifier resource.Identifier, opts resource.DeleteOptions) error { + return c.client.Delete(ctx, identifier, opts) +} + +type GetMetaRequest struct { + Headers http.Header +} + +func (c *PluginClient) GetMeta(ctx context.Context, identifier resource.Identifier, request GetMetaRequest) (*GetMeta, error) { + resp, err := c.client.SubresourceRequest(ctx, identifier, resource.CustomRouteRequestOptions{ + Path: "/meta", + Verb: "GET", + Headers: request.Headers, + }) + if err != nil { + return nil, err + } + cast := GetMeta{} + err = json.Unmarshal(resp, &cast) + if err != nil { + return nil, fmt.Errorf("unable to unmarshal response bytes into GetMeta: %w", err) + } + return &cast, nil +} diff --git a/apps/plugins/pkg/apis/plugins/v0alpha1/pluginmeta_codec_gen.go b/apps/plugins/pkg/apis/plugins/v0alpha1/plugin_codec_gen.go similarity index 56% rename from apps/plugins/pkg/apis/plugins/v0alpha1/pluginmeta_codec_gen.go rename to apps/plugins/pkg/apis/plugins/v0alpha1/plugin_codec_gen.go index 77fb6f918a2..c8fe78b00f1 100644 --- a/apps/plugins/pkg/apis/plugins/v0alpha1/pluginmeta_codec_gen.go +++ b/apps/plugins/pkg/apis/plugins/v0alpha1/plugin_codec_gen.go @@ -11,18 +11,18 @@ import ( "github.com/grafana/grafana-app-sdk/resource" ) -// PluginMetaJSONCodec is an implementation of resource.Codec for kubernetes JSON encoding -type PluginMetaJSONCodec struct{} +// PluginJSONCodec is an implementation of resource.Codec for kubernetes JSON encoding +type PluginJSONCodec struct{} // Read reads JSON-encoded bytes from `reader` and unmarshals them into `into` -func (*PluginMetaJSONCodec) Read(reader io.Reader, into resource.Object) error { +func (*PluginJSONCodec) Read(reader io.Reader, into resource.Object) error { return json.NewDecoder(reader).Decode(into) } // Write writes JSON-encoded bytes into `writer` marshaled from `from` -func (*PluginMetaJSONCodec) Write(writer io.Writer, from resource.Object) error { +func (*PluginJSONCodec) Write(writer io.Writer, from resource.Object) error { return json.NewEncoder(writer).Encode(from) } // Interface compliance checks -var _ resource.Codec = &PluginMetaJSONCodec{} +var _ resource.Codec = &PluginJSONCodec{} diff --git a/apps/plugins/pkg/apis/plugins/v0alpha1/plugin_getmeta_response_types_gen.go b/apps/plugins/pkg/apis/plugins/v0alpha1/plugin_getmeta_response_types_gen.go new file mode 100644 index 00000000000..6b0e6899a5b --- /dev/null +++ b/apps/plugins/pkg/apis/plugins/v0alpha1/plugin_getmeta_response_types_gen.go @@ -0,0 +1,463 @@ +// Code generated - EDITING IS FUTILE. DO NOT EDIT. + +package v0alpha1 + +import ( + time "time" +) + +// +k8s:openapi-gen=true +type Info struct { + // Required fields + // +listType=set + Keywords []string `json:"keywords"` + Logos V0alpha1InfoLogos `json:"logos"` + Updated time.Time `json:"updated"` + Version string `json:"version"` + // Optional fields + Author *V0alpha1InfoAuthor `json:"author,omitempty"` + Description *string `json:"description,omitempty"` + // +listType=atomic + Links []V0alpha1InfoLinks `json:"links,omitempty"` + // +listType=atomic + Screenshots []V0alpha1InfoScreenshots `json:"screenshots,omitempty"` +} + +// NewInfo creates a new Info object. +func NewInfo() *Info { + return &Info{ + Keywords: []string{}, + Logos: *NewV0alpha1InfoLogos(), + } +} + +// +k8s:openapi-gen=true +type Dependencies struct { + // Required field + GrafanaDependency string `json:"grafanaDependency"` + // Optional fields + GrafanaVersion *string `json:"grafanaVersion,omitempty"` + // +listType=set + // +listMapKey=id + Plugins []V0alpha1DependenciesPlugins `json:"plugins,omitempty"` + Extensions *V0alpha1DependenciesExtensions `json:"extensions,omitempty"` +} + +// NewDependencies creates a new Dependencies object. +func NewDependencies() *Dependencies { + return &Dependencies{} +} + +// +k8s:openapi-gen=true +type EnterpriseFeatures struct { + // Allow additional properties + HealthDiagnosticsErrors *bool `json:"healthDiagnosticsErrors,omitempty"` +} + +// NewEnterpriseFeatures creates a new EnterpriseFeatures object. +func NewEnterpriseFeatures() *EnterpriseFeatures { + return &EnterpriseFeatures{ + HealthDiagnosticsErrors: (func(input bool) *bool { return &input })(false), + } +} + +// +k8s:openapi-gen=true +type Include struct { + Uid *string `json:"uid,omitempty"` + Type *IncludeType `json:"type,omitempty"` + Name *string `json:"name,omitempty"` + Component *string `json:"component,omitempty"` + Role *IncludeRole `json:"role,omitempty"` + Action *string `json:"action,omitempty"` + Path *string `json:"path,omitempty"` + AddToNav *bool `json:"addToNav,omitempty"` + DefaultNav *bool `json:"defaultNav,omitempty"` + Icon *string `json:"icon,omitempty"` +} + +// NewInclude creates a new Include object. +func NewInclude() *Include { + return &Include{} +} + +// +k8s:openapi-gen=true +type QueryOptions struct { + MaxDataPoints *bool `json:"maxDataPoints,omitempty"` + MinInterval *bool `json:"minInterval,omitempty"` + CacheTimeout *bool `json:"cacheTimeout,omitempty"` +} + +// NewQueryOptions creates a new QueryOptions object. +func NewQueryOptions() *QueryOptions { + return &QueryOptions{} +} + +// +k8s:openapi-gen=true +type Route struct { + Path *string `json:"path,omitempty"` + Method *string `json:"method,omitempty"` + Url *string `json:"url,omitempty"` + ReqSignedIn *bool `json:"reqSignedIn,omitempty"` + ReqRole *string `json:"reqRole,omitempty"` + ReqAction *string `json:"reqAction,omitempty"` + // +listType=atomic + Headers []string `json:"headers,omitempty"` + Body map[string]interface{} `json:"body,omitempty"` + TokenAuth *V0alpha1RouteTokenAuth `json:"tokenAuth,omitempty"` + JwtTokenAuth *V0alpha1RouteJwtTokenAuth `json:"jwtTokenAuth,omitempty"` + // +listType=atomic + UrlParams []V0alpha1RouteUrlParams `json:"urlParams,omitempty"` +} + +// NewRoute creates a new Route object. +func NewRoute() *Route { + return &Route{} +} + +// +k8s:openapi-gen=true +type IAM struct { + // +listType=atomic + Permissions []V0alpha1IAMPermissions `json:"permissions,omitempty"` +} + +// NewIAM creates a new IAM object. +func NewIAM() *IAM { + return &IAM{} +} + +// +k8s:openapi-gen=true +type Role struct { + Role *V0alpha1RoleRole `json:"role,omitempty"` + // +listType=set + Grants []string `json:"grants,omitempty"` +} + +// NewRole creates a new Role object. +func NewRole() *Role { + return &Role{} +} + +// +k8s:openapi-gen=true +type Extensions struct { + // +listType=atomic + AddedComponents []V0alpha1ExtensionsAddedComponents `json:"addedComponents,omitempty"` + // +listType=atomic + AddedLinks []V0alpha1ExtensionsAddedLinks `json:"addedLinks,omitempty"` + // +listType=set + // +listMapKey=id + ExposedComponents []V0alpha1ExtensionsExposedComponents `json:"exposedComponents,omitempty"` + // +listType=set + // +listMapKey=id + ExtensionPoints []V0alpha1ExtensionsExtensionPoints `json:"extensionPoints,omitempty"` +} + +// NewExtensions creates a new Extensions object. +func NewExtensions() *Extensions { + return &Extensions{} +} + +// +k8s:openapi-gen=true +type GetMeta struct { + // Unique name of the plugin + Id string `json:"id"` + // Plugin type + Type GetMetaType `json:"type"` + // Human-readable name of the plugin + Name string `json:"name"` + // Metadata for the plugin + Info Info `json:"info"` + // Dependency information + Dependencies Dependencies `json:"dependencies"` + // Optional fields + Alerting *bool `json:"alerting,omitempty"` + Annotations *bool `json:"annotations,omitempty"` + AutoEnabled *bool `json:"autoEnabled,omitempty"` + Backend *bool `json:"backend,omitempty"` + BuildMode *string `json:"buildMode,omitempty"` + BuiltIn *bool `json:"builtIn,omitempty"` + Category *GetMetaCategory `json:"category,omitempty"` + EnterpriseFeatures *EnterpriseFeatures `json:"enterpriseFeatures,omitempty"` + Executable *string `json:"executable,omitempty"` + HideFromList *bool `json:"hideFromList,omitempty"` + // +listType=atomic + Includes []Include `json:"includes,omitempty"` + Logs *bool `json:"logs,omitempty"` + Metrics *bool `json:"metrics,omitempty"` + MultiValueFilterOperators *bool `json:"multiValueFilterOperators,omitempty"` + PascalName *string `json:"pascalName,omitempty"` + Preload *bool `json:"preload,omitempty"` + QueryOptions *QueryOptions `json:"queryOptions,omitempty"` + // +listType=atomic + Routes []Route `json:"routes,omitempty"` + SkipDataQuery *bool `json:"skipDataQuery,omitempty"` + State *GetMetaState `json:"state,omitempty"` + Streaming *bool `json:"streaming,omitempty"` + Tracing *bool `json:"tracing,omitempty"` + Iam *IAM `json:"iam,omitempty"` + // +listType=atomic + Roles []Role `json:"roles,omitempty"` + Extensions *Extensions `json:"extensions,omitempty"` +} + +// NewGetMeta creates a new GetMeta object. +func NewGetMeta() *GetMeta { + return &GetMeta{ + Info: *NewInfo(), + Dependencies: *NewDependencies(), + } +} + +// +k8s:openapi-gen=true +type V0alpha1InfoLogos struct { + Small string `json:"small"` + Large string `json:"large"` +} + +// NewV0alpha1InfoLogos creates a new V0alpha1InfoLogos object. +func NewV0alpha1InfoLogos() *V0alpha1InfoLogos { + return &V0alpha1InfoLogos{} +} + +// +k8s:openapi-gen=true +type V0alpha1InfoAuthor struct { + Name *string `json:"name,omitempty"` + Email *string `json:"email,omitempty"` + Url *string `json:"url,omitempty"` +} + +// NewV0alpha1InfoAuthor creates a new V0alpha1InfoAuthor object. +func NewV0alpha1InfoAuthor() *V0alpha1InfoAuthor { + return &V0alpha1InfoAuthor{} +} + +// +k8s:openapi-gen=true +type V0alpha1InfoLinks struct { + Name *string `json:"name,omitempty"` + Url *string `json:"url,omitempty"` +} + +// NewV0alpha1InfoLinks creates a new V0alpha1InfoLinks object. +func NewV0alpha1InfoLinks() *V0alpha1InfoLinks { + return &V0alpha1InfoLinks{} +} + +// +k8s:openapi-gen=true +type V0alpha1InfoScreenshots struct { + Name *string `json:"name,omitempty"` + Path *string `json:"path,omitempty"` +} + +// NewV0alpha1InfoScreenshots creates a new V0alpha1InfoScreenshots object. +func NewV0alpha1InfoScreenshots() *V0alpha1InfoScreenshots { + return &V0alpha1InfoScreenshots{} +} + +// +k8s:openapi-gen=true +type V0alpha1DependenciesPlugins struct { + Id string `json:"id"` + Type V0alpha1DependenciesPluginsType `json:"type"` + Name string `json:"name"` +} + +// NewV0alpha1DependenciesPlugins creates a new V0alpha1DependenciesPlugins object. +func NewV0alpha1DependenciesPlugins() *V0alpha1DependenciesPlugins { + return &V0alpha1DependenciesPlugins{} +} + +// +k8s:openapi-gen=true +type V0alpha1DependenciesExtensions struct { + // +listType=set + ExposedComponents []string `json:"exposedComponents,omitempty"` +} + +// NewV0alpha1DependenciesExtensions creates a new V0alpha1DependenciesExtensions object. +func NewV0alpha1DependenciesExtensions() *V0alpha1DependenciesExtensions { + return &V0alpha1DependenciesExtensions{} +} + +// +k8s:openapi-gen=true +type V0alpha1RouteTokenAuth struct { + Url *string `json:"url,omitempty"` + // +listType=set + Scopes []string `json:"scopes,omitempty"` + Params map[string]interface{} `json:"params,omitempty"` +} + +// NewV0alpha1RouteTokenAuth creates a new V0alpha1RouteTokenAuth object. +func NewV0alpha1RouteTokenAuth() *V0alpha1RouteTokenAuth { + return &V0alpha1RouteTokenAuth{} +} + +// +k8s:openapi-gen=true +type V0alpha1RouteJwtTokenAuth struct { + Url *string `json:"url,omitempty"` + // +listType=set + Scopes []string `json:"scopes,omitempty"` + Params map[string]interface{} `json:"params,omitempty"` +} + +// NewV0alpha1RouteJwtTokenAuth creates a new V0alpha1RouteJwtTokenAuth object. +func NewV0alpha1RouteJwtTokenAuth() *V0alpha1RouteJwtTokenAuth { + return &V0alpha1RouteJwtTokenAuth{} +} + +// +k8s:openapi-gen=true +type V0alpha1RouteUrlParams struct { + Name *string `json:"name,omitempty"` + Content *string `json:"content,omitempty"` +} + +// NewV0alpha1RouteUrlParams creates a new V0alpha1RouteUrlParams object. +func NewV0alpha1RouteUrlParams() *V0alpha1RouteUrlParams { + return &V0alpha1RouteUrlParams{} +} + +// +k8s:openapi-gen=true +type V0alpha1IAMPermissions struct { + Action *string `json:"action,omitempty"` + Scope *string `json:"scope,omitempty"` +} + +// NewV0alpha1IAMPermissions creates a new V0alpha1IAMPermissions object. +func NewV0alpha1IAMPermissions() *V0alpha1IAMPermissions { + return &V0alpha1IAMPermissions{} +} + +// +k8s:openapi-gen=true +type V0alpha1RoleRolePermissions struct { + Action *string `json:"action,omitempty"` + Scope *string `json:"scope,omitempty"` +} + +// NewV0alpha1RoleRolePermissions creates a new V0alpha1RoleRolePermissions object. +func NewV0alpha1RoleRolePermissions() *V0alpha1RoleRolePermissions { + return &V0alpha1RoleRolePermissions{} +} + +// +k8s:openapi-gen=true +type V0alpha1RoleRole struct { + Name *string `json:"name,omitempty"` + Description *string `json:"description,omitempty"` + // +listType=atomic + Permissions []V0alpha1RoleRolePermissions `json:"permissions,omitempty"` +} + +// NewV0alpha1RoleRole creates a new V0alpha1RoleRole object. +func NewV0alpha1RoleRole() *V0alpha1RoleRole { + return &V0alpha1RoleRole{} +} + +// +k8s:openapi-gen=true +type V0alpha1ExtensionsAddedComponents struct { + // +listType=set + Targets []string `json:"targets"` + Title string `json:"title"` + Description *string `json:"description,omitempty"` +} + +// NewV0alpha1ExtensionsAddedComponents creates a new V0alpha1ExtensionsAddedComponents object. +func NewV0alpha1ExtensionsAddedComponents() *V0alpha1ExtensionsAddedComponents { + return &V0alpha1ExtensionsAddedComponents{ + Targets: []string{}, + } +} + +// +k8s:openapi-gen=true +type V0alpha1ExtensionsAddedLinks struct { + // +listType=set + Targets []string `json:"targets"` + Title string `json:"title"` + Description *string `json:"description,omitempty"` +} + +// NewV0alpha1ExtensionsAddedLinks creates a new V0alpha1ExtensionsAddedLinks object. +func NewV0alpha1ExtensionsAddedLinks() *V0alpha1ExtensionsAddedLinks { + return &V0alpha1ExtensionsAddedLinks{ + Targets: []string{}, + } +} + +// +k8s:openapi-gen=true +type V0alpha1ExtensionsExposedComponents struct { + Id string `json:"id"` + Title *string `json:"title,omitempty"` + Description *string `json:"description,omitempty"` +} + +// NewV0alpha1ExtensionsExposedComponents creates a new V0alpha1ExtensionsExposedComponents object. +func NewV0alpha1ExtensionsExposedComponents() *V0alpha1ExtensionsExposedComponents { + return &V0alpha1ExtensionsExposedComponents{} +} + +// +k8s:openapi-gen=true +type V0alpha1ExtensionsExtensionPoints struct { + Id string `json:"id"` + Title *string `json:"title,omitempty"` + Description *string `json:"description,omitempty"` +} + +// NewV0alpha1ExtensionsExtensionPoints creates a new V0alpha1ExtensionsExtensionPoints object. +func NewV0alpha1ExtensionsExtensionPoints() *V0alpha1ExtensionsExtensionPoints { + return &V0alpha1ExtensionsExtensionPoints{} +} + +// +k8s:openapi-gen=true +type IncludeType string + +const ( + IncludeTypeDashboard IncludeType = "dashboard" + IncludeTypePage IncludeType = "page" + IncludeTypePanel IncludeType = "panel" + IncludeTypeDatasource IncludeType = "datasource" +) + +// +k8s:openapi-gen=true +type IncludeRole string + +const ( + IncludeRoleAdmin IncludeRole = "Admin" + IncludeRoleEditor IncludeRole = "Editor" + IncludeRoleViewer IncludeRole = "Viewer" +) + +// +k8s:openapi-gen=true +type GetMetaType string + +const ( + GetMetaTypeApp GetMetaType = "app" + GetMetaTypeDatasource GetMetaType = "datasource" + GetMetaTypePanel GetMetaType = "panel" + GetMetaTypeRenderer GetMetaType = "renderer" +) + +// +k8s:openapi-gen=true +type GetMetaCategory string + +const ( + GetMetaCategoryTsdb GetMetaCategory = "tsdb" + GetMetaCategoryLogging GetMetaCategory = "logging" + GetMetaCategoryCloud GetMetaCategory = "cloud" + GetMetaCategoryTracing GetMetaCategory = "tracing" + GetMetaCategoryProfiling GetMetaCategory = "profiling" + GetMetaCategorySql GetMetaCategory = "sql" + GetMetaCategoryEnterprise GetMetaCategory = "enterprise" + GetMetaCategoryIot GetMetaCategory = "iot" + GetMetaCategoryOther GetMetaCategory = "other" +) + +// +k8s:openapi-gen=true +type GetMetaState string + +const ( + GetMetaStateAlpha GetMetaState = "alpha" + GetMetaStateBeta GetMetaState = "beta" +) + +// +k8s:openapi-gen=true +type V0alpha1DependenciesPluginsType string + +const ( + V0alpha1DependenciesPluginsTypeApp V0alpha1DependenciesPluginsType = "app" + V0alpha1DependenciesPluginsTypeDatasource V0alpha1DependenciesPluginsType = "datasource" + V0alpha1DependenciesPluginsTypePanel V0alpha1DependenciesPluginsType = "panel" +) diff --git a/apps/plugins/pkg/apis/plugins/v0alpha1/pluginmeta_metadata_gen.go b/apps/plugins/pkg/apis/plugins/v0alpha1/plugin_metadata_gen.go similarity index 85% rename from apps/plugins/pkg/apis/plugins/v0alpha1/pluginmeta_metadata_gen.go rename to apps/plugins/pkg/apis/plugins/v0alpha1/plugin_metadata_gen.go index 7d3b3c9c6b8..fe30fe5e614 100644 --- a/apps/plugins/pkg/apis/plugins/v0alpha1/pluginmeta_metadata_gen.go +++ b/apps/plugins/pkg/apis/plugins/v0alpha1/plugin_metadata_gen.go @@ -9,7 +9,7 @@ import ( // metadata contains embedded CommonMetadata and can be extended with custom string fields // TODO: use CommonMetadata instead of redefining here; currently needs to be defined here // without external reference as using the CommonMetadata reference breaks thema codegen. -type PluginMetaMetadata struct { +type PluginMetadata struct { UpdateTimestamp time.Time `json:"updateTimestamp"` CreatedBy string `json:"createdBy"` Uid string `json:"uid"` @@ -22,9 +22,9 @@ type PluginMetaMetadata struct { Labels map[string]string `json:"labels"` } -// NewPluginMetaMetadata creates a new PluginMetaMetadata object. -func NewPluginMetaMetadata() *PluginMetaMetadata { - return &PluginMetaMetadata{ +// NewPluginMetadata creates a new PluginMetadata object. +func NewPluginMetadata() *PluginMetadata { + return &PluginMetadata{ Finalizers: []string{}, Labels: map[string]string{}, } diff --git a/apps/plugins/pkg/apis/plugins/v0alpha1/pluginmeta_object_gen.go b/apps/plugins/pkg/apis/plugins/v0alpha1/plugin_object_gen.go similarity index 69% rename from apps/plugins/pkg/apis/plugins/v0alpha1/pluginmeta_object_gen.go rename to apps/plugins/pkg/apis/plugins/v0alpha1/plugin_object_gen.go index dac431ebf12..d2cdedba399 100644 --- a/apps/plugins/pkg/apis/plugins/v0alpha1/pluginmeta_object_gen.go +++ b/apps/plugins/pkg/apis/plugins/v0alpha1/plugin_object_gen.go @@ -15,22 +15,22 @@ import ( ) // +k8s:openapi-gen=true -type PluginMeta struct { +type Plugin struct { metav1.TypeMeta `json:",inline" yaml:",inline"` metav1.ObjectMeta `json:"metadata" yaml:"metadata"` - // Spec is the spec of the PluginMeta - Spec PluginMetaSpec `json:"spec" yaml:"spec"` + // Spec is the spec of the Plugin + Spec PluginSpec `json:"spec" yaml:"spec"` - Status PluginMetaStatus `json:"status" yaml:"status"` + Status PluginStatus `json:"status" yaml:"status"` } -func (o *PluginMeta) GetSpec() any { +func (o *Plugin) GetSpec() any { return o.Spec } -func (o *PluginMeta) SetSpec(spec any) error { - cast, ok := spec.(PluginMetaSpec) +func (o *Plugin) SetSpec(spec any) error { + cast, ok := spec.(PluginSpec) if !ok { return fmt.Errorf("cannot set spec type %#v, not of type Spec", spec) } @@ -38,13 +38,13 @@ func (o *PluginMeta) SetSpec(spec any) error { return nil } -func (o *PluginMeta) GetSubresources() map[string]any { +func (o *Plugin) GetSubresources() map[string]any { return map[string]any{ "status": o.Status, } } -func (o *PluginMeta) GetSubresource(name string) (any, bool) { +func (o *Plugin) GetSubresource(name string) (any, bool) { switch name { case "status": return o.Status, true @@ -53,12 +53,12 @@ func (o *PluginMeta) GetSubresource(name string) (any, bool) { } } -func (o *PluginMeta) SetSubresource(name string, value any) error { +func (o *Plugin) SetSubresource(name string, value any) error { switch name { case "status": - cast, ok := value.(PluginMetaStatus) + cast, ok := value.(PluginStatus) if !ok { - return fmt.Errorf("cannot set status type %#v, not of type PluginMetaStatus", value) + return fmt.Errorf("cannot set status type %#v, not of type PluginStatus", value) } o.Status = cast return nil @@ -67,7 +67,7 @@ func (o *PluginMeta) SetSubresource(name string, value any) error { } } -func (o *PluginMeta) GetStaticMetadata() resource.StaticMetadata { +func (o *Plugin) GetStaticMetadata() resource.StaticMetadata { gvk := o.GroupVersionKind() return resource.StaticMetadata{ Name: o.ObjectMeta.Name, @@ -78,7 +78,7 @@ func (o *PluginMeta) GetStaticMetadata() resource.StaticMetadata { } } -func (o *PluginMeta) SetStaticMetadata(metadata resource.StaticMetadata) { +func (o *Plugin) SetStaticMetadata(metadata resource.StaticMetadata) { o.Name = metadata.Name o.Namespace = metadata.Namespace o.SetGroupVersionKind(schema.GroupVersionKind{ @@ -88,7 +88,7 @@ func (o *PluginMeta) SetStaticMetadata(metadata resource.StaticMetadata) { }) } -func (o *PluginMeta) GetCommonMetadata() resource.CommonMetadata { +func (o *Plugin) GetCommonMetadata() resource.CommonMetadata { dt := o.DeletionTimestamp var deletionTimestamp *time.Time if dt != nil { @@ -120,7 +120,7 @@ func (o *PluginMeta) GetCommonMetadata() resource.CommonMetadata { } } -func (o *PluginMeta) SetCommonMetadata(metadata resource.CommonMetadata) { +func (o *Plugin) SetCommonMetadata(metadata resource.CommonMetadata) { o.UID = types.UID(metadata.UID) o.ResourceVersion = metadata.ResourceVersion o.Generation = metadata.Generation @@ -165,7 +165,7 @@ func (o *PluginMeta) SetCommonMetadata(metadata resource.CommonMetadata) { } } -func (o *PluginMeta) GetCreatedBy() string { +func (o *Plugin) GetCreatedBy() string { if o.ObjectMeta.Annotations == nil { o.ObjectMeta.Annotations = make(map[string]string) } @@ -173,7 +173,7 @@ func (o *PluginMeta) GetCreatedBy() string { return o.ObjectMeta.Annotations["grafana.com/createdBy"] } -func (o *PluginMeta) SetCreatedBy(createdBy string) { +func (o *Plugin) SetCreatedBy(createdBy string) { if o.ObjectMeta.Annotations == nil { o.ObjectMeta.Annotations = make(map[string]string) } @@ -181,7 +181,7 @@ func (o *PluginMeta) SetCreatedBy(createdBy string) { o.ObjectMeta.Annotations["grafana.com/createdBy"] = createdBy } -func (o *PluginMeta) GetUpdateTimestamp() time.Time { +func (o *Plugin) GetUpdateTimestamp() time.Time { if o.ObjectMeta.Annotations == nil { o.ObjectMeta.Annotations = make(map[string]string) } @@ -190,7 +190,7 @@ func (o *PluginMeta) GetUpdateTimestamp() time.Time { return parsed } -func (o *PluginMeta) SetUpdateTimestamp(updateTimestamp time.Time) { +func (o *Plugin) SetUpdateTimestamp(updateTimestamp time.Time) { if o.ObjectMeta.Annotations == nil { o.ObjectMeta.Annotations = make(map[string]string) } @@ -198,7 +198,7 @@ func (o *PluginMeta) SetUpdateTimestamp(updateTimestamp time.Time) { o.ObjectMeta.Annotations["grafana.com/updateTimestamp"] = updateTimestamp.Format(time.RFC3339) } -func (o *PluginMeta) GetUpdatedBy() string { +func (o *Plugin) GetUpdatedBy() string { if o.ObjectMeta.Annotations == nil { o.ObjectMeta.Annotations = make(map[string]string) } @@ -206,7 +206,7 @@ func (o *PluginMeta) GetUpdatedBy() string { return o.ObjectMeta.Annotations["grafana.com/updatedBy"] } -func (o *PluginMeta) SetUpdatedBy(updatedBy string) { +func (o *Plugin) SetUpdatedBy(updatedBy string) { if o.ObjectMeta.Annotations == nil { o.ObjectMeta.Annotations = make(map[string]string) } @@ -214,21 +214,21 @@ func (o *PluginMeta) SetUpdatedBy(updatedBy string) { o.ObjectMeta.Annotations["grafana.com/updatedBy"] = updatedBy } -func (o *PluginMeta) Copy() resource.Object { +func (o *Plugin) Copy() resource.Object { return resource.CopyObject(o) } -func (o *PluginMeta) DeepCopyObject() runtime.Object { +func (o *Plugin) DeepCopyObject() runtime.Object { return o.Copy() } -func (o *PluginMeta) DeepCopy() *PluginMeta { - cpy := &PluginMeta{} +func (o *Plugin) DeepCopy() *Plugin { + cpy := &Plugin{} o.DeepCopyInto(cpy) return cpy } -func (o *PluginMeta) DeepCopyInto(dst *PluginMeta) { +func (o *Plugin) DeepCopyInto(dst *Plugin) { dst.TypeMeta.APIVersion = o.TypeMeta.APIVersion dst.TypeMeta.Kind = o.TypeMeta.Kind o.ObjectMeta.DeepCopyInto(&dst.ObjectMeta) @@ -237,34 +237,34 @@ func (o *PluginMeta) DeepCopyInto(dst *PluginMeta) { } // Interface compliance compile-time check -var _ resource.Object = &PluginMeta{} +var _ resource.Object = &Plugin{} // +k8s:openapi-gen=true -type PluginMetaList struct { +type PluginList struct { metav1.TypeMeta `json:",inline" yaml:",inline"` metav1.ListMeta `json:"metadata" yaml:"metadata"` - Items []PluginMeta `json:"items" yaml:"items"` + Items []Plugin `json:"items" yaml:"items"` } -func (o *PluginMetaList) DeepCopyObject() runtime.Object { +func (o *PluginList) DeepCopyObject() runtime.Object { return o.Copy() } -func (o *PluginMetaList) Copy() resource.ListObject { - cpy := &PluginMetaList{ +func (o *PluginList) Copy() resource.ListObject { + cpy := &PluginList{ TypeMeta: o.TypeMeta, - Items: make([]PluginMeta, len(o.Items)), + Items: make([]Plugin, len(o.Items)), } o.ListMeta.DeepCopyInto(&cpy.ListMeta) for i := 0; i < len(o.Items); i++ { - if item, ok := o.Items[i].Copy().(*PluginMeta); ok { + if item, ok := o.Items[i].Copy().(*Plugin); ok { cpy.Items[i] = *item } } return cpy } -func (o *PluginMetaList) GetItems() []resource.Object { +func (o *PluginList) GetItems() []resource.Object { items := make([]resource.Object, len(o.Items)) for i := 0; i < len(o.Items); i++ { items[i] = &o.Items[i] @@ -272,48 +272,48 @@ func (o *PluginMetaList) GetItems() []resource.Object { return items } -func (o *PluginMetaList) SetItems(items []resource.Object) { - o.Items = make([]PluginMeta, len(items)) +func (o *PluginList) SetItems(items []resource.Object) { + o.Items = make([]Plugin, len(items)) for i := 0; i < len(items); i++ { - o.Items[i] = *items[i].(*PluginMeta) + o.Items[i] = *items[i].(*Plugin) } } -func (o *PluginMetaList) DeepCopy() *PluginMetaList { - cpy := &PluginMetaList{} +func (o *PluginList) DeepCopy() *PluginList { + cpy := &PluginList{} o.DeepCopyInto(cpy) return cpy } -func (o *PluginMetaList) DeepCopyInto(dst *PluginMetaList) { +func (o *PluginList) DeepCopyInto(dst *PluginList) { resource.CopyObjectInto(dst, o) } // Interface compliance compile-time check -var _ resource.ListObject = &PluginMetaList{} +var _ resource.ListObject = &PluginList{} // Copy methods for all subresource types // DeepCopy creates a full deep copy of Spec -func (s *PluginMetaSpec) DeepCopy() *PluginMetaSpec { - cpy := &PluginMetaSpec{} +func (s *PluginSpec) DeepCopy() *PluginSpec { + cpy := &PluginSpec{} s.DeepCopyInto(cpy) return cpy } // DeepCopyInto deep copies Spec into another Spec object -func (s *PluginMetaSpec) DeepCopyInto(dst *PluginMetaSpec) { +func (s *PluginSpec) DeepCopyInto(dst *PluginSpec) { resource.CopyObjectInto(dst, s) } -// DeepCopy creates a full deep copy of PluginMetaStatus -func (s *PluginMetaStatus) DeepCopy() *PluginMetaStatus { - cpy := &PluginMetaStatus{} +// DeepCopy creates a full deep copy of PluginStatus +func (s *PluginStatus) DeepCopy() *PluginStatus { + cpy := &PluginStatus{} s.DeepCopyInto(cpy) return cpy } -// DeepCopyInto deep copies PluginMetaStatus into another PluginMetaStatus object -func (s *PluginMetaStatus) DeepCopyInto(dst *PluginMetaStatus) { +// DeepCopyInto deep copies PluginStatus into another PluginStatus object +func (s *PluginStatus) DeepCopyInto(dst *PluginStatus) { resource.CopyObjectInto(dst, s) } diff --git a/apps/plugins/pkg/apis/plugins/v0alpha1/plugin_schema_gen.go b/apps/plugins/pkg/apis/plugins/v0alpha1/plugin_schema_gen.go new file mode 100644 index 00000000000..97024275a1c --- /dev/null +++ b/apps/plugins/pkg/apis/plugins/v0alpha1/plugin_schema_gen.go @@ -0,0 +1,34 @@ +// +// Code generated by grafana-app-sdk. DO NOT EDIT. +// + +package v0alpha1 + +import ( + "github.com/grafana/grafana-app-sdk/resource" +) + +// schema is unexported to prevent accidental overwrites +var ( + schemaPlugin = resource.NewSimpleSchema("plugins.grafana.app", "v0alpha1", &Plugin{}, &PluginList{}, resource.WithKind("Plugin"), + resource.WithPlural("plugins"), resource.WithScope(resource.NamespacedScope)) + kindPlugin = resource.Kind{ + Schema: schemaPlugin, + Codecs: map[resource.KindEncoding]resource.Codec{ + resource.KindEncodingJSON: &PluginJSONCodec{}, + }, + } +) + +// Kind returns a resource.Kind for this Schema with a JSON codec +func PluginKind() resource.Kind { + return kindPlugin +} + +// Schema returns a resource.SimpleSchema representation of Plugin +func PluginSchema() *resource.SimpleSchema { + return schemaPlugin +} + +// Interface compliance checks +var _ resource.Schema = kindPlugin diff --git a/apps/plugins/pkg/apis/plugins/v0alpha1/plugin_spec_gen.go b/apps/plugins/pkg/apis/plugins/v0alpha1/plugin_spec_gen.go new file mode 100644 index 00000000000..d46a0a4aed1 --- /dev/null +++ b/apps/plugins/pkg/apis/plugins/v0alpha1/plugin_spec_gen.go @@ -0,0 +1,25 @@ +// Code generated - EDITING IS FUTILE. DO NOT EDIT. + +package v0alpha1 + +// +k8s:openapi-gen=true +type PluginSpec struct { + Id string `json:"id"` + Version string `json:"version"` + Url *string `json:"url,omitempty"` + Class PluginSpecClass `json:"class"` +} + +// NewPluginSpec creates a new PluginSpec object. +func NewPluginSpec() *PluginSpec { + return &PluginSpec{} +} + +// +k8s:openapi-gen=true +type PluginSpecClass string + +const ( + PluginSpecClassCore PluginSpecClass = "core" + PluginSpecClassExternal PluginSpecClass = "external" + PluginSpecClassCdn PluginSpecClass = "cdn" +) diff --git a/apps/plugins/pkg/apis/plugins/v0alpha1/pluginmeta_status_gen.go b/apps/plugins/pkg/apis/plugins/v0alpha1/plugin_status_gen.go similarity index 52% rename from apps/plugins/pkg/apis/plugins/v0alpha1/pluginmeta_status_gen.go rename to apps/plugins/pkg/apis/plugins/v0alpha1/plugin_status_gen.go index 60fa37dbb32..55ecac4408f 100644 --- a/apps/plugins/pkg/apis/plugins/v0alpha1/pluginmeta_status_gen.go +++ b/apps/plugins/pkg/apis/plugins/v0alpha1/plugin_status_gen.go @@ -3,42 +3,42 @@ package v0alpha1 // +k8s:openapi-gen=true -type PluginMetastatusOperatorState struct { +type PluginstatusOperatorState struct { // lastEvaluation is the ResourceVersion last evaluated LastEvaluation string `json:"lastEvaluation"` // state describes the state of the lastEvaluation. // It is limited to three possible states for machine evaluation. - State PluginMetaStatusOperatorStateState `json:"state"` + State PluginStatusOperatorStateState `json:"state"` // descriptiveState is an optional more descriptive state field which has no requirements on format DescriptiveState *string `json:"descriptiveState,omitempty"` // details contains any extra information that is operator-specific Details map[string]interface{} `json:"details,omitempty"` } -// NewPluginMetastatusOperatorState creates a new PluginMetastatusOperatorState object. -func NewPluginMetastatusOperatorState() *PluginMetastatusOperatorState { - return &PluginMetastatusOperatorState{} +// NewPluginstatusOperatorState creates a new PluginstatusOperatorState object. +func NewPluginstatusOperatorState() *PluginstatusOperatorState { + return &PluginstatusOperatorState{} } // +k8s:openapi-gen=true -type PluginMetaStatus struct { +type PluginStatus struct { // operatorStates is a map of operator ID to operator state evaluations. // Any operator which consumes this kind SHOULD add its state evaluation information to this field. - OperatorStates map[string]PluginMetastatusOperatorState `json:"operatorStates,omitempty"` + OperatorStates map[string]PluginstatusOperatorState `json:"operatorStates,omitempty"` // additionalFields is reserved for future use AdditionalFields map[string]interface{} `json:"additionalFields,omitempty"` } -// NewPluginMetaStatus creates a new PluginMetaStatus object. -func NewPluginMetaStatus() *PluginMetaStatus { - return &PluginMetaStatus{} +// NewPluginStatus creates a new PluginStatus object. +func NewPluginStatus() *PluginStatus { + return &PluginStatus{} } // +k8s:openapi-gen=true -type PluginMetaStatusOperatorStateState string +type PluginStatusOperatorStateState string const ( - PluginMetaStatusOperatorStateStateSuccess PluginMetaStatusOperatorStateState = "success" - PluginMetaStatusOperatorStateStateInProgress PluginMetaStatusOperatorStateState = "in_progress" - PluginMetaStatusOperatorStateStateFailed PluginMetaStatusOperatorStateState = "failed" + PluginStatusOperatorStateStateSuccess PluginStatusOperatorStateState = "success" + PluginStatusOperatorStateStateInProgress PluginStatusOperatorStateState = "in_progress" + PluginStatusOperatorStateStateFailed PluginStatusOperatorStateState = "failed" ) diff --git a/apps/plugins/pkg/apis/plugins/v0alpha1/plugininstall_client_gen.go b/apps/plugins/pkg/apis/plugins/v0alpha1/plugininstall_client_gen.go deleted file mode 100644 index 7733db871e0..00000000000 --- a/apps/plugins/pkg/apis/plugins/v0alpha1/plugininstall_client_gen.go +++ /dev/null @@ -1,99 +0,0 @@ -package v0alpha1 - -import ( - "context" - - "github.com/grafana/grafana-app-sdk/resource" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -type PluginInstallClient struct { - client *resource.TypedClient[*PluginInstall, *PluginInstallList] -} - -func NewPluginInstallClient(client resource.Client) *PluginInstallClient { - return &PluginInstallClient{ - client: resource.NewTypedClient[*PluginInstall, *PluginInstallList](client, PluginInstallKind()), - } -} - -func NewPluginInstallClientFromGenerator(generator resource.ClientGenerator) (*PluginInstallClient, error) { - c, err := generator.ClientFor(PluginInstallKind()) - if err != nil { - return nil, err - } - return NewPluginInstallClient(c), nil -} - -func (c *PluginInstallClient) Get(ctx context.Context, identifier resource.Identifier) (*PluginInstall, error) { - return c.client.Get(ctx, identifier) -} - -func (c *PluginInstallClient) List(ctx context.Context, namespace string, opts resource.ListOptions) (*PluginInstallList, error) { - return c.client.List(ctx, namespace, opts) -} - -func (c *PluginInstallClient) ListAll(ctx context.Context, namespace string, opts resource.ListOptions) (*PluginInstallList, error) { - resp, err := c.client.List(ctx, namespace, resource.ListOptions{ - ResourceVersion: opts.ResourceVersion, - Limit: opts.Limit, - LabelFilters: opts.LabelFilters, - FieldSelectors: opts.FieldSelectors, - }) - if err != nil { - return nil, err - } - for resp.GetContinue() != "" { - page, err := c.client.List(ctx, namespace, resource.ListOptions{ - Continue: resp.GetContinue(), - ResourceVersion: opts.ResourceVersion, - Limit: opts.Limit, - LabelFilters: opts.LabelFilters, - FieldSelectors: opts.FieldSelectors, - }) - if err != nil { - return nil, err - } - resp.SetContinue(page.GetContinue()) - resp.SetResourceVersion(page.GetResourceVersion()) - resp.SetItems(append(resp.GetItems(), page.GetItems()...)) - } - return resp, nil -} - -func (c *PluginInstallClient) Create(ctx context.Context, obj *PluginInstall, opts resource.CreateOptions) (*PluginInstall, error) { - // Make sure apiVersion and kind are set - obj.APIVersion = GroupVersion.Identifier() - obj.Kind = PluginInstallKind().Kind() - return c.client.Create(ctx, obj, opts) -} - -func (c *PluginInstallClient) Update(ctx context.Context, obj *PluginInstall, opts resource.UpdateOptions) (*PluginInstall, error) { - return c.client.Update(ctx, obj, opts) -} - -func (c *PluginInstallClient) Patch(ctx context.Context, identifier resource.Identifier, req resource.PatchRequest, opts resource.PatchOptions) (*PluginInstall, error) { - return c.client.Patch(ctx, identifier, req, opts) -} - -func (c *PluginInstallClient) UpdateStatus(ctx context.Context, identifier resource.Identifier, newStatus PluginInstallStatus, opts resource.UpdateOptions) (*PluginInstall, error) { - return c.client.Update(ctx, &PluginInstall{ - TypeMeta: metav1.TypeMeta{ - Kind: PluginInstallKind().Kind(), - APIVersion: GroupVersion.Identifier(), - }, - ObjectMeta: metav1.ObjectMeta{ - ResourceVersion: opts.ResourceVersion, - Namespace: identifier.Namespace, - Name: identifier.Name, - }, - Status: newStatus, - }, resource.UpdateOptions{ - Subresource: "status", - ResourceVersion: opts.ResourceVersion, - }) -} - -func (c *PluginInstallClient) Delete(ctx context.Context, identifier resource.Identifier, opts resource.DeleteOptions) error { - return c.client.Delete(ctx, identifier, opts) -} diff --git a/apps/plugins/pkg/apis/plugins/v0alpha1/plugininstall_codec_gen.go b/apps/plugins/pkg/apis/plugins/v0alpha1/plugininstall_codec_gen.go deleted file mode 100644 index 48b7e98fd2f..00000000000 --- a/apps/plugins/pkg/apis/plugins/v0alpha1/plugininstall_codec_gen.go +++ /dev/null @@ -1,28 +0,0 @@ -// -// Code generated by grafana-app-sdk. DO NOT EDIT. -// - -package v0alpha1 - -import ( - "encoding/json" - "io" - - "github.com/grafana/grafana-app-sdk/resource" -) - -// PluginInstallJSONCodec is an implementation of resource.Codec for kubernetes JSON encoding -type PluginInstallJSONCodec struct{} - -// Read reads JSON-encoded bytes from `reader` and unmarshals them into `into` -func (*PluginInstallJSONCodec) Read(reader io.Reader, into resource.Object) error { - return json.NewDecoder(reader).Decode(into) -} - -// Write writes JSON-encoded bytes into `writer` marshaled from `from` -func (*PluginInstallJSONCodec) Write(writer io.Writer, from resource.Object) error { - return json.NewEncoder(writer).Encode(from) -} - -// Interface compliance checks -var _ resource.Codec = &PluginInstallJSONCodec{} diff --git a/apps/plugins/pkg/apis/plugins/v0alpha1/plugininstall_metadata_gen.go b/apps/plugins/pkg/apis/plugins/v0alpha1/plugininstall_metadata_gen.go deleted file mode 100644 index 0e944597301..00000000000 --- a/apps/plugins/pkg/apis/plugins/v0alpha1/plugininstall_metadata_gen.go +++ /dev/null @@ -1,31 +0,0 @@ -// Code generated - EDITING IS FUTILE. DO NOT EDIT. - -package v0alpha1 - -import ( - time "time" -) - -// metadata contains embedded CommonMetadata and can be extended with custom string fields -// TODO: use CommonMetadata instead of redefining here; currently needs to be defined here -// without external reference as using the CommonMetadata reference breaks thema codegen. -type PluginInstallMetadata struct { - UpdateTimestamp time.Time `json:"updateTimestamp"` - CreatedBy string `json:"createdBy"` - Uid string `json:"uid"` - CreationTimestamp time.Time `json:"creationTimestamp"` - DeletionTimestamp *time.Time `json:"deletionTimestamp,omitempty"` - Finalizers []string `json:"finalizers"` - ResourceVersion string `json:"resourceVersion"` - Generation int64 `json:"generation"` - UpdatedBy string `json:"updatedBy"` - Labels map[string]string `json:"labels"` -} - -// NewPluginInstallMetadata creates a new PluginInstallMetadata object. -func NewPluginInstallMetadata() *PluginInstallMetadata { - return &PluginInstallMetadata{ - Finalizers: []string{}, - Labels: map[string]string{}, - } -} diff --git a/apps/plugins/pkg/apis/plugins/v0alpha1/plugininstall_object_gen.go b/apps/plugins/pkg/apis/plugins/v0alpha1/plugininstall_object_gen.go deleted file mode 100644 index 6ceaa603baa..00000000000 --- a/apps/plugins/pkg/apis/plugins/v0alpha1/plugininstall_object_gen.go +++ /dev/null @@ -1,319 +0,0 @@ -// -// Code generated by grafana-app-sdk. DO NOT EDIT. -// - -package v0alpha1 - -import ( - "fmt" - "github.com/grafana/grafana-app-sdk/resource" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apimachinery/pkg/types" - "time" -) - -// +k8s:openapi-gen=true -type PluginInstall struct { - metav1.TypeMeta `json:",inline" yaml:",inline"` - metav1.ObjectMeta `json:"metadata" yaml:"metadata"` - - // Spec is the spec of the PluginInstall - Spec PluginInstallSpec `json:"spec" yaml:"spec"` - - Status PluginInstallStatus `json:"status" yaml:"status"` -} - -func (o *PluginInstall) GetSpec() any { - return o.Spec -} - -func (o *PluginInstall) SetSpec(spec any) error { - cast, ok := spec.(PluginInstallSpec) - if !ok { - return fmt.Errorf("cannot set spec type %#v, not of type Spec", spec) - } - o.Spec = cast - return nil -} - -func (o *PluginInstall) GetSubresources() map[string]any { - return map[string]any{ - "status": o.Status, - } -} - -func (o *PluginInstall) GetSubresource(name string) (any, bool) { - switch name { - case "status": - return o.Status, true - default: - return nil, false - } -} - -func (o *PluginInstall) SetSubresource(name string, value any) error { - switch name { - case "status": - cast, ok := value.(PluginInstallStatus) - if !ok { - return fmt.Errorf("cannot set status type %#v, not of type PluginInstallStatus", value) - } - o.Status = cast - return nil - default: - return fmt.Errorf("subresource '%s' does not exist", name) - } -} - -func (o *PluginInstall) GetStaticMetadata() resource.StaticMetadata { - gvk := o.GroupVersionKind() - return resource.StaticMetadata{ - Name: o.ObjectMeta.Name, - Namespace: o.ObjectMeta.Namespace, - Group: gvk.Group, - Version: gvk.Version, - Kind: gvk.Kind, - } -} - -func (o *PluginInstall) SetStaticMetadata(metadata resource.StaticMetadata) { - o.Name = metadata.Name - o.Namespace = metadata.Namespace - o.SetGroupVersionKind(schema.GroupVersionKind{ - Group: metadata.Group, - Version: metadata.Version, - Kind: metadata.Kind, - }) -} - -func (o *PluginInstall) GetCommonMetadata() resource.CommonMetadata { - dt := o.DeletionTimestamp - var deletionTimestamp *time.Time - if dt != nil { - deletionTimestamp = &dt.Time - } - // Legacy ExtraFields support - extraFields := make(map[string]any) - if o.Annotations != nil { - extraFields["annotations"] = o.Annotations - } - if o.ManagedFields != nil { - extraFields["managedFields"] = o.ManagedFields - } - if o.OwnerReferences != nil { - extraFields["ownerReferences"] = o.OwnerReferences - } - return resource.CommonMetadata{ - UID: string(o.UID), - ResourceVersion: o.ResourceVersion, - Generation: o.Generation, - Labels: o.Labels, - CreationTimestamp: o.CreationTimestamp.Time, - DeletionTimestamp: deletionTimestamp, - Finalizers: o.Finalizers, - UpdateTimestamp: o.GetUpdateTimestamp(), - CreatedBy: o.GetCreatedBy(), - UpdatedBy: o.GetUpdatedBy(), - ExtraFields: extraFields, - } -} - -func (o *PluginInstall) SetCommonMetadata(metadata resource.CommonMetadata) { - o.UID = types.UID(metadata.UID) - o.ResourceVersion = metadata.ResourceVersion - o.Generation = metadata.Generation - o.Labels = metadata.Labels - o.CreationTimestamp = metav1.NewTime(metadata.CreationTimestamp) - if metadata.DeletionTimestamp != nil { - dt := metav1.NewTime(*metadata.DeletionTimestamp) - o.DeletionTimestamp = &dt - } else { - o.DeletionTimestamp = nil - } - o.Finalizers = metadata.Finalizers - if o.Annotations == nil { - o.Annotations = make(map[string]string) - } - if !metadata.UpdateTimestamp.IsZero() { - o.SetUpdateTimestamp(metadata.UpdateTimestamp) - } - if metadata.CreatedBy != "" { - o.SetCreatedBy(metadata.CreatedBy) - } - if metadata.UpdatedBy != "" { - o.SetUpdatedBy(metadata.UpdatedBy) - } - // Legacy support for setting Annotations, ManagedFields, and OwnerReferences via ExtraFields - if metadata.ExtraFields != nil { - if annotations, ok := metadata.ExtraFields["annotations"]; ok { - if cast, ok := annotations.(map[string]string); ok { - o.Annotations = cast - } - } - if managedFields, ok := metadata.ExtraFields["managedFields"]; ok { - if cast, ok := managedFields.([]metav1.ManagedFieldsEntry); ok { - o.ManagedFields = cast - } - } - if ownerReferences, ok := metadata.ExtraFields["ownerReferences"]; ok { - if cast, ok := ownerReferences.([]metav1.OwnerReference); ok { - o.OwnerReferences = cast - } - } - } -} - -func (o *PluginInstall) GetCreatedBy() string { - if o.ObjectMeta.Annotations == nil { - o.ObjectMeta.Annotations = make(map[string]string) - } - - return o.ObjectMeta.Annotations["grafana.com/createdBy"] -} - -func (o *PluginInstall) SetCreatedBy(createdBy string) { - if o.ObjectMeta.Annotations == nil { - o.ObjectMeta.Annotations = make(map[string]string) - } - - o.ObjectMeta.Annotations["grafana.com/createdBy"] = createdBy -} - -func (o *PluginInstall) GetUpdateTimestamp() time.Time { - if o.ObjectMeta.Annotations == nil { - o.ObjectMeta.Annotations = make(map[string]string) - } - - parsed, _ := time.Parse(time.RFC3339, o.ObjectMeta.Annotations["grafana.com/updateTimestamp"]) - return parsed -} - -func (o *PluginInstall) SetUpdateTimestamp(updateTimestamp time.Time) { - if o.ObjectMeta.Annotations == nil { - o.ObjectMeta.Annotations = make(map[string]string) - } - - o.ObjectMeta.Annotations["grafana.com/updateTimestamp"] = updateTimestamp.Format(time.RFC3339) -} - -func (o *PluginInstall) GetUpdatedBy() string { - if o.ObjectMeta.Annotations == nil { - o.ObjectMeta.Annotations = make(map[string]string) - } - - return o.ObjectMeta.Annotations["grafana.com/updatedBy"] -} - -func (o *PluginInstall) SetUpdatedBy(updatedBy string) { - if o.ObjectMeta.Annotations == nil { - o.ObjectMeta.Annotations = make(map[string]string) - } - - o.ObjectMeta.Annotations["grafana.com/updatedBy"] = updatedBy -} - -func (o *PluginInstall) Copy() resource.Object { - return resource.CopyObject(o) -} - -func (o *PluginInstall) DeepCopyObject() runtime.Object { - return o.Copy() -} - -func (o *PluginInstall) DeepCopy() *PluginInstall { - cpy := &PluginInstall{} - o.DeepCopyInto(cpy) - return cpy -} - -func (o *PluginInstall) DeepCopyInto(dst *PluginInstall) { - dst.TypeMeta.APIVersion = o.TypeMeta.APIVersion - dst.TypeMeta.Kind = o.TypeMeta.Kind - o.ObjectMeta.DeepCopyInto(&dst.ObjectMeta) - o.Spec.DeepCopyInto(&dst.Spec) - o.Status.DeepCopyInto(&dst.Status) -} - -// Interface compliance compile-time check -var _ resource.Object = &PluginInstall{} - -// +k8s:openapi-gen=true -type PluginInstallList struct { - metav1.TypeMeta `json:",inline" yaml:",inline"` - metav1.ListMeta `json:"metadata" yaml:"metadata"` - Items []PluginInstall `json:"items" yaml:"items"` -} - -func (o *PluginInstallList) DeepCopyObject() runtime.Object { - return o.Copy() -} - -func (o *PluginInstallList) Copy() resource.ListObject { - cpy := &PluginInstallList{ - TypeMeta: o.TypeMeta, - Items: make([]PluginInstall, len(o.Items)), - } - o.ListMeta.DeepCopyInto(&cpy.ListMeta) - for i := 0; i < len(o.Items); i++ { - if item, ok := o.Items[i].Copy().(*PluginInstall); ok { - cpy.Items[i] = *item - } - } - return cpy -} - -func (o *PluginInstallList) GetItems() []resource.Object { - items := make([]resource.Object, len(o.Items)) - for i := 0; i < len(o.Items); i++ { - items[i] = &o.Items[i] - } - return items -} - -func (o *PluginInstallList) SetItems(items []resource.Object) { - o.Items = make([]PluginInstall, len(items)) - for i := 0; i < len(items); i++ { - o.Items[i] = *items[i].(*PluginInstall) - } -} - -func (o *PluginInstallList) DeepCopy() *PluginInstallList { - cpy := &PluginInstallList{} - o.DeepCopyInto(cpy) - return cpy -} - -func (o *PluginInstallList) DeepCopyInto(dst *PluginInstallList) { - resource.CopyObjectInto(dst, o) -} - -// Interface compliance compile-time check -var _ resource.ListObject = &PluginInstallList{} - -// Copy methods for all subresource types - -// DeepCopy creates a full deep copy of Spec -func (s *PluginInstallSpec) DeepCopy() *PluginInstallSpec { - cpy := &PluginInstallSpec{} - s.DeepCopyInto(cpy) - return cpy -} - -// DeepCopyInto deep copies Spec into another Spec object -func (s *PluginInstallSpec) DeepCopyInto(dst *PluginInstallSpec) { - resource.CopyObjectInto(dst, s) -} - -// DeepCopy creates a full deep copy of PluginInstallStatus -func (s *PluginInstallStatus) DeepCopy() *PluginInstallStatus { - cpy := &PluginInstallStatus{} - s.DeepCopyInto(cpy) - return cpy -} - -// DeepCopyInto deep copies PluginInstallStatus into another PluginInstallStatus object -func (s *PluginInstallStatus) DeepCopyInto(dst *PluginInstallStatus) { - resource.CopyObjectInto(dst, s) -} diff --git a/apps/plugins/pkg/apis/plugins/v0alpha1/plugininstall_schema_gen.go b/apps/plugins/pkg/apis/plugins/v0alpha1/plugininstall_schema_gen.go deleted file mode 100644 index 85ea40cd157..00000000000 --- a/apps/plugins/pkg/apis/plugins/v0alpha1/plugininstall_schema_gen.go +++ /dev/null @@ -1,34 +0,0 @@ -// -// Code generated by grafana-app-sdk. DO NOT EDIT. -// - -package v0alpha1 - -import ( - "github.com/grafana/grafana-app-sdk/resource" -) - -// schema is unexported to prevent accidental overwrites -var ( - schemaPluginInstall = resource.NewSimpleSchema("plugins.grafana.app", "v0alpha1", &PluginInstall{}, &PluginInstallList{}, resource.WithKind("PluginInstall"), - resource.WithPlural("plugininstalls"), resource.WithScope(resource.NamespacedScope)) - kindPluginInstall = resource.Kind{ - Schema: schemaPluginInstall, - Codecs: map[resource.KindEncoding]resource.Codec{ - resource.KindEncodingJSON: &PluginInstallJSONCodec{}, - }, - } -) - -// Kind returns a resource.Kind for this Schema with a JSON codec -func PluginInstallKind() resource.Kind { - return kindPluginInstall -} - -// Schema returns a resource.SimpleSchema representation of PluginInstall -func PluginInstallSchema() *resource.SimpleSchema { - return schemaPluginInstall -} - -// Interface compliance checks -var _ resource.Schema = kindPluginInstall diff --git a/apps/plugins/pkg/apis/plugins/v0alpha1/plugininstall_spec_gen.go b/apps/plugins/pkg/apis/plugins/v0alpha1/plugininstall_spec_gen.go deleted file mode 100644 index eeccd7f656d..00000000000 --- a/apps/plugins/pkg/apis/plugins/v0alpha1/plugininstall_spec_gen.go +++ /dev/null @@ -1,25 +0,0 @@ -// Code generated - EDITING IS FUTILE. DO NOT EDIT. - -package v0alpha1 - -// +k8s:openapi-gen=true -type PluginInstallSpec struct { - Id string `json:"id"` - Version string `json:"version"` - Url *string `json:"url,omitempty"` - Class PluginInstallSpecClass `json:"class"` -} - -// NewPluginInstallSpec creates a new PluginInstallSpec object. -func NewPluginInstallSpec() *PluginInstallSpec { - return &PluginInstallSpec{} -} - -// +k8s:openapi-gen=true -type PluginInstallSpecClass string - -const ( - PluginInstallSpecClassCore PluginInstallSpecClass = "core" - PluginInstallSpecClassExternal PluginInstallSpecClass = "external" - PluginInstallSpecClassCdn PluginInstallSpecClass = "cdn" -) diff --git a/apps/plugins/pkg/apis/plugins/v0alpha1/plugininstall_status_gen.go b/apps/plugins/pkg/apis/plugins/v0alpha1/plugininstall_status_gen.go deleted file mode 100644 index 77fc07860b0..00000000000 --- a/apps/plugins/pkg/apis/plugins/v0alpha1/plugininstall_status_gen.go +++ /dev/null @@ -1,44 +0,0 @@ -// Code generated - EDITING IS FUTILE. DO NOT EDIT. - -package v0alpha1 - -// +k8s:openapi-gen=true -type PluginInstallstatusOperatorState struct { - // lastEvaluation is the ResourceVersion last evaluated - LastEvaluation string `json:"lastEvaluation"` - // state describes the state of the lastEvaluation. - // It is limited to three possible states for machine evaluation. - State PluginInstallStatusOperatorStateState `json:"state"` - // descriptiveState is an optional more descriptive state field which has no requirements on format - DescriptiveState *string `json:"descriptiveState,omitempty"` - // details contains any extra information that is operator-specific - Details map[string]interface{} `json:"details,omitempty"` -} - -// NewPluginInstallstatusOperatorState creates a new PluginInstallstatusOperatorState object. -func NewPluginInstallstatusOperatorState() *PluginInstallstatusOperatorState { - return &PluginInstallstatusOperatorState{} -} - -// +k8s:openapi-gen=true -type PluginInstallStatus struct { - // operatorStates is a map of operator ID to operator state evaluations. - // Any operator which consumes this kind SHOULD add its state evaluation information to this field. - OperatorStates map[string]PluginInstallstatusOperatorState `json:"operatorStates,omitempty"` - // additionalFields is reserved for future use - AdditionalFields map[string]interface{} `json:"additionalFields,omitempty"` -} - -// NewPluginInstallStatus creates a new PluginInstallStatus object. -func NewPluginInstallStatus() *PluginInstallStatus { - return &PluginInstallStatus{} -} - -// +k8s:openapi-gen=true -type PluginInstallStatusOperatorStateState string - -const ( - PluginInstallStatusOperatorStateStateSuccess PluginInstallStatusOperatorStateState = "success" - PluginInstallStatusOperatorStateStateInProgress PluginInstallStatusOperatorStateState = "in_progress" - PluginInstallStatusOperatorStateStateFailed PluginInstallStatusOperatorStateState = "failed" -) diff --git a/apps/plugins/pkg/apis/plugins/v0alpha1/pluginmeta_client_gen.go b/apps/plugins/pkg/apis/plugins/v0alpha1/pluginmeta_client_gen.go deleted file mode 100644 index e7788e27a33..00000000000 --- a/apps/plugins/pkg/apis/plugins/v0alpha1/pluginmeta_client_gen.go +++ /dev/null @@ -1,99 +0,0 @@ -package v0alpha1 - -import ( - "context" - - "github.com/grafana/grafana-app-sdk/resource" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -type PluginMetaClient struct { - client *resource.TypedClient[*PluginMeta, *PluginMetaList] -} - -func NewPluginMetaClient(client resource.Client) *PluginMetaClient { - return &PluginMetaClient{ - client: resource.NewTypedClient[*PluginMeta, *PluginMetaList](client, PluginMetaKind()), - } -} - -func NewPluginMetaClientFromGenerator(generator resource.ClientGenerator) (*PluginMetaClient, error) { - c, err := generator.ClientFor(PluginMetaKind()) - if err != nil { - return nil, err - } - return NewPluginMetaClient(c), nil -} - -func (c *PluginMetaClient) Get(ctx context.Context, identifier resource.Identifier) (*PluginMeta, error) { - return c.client.Get(ctx, identifier) -} - -func (c *PluginMetaClient) List(ctx context.Context, namespace string, opts resource.ListOptions) (*PluginMetaList, error) { - return c.client.List(ctx, namespace, opts) -} - -func (c *PluginMetaClient) ListAll(ctx context.Context, namespace string, opts resource.ListOptions) (*PluginMetaList, error) { - resp, err := c.client.List(ctx, namespace, resource.ListOptions{ - ResourceVersion: opts.ResourceVersion, - Limit: opts.Limit, - LabelFilters: opts.LabelFilters, - FieldSelectors: opts.FieldSelectors, - }) - if err != nil { - return nil, err - } - for resp.GetContinue() != "" { - page, err := c.client.List(ctx, namespace, resource.ListOptions{ - Continue: resp.GetContinue(), - ResourceVersion: opts.ResourceVersion, - Limit: opts.Limit, - LabelFilters: opts.LabelFilters, - FieldSelectors: opts.FieldSelectors, - }) - if err != nil { - return nil, err - } - resp.SetContinue(page.GetContinue()) - resp.SetResourceVersion(page.GetResourceVersion()) - resp.SetItems(append(resp.GetItems(), page.GetItems()...)) - } - return resp, nil -} - -func (c *PluginMetaClient) Create(ctx context.Context, obj *PluginMeta, opts resource.CreateOptions) (*PluginMeta, error) { - // Make sure apiVersion and kind are set - obj.APIVersion = GroupVersion.Identifier() - obj.Kind = PluginMetaKind().Kind() - return c.client.Create(ctx, obj, opts) -} - -func (c *PluginMetaClient) Update(ctx context.Context, obj *PluginMeta, opts resource.UpdateOptions) (*PluginMeta, error) { - return c.client.Update(ctx, obj, opts) -} - -func (c *PluginMetaClient) Patch(ctx context.Context, identifier resource.Identifier, req resource.PatchRequest, opts resource.PatchOptions) (*PluginMeta, error) { - return c.client.Patch(ctx, identifier, req, opts) -} - -func (c *PluginMetaClient) UpdateStatus(ctx context.Context, identifier resource.Identifier, newStatus PluginMetaStatus, opts resource.UpdateOptions) (*PluginMeta, error) { - return c.client.Update(ctx, &PluginMeta{ - TypeMeta: metav1.TypeMeta{ - Kind: PluginMetaKind().Kind(), - APIVersion: GroupVersion.Identifier(), - }, - ObjectMeta: metav1.ObjectMeta{ - ResourceVersion: opts.ResourceVersion, - Namespace: identifier.Namespace, - Name: identifier.Name, - }, - Status: newStatus, - }, resource.UpdateOptions{ - Subresource: "status", - ResourceVersion: opts.ResourceVersion, - }) -} - -func (c *PluginMetaClient) Delete(ctx context.Context, identifier resource.Identifier, opts resource.DeleteOptions) error { - return c.client.Delete(ctx, identifier, opts) -} diff --git a/apps/plugins/pkg/apis/plugins/v0alpha1/pluginmeta_schema_gen.go b/apps/plugins/pkg/apis/plugins/v0alpha1/pluginmeta_schema_gen.go deleted file mode 100644 index a4022c8de97..00000000000 --- a/apps/plugins/pkg/apis/plugins/v0alpha1/pluginmeta_schema_gen.go +++ /dev/null @@ -1,34 +0,0 @@ -// -// Code generated by grafana-app-sdk. DO NOT EDIT. -// - -package v0alpha1 - -import ( - "github.com/grafana/grafana-app-sdk/resource" -) - -// schema is unexported to prevent accidental overwrites -var ( - schemaPluginMeta = resource.NewSimpleSchema("plugins.grafana.app", "v0alpha1", &PluginMeta{}, &PluginMetaList{}, resource.WithKind("PluginMeta"), - resource.WithPlural("pluginmetas"), resource.WithScope(resource.NamespacedScope)) - kindPluginMeta = resource.Kind{ - Schema: schemaPluginMeta, - Codecs: map[resource.KindEncoding]resource.Codec{ - resource.KindEncodingJSON: &PluginMetaJSONCodec{}, - }, - } -) - -// Kind returns a resource.Kind for this Schema with a JSON codec -func PluginMetaKind() resource.Kind { - return kindPluginMeta -} - -// Schema returns a resource.SimpleSchema representation of PluginMeta -func PluginMetaSchema() *resource.SimpleSchema { - return schemaPluginMeta -} - -// Interface compliance checks -var _ resource.Schema = kindPluginMeta diff --git a/apps/plugins/pkg/apis/plugins/v0alpha1/pluginmeta_spec_gen.go b/apps/plugins/pkg/apis/plugins/v0alpha1/pluginmeta_spec_gen.go deleted file mode 100644 index 8020e34efda..00000000000 --- a/apps/plugins/pkg/apis/plugins/v0alpha1/pluginmeta_spec_gen.go +++ /dev/null @@ -1,477 +0,0 @@ -// Code generated - EDITING IS FUTILE. DO NOT EDIT. - -package v0alpha1 - -import ( - time "time" -) - -// JSON configuration schema for Grafana plugins -// Converted from: https://github.com/grafana/grafana/blob/main/docs/sources/developers/plugins/plugin.schema.json -// +k8s:openapi-gen=true -type PluginMetaJSONData struct { - // Unique name of the plugin - Id string `json:"id"` - // Plugin type - Type PluginMetaJSONDataType `json:"type"` - // Human-readable name of the plugin - Name string `json:"name"` - // Metadata for the plugin - Info PluginMetaInfo `json:"info"` - // Dependency information - Dependencies PluginMetaDependencies `json:"dependencies"` - // Optional fields - Alerting *bool `json:"alerting,omitempty"` - Annotations *bool `json:"annotations,omitempty"` - AutoEnabled *bool `json:"autoEnabled,omitempty"` - Backend *bool `json:"backend,omitempty"` - BuildMode *string `json:"buildMode,omitempty"` - BuiltIn *bool `json:"builtIn,omitempty"` - Category *PluginMetaJSONDataCategory `json:"category,omitempty"` - EnterpriseFeatures *PluginMetaEnterpriseFeatures `json:"enterpriseFeatures,omitempty"` - Executable *string `json:"executable,omitempty"` - HideFromList *bool `json:"hideFromList,omitempty"` - // +listType=atomic - Includes []PluginMetaInclude `json:"includes,omitempty"` - Logs *bool `json:"logs,omitempty"` - Metrics *bool `json:"metrics,omitempty"` - MultiValueFilterOperators *bool `json:"multiValueFilterOperators,omitempty"` - PascalName *string `json:"pascalName,omitempty"` - Preload *bool `json:"preload,omitempty"` - QueryOptions *PluginMetaQueryOptions `json:"queryOptions,omitempty"` - // +listType=atomic - Routes []PluginMetaRoute `json:"routes,omitempty"` - SkipDataQuery *bool `json:"skipDataQuery,omitempty"` - State *PluginMetaJSONDataState `json:"state,omitempty"` - Streaming *bool `json:"streaming,omitempty"` - Tracing *bool `json:"tracing,omitempty"` - Iam *PluginMetaIAM `json:"iam,omitempty"` - // +listType=atomic - Roles []PluginMetaRole `json:"roles,omitempty"` - Extensions *PluginMetaExtensions `json:"extensions,omitempty"` -} - -// NewPluginMetaJSONData creates a new PluginMetaJSONData object. -func NewPluginMetaJSONData() *PluginMetaJSONData { - return &PluginMetaJSONData{ - Info: *NewPluginMetaInfo(), - Dependencies: *NewPluginMetaDependencies(), - } -} - -// +k8s:openapi-gen=true -type PluginMetaInfo struct { - // Required fields - // +listType=set - Keywords []string `json:"keywords"` - Logos PluginMetaV0alpha1InfoLogos `json:"logos"` - Updated time.Time `json:"updated"` - Version string `json:"version"` - // Optional fields - Author *PluginMetaV0alpha1InfoAuthor `json:"author,omitempty"` - Description *string `json:"description,omitempty"` - // +listType=atomic - Links []PluginMetaV0alpha1InfoLinks `json:"links,omitempty"` - // +listType=atomic - Screenshots []PluginMetaV0alpha1InfoScreenshots `json:"screenshots,omitempty"` -} - -// NewPluginMetaInfo creates a new PluginMetaInfo object. -func NewPluginMetaInfo() *PluginMetaInfo { - return &PluginMetaInfo{ - Keywords: []string{}, - Logos: *NewPluginMetaV0alpha1InfoLogos(), - } -} - -// +k8s:openapi-gen=true -type PluginMetaDependencies struct { - // Required field - GrafanaDependency string `json:"grafanaDependency"` - // Optional fields - GrafanaVersion *string `json:"grafanaVersion,omitempty"` - // +listType=set - // +listMapKey=id - Plugins []PluginMetaV0alpha1DependenciesPlugins `json:"plugins,omitempty"` - Extensions *PluginMetaV0alpha1DependenciesExtensions `json:"extensions,omitempty"` -} - -// NewPluginMetaDependencies creates a new PluginMetaDependencies object. -func NewPluginMetaDependencies() *PluginMetaDependencies { - return &PluginMetaDependencies{} -} - -// +k8s:openapi-gen=true -type PluginMetaEnterpriseFeatures struct { - // Allow additional properties - HealthDiagnosticsErrors *bool `json:"healthDiagnosticsErrors,omitempty"` -} - -// NewPluginMetaEnterpriseFeatures creates a new PluginMetaEnterpriseFeatures object. -func NewPluginMetaEnterpriseFeatures() *PluginMetaEnterpriseFeatures { - return &PluginMetaEnterpriseFeatures{ - HealthDiagnosticsErrors: (func(input bool) *bool { return &input })(false), - } -} - -// +k8s:openapi-gen=true -type PluginMetaInclude struct { - Uid *string `json:"uid,omitempty"` - Type *PluginMetaIncludeType `json:"type,omitempty"` - Name *string `json:"name,omitempty"` - Component *string `json:"component,omitempty"` - Role *PluginMetaIncludeRole `json:"role,omitempty"` - Action *string `json:"action,omitempty"` - Path *string `json:"path,omitempty"` - AddToNav *bool `json:"addToNav,omitempty"` - DefaultNav *bool `json:"defaultNav,omitempty"` - Icon *string `json:"icon,omitempty"` -} - -// NewPluginMetaInclude creates a new PluginMetaInclude object. -func NewPluginMetaInclude() *PluginMetaInclude { - return &PluginMetaInclude{} -} - -// +k8s:openapi-gen=true -type PluginMetaQueryOptions struct { - MaxDataPoints *bool `json:"maxDataPoints,omitempty"` - MinInterval *bool `json:"minInterval,omitempty"` - CacheTimeout *bool `json:"cacheTimeout,omitempty"` -} - -// NewPluginMetaQueryOptions creates a new PluginMetaQueryOptions object. -func NewPluginMetaQueryOptions() *PluginMetaQueryOptions { - return &PluginMetaQueryOptions{} -} - -// +k8s:openapi-gen=true -type PluginMetaRoute struct { - Path *string `json:"path,omitempty"` - Method *string `json:"method,omitempty"` - Url *string `json:"url,omitempty"` - ReqSignedIn *bool `json:"reqSignedIn,omitempty"` - ReqRole *string `json:"reqRole,omitempty"` - ReqAction *string `json:"reqAction,omitempty"` - // +listType=atomic - Headers []string `json:"headers,omitempty"` - Body map[string]interface{} `json:"body,omitempty"` - TokenAuth *PluginMetaV0alpha1RouteTokenAuth `json:"tokenAuth,omitempty"` - JwtTokenAuth *PluginMetaV0alpha1RouteJwtTokenAuth `json:"jwtTokenAuth,omitempty"` - // +listType=atomic - UrlParams []PluginMetaV0alpha1RouteUrlParams `json:"urlParams,omitempty"` -} - -// NewPluginMetaRoute creates a new PluginMetaRoute object. -func NewPluginMetaRoute() *PluginMetaRoute { - return &PluginMetaRoute{} -} - -// +k8s:openapi-gen=true -type PluginMetaIAM struct { - // +listType=atomic - Permissions []PluginMetaV0alpha1IAMPermissions `json:"permissions,omitempty"` -} - -// NewPluginMetaIAM creates a new PluginMetaIAM object. -func NewPluginMetaIAM() *PluginMetaIAM { - return &PluginMetaIAM{} -} - -// +k8s:openapi-gen=true -type PluginMetaRole struct { - Role *PluginMetaV0alpha1RoleRole `json:"role,omitempty"` - // +listType=set - Grants []string `json:"grants,omitempty"` -} - -// NewPluginMetaRole creates a new PluginMetaRole object. -func NewPluginMetaRole() *PluginMetaRole { - return &PluginMetaRole{} -} - -// +k8s:openapi-gen=true -type PluginMetaExtensions struct { - // +listType=atomic - AddedComponents []PluginMetaV0alpha1ExtensionsAddedComponents `json:"addedComponents,omitempty"` - // +listType=atomic - AddedLinks []PluginMetaV0alpha1ExtensionsAddedLinks `json:"addedLinks,omitempty"` - // +listType=set - // +listMapKey=id - ExposedComponents []PluginMetaV0alpha1ExtensionsExposedComponents `json:"exposedComponents,omitempty"` - // +listType=set - // +listMapKey=id - ExtensionPoints []PluginMetaV0alpha1ExtensionsExtensionPoints `json:"extensionPoints,omitempty"` -} - -// NewPluginMetaExtensions creates a new PluginMetaExtensions object. -func NewPluginMetaExtensions() *PluginMetaExtensions { - return &PluginMetaExtensions{} -} - -// +k8s:openapi-gen=true -type PluginMetaSpec struct { - PluginJSON PluginMetaJSONData `json:"pluginJSON"` -} - -// NewPluginMetaSpec creates a new PluginMetaSpec object. -func NewPluginMetaSpec() *PluginMetaSpec { - return &PluginMetaSpec{ - PluginJSON: *NewPluginMetaJSONData(), - } -} - -// +k8s:openapi-gen=true -type PluginMetaV0alpha1InfoLogos struct { - Small string `json:"small"` - Large string `json:"large"` -} - -// NewPluginMetaV0alpha1InfoLogos creates a new PluginMetaV0alpha1InfoLogos object. -func NewPluginMetaV0alpha1InfoLogos() *PluginMetaV0alpha1InfoLogos { - return &PluginMetaV0alpha1InfoLogos{} -} - -// +k8s:openapi-gen=true -type PluginMetaV0alpha1InfoAuthor struct { - Name *string `json:"name,omitempty"` - Email *string `json:"email,omitempty"` - Url *string `json:"url,omitempty"` -} - -// NewPluginMetaV0alpha1InfoAuthor creates a new PluginMetaV0alpha1InfoAuthor object. -func NewPluginMetaV0alpha1InfoAuthor() *PluginMetaV0alpha1InfoAuthor { - return &PluginMetaV0alpha1InfoAuthor{} -} - -// +k8s:openapi-gen=true -type PluginMetaV0alpha1InfoLinks struct { - Name *string `json:"name,omitempty"` - Url *string `json:"url,omitempty"` -} - -// NewPluginMetaV0alpha1InfoLinks creates a new PluginMetaV0alpha1InfoLinks object. -func NewPluginMetaV0alpha1InfoLinks() *PluginMetaV0alpha1InfoLinks { - return &PluginMetaV0alpha1InfoLinks{} -} - -// +k8s:openapi-gen=true -type PluginMetaV0alpha1InfoScreenshots struct { - Name *string `json:"name,omitempty"` - Path *string `json:"path,omitempty"` -} - -// NewPluginMetaV0alpha1InfoScreenshots creates a new PluginMetaV0alpha1InfoScreenshots object. -func NewPluginMetaV0alpha1InfoScreenshots() *PluginMetaV0alpha1InfoScreenshots { - return &PluginMetaV0alpha1InfoScreenshots{} -} - -// +k8s:openapi-gen=true -type PluginMetaV0alpha1DependenciesPlugins struct { - Id string `json:"id"` - Type PluginMetaV0alpha1DependenciesPluginsType `json:"type"` - Name string `json:"name"` -} - -// NewPluginMetaV0alpha1DependenciesPlugins creates a new PluginMetaV0alpha1DependenciesPlugins object. -func NewPluginMetaV0alpha1DependenciesPlugins() *PluginMetaV0alpha1DependenciesPlugins { - return &PluginMetaV0alpha1DependenciesPlugins{} -} - -// +k8s:openapi-gen=true -type PluginMetaV0alpha1DependenciesExtensions struct { - // +listType=set - ExposedComponents []string `json:"exposedComponents,omitempty"` -} - -// NewPluginMetaV0alpha1DependenciesExtensions creates a new PluginMetaV0alpha1DependenciesExtensions object. -func NewPluginMetaV0alpha1DependenciesExtensions() *PluginMetaV0alpha1DependenciesExtensions { - return &PluginMetaV0alpha1DependenciesExtensions{} -} - -// +k8s:openapi-gen=true -type PluginMetaV0alpha1RouteTokenAuth struct { - Url *string `json:"url,omitempty"` - // +listType=set - Scopes []string `json:"scopes,omitempty"` - Params map[string]interface{} `json:"params,omitempty"` -} - -// NewPluginMetaV0alpha1RouteTokenAuth creates a new PluginMetaV0alpha1RouteTokenAuth object. -func NewPluginMetaV0alpha1RouteTokenAuth() *PluginMetaV0alpha1RouteTokenAuth { - return &PluginMetaV0alpha1RouteTokenAuth{} -} - -// +k8s:openapi-gen=true -type PluginMetaV0alpha1RouteJwtTokenAuth struct { - Url *string `json:"url,omitempty"` - // +listType=set - Scopes []string `json:"scopes,omitempty"` - Params map[string]interface{} `json:"params,omitempty"` -} - -// NewPluginMetaV0alpha1RouteJwtTokenAuth creates a new PluginMetaV0alpha1RouteJwtTokenAuth object. -func NewPluginMetaV0alpha1RouteJwtTokenAuth() *PluginMetaV0alpha1RouteJwtTokenAuth { - return &PluginMetaV0alpha1RouteJwtTokenAuth{} -} - -// +k8s:openapi-gen=true -type PluginMetaV0alpha1RouteUrlParams struct { - Name *string `json:"name,omitempty"` - Content *string `json:"content,omitempty"` -} - -// NewPluginMetaV0alpha1RouteUrlParams creates a new PluginMetaV0alpha1RouteUrlParams object. -func NewPluginMetaV0alpha1RouteUrlParams() *PluginMetaV0alpha1RouteUrlParams { - return &PluginMetaV0alpha1RouteUrlParams{} -} - -// +k8s:openapi-gen=true -type PluginMetaV0alpha1IAMPermissions struct { - Action *string `json:"action,omitempty"` - Scope *string `json:"scope,omitempty"` -} - -// NewPluginMetaV0alpha1IAMPermissions creates a new PluginMetaV0alpha1IAMPermissions object. -func NewPluginMetaV0alpha1IAMPermissions() *PluginMetaV0alpha1IAMPermissions { - return &PluginMetaV0alpha1IAMPermissions{} -} - -// +k8s:openapi-gen=true -type PluginMetaV0alpha1RoleRolePermissions struct { - Action *string `json:"action,omitempty"` - Scope *string `json:"scope,omitempty"` -} - -// NewPluginMetaV0alpha1RoleRolePermissions creates a new PluginMetaV0alpha1RoleRolePermissions object. -func NewPluginMetaV0alpha1RoleRolePermissions() *PluginMetaV0alpha1RoleRolePermissions { - return &PluginMetaV0alpha1RoleRolePermissions{} -} - -// +k8s:openapi-gen=true -type PluginMetaV0alpha1RoleRole struct { - Name *string `json:"name,omitempty"` - Description *string `json:"description,omitempty"` - // +listType=atomic - Permissions []PluginMetaV0alpha1RoleRolePermissions `json:"permissions,omitempty"` -} - -// NewPluginMetaV0alpha1RoleRole creates a new PluginMetaV0alpha1RoleRole object. -func NewPluginMetaV0alpha1RoleRole() *PluginMetaV0alpha1RoleRole { - return &PluginMetaV0alpha1RoleRole{} -} - -// +k8s:openapi-gen=true -type PluginMetaV0alpha1ExtensionsAddedComponents struct { - // +listType=set - Targets []string `json:"targets"` - Title string `json:"title"` - Description *string `json:"description,omitempty"` -} - -// NewPluginMetaV0alpha1ExtensionsAddedComponents creates a new PluginMetaV0alpha1ExtensionsAddedComponents object. -func NewPluginMetaV0alpha1ExtensionsAddedComponents() *PluginMetaV0alpha1ExtensionsAddedComponents { - return &PluginMetaV0alpha1ExtensionsAddedComponents{ - Targets: []string{}, - } -} - -// +k8s:openapi-gen=true -type PluginMetaV0alpha1ExtensionsAddedLinks struct { - // +listType=set - Targets []string `json:"targets"` - Title string `json:"title"` - Description *string `json:"description,omitempty"` -} - -// NewPluginMetaV0alpha1ExtensionsAddedLinks creates a new PluginMetaV0alpha1ExtensionsAddedLinks object. -func NewPluginMetaV0alpha1ExtensionsAddedLinks() *PluginMetaV0alpha1ExtensionsAddedLinks { - return &PluginMetaV0alpha1ExtensionsAddedLinks{ - Targets: []string{}, - } -} - -// +k8s:openapi-gen=true -type PluginMetaV0alpha1ExtensionsExposedComponents struct { - Id string `json:"id"` - Title *string `json:"title,omitempty"` - Description *string `json:"description,omitempty"` -} - -// NewPluginMetaV0alpha1ExtensionsExposedComponents creates a new PluginMetaV0alpha1ExtensionsExposedComponents object. -func NewPluginMetaV0alpha1ExtensionsExposedComponents() *PluginMetaV0alpha1ExtensionsExposedComponents { - return &PluginMetaV0alpha1ExtensionsExposedComponents{} -} - -// +k8s:openapi-gen=true -type PluginMetaV0alpha1ExtensionsExtensionPoints struct { - Id string `json:"id"` - Title *string `json:"title,omitempty"` - Description *string `json:"description,omitempty"` -} - -// NewPluginMetaV0alpha1ExtensionsExtensionPoints creates a new PluginMetaV0alpha1ExtensionsExtensionPoints object. -func NewPluginMetaV0alpha1ExtensionsExtensionPoints() *PluginMetaV0alpha1ExtensionsExtensionPoints { - return &PluginMetaV0alpha1ExtensionsExtensionPoints{} -} - -// +k8s:openapi-gen=true -type PluginMetaJSONDataType string - -const ( - PluginMetaJSONDataTypeApp PluginMetaJSONDataType = "app" - PluginMetaJSONDataTypeDatasource PluginMetaJSONDataType = "datasource" - PluginMetaJSONDataTypePanel PluginMetaJSONDataType = "panel" - PluginMetaJSONDataTypeRenderer PluginMetaJSONDataType = "renderer" -) - -// +k8s:openapi-gen=true -type PluginMetaJSONDataCategory string - -const ( - PluginMetaJSONDataCategoryTsdb PluginMetaJSONDataCategory = "tsdb" - PluginMetaJSONDataCategoryLogging PluginMetaJSONDataCategory = "logging" - PluginMetaJSONDataCategoryCloud PluginMetaJSONDataCategory = "cloud" - PluginMetaJSONDataCategoryTracing PluginMetaJSONDataCategory = "tracing" - PluginMetaJSONDataCategoryProfiling PluginMetaJSONDataCategory = "profiling" - PluginMetaJSONDataCategorySql PluginMetaJSONDataCategory = "sql" - PluginMetaJSONDataCategoryEnterprise PluginMetaJSONDataCategory = "enterprise" - PluginMetaJSONDataCategoryIot PluginMetaJSONDataCategory = "iot" - PluginMetaJSONDataCategoryOther PluginMetaJSONDataCategory = "other" -) - -// +k8s:openapi-gen=true -type PluginMetaJSONDataState string - -const ( - PluginMetaJSONDataStateAlpha PluginMetaJSONDataState = "alpha" - PluginMetaJSONDataStateBeta PluginMetaJSONDataState = "beta" -) - -// +k8s:openapi-gen=true -type PluginMetaIncludeType string - -const ( - PluginMetaIncludeTypeDashboard PluginMetaIncludeType = "dashboard" - PluginMetaIncludeTypePage PluginMetaIncludeType = "page" - PluginMetaIncludeTypePanel PluginMetaIncludeType = "panel" - PluginMetaIncludeTypeDatasource PluginMetaIncludeType = "datasource" -) - -// +k8s:openapi-gen=true -type PluginMetaIncludeRole string - -const ( - PluginMetaIncludeRoleAdmin PluginMetaIncludeRole = "Admin" - PluginMetaIncludeRoleEditor PluginMetaIncludeRole = "Editor" - PluginMetaIncludeRoleViewer PluginMetaIncludeRole = "Viewer" -) - -// +k8s:openapi-gen=true -type PluginMetaV0alpha1DependenciesPluginsType string - -const ( - PluginMetaV0alpha1DependenciesPluginsTypeApp PluginMetaV0alpha1DependenciesPluginsType = "app" - PluginMetaV0alpha1DependenciesPluginsTypeDatasource PluginMetaV0alpha1DependenciesPluginsType = "datasource" - PluginMetaV0alpha1DependenciesPluginsTypePanel PluginMetaV0alpha1DependenciesPluginsType = "panel" -) diff --git a/apps/plugins/pkg/apis/plugins_manifest.go b/apps/plugins/pkg/apis/plugins_manifest.go index 84a55555c2b..428971aa0b5 100644 --- a/apps/plugins/pkg/apis/plugins_manifest.go +++ b/apps/plugins/pkg/apis/plugins_manifest.go @@ -20,12 +20,9 @@ import ( ) var ( - rawSchemaPluginMetav0alpha1 = []byte(`{"Dependencies":{"additionalProperties":false,"properties":{"extensions":{"additionalProperties":false,"properties":{"exposedComponents":{"description":"+listType=set","items":{"type":"string"},"type":"array"}},"type":"object"},"grafanaDependency":{"description":"Required field","type":"string"},"grafanaVersion":{"description":"Optional fields","type":"string"},"plugins":{"description":"+listType=set\n+listMapKey=id","items":{"additionalProperties":false,"properties":{"id":{"type":"string"},"name":{"type":"string"},"type":{"enum":["app","datasource","panel"],"type":"string"}},"required":["id","type","name"],"type":"object"},"type":"array"}},"required":["grafanaDependency"],"type":"object"},"EnterpriseFeatures":{"additionalProperties":false,"properties":{"healthDiagnosticsErrors":{"default":false,"description":"Allow additional properties","type":"boolean"}},"type":"object"},"Extensions":{"additionalProperties":false,"properties":{"addedComponents":{"description":"+listType=atomic","items":{"additionalProperties":false,"properties":{"description":{"type":"string"},"targets":{"description":"+listType=set","items":{"type":"string"},"type":"array"},"title":{"type":"string"}},"required":["targets","title"],"type":"object"},"type":"array"},"addedLinks":{"description":"+listType=atomic","items":{"additionalProperties":false,"properties":{"description":{"type":"string"},"targets":{"description":"+listType=set","items":{"type":"string"},"type":"array"},"title":{"type":"string"}},"required":["targets","title"],"type":"object"},"type":"array"},"exposedComponents":{"description":"+listType=set\n+listMapKey=id","items":{"additionalProperties":false,"properties":{"description":{"type":"string"},"id":{"type":"string"},"title":{"type":"string"}},"required":["id"],"type":"object"},"type":"array"},"extensionPoints":{"description":"+listType=set\n+listMapKey=id","items":{"additionalProperties":false,"properties":{"description":{"type":"string"},"id":{"type":"string"},"title":{"type":"string"}},"required":["id"],"type":"object"},"type":"array"}},"type":"object"},"IAM":{"additionalProperties":false,"properties":{"permissions":{"description":"+listType=atomic","items":{"additionalProperties":false,"properties":{"action":{"type":"string"},"scope":{"type":"string"}},"type":"object"},"type":"array"}},"type":"object"},"Include":{"additionalProperties":false,"properties":{"action":{"type":"string"},"addToNav":{"type":"boolean"},"component":{"type":"string"},"defaultNav":{"type":"boolean"},"icon":{"type":"string"},"name":{"type":"string"},"path":{"type":"string"},"role":{"enum":["Admin","Editor","Viewer"],"type":"string"},"type":{"enum":["dashboard","page","panel","datasource"],"type":"string"},"uid":{"type":"string"}},"type":"object"},"Info":{"additionalProperties":false,"properties":{"author":{"additionalProperties":false,"description":"Optional fields","properties":{"email":{"type":"string"},"name":{"type":"string"},"url":{"type":"string"}},"type":"object"},"description":{"type":"string"},"keywords":{"description":"Required fields\n+listType=set","items":{"type":"string"},"type":"array"},"links":{"description":"+listType=atomic","items":{"additionalProperties":false,"properties":{"name":{"type":"string"},"url":{"type":"string"}},"type":"object"},"type":"array"},"logos":{"additionalProperties":false,"properties":{"large":{"type":"string"},"small":{"type":"string"}},"required":["small","large"],"type":"object"},"screenshots":{"description":"+listType=atomic","items":{"additionalProperties":false,"properties":{"name":{"type":"string"},"path":{"type":"string"}},"type":"object"},"type":"array"},"updated":{"format":"date-time","type":"string"},"version":{"type":"string"}},"required":["keywords","logos","updated","version"],"type":"object"},"JSONData":{"additionalProperties":false,"description":"JSON configuration schema for Grafana plugins\nConverted from: https://github.com/grafana/grafana/blob/main/docs/sources/developers/plugins/plugin.schema.json","properties":{"alerting":{"description":"Optional fields","type":"boolean"},"annotations":{"type":"boolean"},"autoEnabled":{"type":"boolean"},"backend":{"type":"boolean"},"buildMode":{"type":"string"},"builtIn":{"type":"boolean"},"category":{"enum":["tsdb","logging","cloud","tracing","profiling","sql","enterprise","iot","other"],"type":"string"},"dependencies":{"$ref":"#/components/schemas/Dependencies","description":"Dependency information"},"enterpriseFeatures":{"$ref":"#/components/schemas/EnterpriseFeatures"},"executable":{"type":"string"},"extensions":{"$ref":"#/components/schemas/Extensions"},"hideFromList":{"type":"boolean"},"iam":{"$ref":"#/components/schemas/IAM"},"id":{"description":"Unique name of the plugin","type":"string"},"includes":{"description":"+listType=atomic","items":{"$ref":"#/components/schemas/Include"},"type":"array"},"info":{"$ref":"#/components/schemas/Info","description":"Metadata for the plugin"},"logs":{"type":"boolean"},"metrics":{"type":"boolean"},"multiValueFilterOperators":{"type":"boolean"},"name":{"description":"Human-readable name of the plugin","type":"string"},"pascalName":{"type":"string"},"preload":{"type":"boolean"},"queryOptions":{"$ref":"#/components/schemas/QueryOptions"},"roles":{"description":"+listType=atomic","items":{"$ref":"#/components/schemas/Role"},"type":"array"},"routes":{"description":"+listType=atomic","items":{"$ref":"#/components/schemas/Route"},"type":"array"},"skipDataQuery":{"type":"boolean"},"state":{"enum":["alpha","beta"],"type":"string"},"streaming":{"type":"boolean"},"tracing":{"type":"boolean"},"type":{"description":"Plugin type","enum":["app","datasource","panel","renderer"],"type":"string"}},"required":["id","type","name","info","dependencies"],"type":"object"},"OperatorState":{"additionalProperties":false,"properties":{"descriptiveState":{"description":"descriptiveState is an optional more descriptive state field which has no requirements on format","type":"string"},"details":{"additionalProperties":{"additionalProperties":{},"type":"object"},"description":"details contains any extra information that is operator-specific","type":"object"},"lastEvaluation":{"description":"lastEvaluation is the ResourceVersion last evaluated","type":"string"},"state":{"description":"state describes the state of the lastEvaluation.\nIt is limited to three possible states for machine evaluation.","enum":["success","in_progress","failed"],"type":"string"}},"required":["lastEvaluation","state"],"type":"object"},"PluginMeta":{"properties":{"spec":{"$ref":"#/components/schemas/spec"},"status":{"$ref":"#/components/schemas/status"}},"required":["spec"]},"QueryOptions":{"additionalProperties":false,"properties":{"cacheTimeout":{"type":"boolean"},"maxDataPoints":{"type":"boolean"},"minInterval":{"type":"boolean"}},"type":"object"},"Role":{"additionalProperties":false,"properties":{"grants":{"description":"+listType=set","items":{"type":"string"},"type":"array"},"role":{"additionalProperties":false,"properties":{"description":{"type":"string"},"name":{"type":"string"},"permissions":{"description":"+listType=atomic","items":{"additionalProperties":false,"properties":{"action":{"type":"string"},"scope":{"type":"string"}},"type":"object"},"type":"array"}},"type":"object"}},"type":"object"},"Route":{"additionalProperties":false,"properties":{"body":{"additionalProperties":{"additionalProperties":{},"type":"object"},"type":"object"},"headers":{"description":"+listType=atomic","items":{"type":"string"},"type":"array"},"jwtTokenAuth":{"additionalProperties":false,"properties":{"params":{"additionalProperties":{"additionalProperties":{},"type":"object"},"type":"object"},"scopes":{"description":"+listType=set","items":{"type":"string"},"type":"array"},"url":{"type":"string"}},"type":"object"},"method":{"type":"string"},"path":{"type":"string"},"reqAction":{"type":"string"},"reqRole":{"type":"string"},"reqSignedIn":{"type":"boolean"},"tokenAuth":{"additionalProperties":false,"properties":{"params":{"additionalProperties":{"additionalProperties":{},"type":"object"},"type":"object"},"scopes":{"description":"+listType=set","items":{"type":"string"},"type":"array"},"url":{"type":"string"}},"type":"object"},"url":{"type":"string"},"urlParams":{"description":"+listType=atomic","items":{"additionalProperties":false,"properties":{"content":{"type":"string"},"name":{"type":"string"}},"type":"object"},"type":"array"}},"type":"object"},"spec":{"additionalProperties":false,"properties":{"pluginJSON":{"$ref":"#/components/schemas/JSONData"}},"required":["pluginJSON"],"type":"object"},"status":{"additionalProperties":false,"properties":{"additionalFields":{"additionalProperties":{"additionalProperties":{},"type":"object"},"description":"additionalFields is reserved for future use","type":"object"},"operatorStates":{"additionalProperties":{"$ref":"#/components/schemas/OperatorState"},"description":"operatorStates is a map of operator ID to operator state evaluations.\nAny operator which consumes this kind SHOULD add its state evaluation information to this field.","type":"object"}},"type":"object"}}`) - versionSchemaPluginMetav0alpha1 app.VersionSchema - _ = json.Unmarshal(rawSchemaPluginMetav0alpha1, &versionSchemaPluginMetav0alpha1) - rawSchemaPluginInstallv0alpha1 = []byte(`{"OperatorState":{"additionalProperties":false,"properties":{"descriptiveState":{"description":"descriptiveState is an optional more descriptive state field which has no requirements on format","type":"string"},"details":{"additionalProperties":{"additionalProperties":{},"type":"object"},"description":"details contains any extra information that is operator-specific","type":"object"},"lastEvaluation":{"description":"lastEvaluation is the ResourceVersion last evaluated","type":"string"},"state":{"description":"state describes the state of the lastEvaluation.\nIt is limited to three possible states for machine evaluation.","enum":["success","in_progress","failed"],"type":"string"}},"required":["lastEvaluation","state"],"type":"object"},"PluginInstall":{"properties":{"spec":{"$ref":"#/components/schemas/spec"},"status":{"$ref":"#/components/schemas/status"}},"required":["spec"]},"spec":{"additionalProperties":false,"properties":{"class":{"enum":["core","external","cdn"],"type":"string"},"id":{"type":"string"},"url":{"type":"string"},"version":{"type":"string"}},"required":["id","version","class"],"type":"object"},"status":{"additionalProperties":false,"properties":{"additionalFields":{"additionalProperties":{"additionalProperties":{},"type":"object"},"description":"additionalFields is reserved for future use","type":"object"},"operatorStates":{"additionalProperties":{"$ref":"#/components/schemas/OperatorState"},"description":"operatorStates is a map of operator ID to operator state evaluations.\nAny operator which consumes this kind SHOULD add its state evaluation information to this field.","type":"object"}},"type":"object"}}`) - versionSchemaPluginInstallv0alpha1 app.VersionSchema - _ = json.Unmarshal(rawSchemaPluginInstallv0alpha1, &versionSchemaPluginInstallv0alpha1) + rawSchemaPluginv0alpha1 = []byte(`{"OperatorState":{"additionalProperties":false,"properties":{"descriptiveState":{"description":"descriptiveState is an optional more descriptive state field which has no requirements on format","type":"string"},"details":{"additionalProperties":{"additionalProperties":{},"type":"object"},"description":"details contains any extra information that is operator-specific","type":"object"},"lastEvaluation":{"description":"lastEvaluation is the ResourceVersion last evaluated","type":"string"},"state":{"description":"state describes the state of the lastEvaluation.\nIt is limited to three possible states for machine evaluation.","enum":["success","in_progress","failed"],"type":"string"}},"required":["lastEvaluation","state"],"type":"object"},"Plugin":{"properties":{"spec":{"$ref":"#/components/schemas/spec"},"status":{"$ref":"#/components/schemas/status"}},"required":["spec"]},"getMetaDependencies":{"type":"object","required":["grafanaDependency"],"properties":{"extensions":{"type":"object","properties":{"exposedComponents":{"description":"+listType=set","type":"array","items":{"type":"string"}}},"additionalProperties":false},"grafanaDependency":{"description":"Required field","type":"string"},"grafanaVersion":{"description":"Optional fields","type":"string"},"plugins":{"description":"+listType=set\n+listMapKey=id","type":"array","items":{"type":"object","required":["id","type","name"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"type":{"type":"string","enum":["app","datasource","panel"]}},"additionalProperties":false}}},"additionalProperties":false},"getMetaEnterpriseFeatures":{"type":"object","properties":{"healthDiagnosticsErrors":{"description":"Allow additional properties","type":"boolean","default":false}},"additionalProperties":false},"getMetaExtensions":{"type":"object","properties":{"addedComponents":{"description":"+listType=atomic","type":"array","items":{"type":"object","required":["targets","title"],"properties":{"description":{"type":"string"},"targets":{"description":"+listType=set","type":"array","items":{"type":"string"}},"title":{"type":"string"}},"additionalProperties":false}},"addedLinks":{"description":"+listType=atomic","type":"array","items":{"type":"object","required":["targets","title"],"properties":{"description":{"type":"string"},"targets":{"description":"+listType=set","type":"array","items":{"type":"string"}},"title":{"type":"string"}},"additionalProperties":false}},"exposedComponents":{"description":"+listType=set\n+listMapKey=id","type":"array","items":{"type":"object","required":["id"],"properties":{"description":{"type":"string"},"id":{"type":"string"},"title":{"type":"string"}},"additionalProperties":false}},"extensionPoints":{"description":"+listType=set\n+listMapKey=id","type":"array","items":{"type":"object","required":["id"],"properties":{"description":{"type":"string"},"id":{"type":"string"},"title":{"type":"string"}},"additionalProperties":false}}},"additionalProperties":false},"getMetaIAM":{"type":"object","properties":{"permissions":{"description":"+listType=atomic","type":"array","items":{"type":"object","properties":{"action":{"type":"string"},"scope":{"type":"string"}},"additionalProperties":false}}},"additionalProperties":false},"getMetaInclude":{"type":"object","properties":{"action":{"type":"string"},"addToNav":{"type":"boolean"},"component":{"type":"string"},"defaultNav":{"type":"boolean"},"icon":{"type":"string"},"name":{"type":"string"},"path":{"type":"string"},"role":{"type":"string","enum":["Admin","Editor","Viewer"]},"type":{"type":"string","enum":["dashboard","page","panel","datasource"]},"uid":{"type":"string"}},"additionalProperties":false},"getMetaInfo":{"type":"object","required":["keywords","logos","updated","version"],"properties":{"author":{"description":"Optional fields","type":"object","properties":{"email":{"type":"string"},"name":{"type":"string"},"url":{"type":"string"}},"additionalProperties":false},"description":{"type":"string"},"keywords":{"description":"Required fields\n+listType=set","type":"array","items":{"type":"string"}},"links":{"description":"+listType=atomic","type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"url":{"type":"string"}},"additionalProperties":false}},"logos":{"type":"object","required":["small","large"],"properties":{"large":{"type":"string"},"small":{"type":"string"}},"additionalProperties":false},"screenshots":{"description":"+listType=atomic","type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"path":{"type":"string"}},"additionalProperties":false}},"updated":{"type":"string","format":"date-time"},"version":{"type":"string"}},"additionalProperties":false},"getMetaQueryOptions":{"type":"object","properties":{"cacheTimeout":{"type":"boolean"},"maxDataPoints":{"type":"boolean"},"minInterval":{"type":"boolean"}},"additionalProperties":false},"getMetaRole":{"type":"object","properties":{"grants":{"description":"+listType=set","type":"array","items":{"type":"string"}},"role":{"type":"object","properties":{"description":{"type":"string"},"name":{"type":"string"},"permissions":{"description":"+listType=atomic","type":"array","items":{"type":"object","properties":{"action":{"type":"string"},"scope":{"type":"string"}},"additionalProperties":false}}},"additionalProperties":false}},"additionalProperties":false},"getMetaRoute":{"type":"object","properties":{"body":{"type":"object","additionalProperties":{"type":"object","additionalProperties":{}}},"headers":{"description":"+listType=atomic","type":"array","items":{"type":"string"}},"jwtTokenAuth":{"type":"object","properties":{"params":{"type":"object","additionalProperties":{"type":"object","additionalProperties":{}}},"scopes":{"description":"+listType=set","type":"array","items":{"type":"string"}},"url":{"type":"string"}},"additionalProperties":false},"method":{"type":"string"},"path":{"type":"string"},"reqAction":{"type":"string"},"reqRole":{"type":"string"},"reqSignedIn":{"type":"boolean"},"tokenAuth":{"type":"object","properties":{"params":{"type":"object","additionalProperties":{"type":"object","additionalProperties":{}}},"scopes":{"description":"+listType=set","type":"array","items":{"type":"string"}},"url":{"type":"string"}},"additionalProperties":false},"url":{"type":"string"},"urlParams":{"description":"+listType=atomic","type":"array","items":{"type":"object","properties":{"content":{"type":"string"},"name":{"type":"string"}},"additionalProperties":false}}},"additionalProperties":false},"spec":{"additionalProperties":false,"properties":{"class":{"enum":["core","external","cdn"],"type":"string"},"id":{"type":"string"},"url":{"type":"string"},"version":{"type":"string"}},"required":["id","version","class"],"type":"object"},"status":{"additionalProperties":false,"properties":{"additionalFields":{"additionalProperties":{"additionalProperties":{},"type":"object"},"description":"additionalFields is reserved for future use","type":"object"},"operatorStates":{"additionalProperties":{"$ref":"#/components/schemas/OperatorState"},"description":"operatorStates is a map of operator ID to operator state evaluations.\nAny operator which consumes this kind SHOULD add its state evaluation information to this field.","type":"object"}},"type":"object"}}`) + versionSchemaPluginv0alpha1 app.VersionSchema + _ = json.Unmarshal(rawSchemaPluginv0alpha1, &versionSchemaPluginv0alpha1) ) var appManifestData = app.ManifestData{ @@ -35,22 +32,237 @@ var appManifestData = app.ManifestData{ Versions: []app.ManifestVersion{ { Name: "v0alpha1", - Served: false, + Served: true, Kinds: []app.ManifestVersionKind{ { - Kind: "PluginMeta", - Plural: "PluginMetas", + Kind: "Plugin", + Plural: "Plugins", Scope: "Namespaced", Conversion: false, - Schema: &versionSchemaPluginMetav0alpha1, - }, + Schema: &versionSchemaPluginv0alpha1, + Routes: map[string]spec3.PathProps{ + "/meta": { + Get: &spec3.Operation{ + OperationProps: spec3.OperationProps{ - { - Kind: "PluginInstall", - Plural: "PluginInstalls", - Scope: "Namespaced", - Conversion: false, - Schema: &versionSchemaPluginInstallv0alpha1, + OperationId: "getMeta", + + Responses: &spec3.Responses{ + ResponsesProps: spec3.ResponsesProps{ + Default: &spec3.Response{ + ResponseProps: spec3.ResponseProps{ + Description: "Default OK response", + Content: map[string]*spec3.MediaType{ + "application/json": { + MediaTypeProps: spec3.MediaTypeProps{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "alerting": { + SchemaProps: spec.SchemaProps{ + Type: []string{"boolean"}, + Description: "Optional fields", + }, + }, + "annotations": { + SchemaProps: spec.SchemaProps{ + Type: []string{"boolean"}, + }, + }, + "autoEnabled": { + SchemaProps: spec.SchemaProps{ + Type: []string{"boolean"}, + }, + }, + "backend": { + SchemaProps: spec.SchemaProps{ + Type: []string{"boolean"}, + }, + }, + "buildMode": { + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + }, + }, + "builtIn": { + SchemaProps: spec.SchemaProps{ + Type: []string{"boolean"}, + }, + }, + "category": { + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + Enum: []interface{}{ + "tsdb", + "logging", + "cloud", + "tracing", + "profiling", + "sql", + "enterprise", + "iot", + "other", + }, + }, + }, + "dependencies": { + SchemaProps: spec.SchemaProps{ + + Description: "Dependency information", + Ref: spec.MustCreateRef("#/components/schemas/getMetaDependencies"), + }, + }, + "enterpriseFeatures": { + SchemaProps: spec.SchemaProps{ + + Ref: spec.MustCreateRef("#/components/schemas/getMetaEnterpriseFeatures"), + }, + }, + "executable": { + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + }, + }, + "extensions": { + SchemaProps: spec.SchemaProps{ + + Ref: spec.MustCreateRef("#/components/schemas/getMetaExtensions"), + }, + }, + "hideFromList": { + SchemaProps: spec.SchemaProps{ + Type: []string{"boolean"}, + }, + }, + "iam": { + SchemaProps: spec.SchemaProps{ + + Ref: spec.MustCreateRef("#/components/schemas/getMetaIAM"), + }, + }, + "id": { + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + Description: "Unique name of the plugin", + }, + }, + "includes": { + SchemaProps: spec.SchemaProps{ + Type: []string{"array"}, + Description: "+listType=atomic", + }, + }, + "info": { + SchemaProps: spec.SchemaProps{ + + Description: "Metadata for the plugin", + Ref: spec.MustCreateRef("#/components/schemas/getMetaInfo"), + }, + }, + "logs": { + SchemaProps: spec.SchemaProps{ + Type: []string{"boolean"}, + }, + }, + "metrics": { + SchemaProps: spec.SchemaProps{ + Type: []string{"boolean"}, + }, + }, + "multiValueFilterOperators": { + SchemaProps: spec.SchemaProps{ + Type: []string{"boolean"}, + }, + }, + "name": { + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + Description: "Human-readable name of the plugin", + }, + }, + "pascalName": { + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + }, + }, + "preload": { + SchemaProps: spec.SchemaProps{ + Type: []string{"boolean"}, + }, + }, + "queryOptions": { + SchemaProps: spec.SchemaProps{ + + Ref: spec.MustCreateRef("#/components/schemas/getMetaQueryOptions"), + }, + }, + "roles": { + SchemaProps: spec.SchemaProps{ + Type: []string{"array"}, + Description: "+listType=atomic", + }, + }, + "routes": { + SchemaProps: spec.SchemaProps{ + Type: []string{"array"}, + Description: "+listType=atomic", + }, + }, + "skipDataQuery": { + SchemaProps: spec.SchemaProps{ + Type: []string{"boolean"}, + }, + }, + "state": { + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + Enum: []interface{}{ + "alpha", + "beta", + }, + }, + }, + "streaming": { + SchemaProps: spec.SchemaProps{ + Type: []string{"boolean"}, + }, + }, + "tracing": { + SchemaProps: spec.SchemaProps{ + Type: []string{"boolean"}, + }, + }, + "type": { + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + Description: "Plugin type", + Enum: []interface{}{ + "app", + "datasource", + "panel", + "renderer", + }, + }, + }, + }, + Required: []string{ + "id", + "type", + "name", + "info", + "dependencies", + }, + }}, + }}, + }, + }, + }, + }}, + }, + }, + }, + }, }, }, Routes: app.ManifestVersionRoutes{ @@ -71,8 +283,7 @@ func RemoteManifest() app.Manifest { } var kindVersionToGoType = map[string]resource.Kind{ - "PluginMeta/v0alpha1": v0alpha1.PluginMetaKind(), - "PluginInstall/v0alpha1": v0alpha1.PluginInstallKind(), + "Plugin/v0alpha1": v0alpha1.PluginKind(), } // ManifestGoTypeAssociator returns the associated resource.Kind instance for a given Kind and Version, if one exists. @@ -82,7 +293,9 @@ func ManifestGoTypeAssociator(kind, version string) (goType resource.Kind, exist return goType, exists } -var customRouteToGoResponseType = map[string]any{} +var customRouteToGoResponseType = map[string]any{ + "v0alpha1|Plugin|meta|GET": v0alpha1.GetMeta{}, +} // ManifestCustomRouteResponsesAssociator returns the associated response go type for a given kind, version, custom route path, and method, if one exists. // kind may be empty for custom routes which are not kind subroutes. Leading slashes are removed from subroute paths. diff --git a/apps/plugins/pkg/app/app.go b/apps/plugins/pkg/app/app.go index 5503126704b..903e2580ab0 100644 --- a/apps/plugins/pkg/app/app.go +++ b/apps/plugins/pkg/app/app.go @@ -2,8 +2,11 @@ package app import ( "context" + "net/http" "github.com/grafana/grafana-app-sdk/app" + "github.com/grafana/grafana-app-sdk/k8s" + "github.com/grafana/grafana-app-sdk/logging" "github.com/grafana/grafana-app-sdk/operator" "github.com/grafana/grafana-app-sdk/resource" "github.com/grafana/grafana-app-sdk/simple" @@ -11,16 +14,15 @@ import ( "k8s.io/klog/v2" pluginsapi "github.com/grafana/grafana/apps/plugins/pkg/apis" + pluginsv0alpha1 "github.com/grafana/grafana/apps/plugins/pkg/apis/plugins/v0alpha1" ) func New(cfg app.Config) (app.App, error) { - managedKinds := []simple.AppManagedKind{} - for _, kinds := range GetKinds() { - for _, k := range kinds { - managedKinds = append(managedKinds, simple.AppManagedKind{ - Kind: k, - }) - } + cfg.KubeConfig.APIPath = "apis" + clientGenerator := k8s.NewClientRegistry(cfg.KubeConfig, k8s.DefaultClientConfig()) + client, err := pluginsv0alpha1.NewPluginClientFromGenerator(clientGenerator) + if err != nil { + return nil, err } simpleConfig := simple.AppConfig{ @@ -33,7 +35,32 @@ func New(cfg app.Config) (app.App, error) { }, }, }, - ManagedKinds: managedKinds, + ManagedKinds: []simple.AppManagedKind{ + { + Kind: pluginsv0alpha1.PluginKind(), + CustomRoutes: simple.AppCustomRouteHandlers{ + simple.AppCustomRoute{ + Method: http.MethodGet, + Path: "meta", + }: func(ctx context.Context, w app.CustomRouteResponseWriter, req *app.CustomRouteRequest) error { + plugin, err := client.Get(ctx, resource.Identifier{ + Namespace: req.ResourceIdentifier.Namespace, + Name: req.ResourceIdentifier.Name, + }) + if err != nil { + return err + } + logging.DefaultLogger.Debug("fetched plugin", "plugin", plugin) + // TODO: Implement this in future PR + w.WriteHeader(http.StatusNotImplemented) + if _, err := w.Write([]byte("Not implemented")); err != nil { + return err + } + return nil + }, + }, + }, + }, } a, err := simple.NewApp(simpleConfig) diff --git a/apps/plugins/pkg/app/install/registrar.go b/apps/plugins/pkg/app/install/registrar.go index efb7de11080..98d7c02b94b 100644 --- a/apps/plugins/pkg/app/install/registrar.go +++ b/apps/plugins/pkg/app/install/registrar.go @@ -41,12 +41,12 @@ type PluginInstall struct { Source Source } -func (p *PluginInstall) ToPluginInstallV0Alpha1(namespace string) *pluginsv0alpha1.PluginInstall { +func (p *PluginInstall) ToPluginInstallV0Alpha1(namespace string) *pluginsv0alpha1.Plugin { var url *string = nil if p.URL != "" { url = &p.URL } - return &pluginsv0alpha1.PluginInstall{ + return &pluginsv0alpha1.Plugin{ ObjectMeta: metav1.ObjectMeta{ Namespace: namespace, Name: p.ID, @@ -54,16 +54,16 @@ func (p *PluginInstall) ToPluginInstallV0Alpha1(namespace string) *pluginsv0alph PluginInstallSourceAnnotation: p.Source, }, }, - Spec: pluginsv0alpha1.PluginInstallSpec{ + Spec: pluginsv0alpha1.PluginSpec{ Id: p.ID, Version: p.Version, Url: url, - Class: pluginsv0alpha1.PluginInstallSpecClass(p.Class), + Class: pluginsv0alpha1.PluginSpecClass(p.Class), }, } } -func (p *PluginInstall) ShouldUpdate(existing *pluginsv0alpha1.PluginInstall) bool { +func (p *PluginInstall) ShouldUpdate(existing *pluginsv0alpha1.Plugin) bool { update := p.ToPluginInstallV0Alpha1(existing.Namespace) if source, ok := existing.Annotations[PluginInstallSourceAnnotation]; ok && source != p.Source { return true @@ -92,7 +92,7 @@ func equalStringPointers(a, b *string) bool { type InstallRegistrar struct { clientGenerator resource.ClientGenerator - client *pluginsv0alpha1.PluginInstallClient + client *pluginsv0alpha1.PluginClient clientOnce sync.Once } @@ -103,9 +103,9 @@ func NewInstallRegistrar(clientGenerator resource.ClientGenerator) *InstallRegis } } -func (r *InstallRegistrar) GetClient() (*pluginsv0alpha1.PluginInstallClient, error) { +func (r *InstallRegistrar) GetClient() (*pluginsv0alpha1.PluginClient, error) { r.clientOnce.Do(func() { - client, err := pluginsv0alpha1.NewPluginInstallClientFromGenerator(r.clientGenerator) + client, err := pluginsv0alpha1.NewPluginClientFromGenerator(r.clientGenerator) if err != nil { r.client = nil return diff --git a/apps/plugins/pkg/app/storage.go b/apps/plugins/pkg/app/storage.go deleted file mode 100644 index 9fca277abfc..00000000000 --- a/apps/plugins/pkg/app/storage.go +++ /dev/null @@ -1,75 +0,0 @@ -package app - -import ( - "context" - "strings" - - apierrors "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/apis/meta/internalversion" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apiserver/pkg/registry/rest" - - claims "github.com/grafana/authlib/types" - pluginsv0alpha1 "github.com/grafana/grafana/apps/plugins/pkg/apis/plugins/v0alpha1" -) - -var ( - _ rest.Scoper = (*PluginMetaStorage)(nil) - _ rest.SingularNameProvider = (*PluginMetaStorage)(nil) - _ rest.Getter = (*PluginMetaStorage)(nil) - _ rest.Lister = (*PluginMetaStorage)(nil) - _ rest.Storage = (*PluginMetaStorage)(nil) - _ rest.TableConvertor = (*PluginMetaStorage)(nil) -) - -type PluginMetaStorage struct { - gr schema.GroupResource - namespacer claims.NamespaceFormatter - tableConverter rest.TableConvertor -} - -func NewPluginMetaStorage( - namespacer claims.NamespaceFormatter, -) *PluginMetaStorage { - gr := schema.GroupResource{ - Group: pluginsv0alpha1.PluginMetaKind().Group(), - Resource: strings.ToLower(pluginsv0alpha1.PluginMetaKind().Plural()), - } - return &PluginMetaStorage{ - gr: gr, - namespacer: namespacer, - tableConverter: rest.NewDefaultTableConvertor(gr), - } -} - -func (s *PluginMetaStorage) New() runtime.Object { - return pluginsv0alpha1.PluginMetaKind().ZeroValue() -} - -func (s *PluginMetaStorage) Destroy() {} - -func (s *PluginMetaStorage) NamespaceScoped() bool { - return true -} - -func (s *PluginMetaStorage) GetSingularName() string { - return strings.ToLower(pluginsv0alpha1.PluginMetaKind().Kind()) -} - -func (s *PluginMetaStorage) NewList() runtime.Object { - return pluginsv0alpha1.PluginMetaKind().ZeroListValue() -} - -func (s *PluginMetaStorage) ConvertToTable(ctx context.Context, object runtime.Object, tableOptions runtime.Object) (*metav1.Table, error) { - return s.tableConverter.ConvertToTable(ctx, object, tableOptions) -} - -func (s *PluginMetaStorage) List(ctx context.Context, options *internalversion.ListOptions) (runtime.Object, error) { - return s.NewList(), nil -} - -func (s *PluginMetaStorage) Get(ctx context.Context, name string, options *metav1.GetOptions) (runtime.Object, error) { - return nil, apierrors.NewNotFound(s.gr, name) -} diff --git a/pkg/registry/apps/plugins/register.go b/pkg/registry/apps/plugins/register.go index 2929efda78f..e95b120cd66 100644 --- a/pkg/registry/apps/plugins/register.go +++ b/pkg/registry/apps/plugins/register.go @@ -1,20 +1,15 @@ package plugins import ( - "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apiserver/pkg/authorization/authorizer" - "k8s.io/apiserver/pkg/registry/generic" - "k8s.io/apiserver/pkg/registry/rest" restclient "k8s.io/client-go/rest" "github.com/grafana/grafana-app-sdk/app" appsdkapiserver "github.com/grafana/grafana-app-sdk/k8s/apiserver" "github.com/grafana/grafana-app-sdk/simple" pluginsappapis "github.com/grafana/grafana/apps/plugins/pkg/apis" - pluginsv0alpha1 "github.com/grafana/grafana/apps/plugins/pkg/apis/plugins/v0alpha1" pluginsapp "github.com/grafana/grafana/apps/plugins/pkg/app" "github.com/grafana/grafana/pkg/services/apiserver/appinstaller" - "github.com/grafana/grafana/pkg/services/apiserver/endpoints/request" "github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/setting" ) @@ -26,16 +21,13 @@ var ( type PluginsAppInstaller struct { appsdkapiserver.AppInstaller - cfg *setting.Cfg } func RegisterAppInstaller( cfg *setting.Cfg, features featuremgmt.FeatureToggles, ) (*PluginsAppInstaller, error) { - installer := &PluginsAppInstaller{ - cfg: cfg, - } + installer := &PluginsAppInstaller{} specificConfig := any(nil) provider := simple.NewAppProvider(pluginsappapis.LocalManifest(), specificConfig, pluginsapp.New) appConfig := app.Config{ @@ -51,21 +43,6 @@ func RegisterAppInstaller( return installer, nil } -func (p *PluginsAppInstaller) InstallAPIs( - server appsdkapiserver.GenericAPIServer, - restOptsGetter generic.RESTOptionsGetter, -) error { - pluginMetaGVR := pluginsv0alpha1.PluginMetaKind().GroupVersionResource() - replacedStorage := map[schema.GroupVersionResource]rest.Storage{ - pluginMetaGVR: pluginsapp.NewPluginMetaStorage(request.GetNamespaceMapper(p.cfg)), - } - wrappedServer := &customStorageWrapper{ - wrapped: server, - replace: replacedStorage, - } - return p.AppInstaller.InstallAPIs(wrappedServer, restOptsGetter) -} - // GetAuthorizer returns the authorizer for the plugins app. func (p *PluginsAppInstaller) GetAuthorizer() authorizer.Authorizer { return pluginsapp.GetAuthorizer() diff --git a/pkg/services/pluginsintegration/installsync/syncer.go b/pkg/services/pluginsintegration/installsync/syncer.go index ac6d6ba3d32..1f056a6e85b 100644 --- a/pkg/services/pluginsintegration/installsync/syncer.go +++ b/pkg/services/pluginsintegration/installsync/syncer.go @@ -4,6 +4,7 @@ import ( "context" "time" + "github.com/grafana/grafana-app-sdk/logging" "github.com/grafana/grafana-app-sdk/resource" "github.com/grafana/grafana/apps/plugins/pkg/app/install" @@ -90,6 +91,11 @@ func (s *syncer) Sync(ctx context.Context, source install.Source, installedPlugi return nil } + if !s.featureToggles.IsEnabled(ctx, featuremgmt.FlagPluginStoreServiceLoading) { + logging.DefaultLogger.Warn("pluginInstallAPISync is enabled, but pluginStoreServiceLoading is disabled. skipping plugin sync.") + return nil + } + if len(installedPlugins) == 0 { return nil } diff --git a/pkg/services/pluginsintegration/installsync/syncer_test.go b/pkg/services/pluginsintegration/installsync/syncer_test.go index a1ca40638b0..e8894436083 100644 --- a/pkg/services/pluginsintegration/installsync/syncer_test.go +++ b/pkg/services/pluginsintegration/installsync/syncer_test.go @@ -20,234 +20,68 @@ import ( "github.com/grafana/grafana/pkg/services/org/orgtest" ) -// Test helpers to avoid import cycles -type fakeServerLock struct { - lockFunc func(ctx context.Context, actionName string, maxInterval time.Duration, fn func(ctx context.Context)) error -} - -func (f *fakeServerLock) LockExecuteAndRelease(ctx context.Context, actionName string, maxInterval time.Duration, fn func(ctx context.Context)) error { - if f.lockFunc != nil { - return f.lockFunc(ctx, actionName, maxInterval, fn) - } - fn(ctx) - return nil -} - -type fakePluginInstallClient struct { - listAllFunc func(ctx context.Context, namespace string, opts resource.ListOptions) (*pluginsv0alpha1.PluginInstallList, error) - getFunc func(ctx context.Context, identifier resource.Identifier) (*pluginsv0alpha1.PluginInstall, error) - createFunc func(ctx context.Context, obj *pluginsv0alpha1.PluginInstall, opts resource.CreateOptions) (*pluginsv0alpha1.PluginInstall, error) - updateFunc func(ctx context.Context, obj *pluginsv0alpha1.PluginInstall, opts resource.UpdateOptions) (*pluginsv0alpha1.PluginInstall, error) - deleteFunc func(ctx context.Context, identifier resource.Identifier, opts resource.DeleteOptions) error -} - -func (f *fakePluginInstallClient) Get(ctx context.Context, identifier resource.Identifier) (*pluginsv0alpha1.PluginInstall, error) { - if f.getFunc != nil { - return f.getFunc(ctx, identifier) - } - // Return a proper k8s NotFound error - return nil, errorsK8s.NewNotFound(schema.GroupResource{ - Group: pluginsv0alpha1.APIGroup, - Resource: "plugininstalls", - }, identifier.Name) -} - -func (f *fakePluginInstallClient) ListAll(ctx context.Context, namespace string, opts resource.ListOptions) (*pluginsv0alpha1.PluginInstallList, error) { - if f.listAllFunc != nil { - return f.listAllFunc(ctx, namespace, opts) - } - return &pluginsv0alpha1.PluginInstallList{}, nil -} - -func (f *fakePluginInstallClient) List(ctx context.Context, namespace string, opts resource.ListOptions) (*pluginsv0alpha1.PluginInstallList, error) { - return f.ListAll(ctx, namespace, opts) -} - -func (f *fakePluginInstallClient) Create(ctx context.Context, obj *pluginsv0alpha1.PluginInstall, opts resource.CreateOptions) (*pluginsv0alpha1.PluginInstall, error) { - if f.createFunc != nil { - return f.createFunc(ctx, obj, opts) - } - return obj, nil -} - -func (f *fakePluginInstallClient) Update(ctx context.Context, obj *pluginsv0alpha1.PluginInstall, opts resource.UpdateOptions) (*pluginsv0alpha1.PluginInstall, error) { - if f.updateFunc != nil { - return f.updateFunc(ctx, obj, opts) - } - return obj, nil -} - -func (f *fakePluginInstallClient) UpdateStatus(ctx context.Context, identifier resource.Identifier, newStatus pluginsv0alpha1.PluginInstallStatus, opts resource.UpdateOptions) (*pluginsv0alpha1.PluginInstall, error) { - return nil, nil -} - -func (f *fakePluginInstallClient) Patch(ctx context.Context, identifier resource.Identifier, req resource.PatchRequest, opts resource.PatchOptions) (*pluginsv0alpha1.PluginInstall, error) { - return nil, nil -} - -func (f *fakePluginInstallClient) Delete(ctx context.Context, identifier resource.Identifier, opts resource.DeleteOptions) error { - if f.deleteFunc != nil { - return f.deleteFunc(ctx, identifier, opts) - } - return nil -} - -type fakeClientGenerator struct { - client *fakePluginInstallClient -} - -func (f *fakeClientGenerator) ClientFor(kind resource.Kind) (resource.Client, error) { - return &fakeResourceClient{client: f.client}, nil -} - -type fakeResourceClient struct { - client *fakePluginInstallClient -} - -func (f *fakeResourceClient) Get(ctx context.Context, identifier resource.Identifier) (resource.Object, error) { - return f.client.Get(ctx, identifier) -} - -func (f *fakeResourceClient) GetInto(ctx context.Context, identifier resource.Identifier, into resource.Object) error { - obj, err := f.client.Get(ctx, identifier) - if err != nil { - return err - } - // Copy the object data into the provided 'into' object - if target, ok := into.(*pluginsv0alpha1.PluginInstall); ok { - *target = *obj - } - return nil -} - -func (f *fakeResourceClient) List(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) { - return f.client.ListAll(ctx, namespace, options) -} - -func (f *fakeResourceClient) ListInto(ctx context.Context, namespace string, options resource.ListOptions, into resource.ListObject) error { - list, err := f.client.ListAll(ctx, namespace, options) - if err != nil { - return err - } - // Copy the list data into the provided 'into' object - if target, ok := into.(*pluginsv0alpha1.PluginInstallList); ok { - *target = *list - } - return nil -} - -func (f *fakeResourceClient) Create(ctx context.Context, identifier resource.Identifier, obj resource.Object, options resource.CreateOptions) (resource.Object, error) { - plugin := obj.(*pluginsv0alpha1.PluginInstall) - return f.client.Create(ctx, plugin, options) -} - -func (f *fakeResourceClient) CreateInto(ctx context.Context, identifier resource.Identifier, obj resource.Object, options resource.CreateOptions, into resource.Object) error { - created, err := f.Create(ctx, identifier, obj, options) - if err != nil { - return err - } - // Copy the created object data into the provided 'into' object - if plugin, ok := created.(*pluginsv0alpha1.PluginInstall); ok { - if target, ok := into.(*pluginsv0alpha1.PluginInstall); ok { - *target = *plugin - } - } - return nil -} - -func (f *fakeResourceClient) Update(ctx context.Context, identifier resource.Identifier, obj resource.Object, options resource.UpdateOptions) (resource.Object, error) { - plugin := obj.(*pluginsv0alpha1.PluginInstall) - return f.client.Update(ctx, plugin, options) -} - -func (f *fakeResourceClient) UpdateInto(ctx context.Context, identifier resource.Identifier, obj resource.Object, options resource.UpdateOptions, into resource.Object) error { - updated, err := f.Update(ctx, identifier, obj, options) - if err != nil { - return err - } - // Copy the updated object data into the provided 'into' object - if plugin, ok := updated.(*pluginsv0alpha1.PluginInstall); ok { - if target, ok := into.(*pluginsv0alpha1.PluginInstall); ok { - *target = *plugin - } - } - return nil -} - -func (f *fakeResourceClient) Patch(ctx context.Context, identifier resource.Identifier, patch resource.PatchRequest, options resource.PatchOptions) (resource.Object, error) { - return f.client.Patch(ctx, identifier, patch, options) -} - -func (f *fakeResourceClient) PatchInto(ctx context.Context, identifier resource.Identifier, patch resource.PatchRequest, options resource.PatchOptions, into resource.Object) error { - patched, err := f.Patch(ctx, identifier, patch, options) - if err != nil { - return err - } - // Copy the patched object data into the provided 'into' object - if plugin, ok := patched.(*pluginsv0alpha1.PluginInstall); ok { - if target, ok := into.(*pluginsv0alpha1.PluginInstall); ok { - *target = *plugin - } - } - return nil -} - -func (f *fakeResourceClient) Delete(ctx context.Context, identifier resource.Identifier, options resource.DeleteOptions) error { - return f.client.Delete(ctx, identifier, options) -} - -func (f *fakeResourceClient) SubresourceRequest(ctx context.Context, identifier resource.Identifier, req resource.CustomRouteRequestOptions) ([]byte, error) { - return []byte{}, nil -} - -func (f *fakeResourceClient) Watch(ctx context.Context, namespace string, options resource.WatchOptions) (resource.WatchResponse, error) { - return &fakeWatchResponse{}, nil -} - -type fakeWatchResponse struct{} - -func (f *fakeWatchResponse) Stop() {} - -func (f *fakeWatchResponse) WatchEvents() <-chan resource.WatchEvent { - ch := make(chan resource.WatchEvent) - close(ch) - return ch -} - func TestSyncer_Sync(t *testing.T) { tests := []struct { - name string - featureToggleEnabled bool - orgs []*org.OrgDTO - orgServiceError error - serverLockError error - expectedError error - expectSyncCalls int + name string + pluginInstallAPISyncEnabled bool + pluginStoreServiceEnabled bool + installedPlugins []*plugins.Plugin + orgs []*org.OrgDTO + orgServiceError error + serverLockError error + expectedError error + expectSyncCalls int }{ { - name: "feature toggle disabled", - featureToggleEnabled: false, - orgs: []*org.OrgDTO{{ID: 1, Name: "Org 1"}}, - expectedError: nil, - expectSyncCalls: 0, + name: "plugin install API sync feature toggle disabled", + pluginInstallAPISyncEnabled: false, + pluginStoreServiceEnabled: true, + installedPlugins: []*plugins.Plugin{{JSONData: plugins.JSONData{ID: "test-plugin", Info: plugins.Info{Version: "1.0.0"}}, Class: plugins.ClassCore}}, + orgs: []*org.OrgDTO{{ID: 1, Name: "Org 1"}}, + expectedError: nil, + expectSyncCalls: 0, }, { - name: "feature toggle enabled, no orgs", - featureToggleEnabled: true, - orgs: []*org.OrgDTO{}, - expectedError: nil, - expectSyncCalls: 0, + name: "plugin store service feature toggle disabled", + pluginInstallAPISyncEnabled: true, + pluginStoreServiceEnabled: false, + installedPlugins: []*plugins.Plugin{{JSONData: plugins.JSONData{ID: "test-plugin", Info: plugins.Info{Version: "1.0.0"}}, Class: plugins.ClassCore}}, + orgs: []*org.OrgDTO{{ID: 1, Name: "Org 1"}}, + expectedError: nil, + expectSyncCalls: 0, }, { - name: "feature toggle enabled, single org", - featureToggleEnabled: true, - orgs: []*org.OrgDTO{{ID: 1, Name: "Org 1"}}, - expectedError: nil, - expectSyncCalls: 1, + name: "both feature toggles enabled, no orgs", + pluginInstallAPISyncEnabled: true, + pluginStoreServiceEnabled: true, + installedPlugins: []*plugins.Plugin{{JSONData: plugins.JSONData{ID: "test-plugin", Info: plugins.Info{Version: "1.0.0"}}, Class: plugins.ClassCore}}, + orgs: []*org.OrgDTO{}, + expectedError: nil, + expectSyncCalls: 0, }, { - name: "feature toggle enabled, multiple orgs", - featureToggleEnabled: true, + name: "both feature toggles enabled, empty installed plugins", + pluginInstallAPISyncEnabled: true, + pluginStoreServiceEnabled: true, + installedPlugins: []*plugins.Plugin{}, + orgs: []*org.OrgDTO{{ID: 1, Name: "Org 1"}}, + expectedError: nil, + expectSyncCalls: 0, + }, + { + name: "both feature toggles enabled, single org", + pluginInstallAPISyncEnabled: true, + pluginStoreServiceEnabled: true, + installedPlugins: []*plugins.Plugin{{JSONData: plugins.JSONData{ID: "test-plugin", Info: plugins.Info{Version: "1.0.0"}}, Class: plugins.ClassCore}}, + orgs: []*org.OrgDTO{{ID: 1, Name: "Org 1"}}, + expectedError: nil, + expectSyncCalls: 1, + }, + { + name: "both feature toggles enabled, multiple orgs", + pluginInstallAPISyncEnabled: true, + pluginStoreServiceEnabled: true, + installedPlugins: []*plugins.Plugin{{JSONData: plugins.JSONData{ID: "test-plugin", Info: plugins.Info{Version: "1.0.0"}}, Class: plugins.ClassCore}}, orgs: []*org.OrgDTO{ {ID: 1, Name: "Org 1"}, {ID: 2, Name: "Org 2"}, @@ -257,20 +91,24 @@ func TestSyncer_Sync(t *testing.T) { expectSyncCalls: 3, }, { - name: "org service error", - featureToggleEnabled: true, - orgs: nil, - orgServiceError: errors.New("org service error"), - expectedError: errors.New("org service error"), - expectSyncCalls: 0, + name: "org service error", + pluginInstallAPISyncEnabled: true, + pluginStoreServiceEnabled: true, + installedPlugins: []*plugins.Plugin{{JSONData: plugins.JSONData{ID: "test-plugin", Info: plugins.Info{Version: "1.0.0"}}, Class: plugins.ClassCore}}, + orgs: nil, + orgServiceError: errors.New("org service error"), + expectedError: errors.New("org service error"), + expectSyncCalls: 0, }, { - name: "server lock error", - featureToggleEnabled: true, - orgs: []*org.OrgDTO{{ID: 1, Name: "Org 1"}}, - serverLockError: errors.New("lock error"), - expectedError: errors.New("lock error"), - expectSyncCalls: 0, + name: "server lock error", + pluginInstallAPISyncEnabled: true, + pluginStoreServiceEnabled: true, + installedPlugins: []*plugins.Plugin{{JSONData: plugins.JSONData{ID: "test-plugin", Info: plugins.Info{Version: "1.0.0"}}, Class: plugins.ClassCore}}, + orgs: []*org.OrgDTO{{ID: 1, Name: "Org 1"}}, + serverLockError: errors.New("lock error"), + expectedError: errors.New("lock error"), + expectSyncCalls: 0, }, } @@ -280,7 +118,8 @@ func TestSyncer_Sync(t *testing.T) { // Setup feature toggles ft := featuremgmt.NewMockFeatureToggles(t) - ft.EXPECT().IsEnabled(ctx, featuremgmt.FlagPluginInstallAPISync).Return(tt.featureToggleEnabled).Maybe() + ft.EXPECT().IsEnabled(ctx, featuremgmt.FlagPluginInstallAPISync).Return(tt.pluginInstallAPISyncEnabled).Maybe() + ft.EXPECT().IsEnabled(ctx, featuremgmt.FlagPluginStoreServiceLoading).Return(tt.pluginStoreServiceEnabled).Maybe() // Setup org service orgService := orgtest.NewOrgServiceFake() @@ -298,12 +137,12 @@ func TestSyncer_Sync(t *testing.T) { // Setup fake client and registrar syncCalls := 0 fakeClient := &fakePluginInstallClient{ - createFunc: func(ctx context.Context, obj *pluginsv0alpha1.PluginInstall, opts resource.CreateOptions) (*pluginsv0alpha1.PluginInstall, error) { + createFunc: func(ctx context.Context, obj *pluginsv0alpha1.Plugin, opts resource.CreateOptions) (*pluginsv0alpha1.Plugin, error) { syncCalls++ return obj, nil }, - listAllFunc: func(ctx context.Context, namespace string, opts resource.ListOptions) (*pluginsv0alpha1.PluginInstallList, error) { - return &pluginsv0alpha1.PluginInstallList{}, nil + listAllFunc: func(ctx context.Context, namespace string, opts resource.ListOptions) (*pluginsv0alpha1.PluginList, error) { + return &pluginsv0alpha1.PluginList{}, nil }, } clientGen := &fakeClientGenerator{client: fakeClient} @@ -320,10 +159,7 @@ func TestSyncer_Sync(t *testing.T) { ) // Execute - installedPlugins := []*plugins.Plugin{ - {JSONData: plugins.JSONData{ID: "test-plugin", Info: plugins.Info{Version: "1.0.0"}}}, - } - err := s.Sync(ctx, install.SourcePluginStore, installedPlugins) + err := s.Sync(ctx, install.SourcePluginStore, tt.installedPlugins) // Verify if tt.expectedError != nil { @@ -342,7 +178,7 @@ func TestSyncer_syncNamespace(t *testing.T) { tests := []struct { name string installedPlugins []*plugins.Plugin - apiPlugins []pluginsv0alpha1.PluginInstall + apiPlugins []pluginsv0alpha1.Plugin clientListError error expectedError error expectedRegCalls int @@ -353,7 +189,7 @@ func TestSyncer_syncNamespace(t *testing.T) { { name: "no installed plugins, no API plugins", installedPlugins: []*plugins.Plugin{}, - apiPlugins: []pluginsv0alpha1.PluginInstall{}, + apiPlugins: []pluginsv0alpha1.Plugin{}, expectedError: nil, expectedRegCalls: 0, expectedUnregCalls: 0, @@ -364,7 +200,7 @@ func TestSyncer_syncNamespace(t *testing.T) { {JSONData: plugins.JSONData{ID: "plugin-1", Info: plugins.Info{Version: "1.0.0"}}, Class: plugins.ClassCore}, {JSONData: plugins.JSONData{ID: "plugin-2", Info: plugins.Info{Version: "2.0.0"}}, Class: plugins.ClassExternal}, }, - apiPlugins: []pluginsv0alpha1.PluginInstall{}, + apiPlugins: []pluginsv0alpha1.Plugin{}, expectedError: nil, expectedRegCalls: 2, expectedUnregCalls: 0, @@ -373,7 +209,7 @@ func TestSyncer_syncNamespace(t *testing.T) { { name: "API plugins only", installedPlugins: []*plugins.Plugin{}, - apiPlugins: []pluginsv0alpha1.PluginInstall{ + apiPlugins: []pluginsv0alpha1.Plugin{ { ObjectMeta: metav1.ObjectMeta{ Name: "plugin-1", @@ -381,7 +217,7 @@ func TestSyncer_syncNamespace(t *testing.T) { install.PluginInstallSourceAnnotation: install.SourcePluginStore, }, }, - Spec: pluginsv0alpha1.PluginInstallSpec{Id: "plugin-1"}, + Spec: pluginsv0alpha1.PluginSpec{Id: "plugin-1"}, }, { ObjectMeta: metav1.ObjectMeta{ @@ -390,7 +226,7 @@ func TestSyncer_syncNamespace(t *testing.T) { install.PluginInstallSourceAnnotation: install.SourcePluginStore, }, }, - Spec: pluginsv0alpha1.PluginInstallSpec{Id: "plugin-2"}, + Spec: pluginsv0alpha1.PluginSpec{Id: "plugin-2"}, }, }, expectedError: nil, @@ -405,7 +241,7 @@ func TestSyncer_syncNamespace(t *testing.T) { {JSONData: plugins.JSONData{ID: "plugin-2", Info: plugins.Info{Version: "2.0.0"}}, Class: plugins.ClassExternal}, {JSONData: plugins.JSONData{ID: "plugin-3", Info: plugins.Info{Version: "3.0.0"}}, Class: plugins.ClassExternal}, }, - apiPlugins: []pluginsv0alpha1.PluginInstall{ + apiPlugins: []pluginsv0alpha1.Plugin{ { ObjectMeta: metav1.ObjectMeta{ Name: "plugin-2", @@ -413,7 +249,7 @@ func TestSyncer_syncNamespace(t *testing.T) { install.PluginInstallSourceAnnotation: install.SourcePluginStore, }, }, - Spec: pluginsv0alpha1.PluginInstallSpec{Id: "plugin-2", Version: "2.0.0"}, + Spec: pluginsv0alpha1.PluginSpec{Id: "plugin-2", Version: "2.0.0"}, }, { ObjectMeta: metav1.ObjectMeta{ @@ -422,7 +258,7 @@ func TestSyncer_syncNamespace(t *testing.T) { install.PluginInstallSourceAnnotation: install.SourcePluginStore, }, }, - Spec: pluginsv0alpha1.PluginInstallSpec{Id: "plugin-4"}, + Spec: pluginsv0alpha1.PluginSpec{Id: "plugin-4"}, }, }, expectedError: nil, @@ -434,7 +270,7 @@ func TestSyncer_syncNamespace(t *testing.T) { { name: "list error", installedPlugins: []*plugins.Plugin{}, - apiPlugins: []pluginsv0alpha1.PluginInstall{}, + apiPlugins: []pluginsv0alpha1.Plugin{}, clientListError: errors.New("list error"), expectedError: errors.New("list error"), }, @@ -450,15 +286,15 @@ func TestSyncer_syncNamespace(t *testing.T) { // Setup fake client fakeClient := &fakePluginInstallClient{ - listAllFunc: func(ctx context.Context, namespace string, opts resource.ListOptions) (*pluginsv0alpha1.PluginInstallList, error) { + listAllFunc: func(ctx context.Context, namespace string, opts resource.ListOptions) (*pluginsv0alpha1.PluginList, error) { if tt.clientListError != nil { return nil, tt.clientListError } - return &pluginsv0alpha1.PluginInstallList{ + return &pluginsv0alpha1.PluginList{ Items: tt.apiPlugins, }, nil }, - createFunc: func(ctx context.Context, obj *pluginsv0alpha1.PluginInstall, opts resource.CreateOptions) (*pluginsv0alpha1.PluginInstall, error) { + createFunc: func(ctx context.Context, obj *pluginsv0alpha1.Plugin, opts resource.CreateOptions) (*pluginsv0alpha1.Plugin, error) { registeredIDs = append(registeredIDs, obj.Spec.Id) return obj, nil }, @@ -466,7 +302,7 @@ func TestSyncer_syncNamespace(t *testing.T) { unregisteredIDs = append(unregisteredIDs, identifier.Name) return nil }, - getFunc: func(ctx context.Context, identifier resource.Identifier) (*pluginsv0alpha1.PluginInstall, error) { + getFunc: func(ctx context.Context, identifier resource.Identifier) (*pluginsv0alpha1.Plugin, error) { // Check if plugin exists in apiPlugins for i := range tt.apiPlugins { if tt.apiPlugins[i].Name == identifier.Name { @@ -521,7 +357,7 @@ func TestSyncer_syncNamespace(t *testing.T) { } } -func TestSyncer_getClient(t *testing.T) { +func TestInstallRegistrar_GetClient(t *testing.T) { tests := []struct { name string }{ @@ -559,92 +395,196 @@ func TestSyncer_getClient(t *testing.T) { } } -func TestSyncer_syncAllNamespaces(t *testing.T) { - tests := []struct { - name string - orgs []*org.OrgDTO - orgServiceError error - expectedError error - expectedCalls int - }{ - { - name: "no orgs", - orgs: []*org.OrgDTO{}, - expectedError: nil, - expectedCalls: 0, - }, - { - name: "single org", - orgs: []*org.OrgDTO{ - {ID: 1, Name: "Org 1"}, - }, - expectedError: nil, - expectedCalls: 1, - }, - { - name: "multiple orgs", - orgs: []*org.OrgDTO{ - {ID: 1, Name: "Org 1"}, - {ID: 2, Name: "Org 2"}, - {ID: 3, Name: "Org 3"}, - }, - expectedError: nil, - expectedCalls: 3, - }, - { - name: "org service error", - orgs: nil, - orgServiceError: errors.New("org service error"), - expectedError: errors.New("org service error"), - expectedCalls: 0, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - ctx := context.Background() - - orgService := orgtest.NewOrgServiceFake() - orgService.ExpectedOrgs = tt.orgs - orgService.ExpectedError = tt.orgServiceError - - // Track namespace sync calls - syncCalls := 0 - fakeClient := &fakePluginInstallClient{ - createFunc: func(ctx context.Context, obj *pluginsv0alpha1.PluginInstall, opts resource.CreateOptions) (*pluginsv0alpha1.PluginInstall, error) { - syncCalls++ - return obj, nil - }, - listAllFunc: func(ctx context.Context, namespace string, opts resource.ListOptions) (*pluginsv0alpha1.PluginInstallList, error) { - return &pluginsv0alpha1.PluginInstallList{}, nil - }, - } - - clientGen := &fakeClientGenerator{client: fakeClient} - - s := newSyncer( - featuremgmt.NewMockFeatureToggles(t), - clientGen, - install.NewInstallRegistrar(clientGen), - orgService, - func(orgID int64) string { return "org-1" }, - &fakeServerLock{}, - ) - - installedPlugins := []*plugins.Plugin{ - {JSONData: plugins.JSONData{ID: "test-plugin", Info: plugins.Info{Version: "1.0.0"}}, Class: plugins.ClassCore}, - } - - err := s.syncAllNamespaces(ctx, install.SourcePluginStore, installedPlugins) - - if tt.expectedError != nil { - require.Error(t, err) - require.Equal(t, tt.expectedError.Error(), err.Error()) - } else { - require.NoError(t, err) - } - - require.Equal(t, tt.expectedCalls, syncCalls) - }) +// Test helpers to avoid import cycles +type fakeServerLock struct { + lockFunc func(ctx context.Context, actionName string, maxInterval time.Duration, fn func(ctx context.Context)) error +} + +func (f *fakeServerLock) LockExecuteAndRelease(ctx context.Context, actionName string, maxInterval time.Duration, fn func(ctx context.Context)) error { + if f.lockFunc != nil { + return f.lockFunc(ctx, actionName, maxInterval, fn) + } + fn(ctx) + return nil +} + +type fakePluginInstallClient struct { + listAllFunc func(ctx context.Context, namespace string, opts resource.ListOptions) (*pluginsv0alpha1.PluginList, error) + getFunc func(ctx context.Context, identifier resource.Identifier) (*pluginsv0alpha1.Plugin, error) + createFunc func(ctx context.Context, obj *pluginsv0alpha1.Plugin, opts resource.CreateOptions) (*pluginsv0alpha1.Plugin, error) + updateFunc func(ctx context.Context, obj *pluginsv0alpha1.Plugin, opts resource.UpdateOptions) (*pluginsv0alpha1.Plugin, error) + deleteFunc func(ctx context.Context, identifier resource.Identifier, opts resource.DeleteOptions) error +} + +func (f *fakePluginInstallClient) Get(ctx context.Context, identifier resource.Identifier) (*pluginsv0alpha1.Plugin, error) { + if f.getFunc != nil { + return f.getFunc(ctx, identifier) + } + // Return a proper k8s NotFound error + return nil, errorsK8s.NewNotFound(schema.GroupResource{ + Group: pluginsv0alpha1.APIGroup, + Resource: "plugininstalls", + }, identifier.Name) +} + +func (f *fakePluginInstallClient) ListAll(ctx context.Context, namespace string, opts resource.ListOptions) (*pluginsv0alpha1.PluginList, error) { + if f.listAllFunc != nil { + return f.listAllFunc(ctx, namespace, opts) + } + return &pluginsv0alpha1.PluginList{}, nil +} + +func (f *fakePluginInstallClient) List(ctx context.Context, namespace string, opts resource.ListOptions) (*pluginsv0alpha1.PluginList, error) { + return f.ListAll(ctx, namespace, opts) +} + +func (f *fakePluginInstallClient) Create(ctx context.Context, obj *pluginsv0alpha1.Plugin, opts resource.CreateOptions) (*pluginsv0alpha1.Plugin, error) { + if f.createFunc != nil { + return f.createFunc(ctx, obj, opts) + } + return obj, nil +} + +func (f *fakePluginInstallClient) Update(ctx context.Context, obj *pluginsv0alpha1.Plugin, opts resource.UpdateOptions) (*pluginsv0alpha1.Plugin, error) { + if f.updateFunc != nil { + return f.updateFunc(ctx, obj, opts) + } + return obj, nil +} + +func (f *fakePluginInstallClient) UpdateStatus(ctx context.Context, identifier resource.Identifier, newStatus pluginsv0alpha1.PluginStatus, opts resource.UpdateOptions) (*pluginsv0alpha1.Plugin, error) { + return nil, nil +} + +func (f *fakePluginInstallClient) Patch(ctx context.Context, identifier resource.Identifier, req resource.PatchRequest, opts resource.PatchOptions) (*pluginsv0alpha1.Plugin, error) { + return nil, nil +} + +func (f *fakePluginInstallClient) Delete(ctx context.Context, identifier resource.Identifier, opts resource.DeleteOptions) error { + if f.deleteFunc != nil { + return f.deleteFunc(ctx, identifier, opts) + } + return nil +} + +type fakeClientGenerator struct { + client *fakePluginInstallClient +} + +func (f *fakeClientGenerator) ClientFor(kind resource.Kind) (resource.Client, error) { + return &fakeResourceClient{client: f.client}, nil +} + +type fakeResourceClient struct { + client *fakePluginInstallClient +} + +func (f *fakeResourceClient) Get(ctx context.Context, identifier resource.Identifier) (resource.Object, error) { + return f.client.Get(ctx, identifier) +} + +func (f *fakeResourceClient) GetInto(ctx context.Context, identifier resource.Identifier, into resource.Object) error { + obj, err := f.client.Get(ctx, identifier) + if err != nil { + return err + } + // Copy the object data into the provided 'into' object + if target, ok := into.(*pluginsv0alpha1.Plugin); ok { + *target = *obj } + return nil +} + +func (f *fakeResourceClient) List(ctx context.Context, namespace string, options resource.ListOptions) (resource.ListObject, error) { + return f.client.ListAll(ctx, namespace, options) +} + +func (f *fakeResourceClient) ListInto(ctx context.Context, namespace string, options resource.ListOptions, into resource.ListObject) error { + list, err := f.client.ListAll(ctx, namespace, options) + if err != nil { + return err + } + // Copy the list data into the provided 'into' object + if target, ok := into.(*pluginsv0alpha1.PluginList); ok { + *target = *list + } + return nil +} + +func (f *fakeResourceClient) Create(ctx context.Context, identifier resource.Identifier, obj resource.Object, options resource.CreateOptions) (resource.Object, error) { + plugin := obj.(*pluginsv0alpha1.Plugin) + return f.client.Create(ctx, plugin, options) +} + +func (f *fakeResourceClient) CreateInto(ctx context.Context, identifier resource.Identifier, obj resource.Object, options resource.CreateOptions, into resource.Object) error { + created, err := f.Create(ctx, identifier, obj, options) + if err != nil { + return err + } + // Copy the created object data into the provided 'into' object + if plugin, ok := created.(*pluginsv0alpha1.Plugin); ok { + if target, ok := into.(*pluginsv0alpha1.Plugin); ok { + *target = *plugin + } + } + return nil +} + +func (f *fakeResourceClient) Update(ctx context.Context, identifier resource.Identifier, obj resource.Object, options resource.UpdateOptions) (resource.Object, error) { + plugin := obj.(*pluginsv0alpha1.Plugin) + return f.client.Update(ctx, plugin, options) +} + +func (f *fakeResourceClient) UpdateInto(ctx context.Context, identifier resource.Identifier, obj resource.Object, options resource.UpdateOptions, into resource.Object) error { + updated, err := f.Update(ctx, identifier, obj, options) + if err != nil { + return err + } + // Copy the updated object data into the provided 'into' object + if plugin, ok := updated.(*pluginsv0alpha1.Plugin); ok { + if target, ok := into.(*pluginsv0alpha1.Plugin); ok { + *target = *plugin + } + } + return nil +} + +func (f *fakeResourceClient) Patch(ctx context.Context, identifier resource.Identifier, patch resource.PatchRequest, options resource.PatchOptions) (resource.Object, error) { + return f.client.Patch(ctx, identifier, patch, options) +} + +func (f *fakeResourceClient) PatchInto(ctx context.Context, identifier resource.Identifier, patch resource.PatchRequest, options resource.PatchOptions, into resource.Object) error { + patched, err := f.Patch(ctx, identifier, patch, options) + if err != nil { + return err + } + // Copy the patched object data into the provided 'into' object + if plugin, ok := patched.(*pluginsv0alpha1.Plugin); ok { + if target, ok := into.(*pluginsv0alpha1.Plugin); ok { + *target = *plugin + } + } + return nil +} + +func (f *fakeResourceClient) Delete(ctx context.Context, identifier resource.Identifier, options resource.DeleteOptions) error { + return f.client.Delete(ctx, identifier, options) +} + +func (f *fakeResourceClient) SubresourceRequest(ctx context.Context, identifier resource.Identifier, req resource.CustomRouteRequestOptions) ([]byte, error) { + return []byte{}, nil +} + +func (f *fakeResourceClient) Watch(ctx context.Context, namespace string, options resource.WatchOptions) (resource.WatchResponse, error) { + return &fakeWatchResponse{}, nil +} + +type fakeWatchResponse struct{} + +func (f *fakeWatchResponse) Stop() {} + +func (f *fakeWatchResponse) WatchEvents() <-chan resource.WatchEvent { + ch := make(chan resource.WatchEvent) + close(ch) + return ch } diff --git a/pkg/tests/apis/plugins/discovery_test.go b/pkg/tests/apis/plugins/discovery_test.go index 545f2f3bf7d..168aa259dad 100644 --- a/pkg/tests/apis/plugins/discovery_test.go +++ b/pkg/tests/apis/plugins/discovery_test.go @@ -20,19 +20,30 @@ func TestIntegrationPluginsIntegrationDiscovery(t *testing.T) { "freshness": "Current", "resources": [ { - "resource": "plugininstalls", + "resource": "plugins", "responseKind": { "group": "", - "kind": "PluginInstall", + "kind": "Plugin", "version": "" }, "scope": "Namespaced", - "singularResource": "plugininstalls", + "singularResource": "plugins", "subresources": [ { "responseKind": { "group": "", - "kind": "PluginInstall", + "kind": "ResourceCallOptions", + "version": "" + }, + "subresource": "meta", + "verbs": [ + "get" + ] + }, + { + "responseKind": { + "group": "", + "kind": "Plugin", "version": "" }, "subresource": "status", @@ -53,35 +64,6 @@ func TestIntegrationPluginsIntegrationDiscovery(t *testing.T) { "update", "watch" ] - }, - { - "resource": "pluginmetas", - "responseKind": { - "group": "", - "kind": "PluginMeta", - "version": "" - }, - "scope": "Namespaced", - "singularResource": "pluginmeta", - "subresources": [ - { - "responseKind": { - "group": "", - "kind": "PluginMeta", - "version": "" - }, - "subresource": "status", - "verbs": [ - "get", - "patch", - "update" - ] - } - ], - "verbs": [ - "get", - "list" - ] } ] } diff --git a/pkg/tests/apis/plugins/plugininstalls_test.go b/pkg/tests/apis/plugins/plugininstalls_test.go index a9ceecfd7aa..d8c45713337 100644 --- a/pkg/tests/apis/plugins/plugininstalls_test.go +++ b/pkg/tests/apis/plugins/plugininstalls_test.go @@ -16,88 +16,54 @@ import ( "github.com/grafana/grafana/pkg/util/testutil" ) -var gvrPluginInstalls = schema.GroupVersionResource{ +var gvrPlugins = schema.GroupVersionResource{ Group: "plugins.grafana.app", Version: "v0alpha1", - Resource: "plugininstalls", + Resource: "plugins", } func TestMain(m *testing.M) { testsuite.Run(m) } -func TestIntegrationPluginInstalls(t *testing.T) { +func TestIntegrationPlugins(t *testing.T) { testutil.SkipIntegrationTestInShortMode(t) - t.Run("create plugin install", func(t *testing.T) { + t.Run("create plugin", func(t *testing.T) { helper := setupHelper(t) ctx := context.Background() client := helper.GetResourceClient(apis.ResourceClientArgs{ User: helper.Org1.Admin, - GVR: gvrPluginInstalls, + GVR: gvrPlugins, }) pluginName := "test-plugin-create" - pluginInstall := helper.LoadYAMLOrJSON(fmt.Sprintf(`{ + plugin := helper.LoadYAMLOrJSON(fmt.Sprintf(`{ "apiVersion": "plugins.grafana.app/v0alpha1", - "kind": "PluginInstall", + "kind": "Plugin", "metadata": {"name": "%s"}, "spec": {"version": "1.0.0"} }`, pluginName)) - created, err := client.Resource.Create(ctx, pluginInstall, metav1.CreateOptions{}) + created, err := client.Resource.Create(ctx, plugin, metav1.CreateOptions{}) require.NoError(t, err) require.NotNil(t, created) require.Equal(t, pluginName, created.GetName()) }) - t.Run("create plugin install with status is ignored", func(t *testing.T) { - t.Skip("status is not ignored on create. this might require a change in the SDK. skipping for now") - helper := setupHelper(t) - ctx := context.Background() - client := helper.GetResourceClient(apis.ResourceClientArgs{ - User: helper.Org1.Admin, - GVR: gvrPluginInstalls, - }) - pluginName := "test-plugin-create-with-status" - pluginInstall := helper.LoadYAMLOrJSON(fmt.Sprintf(`{ - "apiVersion": "plugins.grafana.app/v0alpha1", - "kind": "PluginInstall", - "metadata": {"name": "%s"}, - "spec": {"version": "1.0.0"}, - "status": { - "operatorStates": { - "test-operator": { - "lastEvaluation": "1", - "state": "success" - } - } - } - }`, pluginName)) - created, err := client.Resource.Create(ctx, pluginInstall, metav1.CreateOptions{}) - require.NoError(t, err) - require.NotNil(t, created) - require.Equal(t, pluginName, created.GetName()) - // Status should be empty as it's ignored on create - status, found, err := unstructured.NestedMap(created.Object, "status") - require.NoError(t, err) - require.True(t, found) // status field should exist - require.Empty(t, status) // but it should be empty - }) - t.Run("get plugin install", func(t *testing.T) { helper := setupHelper(t) ctx := context.Background() client := helper.GetResourceClient(apis.ResourceClientArgs{ User: helper.Org1.Admin, - GVR: gvrPluginInstalls, + GVR: gvrPlugins, }) pluginName := "test-plugin-get" - pluginInstall := helper.LoadYAMLOrJSON(fmt.Sprintf(`{ + plugin := helper.LoadYAMLOrJSON(fmt.Sprintf(`{ "apiVersion": "plugins.grafana.app/v0alpha1", - "kind": "PluginInstall", + "kind": "Plugin", "metadata": {"name": "%s"}, "spec": {"version": "1.0.0"} }`, pluginName)) - created, err := client.Resource.Create(ctx, pluginInstall, metav1.CreateOptions{}) + created, err := client.Resource.Create(ctx, plugin, metav1.CreateOptions{}) require.NoError(t, err) fetched, err := client.Resource.Get(ctx, pluginName, metav1.GetOptions{}) require.NoError(t, err) @@ -111,16 +77,16 @@ func TestIntegrationPluginInstalls(t *testing.T) { ctx := context.Background() client := helper.GetResourceClient(apis.ResourceClientArgs{ User: helper.Org1.Admin, - GVR: gvrPluginInstalls, + GVR: gvrPlugins, }) pluginName := "test-plugin-update" - pluginInstall := helper.LoadYAMLOrJSON(fmt.Sprintf(`{ + plugin := helper.LoadYAMLOrJSON(fmt.Sprintf(`{ "apiVersion": "plugins.grafana.app/v0alpha1", - "kind": "PluginInstall", + "kind": "Plugin", "metadata": {"name": "%s"}, "spec": {"version": "1.0.0"} }`, pluginName)) - created, err := client.Resource.Create(ctx, pluginInstall, metav1.CreateOptions{}) + created, err := client.Resource.Create(ctx, plugin, metav1.CreateOptions{}) require.NoError(t, err) updatedSpec := created.DeepCopy() updatedSpec.Object["spec"] = map[string]interface{}{ @@ -132,116 +98,21 @@ func TestIntegrationPluginInstalls(t *testing.T) { require.Equal(t, "2.0.0", updated.Object["spec"].(map[string]interface{})["version"]) }) - t.Run("update plugin install with status is ignored", func(t *testing.T) { - helper := setupHelper(t) - ctx := context.Background() - client := helper.GetResourceClient(apis.ResourceClientArgs{ - User: helper.Org1.Admin, - GVR: gvrPluginInstalls, - }) - pluginName := "test-plugin-update-with-status" - pluginInstall := helper.LoadYAMLOrJSON(fmt.Sprintf(`{ - "apiVersion": "plugins.grafana.app/v0alpha1", - "kind": "PluginInstall", - "metadata": {"name": "%s"}, - "spec": {"version": "1.0.0"} - }`, pluginName)) - created, err := client.Resource.Create(ctx, pluginInstall, metav1.CreateOptions{}) - require.NoError(t, err) - - // Try to update the status via a normal update - withStatus := created.DeepCopy() - withStatus.Object["status"] = map[string]interface{}{ - "operatorStates": map[string]interface{}{ - "test-operator": map[string]interface{}{ - "lastEvaluation": "1", - "state": "success", - }, - }, - } - updated, err := client.Resource.Update(ctx, withStatus, metav1.UpdateOptions{}) - require.NoError(t, err) - require.NotNil(t, updated) - - // The status should not have been updated - status, found, err := unstructured.NestedMap(updated.Object, "status") - require.NoError(t, err) - require.True(t, found) - require.Empty(t, status) - - // also check with get - fetched, err := client.Resource.Get(ctx, pluginName, metav1.GetOptions{}) - require.NoError(t, err) - require.NotNil(t, fetched) - status, found, err = unstructured.NestedMap(fetched.Object, "status") - require.NoError(t, err) - require.True(t, found) - require.Empty(t, status) - }) - - t.Run("update plugin install status", func(t *testing.T) { - helper := setupHelper(t) - ctx := context.Background() - client := helper.GetResourceClient(apis.ResourceClientArgs{ - User: helper.Org1.Admin, - GVR: gvrPluginInstalls, - }) - pluginName := "test-plugin-status" - pluginInstall := helper.LoadYAMLOrJSON(fmt.Sprintf(`{ - "apiVersion": "plugins.grafana.app/v0alpha1", - "kind": "PluginInstall", - "metadata": {"name": "%s"}, - "spec": {"version": "1.0.0"} - }`, pluginName)) - created, err := client.Resource.Create(ctx, pluginInstall, metav1.CreateOptions{}) - require.NoError(t, err) - - // Update the status - status := created.DeepCopy() - statusPayload := map[string]interface{}{ - "operatorStates": map[string]interface{}{ - "test-operator": map[string]interface{}{ - "lastEvaluation": "1", - "state": "success", - }, - }, - } - status.Object["status"] = statusPayload - updated, err := client.Resource.UpdateStatus(ctx, status, metav1.UpdateOptions{}) - require.NoError(t, err) - require.NotNil(t, updated) - - // Check the status on the returned object - actualStatus, found, err := unstructured.NestedMap(updated.Object, "status") - require.NoError(t, err) - require.True(t, found) - require.Equal(t, statusPayload, actualStatus) - - // Get the status to ensure it persisted - fetched, err := client.Resource.Get(ctx, pluginName, metav1.GetOptions{}) - require.NoError(t, err) - require.NotNil(t, fetched) - actualStatus, found, err = unstructured.NestedMap(fetched.Object, "status") - require.NoError(t, err) - require.True(t, found) - require.Equal(t, statusPayload, actualStatus) - }) - t.Run("list plugin installs", func(t *testing.T) { helper := setupHelper(t) ctx := context.Background() client := helper.GetResourceClient(apis.ResourceClientArgs{ User: helper.Org1.Admin, - GVR: gvrPluginInstalls, + GVR: gvrPlugins, }) pluginName := "test-plugin-list" - pluginInstall := helper.LoadYAMLOrJSON(fmt.Sprintf(`{ + plugin := helper.LoadYAMLOrJSON(fmt.Sprintf(`{ "apiVersion": "plugins.grafana.app/v0alpha1", - "kind": "PluginInstall", + "kind": "Plugin", "metadata": {"name": "%s"}, "spec": {"version": "1.0.0"} }`, pluginName)) - created, err := client.Resource.Create(ctx, pluginInstall, metav1.CreateOptions{}) + created, err := client.Resource.Create(ctx, plugin, metav1.CreateOptions{}) require.NoError(t, err) list, err := client.Resource.List(ctx, metav1.ListOptions{}) require.NoError(t, err) @@ -254,16 +125,16 @@ func TestIntegrationPluginInstalls(t *testing.T) { ctx := context.Background() client := helper.GetResourceClient(apis.ResourceClientArgs{ User: helper.Org1.Admin, - GVR: gvrPluginInstalls, + GVR: gvrPlugins, }) pluginName := "test-plugin-delete" - pluginInstall := helper.LoadYAMLOrJSON(fmt.Sprintf(`{ + plugin := helper.LoadYAMLOrJSON(fmt.Sprintf(`{ "apiVersion": "plugins.grafana.app/v0alpha1", - "kind": "PluginInstall", + "kind": "Plugin", "metadata": {"name": "%s"}, "spec": {"version": "1.0.0"} }`, pluginName)) - _, err := client.Resource.Create(ctx, pluginInstall, metav1.CreateOptions{}) + _, err := client.Resource.Create(ctx, plugin, metav1.CreateOptions{}) require.NoError(t, err) err = client.Resource.Delete(ctx, pluginName, metav1.DeleteOptions{}) require.NoError(t, err) @@ -281,15 +152,15 @@ func TestIntegrationPluginInstalls(t *testing.T) { t.Run(fmt.Sprintf("with basic role: %s", user.Identity.GetOrgRole()), func(t *testing.T) { client := helper.GetResourceClient(apis.ResourceClientArgs{ User: user, - GVR: gvrPluginInstalls, + GVR: gvrPlugins, }) - pluginInstall := helper.LoadYAMLOrJSON(`{ + plugin := helper.LoadYAMLOrJSON(`{ "apiVersion": "plugins.grafana.app/v0alpha1", - "kind": "PluginInstall", + "kind": "Plugin", "metadata": {"name": "test-plugin"}, "spec": {"version": "1.0.0"} }`) - _, err := client.Resource.Create(context.Background(), pluginInstall, metav1.CreateOptions{}) + _, err := client.Resource.Create(context.Background(), plugin, metav1.CreateOptions{}) statusError := helper.AsStatusError(err) require.Equal(t, metav1.StatusReasonForbidden, statusError.Status().Reason) err = client.Resource.Delete(context.Background(), "test-plugin", metav1.DeleteOptions{}) diff --git a/pkg/tests/apis/plugins/pluginsmeta_test.go b/pkg/tests/apis/plugins/pluginsmeta_test.go deleted file mode 100644 index 742dca3effc..00000000000 --- a/pkg/tests/apis/plugins/pluginsmeta_test.go +++ /dev/null @@ -1,47 +0,0 @@ -package plugins - -import ( - "context" - "testing" - - "github.com/stretchr/testify/require" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime/schema" - - "github.com/grafana/grafana/pkg/tests/apis" - "github.com/grafana/grafana/pkg/util/testutil" -) - -var gvrPluginMeta = schema.GroupVersionResource{ - Group: "plugins.grafana.app", - Version: "v0alpha1", - Resource: "pluginmetas", -} - -func TestIntegrationPluginMeta(t *testing.T) { - testutil.SkipIntegrationTestInShortMode(t) - - t.Run("list plugin metas", func(t *testing.T) { - helper := setupHelper(t) - ctx := context.Background() - client := helper.GetResourceClient(apis.ResourceClientArgs{ - User: helper.Org1.Admin, - GVR: gvrPluginMeta, - }) - list, err := client.Resource.List(ctx, metav1.ListOptions{}) - require.NoError(t, err) - require.NotNil(t, list) - require.Empty(t, list.Items) - }) - - t.Run("get plugin meta", func(t *testing.T) { - helper := setupHelper(t) - ctx := context.Background() - client := helper.GetResourceClient(apis.ResourceClientArgs{ - User: helper.Org1.Admin, - GVR: gvrPluginMeta, - }) - _, err := client.Resource.Get(ctx, "example", metav1.GetOptions{}) - require.Error(t, err) - }) -} From 30bd4e7dba1567c41cf15834b5bd336953688d3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ida=20=C5=A0tambuk?= Date: Wed, 29 Oct 2025 18:47:33 +0100 Subject: [PATCH 104/378] CloudWatch Logs: Support Log Anomalies query type (#113067) --- .../x/CloudWatchDataQuery_types.gen.ts | 36 +++ pkg/tsdb/cloudwatch/cloudwatch.go | 19 +- .../kinds/dataquery/types_dataquery_gen.go | 45 ++- pkg/tsdb/cloudwatch/log_anomalies_query.go | 146 +++++++++ .../cloudwatch/log_anomalies_query_test.go | 212 +++++++++++++ pkg/tsdb/cloudwatch/log_sync_query_test.go | 2 +- pkg/tsdb/cloudwatch/mocks/logs.go | 6 + pkg/tsdb/cloudwatch/models/api.go | 1 + pkg/tsdb/cloudwatch/test_utils.go | 16 + .../LogsAnomaliesQueryEditor.tsx | 41 +++ .../LogsQueryEditor/LogsQueryEditor.tsx | 61 +++- .../datasource/cloudwatch/dataquery.cue | 22 +- .../datasource/cloudwatch/dataquery.gen.ts | 36 +++ .../datasource/cloudwatch/datasource.test.ts | 4 +- .../datasource/cloudwatch/datasource.ts | 17 +- .../plugins/datasource/cloudwatch/guards.ts | 18 +- .../CloudWatchLogsQueryRunner.test.ts | 300 +++++++++++++++++- .../query-runner/CloudWatchLogsQueryRunner.ts | 132 +++++++- .../plugins/datasource/cloudwatch/types.ts | 1 + 19 files changed, 1080 insertions(+), 35 deletions(-) create mode 100644 pkg/tsdb/cloudwatch/log_anomalies_query.go create mode 100644 pkg/tsdb/cloudwatch/log_anomalies_query_test.go create mode 100644 public/app/plugins/datasource/cloudwatch/components/QueryEditor/LogsQueryEditor/LogsAnomaliesQueryEditor.tsx diff --git a/packages/grafana-schema/src/raw/composable/cloudwatch/dataquery/x/CloudWatchDataQuery_types.gen.ts b/packages/grafana-schema/src/raw/composable/cloudwatch/dataquery/x/CloudWatchDataQuery_types.gen.ts index 2334d1d1efd..61cb1e34254 100644 --- a/packages/grafana-schema/src/raw/composable/cloudwatch/dataquery/x/CloudWatchDataQuery_types.gen.ts +++ b/packages/grafana-schema/src/raw/composable/cloudwatch/dataquery/x/CloudWatchDataQuery_types.gen.ts @@ -218,6 +218,11 @@ export interface QueryEditorArrayExpression { export type QueryEditorExpression = (QueryEditorArrayExpression | QueryEditorPropertyExpression | QueryEditorGroupByExpression | QueryEditorFunctionExpression | QueryEditorFunctionParameterExpression | QueryEditorOperatorExpression); +export enum LogsMode { + Anomalies = 'Anomalies', + Insights = 'Insights', +} + export enum LogsQueryLanguage { CWLI = 'CWLI', PPL = 'PPL', @@ -241,6 +246,10 @@ export interface CloudWatchLogsQuery extends common.DataQuery { * Log groups to query */ logGroups?: Array; + /** + * Whether a query is a Logs Insights or Logs Anomalies query + */ + logsMode?: LogsMode; /** * Language used for querying logs, can be CWLI, SQL, or PPL. If empty, the default language is CWLI. */ @@ -265,6 +274,33 @@ export const defaultCloudWatchLogsQuery: Partial = { statsGroups: [], }; +/** + * Shape of a Cloudwatch Logs Anomalies query + */ +export interface CloudWatchLogsAnomaliesQuery extends common.DataQuery { + /** + * Used to filter only the anomalies found by a certain anomaly detector + */ + anomalyDetectionARN?: string; + id: string; + /** + * Whether a query is a Logs Insights or Logs Anomalies query + */ + logsMode?: LogsMode; + /** + * Whether a query is a Metrics, Logs or Annotations query + */ + queryMode?: CloudWatchQueryMode; + /** + * AWS region to query for the logs + */ + region: string; + /** + * Filter to return only anomalies that are 'SUPPRESSED', 'UNSUPPRESSED', or 'ALL' (default) + */ + suppressionState?: string; +} + export interface LogGroup { /** * AccountId of the log group diff --git a/pkg/tsdb/cloudwatch/cloudwatch.go b/pkg/tsdb/cloudwatch/cloudwatch.go index 1015393477b..3ebe95515c0 100644 --- a/pkg/tsdb/cloudwatch/cloudwatch.go +++ b/pkg/tsdb/cloudwatch/cloudwatch.go @@ -36,7 +36,7 @@ const ( headerFromAlert = "FromAlert" defaultRegion = "default" - logsQueryMode = "Logs" + queryModeLogs = "Logs" // QueryTypes annotationQuery = "annotationQuery" logAction = "logAction" @@ -45,7 +45,8 @@ const ( type DataQueryJson struct { dataquery.CloudWatchAnnotationQuery - Type string `json:"type,omitempty"` + Type string `json:"type,omitempty"` + LogsMode dataquery.LogsMode `json:"logsMode,omitempty"` } type DataSource struct { @@ -147,12 +148,22 @@ func (ds *DataSource) QueryData(ctx context.Context, req *backend.QueryDataReque if model.QueryMode != "" { queryMode = string(model.QueryMode) } - fromPublicDashboard := model.Type == "" && queryMode == logsQueryMode - isSyncLogQuery := ((fromAlert || fromExpression) && queryMode == logsQueryMode) || fromPublicDashboard + + fromPublicDashboard := model.Type == "" + + isLogInsightsQuery := queryMode == queryModeLogs && (model.LogsMode == "" || model.LogsMode == dataquery.LogsModeInsights) + + isSyncLogQuery := isLogInsightsQuery && ((fromAlert || fromExpression) || fromPublicDashboard) + if isSyncLogQuery { return executeSyncLogQuery(ctx, ds, req) } + isLogsAnomaliesQuery := model.QueryMode == dataquery.CloudWatchQueryModeLogs && model.LogsMode == dataquery.LogsModeAnomalies + if isLogsAnomaliesQuery { + return executeLogAnomaliesQuery(ctx, ds, req) + } + var result *backend.QueryDataResponse switch model.Type { case annotationQuery: diff --git a/pkg/tsdb/cloudwatch/kinds/dataquery/types_dataquery_gen.go b/pkg/tsdb/cloudwatch/kinds/dataquery/types_dataquery_gen.go index 76c706094a6..ce8bc54c6c5 100644 --- a/pkg/tsdb/cloudwatch/kinds/dataquery/types_dataquery_gen.go +++ b/pkg/tsdb/cloudwatch/kinds/dataquery/types_dataquery_gen.go @@ -285,6 +285,13 @@ func NewQueryEditorOperatorValueType() *QueryEditorOperatorValueType { return NewStringOrBoolOrInt64OrArrayOfQueryEditorOperatorType() } +type LogsMode string + +const ( + LogsModeInsights LogsMode = "Insights" + LogsModeAnomalies LogsMode = "Anomalies" +) + type LogsQueryLanguage string const ( @@ -297,7 +304,9 @@ const ( type CloudWatchLogsQuery struct { // Whether a query is a Metrics, Logs, or Annotations query QueryMode CloudWatchQueryMode `json:"queryMode"` - Id string `json:"id"` + // Whether a query is a Logs Insights or Logs Anomalies query + LogsMode *LogsMode `json:"logsMode,omitempty"` + Id string `json:"id"` // AWS region to query for the logs Region string `json:"region"` // The CloudWatch Logs Insights query to execute @@ -347,6 +356,40 @@ func NewLogGroup() *LogGroup { return &LogGroup{} } +// Shape of a Cloudwatch Logs Anomalies query +type CloudWatchLogsAnomaliesQuery struct { + Id string `json:"id"` + // AWS region to query for the logs + Region string `json:"region"` + // Whether a query is a Metrics, Logs or Annotations query + QueryMode *CloudWatchQueryMode `json:"queryMode,omitempty"` + // Whether a query is a Logs Insights or Logs Anomalies query + LogsMode *LogsMode `json:"logsMode,omitempty"` + // Filter to return only anomalies that are 'SUPPRESSED', 'UNSUPPRESSED', or 'ALL' (default) + SuppressionState *string `json:"suppressionState,omitempty"` + // A unique identifier for the query within the list of targets. + // In server side expressions, the refId is used as a variable name to identify results. + // By default, the UI will assign A->Z; however setting meaningful names may be useful. + RefId string `json:"refId"` + // If hide is set to true, Grafana will filter out the response(s) associated with this query before returning it to the panel. + Hide *bool `json:"hide,omitempty"` + // Specify the query flavor + // TODO make this required and give it a default + QueryType *string `json:"queryType,omitempty"` + // Used to filter only the anomalies found by a certain anomaly detector + AnomalyDetectionARN *string `json:"anomalyDetectionARN,omitempty"` + // For mixed data sources the selected datasource is on the query level. + // For non mixed scenarios this is undefined. + // TODO find a better way to do this ^ that's friendly to schema + // TODO this shouldn't be unknown but DataSourceRef | null + Datasource any `json:"datasource,omitempty"` +} + +// NewCloudWatchLogsAnomaliesQuery creates a new CloudWatchLogsAnomaliesQuery object. +func NewCloudWatchLogsAnomaliesQuery() *CloudWatchLogsAnomaliesQuery { + return &CloudWatchLogsAnomaliesQuery{} +} + // Shape of a CloudWatch Annotation query // TS type is CloudWatchDefaultQuery = Omit & CloudWatchMetricsQuery, declared in veneer // #CloudWatchDefaultQuery: #CloudWatchLogsQuery & #CloudWatchMetricsQuery @cuetsy(kind="type") diff --git a/pkg/tsdb/cloudwatch/log_anomalies_query.go b/pkg/tsdb/cloudwatch/log_anomalies_query.go new file mode 100644 index 00000000000..f39b92eeffa --- /dev/null +++ b/pkg/tsdb/cloudwatch/log_anomalies_query.go @@ -0,0 +1,146 @@ +package cloudwatch + +import ( + "context" + "encoding/json" + "fmt" + "strings" + "time" + + "github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs" + + cloudwatchLogsTypes "github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs/types" + "github.com/grafana/grafana-plugin-sdk-go/backend" + "github.com/grafana/grafana-plugin-sdk-go/data" + "github.com/grafana/grafana/pkg/tsdb/cloudwatch/kinds/dataquery" +) + +var executeLogAnomaliesQuery = func(ctx context.Context, ds *DataSource, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) { + resp := backend.NewQueryDataResponse() + + for _, q := range req.Queries { + var anomaliesQuery dataquery.CloudWatchLogsAnomaliesQuery + err := json.Unmarshal(q.JSON, &anomaliesQuery) + if err != nil { + continue + } + + region := anomaliesQuery.Region + if region == "" || region == defaultRegion { + anomaliesQuery.Region = ds.Settings.Region + } + + logsClient, err := ds.getCWLogsClient(ctx, region) + if err != nil { + return nil, err + } + + listAnomaliesInput := &cloudwatchlogs.ListAnomaliesInput{} + if anomaliesQuery.SuppressionState != nil { + listAnomaliesInput.SuppressionState = getSuppressionState(*anomaliesQuery.SuppressionState) + } + + if anomaliesQuery.AnomalyDetectionARN == nil || *anomaliesQuery.AnomalyDetectionARN != "" { + listAnomaliesInput.AnomalyDetectorArn = anomaliesQuery.AnomalyDetectionARN + } + + response, err := logsClient.ListAnomalies(ctx, listAnomaliesInput) + + if err != nil { + result := backend.NewQueryDataResponse() + result.Responses[q.RefID] = backend.ErrorResponseWithErrorSource(backend.DownstreamError(fmt.Errorf("%v: %w", "failed to call cloudwatch:ListAnomalies", err))) + return result, nil + } + + dataframe, err := logsAnomaliesResultsToDataframes(response) + if err != nil { + return nil, err + } + + respD := resp.Responses[q.RefID] + respD.Frames = data.Frames{dataframe} + resp.Responses[q.RefID] = respD + } + + return resp, nil + +} + +func logsAnomaliesResultsToDataframes(response *cloudwatchlogs.ListAnomaliesOutput) (*data.Frame, error) { + frame := data.NewFrame("Log anomalies") + + if len(response.Anomalies) == 0 { + return frame, nil + } + + n := len(response.Anomalies) + anomalyArns := make([]string, n) + descriptions := make([]string, n) + suppressedStatus := make([]bool, n) + + priorities := make([]string, n) + patterns := make([]string, n) + statuses := make([]string, n) + logGroupArnLists := make([]string, n) + firstSeens := make([]time.Time, n) + lastSeens := make([]time.Time, n) + logTrends := make([]*json.RawMessage, n) + + for i, anomaly := range response.Anomalies { + anomalyArns[i] = *anomaly.AnomalyDetectorArn + descriptions[i] = *anomaly.Description + suppressedStatus[i] = *anomaly.Suppressed + priorities[i] = *anomaly.Priority + if anomaly.PatternString != nil { + patterns[i] = *anomaly.PatternString + } + statuses[i] = string(anomaly.State) + logGroupArnLists[i] = strings.Join(anomaly.LogGroupArnList, ",") + + firstSeens[i] = time.UnixMilli(anomaly.FirstSeen) + + lastSeens[i] = time.UnixMilli(anomaly.LastSeen) + + // data.Frame returned from the backend cannot contain fields of type data.Frames + // so histogram is kept as json.RawMessageto be built as sparkline table cell on the FE + histogramField := anomaly.Histogram + histogramJSON, err := json.Marshal(histogramField) + if err != nil { + logTrends[i] = nil + } else { + rawMsg := json.RawMessage(histogramJSON) + logTrends[i] = &rawMsg + } + } + + newFields := make([]*data.Field, 0, len(response.Anomalies)) + + newFields = append(newFields, data.NewField("state", nil, statuses).SetConfig(&data.FieldConfig{DisplayName: "State"})) + newFields = append(newFields, data.NewField("description", nil, descriptions).SetConfig(&data.FieldConfig{DisplayName: "Anomaly"})) + newFields = append(newFields, data.NewField("priority", nil, priorities).SetConfig(&data.FieldConfig{DisplayName: "Priority"})) + newFields = append(newFields, data.NewField("patternString", nil, patterns).SetConfig(&data.FieldConfig{DisplayName: "Log Pattern"})) + // FE expects the field name to be logTrend in order to identify histogram field for sparkline rendering + newFields = append(newFields, data.NewField("logTrend", nil, logTrends).SetConfig(&data.FieldConfig{DisplayName: "Log Trend"})) + newFields = append(newFields, data.NewField("firstSeen", nil, firstSeens).SetConfig(&data.FieldConfig{DisplayName: "First seen"})) + newFields = append(newFields, data.NewField("lastSeen", nil, lastSeens).SetConfig(&data.FieldConfig{DisplayName: "Last seen"})) + newFields = append(newFields, data.NewField("suppressed", nil, suppressedStatus).SetConfig(&data.FieldConfig{DisplayName: "Suppressed?"})) + newFields = append(newFields, data.NewField("logGroupArnList", nil, logGroupArnLists).SetConfig(&data.FieldConfig{DisplayName: "Log Groups"})) + newFields = append(newFields, data.NewField("anomalyArn", nil, anomalyArns).SetConfig(&data.FieldConfig{DisplayName: "Anomaly Arn"})) + + frame.Fields = newFields + setPreferredVisType(frame, data.VisTypeTable) + return frame, nil +} + +func getSuppressionState(suppressionState string) cloudwatchLogsTypes.SuppressionState { + switch suppressionState { + case "suppressed": + return cloudwatchLogsTypes.SuppressionStateSuppressed + case "unsuppressed": + return cloudwatchLogsTypes.SuppressionStateUnsuppressed + case "all": + return "" + default: + return "" + } +} diff --git a/pkg/tsdb/cloudwatch/log_anomalies_query_test.go b/pkg/tsdb/cloudwatch/log_anomalies_query_test.go new file mode 100644 index 00000000000..d9b3b85314d --- /dev/null +++ b/pkg/tsdb/cloudwatch/log_anomalies_query_test.go @@ -0,0 +1,212 @@ +package cloudwatch + +import ( + "context" + "encoding/json" + "testing" + "time" + + "github.com/aws/aws-sdk-go-v2/aws" + cloudwatchLogsTypes "github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs/types" + + "github.com/grafana/grafana-plugin-sdk-go/backend" + "github.com/grafana/grafana/pkg/tsdb/cloudwatch/models" + "github.com/stretchr/testify/assert" +) + +func Test_executeLogAnomaliesQuery(t *testing.T) { + origNewCWClient := NewCWClient + t.Cleanup(func() { + NewCWClient = origNewCWClient + }) + + var cli fakeCWLogsClient + NewCWLogsClient = func(aws.Config) models.CWLogsClient { + return &cli + } + + t.Run("getCWLogsClient is called with correct suppression state", func(t *testing.T) { + testcases := []struct { + name string + suppressionStateInQuery string + result cloudwatchLogsTypes.SuppressionState + }{ + { + "suppressed state", + "suppressed", + cloudwatchLogsTypes.SuppressionStateSuppressed, + }, + { + "unsuppressed state", + "unsuppressed", + cloudwatchLogsTypes.SuppressionStateUnsuppressed, + }, + { + "empty state", + "", + "", + }, + { + "all state", + "all", + "", + }, + } + + for _, tc := range testcases { + t.Run(tc.name, func(t *testing.T) { + cli = fakeCWLogsClient{anomalies: []cloudwatchLogsTypes.Anomaly{}} + ds := newTestDatasource() + + _, err := ds.QueryData(context.Background(), &backend.QueryDataRequest{ + Headers: map[string]string{headerFromAlert: ""}, + PluginContext: backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}}, + Queries: []backend.DataQuery{ + { + TimeRange: backend.TimeRange{From: time.Unix(0, 0), To: time.Unix(1, 0)}, + JSON: json.RawMessage(`{ + "queryMode": "Logs", + "logsMode": "Anomalies", + "suppressionState": "` + tc.suppressionStateInQuery + `", + "region": "us-east-1" + }`), + }, + }, + }) + assert.NoError(t, err) + assert.Equal(t, tc.result, cli.calls.listAnomalies[0].SuppressionState) + }) + } + }) +} + +func Test_executeLogAnomaliesQuery_returns_data_frames(t *testing.T) { + origNewCWClient := NewCWClient + t.Cleanup(func() { + NewCWClient = origNewCWClient + }) + + var cli fakeCWLogsClient + NewCWLogsClient = func(aws.Config) models.CWLogsClient { + return &cli + } + t.Run("returns log anomalies data frames", func(t *testing.T) { + cli = fakeCWLogsClient{anomalies: []cloudwatchLogsTypes.Anomaly{ + { + AnomalyId: aws.String("anomaly-1"), + AnomalyDetectorArn: aws.String("arn:aws:logs:us-east-1:123456789012:anomaly-detector:anomaly-detector-1"), + FirstSeen: 1622505600000, // June 1, 2021 00:00:00 GMT + LastSeen: 1622592000000, // June 2, 2021 00:00:00 GMT + LogGroupArnList: []string{"arn:aws:logs:us-east-1:1234567:log-group-1:id-1", "arn:aws:logs:us-east-1:1234567:log-group-2:id-2"}, + Description: aws.String("Description 1"), + State: cloudwatchLogsTypes.StateActive, + Priority: aws.String("high"), + PatternString: aws.String(`{"ClusterName":"PetSite","Namespace":"default","Service":"service-petsite",,"instance":"instance"-5:Token-6,"job":"kubernetes-service-endpoints","pod_name":"pod_name"-9,"prom_metric_type":"counter"}`), + Suppressed: aws.Bool(false), + Histogram: map[string]int64{ + "1622505600000": 5, + "1622519200000": 10, + "1622532800000": 7, + }, + }, + { + AnomalyId: aws.String("anomaly-2"), + AnomalyDetectorArn: aws.String("arn:aws:logs:us-east-1:123456789012:anomaly-detector:anomaly-detector-2"), + FirstSeen: 1622592000000, // June 2, 2021 00:00:00 GMT + LastSeen: 1622678400000, // June 3, 2021 00:00:00 GMT + LogGroupArnList: []string{"arn:aws:logs:us-east-1:1234567:log-group-1:id-3", "arn:aws:logs:us-east-1:1234567:log-group-2:id-4"}, + Description: aws.String("Description 2"), + State: cloudwatchLogsTypes.StateSuppressed, + Priority: aws.String("low"), + PatternString: aws.String(`{"ClusterName":"PetSite","Namespace":"default","Service":"service-petsite","dotnet_collection_count_total":"dotnet_collection_count_total"-3}`), + Suppressed: aws.Bool(true), + Histogram: map[string]int64{ + "1622592000000": 3, + }, + }, + }} + + ds := newTestDatasource() + + resp, err := ds.QueryData(context.Background(), &backend.QueryDataRequest{ + Headers: map[string]string{headerFromAlert: ""}, + PluginContext: backend.PluginContext{DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{}}, + Queries: []backend.DataQuery{ + { + TimeRange: backend.TimeRange{From: time.Unix(0, 0), To: time.Unix(1, 0)}, + JSON: json.RawMessage(`{ + "queryMode": "Logs", + "logsMode": "Anomalies", + "suppressionState": "all", + "region": "us-east-1" + }`), + }, + }, + }) + + assert.NoError(t, err) + assert.Len(t, resp.Responses, 1) + for _, r := range resp.Responses { + assert.Len(t, r.Frames, 1) + frame := r.Frames[0] + assert.Equal(t, "Log anomalies", frame.Name) + assert.Len(t, frame.Fields, 10) + + stateField := frame.Fields[0] + assert.Equal(t, "state", stateField.Name) + assert.Equal(t, "Active", stateField.At(0)) + assert.Equal(t, "Suppressed", stateField.At(1)) + + descriptionField := frame.Fields[1] + assert.Equal(t, "description", descriptionField.Name) + assert.Equal(t, "Description 1", descriptionField.At(0)) + assert.Equal(t, "Description 2", descriptionField.At(1)) + + priorityField := frame.Fields[2] + assert.Equal(t, "priority", priorityField.Name) + assert.Equal(t, "high", priorityField.At(0)) + assert.Equal(t, "low", priorityField.At(1)) + + patternStringField := frame.Fields[3] + assert.Equal(t, "patternString", patternStringField.Name) + assert.Equal(t, `{"ClusterName":"PetSite","Namespace":"default","Service":"service-petsite",,"instance":"instance"-5:Token-6,"job":"kubernetes-service-endpoints","pod_name":"pod_name"-9,"prom_metric_type":"counter"}`, patternStringField.At(0)) + assert.Equal(t, `{"ClusterName":"PetSite","Namespace":"default","Service":"service-petsite","dotnet_collection_count_total":"dotnet_collection_count_total"-3}`, patternStringField.At(1)) + + histogramField := frame.Fields[4] + assert.Equal(t, "logTrend", histogramField.Name) + + histogram0 := histogramField.At(0).(*json.RawMessage) + var histData0 map[string]int64 + err = json.Unmarshal(*histogram0, &histData0) + assert.NoError(t, err) + assert.Equal(t, int64(5), histData0["1622505600000"]) + assert.Equal(t, int64(10), histData0["1622519200000"]) + assert.Equal(t, int64(7), histData0["1622532800000"]) + + firstSeenField := frame.Fields[5] + assert.Equal(t, "firstSeen", firstSeenField.Name) + assert.Equal(t, time.Unix(1622505600, 0), firstSeenField.At(0)) + assert.Equal(t, time.Unix(1622592000, 0), firstSeenField.At(1)) + + lastSeenField := frame.Fields[6] + assert.Equal(t, "lastSeen", lastSeenField.Name) + assert.Equal(t, time.Unix(1622592000, 0), lastSeenField.At(0)) + assert.Equal(t, time.Unix(1622678400, 0), lastSeenField.At(1)) + + suppressedField := frame.Fields[7] + assert.Equal(t, "suppressed", suppressedField.Name) + assert.Equal(t, false, suppressedField.At(0)) + assert.Equal(t, true, suppressedField.At(1)) + + logGroupArnListField := frame.Fields[8] + assert.Equal(t, "logGroupArnList", logGroupArnListField.Name) + assert.Equal(t, "arn:aws:logs:us-east-1:1234567:log-group-1:id-1,arn:aws:logs:us-east-1:1234567:log-group-2:id-2", logGroupArnListField.At(0)) + assert.Equal(t, "arn:aws:logs:us-east-1:1234567:log-group-1:id-3,arn:aws:logs:us-east-1:1234567:log-group-2:id-4", logGroupArnListField.At(1)) + + anomalyDetectorArnField := frame.Fields[9] + assert.Equal(t, "anomalyArn", anomalyDetectorArnField.Name) + assert.Equal(t, "arn:aws:logs:us-east-1:123456789012:anomaly-detector:anomaly-detector-1", anomalyDetectorArnField.At(0)) + assert.Equal(t, "arn:aws:logs:us-east-1:123456789012:anomaly-detector:anomaly-detector-2", anomalyDetectorArnField.At(1)) + } + }) +} diff --git a/pkg/tsdb/cloudwatch/log_sync_query_test.go b/pkg/tsdb/cloudwatch/log_sync_query_test.go index b1c0b99175e..376464d9340 100644 --- a/pkg/tsdb/cloudwatch/log_sync_query_test.go +++ b/pkg/tsdb/cloudwatch/log_sync_query_test.go @@ -137,7 +137,7 @@ func Test_executeSyncLogQuery(t *testing.T) { executeSyncLogQuery = origExecuteSyncLogQuery }) - t.Run("when query mode is 'Logs' and does not include type or subtype", func(t *testing.T) { + t.Run("when query mode is 'Logs Insights' and does not include type or subtype", func(t *testing.T) { origExecuteSyncLogQuery := executeSyncLogQuery syncCalled := false executeSyncLogQuery = func(ctx context.Context, e *DataSource, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) { diff --git a/pkg/tsdb/cloudwatch/mocks/logs.go b/pkg/tsdb/cloudwatch/mocks/logs.go index 7843fdaacd1..da8dd2cc47c 100644 --- a/pkg/tsdb/cloudwatch/mocks/logs.go +++ b/pkg/tsdb/cloudwatch/mocks/logs.go @@ -66,3 +66,9 @@ func (m *MockLogEvents) GetLogEvents(ctx context.Context, input *cloudwatchlogs. return args.Get(0).(*cloudwatchlogs.GetLogEventsOutput), args.Error(1) } + +func (m *MockLogEvents) ListAnomalies(ctx context.Context, input *cloudwatchlogs.ListAnomaliesInput, optFns ...func(*cloudwatchlogs.Options)) (*cloudwatchlogs.ListAnomaliesOutput, error) { + args := m.Called(ctx, input, optFns) + + return args.Get(0).(*cloudwatchlogs.ListAnomaliesOutput), args.Error(1) +} diff --git a/pkg/tsdb/cloudwatch/models/api.go b/pkg/tsdb/cloudwatch/models/api.go index e4b487288f1..eed0243b69d 100644 --- a/pkg/tsdb/cloudwatch/models/api.go +++ b/pkg/tsdb/cloudwatch/models/api.go @@ -76,6 +76,7 @@ type CWLogsClient interface { cloudwatchlogs.GetLogEventsAPIClient cloudwatchlogs.DescribeLogGroupsAPIClient + cloudwatchlogs.ListAnomaliesAPIClient } type CWClient interface { diff --git a/pkg/tsdb/cloudwatch/test_utils.go b/pkg/tsdb/cloudwatch/test_utils.go index 82ce33099ee..3f4c797dea4 100644 --- a/pkg/tsdb/cloudwatch/test_utils.go +++ b/pkg/tsdb/cloudwatch/test_utils.go @@ -29,12 +29,15 @@ type fakeCWLogsClient struct { queryResults cloudwatchlogs.GetQueryResultsOutput logGroupsIndex int + + anomalies []cloudwatchlogstypes.Anomaly } type logsQueryCalls struct { startQuery []*cloudwatchlogs.StartQueryInput getEvents []*cloudwatchlogs.GetLogEventsInput describeLogGroups []*cloudwatchlogs.DescribeLogGroupsInput + listAnomalies []*cloudwatchlogs.ListAnomaliesInput } func (m *fakeCWLogsClient) GetQueryResults(_ context.Context, _ *cloudwatchlogs.GetQueryResultsInput, _ ...func(*cloudwatchlogs.Options)) (*cloudwatchlogs.GetQueryResultsOutput, error) { @@ -55,6 +58,14 @@ func (m *fakeCWLogsClient) StopQuery(_ context.Context, _ *cloudwatchlogs.StopQu }, nil } +func (m *fakeCWLogsClient) ListAnomalies(_ context.Context, input *cloudwatchlogs.ListAnomaliesInput, _ ...func(*cloudwatchlogs.Options)) (*cloudwatchlogs.ListAnomaliesOutput, error) { + m.calls.listAnomalies = append(m.calls.listAnomalies, input) + + return &cloudwatchlogs.ListAnomaliesOutput{ + Anomalies: m.anomalies, + }, nil +} + type mockLogsSyncClient struct { mock.Mock } @@ -80,6 +91,11 @@ func (m *mockLogsSyncClient) StartQuery(ctx context.Context, input *cloudwatchlo return args.Get(0).(*cloudwatchlogs.StartQueryOutput), args.Error(1) } +func (m *mockLogsSyncClient) ListAnomalies(ctx context.Context, input *cloudwatchlogs.ListAnomaliesInput, optFns ...func(*cloudwatchlogs.Options)) (*cloudwatchlogs.ListAnomaliesOutput, error) { + args := m.Called(ctx, input, optFns) + return args.Get(0).(*cloudwatchlogs.ListAnomaliesOutput), args.Error(1) +} + func (m *fakeCWLogsClient) DescribeLogGroups(_ context.Context, input *cloudwatchlogs.DescribeLogGroupsInput, _ ...func(*cloudwatchlogs.Options)) (*cloudwatchlogs.DescribeLogGroupsOutput, error) { m.calls.describeLogGroups = append(m.calls.describeLogGroups, input) output := &m.logGroups[m.logGroupsIndex] diff --git a/public/app/plugins/datasource/cloudwatch/components/QueryEditor/LogsQueryEditor/LogsAnomaliesQueryEditor.tsx b/public/app/plugins/datasource/cloudwatch/components/QueryEditor/LogsQueryEditor/LogsAnomaliesQueryEditor.tsx new file mode 100644 index 00000000000..218d16e6b98 --- /dev/null +++ b/public/app/plugins/datasource/cloudwatch/components/QueryEditor/LogsQueryEditor/LogsAnomaliesQueryEditor.tsx @@ -0,0 +1,41 @@ +import { EditorField, EditorRow } from '@grafana/plugin-ui'; +import { Combobox, Input } from '@grafana/ui'; + +import { CloudWatchLogsAnomaliesQuery } from '../../../dataquery.gen'; + +interface Props { + query: CloudWatchLogsAnomaliesQuery; + onChange: (value: CloudWatchLogsAnomaliesQuery) => void; +} + +const supressionStateOptions = [ + { label: 'All', value: 'all' }, + { label: 'Suppressed', value: 'suppressed' }, + { label: 'Unsuppressed', value: 'unsuppressed' }, +]; + +export const LogsAnomaliesQueryEditor = (props: Props) => { + return ( + <> + + + { + props.onChange({ ...props.query, anomalyDetectionARN: e.currentTarget.value }); + }} + /> + + + { + props.onChange({ ...props.query, suppressionState: e.value }); + }} + /> + + + + ); +}; diff --git a/public/app/plugins/datasource/cloudwatch/components/QueryEditor/LogsQueryEditor/LogsQueryEditor.tsx b/public/app/plugins/datasource/cloudwatch/components/QueryEditor/LogsQueryEditor/LogsQueryEditor.tsx index 6be68db99cb..bf59c959066 100644 --- a/public/app/plugins/datasource/cloudwatch/components/QueryEditor/LogsQueryEditor/LogsQueryEditor.tsx +++ b/public/app/plugins/datasource/cloudwatch/components/QueryEditor/LogsQueryEditor/LogsQueryEditor.tsx @@ -6,9 +6,10 @@ import { InlineSelect } from '@grafana/plugin-ui'; import { CloudWatchDatasource } from '../../../datasource'; import { DEFAULT_CWLI_QUERY_STRING, DEFAULT_PPL_QUERY_STRING, DEFAULT_SQL_QUERY_STRING } from '../../../defaultQueries'; -import { CloudWatchJsonData, CloudWatchLogsQuery, CloudWatchQuery, LogsQueryLanguage } from '../../../types'; +import { CloudWatchJsonData, CloudWatchLogsQuery, CloudWatchQuery, LogsMode, LogsQueryLanguage } from '../../../types'; import { CloudWatchLink } from './CloudWatchLink'; +import { LogsAnomaliesQueryEditor } from './LogsAnomaliesQueryEditor'; import { CloudWatchLogsQueryField } from './LogsQueryField'; type Props = QueryEditorProps & { @@ -22,6 +23,11 @@ const logsQueryLanguageOptions: Array> = [ { label: 'OpenSearch PPL', value: LogsQueryLanguage.PPL }, ]; +const logsModeOptions: Array> = [ + { label: 'Logs Insights', value: LogsMode.Insights }, + { label: 'Logs Anomalies', value: LogsMode.Anomalies }, +]; + export const CloudWatchLogsQueryEditor = memo(function CloudWatchLogsQueryEditor(props: Props) { const { query, data, datasource, onChange, extraHeaderElementLeft } = props; @@ -42,6 +48,13 @@ export const CloudWatchLogsQueryEditor = memo(function CloudWatchLogsQueryEditor [isQueryNew, onChange, query] ); + const onLogsModeChange = useCallback( + (logsMode: LogsMode | undefined) => { + onChange({ ...query, logsMode }); + }, + [query, onChange] + ); + // if the query has already been saved from before, we shouldn't replace it with a default one useEffectOnce(() => { if (query.expression) { @@ -58,20 +71,32 @@ export const CloudWatchLogsQueryEditor = memo(function CloudWatchLogsQueryEditor useEffect(() => { extraHeaderElementLeft?.( - { - onQueryLanguageChange(value); - }} - /> + <> + { + onLogsModeChange(value); + }} + /> + {query.logsMode !== LogsMode.Anomalies && ( + { + onQueryLanguageChange(value); + }} + /> + )} + ); return () => { extraHeaderElementLeft?.(undefined); }; - }, [extraHeaderElementLeft, onChange, onQueryLanguageChange, query]); + }, [extraHeaderElementLeft, onChange, onQueryLanguageChange, query, onLogsModeChange]); const onQueryStringChange = (query: CloudWatchQuery) => { onChange(query); @@ -79,11 +104,17 @@ export const CloudWatchLogsQueryEditor = memo(function CloudWatchLogsQueryEditor }; return ( - } - /> + <> + {query.logsMode === LogsMode.Anomalies ? ( + + ) : ( + } + /> + )} + ); }); diff --git a/public/app/plugins/datasource/cloudwatch/dataquery.cue b/public/app/plugins/datasource/cloudwatch/dataquery.cue index a0afcfb729f..4144b423419 100644 --- a/public/app/plugins/datasource/cloudwatch/dataquery.cue +++ b/public/app/plugins/datasource/cloudwatch/dataquery.cue @@ -146,7 +146,7 @@ composableKinds: DataQuery: { } @cuetsy(kind="interface") #QueryEditorExpression: #QueryEditorArrayExpression | #QueryEditorPropertyExpression | #QueryEditorGroupByExpression | #QueryEditorFunctionExpression | #QueryEditorFunctionParameterExpression | #QueryEditorOperatorExpression @cuetsy(kind="type") - + #LogsMode: "Insights" | "Anomalies" @cuetsy(kind="enum") #LogsQueryLanguage: "CWLI" | "SQL" | "PPL" @cuetsy(kind="enum") // Shape of a CloudWatch Logs query @@ -155,6 +155,8 @@ composableKinds: DataQuery: { // Whether a query is a Metrics, Logs, or Annotations query queryMode: #CloudWatchQueryMode + // Whether a query is a Logs Insights or Logs Anomalies query + logsMode?: #LogsMode id: string // AWS region to query for the logs region: string @@ -166,9 +168,27 @@ composableKinds: DataQuery: { logGroups?: [...#LogGroup] // @deprecated use logGroups logGroupNames?: [...string] + // Language used for querying logs, can be CWLI, SQL, or PPL. If empty, the default language is CWLI. queryLanguage?: #LogsQueryLanguage } @cuetsy(kind="interface") + + // Shape of a Cloudwatch Logs Anomalies query + #CloudWatchLogsAnomaliesQuery: { + common.DataQuery + id: string + // AWS region to query for the logs + region: string + // Whether a query is a Metrics, Logs or Annotations query + queryMode?: #CloudWatchQueryMode + // Whether a query is a Logs Insights or Logs Anomalies query + logsMode?: #LogsMode + // Filter to return only anomalies that are 'SUPPRESSED', 'UNSUPPRESSED', or 'ALL' (default) + suppressionState?: string + // Used to filter only the anomalies found by a certain anomaly detector + anomalyDetectionARN?: string + } @cuetsy(kind="interface") + #LogGroup: { // ARN of the log group arn: string diff --git a/public/app/plugins/datasource/cloudwatch/dataquery.gen.ts b/public/app/plugins/datasource/cloudwatch/dataquery.gen.ts index 461ca94247e..ba0a1134d2d 100644 --- a/public/app/plugins/datasource/cloudwatch/dataquery.gen.ts +++ b/public/app/plugins/datasource/cloudwatch/dataquery.gen.ts @@ -216,6 +216,11 @@ export interface QueryEditorArrayExpression { export type QueryEditorExpression = (QueryEditorArrayExpression | QueryEditorPropertyExpression | QueryEditorGroupByExpression | QueryEditorFunctionExpression | QueryEditorFunctionParameterExpression | QueryEditorOperatorExpression); +export enum LogsMode { + Anomalies = 'Anomalies', + Insights = 'Insights', +} + export enum LogsQueryLanguage { CWLI = 'CWLI', PPL = 'PPL', @@ -239,6 +244,10 @@ export interface CloudWatchLogsQuery extends common.DataQuery { * Log groups to query */ logGroups?: Array; + /** + * Whether a query is a Logs Insights or Logs Anomalies query + */ + logsMode?: LogsMode; /** * Language used for querying logs, can be CWLI, SQL, or PPL. If empty, the default language is CWLI. */ @@ -263,6 +272,33 @@ export const defaultCloudWatchLogsQuery: Partial = { statsGroups: [], }; +/** + * Shape of a Cloudwatch Logs Anomalies query + */ +export interface CloudWatchLogsAnomaliesQuery extends common.DataQuery { + /** + * Used to filter only the anomalies found by a certain anomaly detector + */ + anomalyDetectionARN?: string; + id: string; + /** + * Whether a query is a Logs Insights or Logs Anomalies query + */ + logsMode?: LogsMode; + /** + * Whether a query is a Metrics, Logs or Annotations query + */ + queryMode?: CloudWatchQueryMode; + /** + * AWS region to query for the logs + */ + region: string; + /** + * Filter to return only anomalies that are 'SUPPRESSED', 'UNSUPPRESSED', or 'ALL' (default) + */ + suppressionState?: string; +} + export interface LogGroup { /** * AccountId of the log group diff --git a/public/app/plugins/datasource/cloudwatch/datasource.test.ts b/public/app/plugins/datasource/cloudwatch/datasource.test.ts index dc15557ee8a..3186c92121c 100644 --- a/public/app/plugins/datasource/cloudwatch/datasource.test.ts +++ b/public/app/plugins/datasource/cloudwatch/datasource.test.ts @@ -306,7 +306,7 @@ describe('datasource', () => { }); }); - it('should add a data link field to log queries', async () => { + it('should add links to log insights queries', async () => { const { datasource } = setupForLogs(); const observable = datasource.query({ @@ -439,7 +439,7 @@ describe('datasource', () => { const { datasource } = setupMockedDataSource(); expect(datasource.getDefaultQuery(CoreApp.PanelEditor).queryMode).toEqual('Metrics'); }); - it('should set default log groups in default query', () => { + it('should set default log groups in default logs insights query', () => { const { datasource } = setupMockedDataSource({ customInstanceSettings: { ...CloudWatchSettings, diff --git a/public/app/plugins/datasource/cloudwatch/datasource.ts b/public/app/plugins/datasource/cloudwatch/datasource.ts index 685dce3c15d..27c240dd6cd 100644 --- a/public/app/plugins/datasource/cloudwatch/datasource.ts +++ b/public/app/plugins/datasource/cloudwatch/datasource.ts @@ -16,7 +16,12 @@ import { DataSourceWithBackend, TemplateSrv, getTemplateSrv } from '@grafana/run import { CloudWatchAnnotationSupport } from './annotationSupport'; import { DEFAULT_METRICS_QUERY, getDefaultLogsQuery } from './defaultQueries'; -import { isCloudWatchAnnotationQuery, isCloudWatchLogsQuery, isCloudWatchMetricsQuery } from './guards'; +import { + isCloudWatchAnnotationQuery, + isCloudWatchLogsQuery, + isCloudWatchMetricsQuery, + isLogsAnomaliesQuery, +} from './guards'; import { CloudWatchLogsLanguageProvider } from './language/cloudwatch-logs/CloudWatchLogsLanguageProvider'; import { LogsSQLCompletionItemProvider, @@ -40,6 +45,7 @@ import { ResourcesAPI } from './resources/ResourcesAPI'; import { CloudWatchAnnotationQuery, CloudWatchJsonData, + CloudWatchLogsAnomaliesQuery, CloudWatchLogsQuery, CloudWatchMetricsQuery, CloudWatchQuery, @@ -104,11 +110,14 @@ export class CloudWatchDatasource const logQueries: CloudWatchLogsQuery[] = []; const metricsQueries: CloudWatchMetricsQuery[] = []; + const logsAnomaliesQueries: CloudWatchLogsAnomaliesQuery[] = []; const annotationQueries: CloudWatchAnnotationQuery[] = []; queries.forEach((query) => { if (isCloudWatchAnnotationQuery(query)) { annotationQueries.push(query); + } else if (isLogsAnomaliesQuery(query)) { + logsAnomaliesQueries.push(query); } else if (isCloudWatchLogsQuery(query)) { logQueries.push(query); } else { @@ -127,6 +136,12 @@ export class CloudWatchDatasource ); } + if (logsAnomaliesQueries.length) { + dataQueryResponses.push( + this.logsQueryRunner.handleLogAnomaliesQueries(logsAnomaliesQueries, options, super.query.bind(this)) + ); + } + if (annotationQueries.length) { dataQueryResponses.push( this.annotationQueryRunner.handleAnnotationQuery(annotationQueries, options, super.query.bind(this)) diff --git a/public/app/plugins/datasource/cloudwatch/guards.ts b/public/app/plugins/datasource/cloudwatch/guards.ts index b5346df3c25..2a54dd9719c 100644 --- a/public/app/plugins/datasource/cloudwatch/guards.ts +++ b/public/app/plugins/datasource/cloudwatch/guards.ts @@ -1,10 +1,26 @@ import { AnnotationQuery } from '@grafana/data'; -import { CloudWatchAnnotationQuery, CloudWatchLogsQuery, CloudWatchMetricsQuery, CloudWatchQuery } from './types'; +import { + CloudWatchAnnotationQuery, + CloudWatchLogsAnomaliesQuery, + CloudWatchLogsQuery, + CloudWatchMetricsQuery, + CloudWatchQuery, + LogsMode, +} from './types'; export const isCloudWatchLogsQuery = (cloudwatchQuery: CloudWatchQuery): cloudwatchQuery is CloudWatchLogsQuery => cloudwatchQuery.queryMode === 'Logs'; +export const isLogsAnomaliesQuery = ( + cloudwatchQuery: CloudWatchQuery +): cloudwatchQuery is CloudWatchLogsAnomaliesQuery => { + if (isCloudWatchLogsQuery(cloudwatchQuery)) { + return cloudwatchQuery.logsMode === LogsMode.Anomalies; + } + return false; +}; + export const isCloudWatchMetricsQuery = (cloudwatchQuery: CloudWatchQuery): cloudwatchQuery is CloudWatchMetricsQuery => cloudwatchQuery.queryMode === 'Metrics' || !cloudwatchQuery.hasOwnProperty('queryMode'); // in early versions of this plugin, queryMode wasn't defined in a CloudWatchMetricsQuery diff --git a/public/app/plugins/datasource/cloudwatch/query-runner/CloudWatchLogsQueryRunner.test.ts b/public/app/plugins/datasource/cloudwatch/query-runner/CloudWatchLogsQueryRunner.test.ts index b38fd288633..ec7715dc4df 100644 --- a/public/app/plugins/datasource/cloudwatch/query-runner/CloudWatchLogsQueryRunner.test.ts +++ b/public/app/plugins/datasource/cloudwatch/query-runner/CloudWatchLogsQueryRunner.test.ts @@ -2,20 +2,26 @@ import { lastValueFrom, of } from 'rxjs'; import { DataQueryRequest, + DataQueryResponse, + Field, FieldType, LogLevel, LogRowContextQueryDirection, LogRowModel, - MutableDataFrame, } from '@grafana/data'; import { regionVariable } from '../mocks/CloudWatchDataSource'; import { setupMockedLogsQueryRunner } from '../mocks/LogsQueryRunner'; import { LogsRequestMock } from '../mocks/Request'; import { validLogsQuery } from '../mocks/queries'; -import { CloudWatchLogsQuery } from '../types'; // Add this import statement +import { TimeRangeMock } from '../mocks/timeRange'; +import { CloudWatchLogsAnomaliesQuery, CloudWatchLogsQuery, LogsMode } from '../types'; // Add this import statement -import { LOGSTREAM_IDENTIFIER_INTERNAL, LOG_IDENTIFIER_INTERNAL } from './CloudWatchLogsQueryRunner'; +import { + LOGSTREAM_IDENTIFIER_INTERNAL, + LOG_IDENTIFIER_INTERNAL, + convertTrendHistogramToSparkline, +} from './CloudWatchLogsQueryRunner'; describe('CloudWatchLogsQueryRunner', () => { beforeEach(() => { @@ -28,14 +34,15 @@ describe('CloudWatchLogsQueryRunner', () => { const row: LogRowModel = { entryFieldIndex: 0, rowIndex: 0, - dataFrame: new MutableDataFrame({ + dataFrame: { refId: 'B', + length: 1, fields: [ - { name: 'ts', type: FieldType.time, values: [1] }, - { name: LOG_IDENTIFIER_INTERNAL, type: FieldType.string, values: ['foo'], labels: {} }, - { name: LOGSTREAM_IDENTIFIER_INTERNAL, type: FieldType.string, values: ['bar'], labels: {} }, + { name: 'ts', type: FieldType.time, values: [1], config: {} }, + { name: LOG_IDENTIFIER_INTERNAL, type: FieldType.string, values: ['foo'], labels: {}, config: {} }, + { name: LOGSTREAM_IDENTIFIER_INTERNAL, type: FieldType.string, values: ['bar'], labels: {}, config: {} }, ], - }), + }, entry: '4', labels: {}, hasAnsi: false, @@ -481,6 +488,120 @@ describe('CloudWatchLogsQueryRunner', () => { }); }); }); + + describe('handleLogAnomaliesQueries', () => { + it('appends -anomalies to the requestId', async () => { + const { runner, queryMock } = setupMockedLogsQueryRunner(); + const logsAnomaliesRequestMock: DataQueryRequest = { + requestId: 'mockId', + range: TimeRangeMock, + rangeRaw: { from: TimeRangeMock.from, to: TimeRangeMock.to }, + targets: [ + { + id: '1', + logsMode: LogsMode.Anomalies, + queryMode: 'Logs', + refId: 'A', + region: 'us-east-1', + }, + ], + interval: '', + intervalMs: 0, + scopedVars: { __interval: { value: '20s' } }, + timezone: '', + app: '', + startTime: 0, + }; + await expect( + runner.handleLogAnomaliesQueries(LogsRequestMock.targets, logsAnomaliesRequestMock, queryMock) + ).toEmitValuesWith(() => { + expect(queryMock.mock.calls[0][0].requestId).toEqual('mockId-logsAnomalies'); + }); + }); + + it('processes log trend histogram data correctly', async () => { + const response = structuredClone(anomaliesQueryResponse); + + convertTrendHistogramToSparkline(response); + + expect(response.data[0].fields.find((field: Field) => field.name === 'Log trend')).toEqual({ + name: 'Log trend', + type: 'frame', + config: { + custom: { + drawStyle: 'bars', + cellOptions: { + type: 'sparkline', + hideValue: true, + }, + }, + }, + values: [ + { + name: 'Trend_row_0', + length: 8, + fields: [ + { + name: 'time', + type: 'time', + values: [ + 1760454000000, 1760544000000, 1760724000000, 1761282000000, 1761300000000, 1761354000000, + 1761372000000, 1761390000000, + ], + config: {}, + }, + { + name: 'value', + type: 'number', + values: [81, 35, 35, 36, 36, 36, 72, 36], + config: {}, + }, + ], + }, + { + name: 'Trend_row_1', + length: 2, + fields: [ + { + name: 'time', + type: 'time', + values: [1760687665000, 1760687670000], + config: {}, + }, + { + name: 'value', + type: 'number', + values: [3, 3], + config: {}, + }, + ], + }, + ], + }); + }); + + it('replaces log trend histogram field at the same index in the frame', () => { + const response = structuredClone(anomaliesQueryResponse); + convertTrendHistogramToSparkline(response); + expect(response.data[0].fields[4].name).toEqual('Log trend'); + }); + + it('ignore invalid timestamps in log trend histogram', () => { + const response = structuredClone(anomaliesQueryResponse); + + response.data[0].fields[4].values[1] = { + invalidTimestamp: 3, + '1760687670000': 3, + anotherInvalidTimestamp: 2, + '1760687670010': 3, + }; + + convertTrendHistogramToSparkline(response); + + expect(response.data[0].fields[4].values[1].fields[0].values.length).toEqual(2); + expect(response.data[0].fields[4].values[1].fields[1].values.length).toEqual(2); + }); + }); }); const rawLogQueriesStub: CloudWatchLogsQuery[] = [ @@ -641,3 +762,166 @@ const getQueryErrorResponseStub = { const stopQueryResponseStub = { state: 'Done', }; + +const anomaliesQueryResponse: DataQueryResponse = { + data: [ + { + name: 'Logs anomalies', + refId: 'A', + meta: { + preferredVisualisationType: 'table', + }, + fields: [ + { + name: 'state', + type: 'string', + typeInfo: { + frame: 'string', + }, + config: { + displayName: 'State', + }, + values: ['Active', 'Active'], + entities: {}, + }, + { + name: 'description', + type: 'string', + typeInfo: { + frame: 'string', + }, + config: { + displayName: 'Anomaly', + }, + values: [ + '50.0% increase in count of value "405" for "code"-3', + '151.3% increase in count of value 1 for "dotnet_collection_count_total"-3', + ], + entities: {}, + }, + { + name: 'priority', + type: 'string', + typeInfo: { + frame: 'string', + }, + config: { + displayName: 'Priority', + }, + values: ['MEDIUM', 'MEDIUM'], + entities: {}, + }, + { + name: 'patternString', + type: 'string', + typeInfo: { + frame: 'string', + }, + config: { + displayName: 'Log Pattern', + }, + values: [ + '{"ClusterName":"PetSite","Namespace":"default","Service":"service-petsite","Timestamp":<*>,"Version":<*>,"code":<*>,"container_name":"petsite","http_requests_received_total":<*>,"instance":<*>:<*>,"job":"kubernetes-service-endpoints","kubernetes_node":<*>,"method":<*>,"pod_name":<*>,"prom_metric_type":"counter"}', + '{"ClusterName":"PetSite","Namespace":"default","Service":"service-petsite","Timestamp":<*>,"Version":<*>,"container_name":"petsite","dotnet_collection_count_total":<*>,"generation":<*>,"instance":<*>:<*>,"job":"kubernetes-service-endpoints","kubernetes_node":<*>,"pod_name":<*>,"prom_metric_type":"counter"}', + ], + entities: {}, + }, + { + name: 'logTrend', + type: 'other', + typeInfo: { + frame: 'json.RawMessage', + nullable: true, + }, + config: { + displayName: 'Log Trend', + }, + values: [ + { + '1760454000000': 81, + '1760544000000': 35, + '1760724000000': 35, + '1761282000000': 36, + '1761300000000': 36, + '1761354000000': 36, + '1761372000000': 72, + '1761390000000': 36, + }, + { + '1760687665000': 3, + '1760687670000': 3, + }, + ], + entities: {}, + }, + { + name: 'firstSeen', + type: 'time', + typeInfo: { + frame: 'time.Time', + }, + config: { + displayName: 'First seen', + }, + values: [1760462460000, 1760687640000], + entities: {}, + }, + { + name: 'lastSeen', + type: 'time', + typeInfo: { + frame: 'time.Time', + }, + config: { + displayName: 'Last seen', + }, + values: [1761393660000, 1760687940000], + entities: {}, + }, + { + name: 'suppressed', + type: 'boolean', + typeInfo: { + frame: 'bool', + }, + config: { + displayName: 'Suppressed?', + }, + values: [false, false], + entities: {}, + }, + { + name: 'logGroupArnList', + type: 'string', + typeInfo: { + frame: 'string', + }, + config: { + displayName: 'Log Groups', + }, + values: [ + 'arn:aws:logs:us-east-2:569069006612:log-group:/aws/containerinsights/PetSite/prometheus', + 'arn:aws:logs:us-east-2:569069006612:log-group:/aws/containerinsights/PetSite/prometheus', + ], + entities: {}, + }, + { + name: 'anomalyArn', + type: 'string', + typeInfo: { + frame: 'string', + }, + config: { + displayName: 'Anomaly Arn', + }, + values: [ + 'arn:aws:logs:us-east-2:569069006612:anomaly-detector:dca8b129-d09d-4167-86e9-7bf62ede2f95', + 'arn:aws:logs:us-east-2:569069006612:anomaly-detector:dca8b129-d09d-4167-86e9-7bf62ede2f95', + ], + entities: {}, + }, + ], + length: 2, + }, + ], +}; diff --git a/public/app/plugins/datasource/cloudwatch/query-runner/CloudWatchLogsQueryRunner.ts b/public/app/plugins/datasource/cloudwatch/query-runner/CloudWatchLogsQueryRunner.ts index 0ccc22029c1..7f1ba927f47 100644 --- a/public/app/plugins/datasource/cloudwatch/query-runner/CloudWatchLogsQueryRunner.ts +++ b/public/app/plugins/datasource/cloudwatch/query-runner/CloudWatchLogsQueryRunner.ts @@ -23,6 +23,8 @@ import { DataQueryRequest, DataQueryResponse, DataSourceInstanceSettings, + Field, + FieldType, LoadingState, LogRowContextOptions, LogRowContextQueryDirection, @@ -33,15 +35,19 @@ import { } from '@grafana/data'; import { TemplateSrv } from '@grafana/runtime'; import { type CustomFormatterVariable } from '@grafana/scenes'; +import { GraphDrawStyle } from '@grafana/schema/dist/esm/index'; +import { TableCellDisplayMode } from '@grafana/ui'; import { CloudWatchJsonData, + CloudWatchLogsAnomaliesQuery, CloudWatchLogsQuery, CloudWatchLogsQueryStatus, CloudWatchLogsRequest, CloudWatchQuery, GetLogEventsRequest, LogAction, + LogsMode, LogsQueryLanguage, QueryParam, StartQueryRequest, @@ -101,6 +107,7 @@ export class CloudWatchLogsQueryRunner extends CloudWatchRequest { logGroups, logGroupNames, queryLanguage: target.queryLanguage, + logsMode: target.logsMode ?? LogsMode.Insights, }; }); @@ -136,6 +143,63 @@ export class CloudWatchLogsQueryRunner extends CloudWatchRequest { ); }; + public handleLogAnomaliesQueries = ( + logAnomaliesQueries: CloudWatchLogsAnomaliesQuery[], + options: DataQueryRequest, + queryFn: (request: DataQueryRequest) => Observable + ): Observable => { + const logAnomalyTargets: StartQueryRequest[] = logAnomaliesQueries.map((target: CloudWatchLogsAnomaliesQuery) => { + return { + refId: target.refId, + region: this.templateSrv.replace(this.getActualRegion(target.region)), + queryString: '', + logGroups: [], + logsMode: LogsMode.Anomalies, + suppressionState: target.suppressionState || 'all', + anomalyDetectionARN: target.anomalyDetectionARN || '', + }; + }); + + const range = options?.range || getDefaultTimeRange(); + // append -logsAnomalies to prevent requestId from matching metric or logs queries from the same panel + const requestId = options?.requestId ? `${options?.requestId}-logsAnomalies` : ''; + + const requestParams: DataQueryRequest = { + ...options, + range, + skipQueryCache: true, + requestId, + interval: options?.interval || '', // dummy + intervalMs: options?.intervalMs || 1, // dummy + scopedVars: options?.scopedVars || {}, // dummy + timezone: options?.timezone || '', // dummy + app: options?.app || '', // dummy + startTime: options?.startTime || 0, // dummy + targets: logAnomalyTargets.map((t) => ({ + ...t, + id: '', + queryMode: 'Logs', + refId: t.refId || 'A', + intervalMs: 1, // dummy + maxDataPoints: 1, // dummy + datasource: this.ref, + type: 'logAction', + logsMode: LogsMode.Anomalies, + })), + }; + + return queryFn(requestParams).pipe( + mergeMap((dataQueryResponse) => { + return from( + (async () => { + convertTrendHistogramToSparkline(dataQueryResponse); + return dataQueryResponse; + })() + ); + }) + ); + }; + /** * Called by datasource.ts, invoked when user clicks on a log row in the logs visualization and the "show context button" */ @@ -450,7 +514,7 @@ export class CloudWatchLogsQueryRunner extends CloudWatchRequest { const hasMissingLogGroups = !query.logGroups?.length; const hasMissingQueryString = !query.expression?.length; - // log groups are not mandatory if language is SQL + // log groups are not mandatory if language is SQL and LogsMode is not Insights const isInvalidCWLIQuery = query.queryLanguage !== 'SQL' && hasMissingLogGroups && hasMissingLegacyLogGroupNames; if (isInvalidCWLIQuery || hasMissingQueryString) { return false; @@ -479,3 +543,69 @@ function parseLogGroupName(logIdentifier: string): string { const colonIndex = logIdentifier.lastIndexOf(':'); return logIdentifier.slice(colonIndex + 1); } + +const LOG_TREND_FIELD_NAME = 'logTrend'; + +/** + * Takes DataQueryResponse and converts any "log trend" fields (that are in JSON.rawMessage form) + * into data frame fields that the table vis will be able to display + */ +export function convertTrendHistogramToSparkline(dataQueryResponse: DataQueryResponse): void { + dataQueryResponse.data.forEach((frame) => { + let fieldIndexToReplace = null; + // log trend histogram field from CW API is of shape Record + const sparklineRawData: Field> = frame.fields.find((field: Field, index: number) => { + if (field.name === LOG_TREND_FIELD_NAME && field.type === FieldType.other) { + fieldIndexToReplace = index; + return true; + } + return false; + }); + + if (sparklineRawData) { + const sparklineField: Field = { + name: 'Log trend', + type: FieldType.frame, + config: { + custom: { + drawStyle: GraphDrawStyle.Bars, + cellOptions: { + type: TableCellDisplayMode.Sparkline, + // hiding the value here as it's not useful or clear on what it represents for log trend + hideValue: true, + }, + }, + }, + values: [], + }; + + sparklineRawData.values.forEach((sparklineValue, rowIndex) => { + const timestamps: number[] = []; + const values: number[] = []; + Object.keys(sparklineValue).map((t, i) => { + let n = Number(t); + if (!isNaN(n)) { + timestamps.push(n); + values.push(sparklineValue[t]); + } + }); + + const sparklineFieldFrame: DataFrame = { + name: `Trend_row_${rowIndex}`, + length: timestamps.length, + fields: [ + { name: 'time', type: FieldType.time, values: timestamps, config: {} }, + { name: 'value', type: FieldType.number, values, config: {} }, + ], + }; + + sparklineField.values.push(sparklineFieldFrame); + }); + + if (fieldIndexToReplace) { + // Make sure sparkline field is placed in the same order as coming from BE + frame.fields[fieldIndexToReplace] = sparklineField; + } + } + }); +} diff --git a/public/app/plugins/datasource/cloudwatch/types.ts b/public/app/plugins/datasource/cloudwatch/types.ts index 97db6242aaf..b774bfade40 100644 --- a/public/app/plugins/datasource/cloudwatch/types.ts +++ b/public/app/plugins/datasource/cloudwatch/types.ts @@ -10,6 +10,7 @@ export type CloudWatchQuery = | raw.CloudWatchMetricsQuery | raw.CloudWatchLogsQuery | raw.CloudWatchAnnotationQuery + | raw.CloudWatchLogsAnomaliesQuery | CloudWatchDefaultQuery; // We want to allow setting defaults for both Logs and Metrics queries From f2404361bf53cb0974e79e0a5bc995762497ce4b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 29 Oct 2025 18:51:40 +0000 Subject: [PATCH 105/378] deps(actions): bump actions/download-artifact from 5 to 6 (#113024) Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 5 to 6. - [Release notes](https://github.com/actions/download-artifact/releases) - [Commits](https://github.com/actions/download-artifact/compare/v5...v6) --- updated-dependencies: - dependency-name: actions/download-artifact dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/backport-workflow.yml | 2 +- .../detect-breaking-changes-levitate.yml | 6 +++--- .github/workflows/pr-e2e-tests.yml | 16 ++++++++-------- .github/workflows/publish-artifact.yml | 2 +- .github/workflows/release-build.yml | 12 ++++++------ 5 files changed, 19 insertions(+), 19 deletions(-) diff --git a/.github/workflows/backport-workflow.yml b/.github/workflows/backport-workflow.yml index f3d6761440c..ef7254ffe6a 100644 --- a/.github/workflows/backport-workflow.yml +++ b/.github/workflows/backport-workflow.yml @@ -36,7 +36,7 @@ jobs: private_key: ${{ fromJSON(steps.secrets.outputs.secrets).APP_PEM }} - name: Download PR info artifact - uses: actions/download-artifact@v5 + uses: actions/download-artifact@v6 id: download-pr-info with: github-token: ${{ github.token }} diff --git a/.github/workflows/detect-breaking-changes-levitate.yml b/.github/workflows/detect-breaking-changes-levitate.yml index 2e9b370d4e0..cd2c123e472 100644 --- a/.github/workflows/detect-breaking-changes-levitate.yml +++ b/.github/workflows/detect-breaking-changes-levitate.yml @@ -141,12 +141,12 @@ jobs: node-version-file: '.nvmrc' - name: Get built packages from pr - uses: actions/download-artifact@v5 + uses: actions/download-artifact@v6 with: name: buildPr - name: Get built packages from base - uses: actions/download-artifact@v5 + uses: actions/download-artifact@v6 with: name: buildBase @@ -225,7 +225,7 @@ jobs: persist-credentials: false - name: 'Download artifact' - uses: actions/download-artifact@v5 + uses: actions/download-artifact@v6 with: name: levitate diff --git a/.github/workflows/pr-e2e-tests.yml b/.github/workflows/pr-e2e-tests.yml index 08b5ad7aba9..30bfc4705ad 100644 --- a/.github/workflows/pr-e2e-tests.yml +++ b/.github/workflows/pr-e2e-tests.yml @@ -159,7 +159,7 @@ jobs: with: registry: 'us-docker.pkg.dev' environment: 'dev' - - uses: actions/download-artifact@4a24838f3d5601fd639834081e118c2995d51e1c + - uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 with: name: grafana-docker-tar-gz path: . @@ -221,10 +221,10 @@ jobs: - uses: actions/checkout@v5 with: persist-credentials: false - - uses: actions/download-artifact@v5 + - uses: actions/download-artifact@v6 with: name: grafana-tar-gz - - uses: actions/download-artifact@v5 + - uses: actions/download-artifact@v6 with: name: ${{ needs.build-e2e-runner.outputs.artifact }} - name: chmod +x @@ -298,7 +298,7 @@ jobs: - uses: actions/checkout@v5 with: persist-credentials: false - - uses: actions/download-artifact@v5 + - uses: actions/download-artifact@v6 with: name: grafana-tar-gz - name: Run E2E tests @@ -360,7 +360,7 @@ jobs: run: | docker cp cpp-e2e-deploy:/outputs.json /tmp/outputs.json - - uses: actions/download-artifact@v5 + - uses: actions/download-artifact@v6 with: name: grafana-tar-gz @@ -400,7 +400,7 @@ jobs: node-version-file: '.nvmrc' - name: Download blob reports from GitHub Actions Artifacts - uses: actions/download-artifact@v5 + uses: actions/download-artifact@v6 with: path: blobs pattern: playwright-blob-* @@ -479,7 +479,7 @@ jobs: - uses: actions/checkout@v5 with: persist-credentials: false - - uses: actions/download-artifact@v5 + - uses: actions/download-artifact@v6 with: name: grafana-tar-gz - name: Run PR a11y test @@ -531,7 +531,7 @@ jobs: - name: Install dependencies run: yarn install --immutable - name: Get pa11y results - uses: actions/download-artifact@v5 + uses: actions/download-artifact@v6 with: name: pa11y-ci-results - name: Extract and publish metrics diff --git a/.github/workflows/publish-artifact.yml b/.github/workflows/publish-artifact.yml index 8ea0b9b90a0..ad0cc86de66 100644 --- a/.github/workflows/publish-artifact.yml +++ b/.github/workflows/publish-artifact.yml @@ -44,7 +44,7 @@ jobs: permissions: id-token: write steps: - - uses: actions/download-artifact@4a24838f3d5601fd639834081e118c2995d51e1c + - uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 with: name: ${{ inputs.name }} pattern: ${{ inputs.pattern }} diff --git a/.github/workflows/release-build.yml b/.github/workflows/release-build.yml index 2fc23359a7a..435fc8b6849 100644 --- a/.github/workflows/release-build.yml +++ b/.github/workflows/release-build.yml @@ -224,27 +224,27 @@ jobs: - build steps: - uses: grafana/shared-workflows/actions/dockerhub-login@dockerhub-login/v1.0.2 - - uses: actions/download-artifact@4a24838f3d5601fd639834081e118c2995d51e1c + - uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 with: name: artifacts-list-linux-amd64 path: . - - uses: actions/download-artifact@4a24838f3d5601fd639834081e118c2995d51e1c + - uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 with: name: artifacts-list-linux-arm64 path: . - - uses: actions/download-artifact@4a24838f3d5601fd639834081e118c2995d51e1c + - uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 with: name: artifacts-list-linux-armv7 path: . - - uses: actions/download-artifact@4a24838f3d5601fd639834081e118c2995d51e1c + - uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 with: name: artifacts-linux-amd64 path: dist - - uses: actions/download-artifact@4a24838f3d5601fd639834081e118c2995d51e1c + - uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 with: name: artifacts-linux-arm64 path: dist - - uses: actions/download-artifact@4a24838f3d5601fd639834081e118c2995d51e1c + - uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 with: name: artifacts-linux-armv7 path: dist From a4df6c8bb99ef810bb201ce80b976120a23c102e Mon Sep 17 00:00:00 2001 From: Yuri Tseretyan Date: Wed, 29 Oct 2025 16:30:38 -0400 Subject: [PATCH 106/378] Alerting: Prohibit receivers with empty name (#113064) --- pkg/services/ngalert/models/receivers.go | 3 + .../ngalert/notifier/receiver_svc_test.go | 16 ++ .../ngalert/provisioning/contactpoints.go | 21 ++- .../provisioning/contactpoints_test.go | 145 +++++++++++------- 4 files changed, 121 insertions(+), 64 deletions(-) diff --git a/pkg/services/ngalert/models/receivers.go b/pkg/services/ngalert/models/receivers.go index 1130711da90..1601ddc94e5 100644 --- a/pkg/services/ngalert/models/receivers.go +++ b/pkg/services/ngalert/models/receivers.go @@ -130,6 +130,9 @@ func (r *Receiver) WithExistingSecureFields(existing *Receiver, integrationSecur // Validate validates all integration settings, ensuring that the integrations are correctly configured. func (r *Receiver) Validate(decryptFn DecryptFn) error { var errs []error + if r.Name == "" { + errs = append(errs, fmt.Errorf("name should not be an empty string")) + } for _, integration := range r.Integrations { if err := integration.Validate(decryptFn); err != nil { errs = append(errs, err) diff --git a/pkg/services/ngalert/notifier/receiver_svc_test.go b/pkg/services/ngalert/notifier/receiver_svc_test.go index 85e7733f4bd..221f3e805d0 100644 --- a/pkg/services/ngalert/notifier/receiver_svc_test.go +++ b/pkg/services/ngalert/notifier/receiver_svc_test.go @@ -476,6 +476,12 @@ func TestReceiverService_Create(t *testing.T) { }, }, }, + { + name: "receiver with empty name fails", + user: writer, + receiver: models.CopyReceiverWith(baseReceiver, models.ReceiverMuts.WithName("")), + expectedErr: legacy_storage.ErrReceiverInvalid, + }, } { t.Run(tc.name, func(t *testing.T) { sut := createReceiverServiceSut(t, &secretsService) @@ -901,6 +907,16 @@ func TestReceiverService_UpdateReceiverName(t *testing.T) { assert.NotNil(t, ruleStore.Calls[0].Args[4]) assert.Falsef(t, ruleStore.Calls[0].Args[5].(bool), "dryrun expected to be false") }) + + t.Run("returns ErrReceiverInvalid if empty name", func(t *testing.T) { + ruleStore := &fakeAlertRuleNotificationStore{} + sut := createReceiverServiceSut(t, &secretsService) + sut.ruleNotificationsStore = ruleStore + baseReceiver.Name = "" + + _, err := sut.UpdateReceiver(context.Background(), &baseReceiver, nil, writer.GetOrgID(), writer) + require.ErrorIs(t, err, legacy_storage.ErrReceiverInvalid) + }) } func TestReceiverServiceAC_Read(t *testing.T) { diff --git a/pkg/services/ngalert/provisioning/contactpoints.go b/pkg/services/ngalert/provisioning/contactpoints.go index d25aa4e959f..14abb8ceaa5 100644 --- a/pkg/services/ngalert/provisioning/contactpoints.go +++ b/pkg/services/ngalert/provisioning/contactpoints.go @@ -309,13 +309,14 @@ func (ecp *ContactPointService) UpdateContactPoint(ctx context.Context, orgID in return err } - oldReceiverName, fullRemoval, newReceiverCreated := stitchReceiver(revision.Config, mergedReceiver) - if oldReceiverName == "" { - return fmt.Errorf("contact point with uid '%s' not found", mergedReceiver.UID) + oldReceiverNameRef, fullRemoval, newReceiverCreated := stitchReceiver(revision.Config, mergedReceiver) + if oldReceiverNameRef == nil { + return fmt.Errorf("%w: contact point with uid '%s' not found", ErrNotFound, mergedReceiver.UID) } + oldReceiverName := *oldReceiverNameRef err = ecp.xact.InTransaction(ctx, func(ctx context.Context) error { - if mergedReceiver.Name != oldReceiverName { + if mergedReceiver.Name != oldReceiverName && oldReceiverName != "" { if newReceiverCreated { // Copy receiver permissions permissionsUpdated, err := ecp.resourcePermissions.CopyPermissions(ctx, orgID, nil, legacy_storage.NameToUid(oldReceiverName), legacy_storage.NameToUid(mergedReceiver.Name)) @@ -373,12 +374,12 @@ func (ecp *ContactPointService) DeleteContactPoint(ctx context.Context, orgID in } } } - if fullRemoval && revision.ReceiverNameUsedByRoutes(name) { + if fullRemoval && name != "" && revision.ReceiverNameUsedByRoutes(name) { return ErrContactPointReferenced.Errorf("") } return ecp.xact.InTransaction(ctx, func(ctx context.Context) error { - if fullRemoval { + if fullRemoval && name != "" { used, err := ecp.notificationSettingsStore.ListNotificationSettings(ctx, models.ListNotificationSettingsQuery{OrgID: orgID, ReceiverName: name}) if err != nil { return fmt.Errorf("failed to query alert rules for reference to the contact point '%s': %w", name, err) @@ -443,7 +444,7 @@ func (ecp *ContactPointService) encryptValue(value string) (string, error) { // stitchReceiver modifies a receiver, target, in an alertmanager configStore. It modifies the given configStore in-place. // Returns true if the configStore was altered in any way, and false otherwise. // If integration was moved to another group and it was the last in the previous group, the second parameter contains the name of the old group that is gone -func stitchReceiver(cfg *apimodels.PostableUserConfig, target *apimodels.PostableGrafanaReceiver) (oldReceiverName string, fullRemoval bool, newReceiverCreated bool) { +func stitchReceiver(cfg *apimodels.PostableUserConfig, target *apimodels.PostableGrafanaReceiver) (oldReceiverName *string, fullRemoval bool, newReceiverCreated bool) { // Algorithm to fix up receivers. Receivers are very complex and depend heavily on internal consistency. // All receivers in a given receiver group have the same name. We must maintain this across renames. groupLoop: @@ -451,7 +452,8 @@ groupLoop: // Does the current group contain the grafana receiver we're interested in? for i, grafanaReceiver := range receiverGroup.GrafanaManagedReceivers { if grafanaReceiver.UID == target.UID { - oldReceiverName = receiverGroup.Name + name := receiverGroup.Name + oldReceiverName = &name // If it's a basic field change, simply replace it. Done! // // NOTE: @@ -519,6 +521,9 @@ groupLoop: } func ValidateContactPoint(ctx context.Context, e *apimodels.EmbeddedContactPoint, decryptFunc alertingNotify.GetDecryptedValueFn) error { + if e.Name == "" { + return errors.New("name is required") + } iType, err := alertingNotify.IntegrationTypeFromString(e.Type) if err != nil { return err diff --git a/pkg/services/ngalert/provisioning/contactpoints_test.go b/pkg/services/ngalert/provisioning/contactpoints_test.go index 34535c1a504..ddddadb1104 100644 --- a/pkg/services/ngalert/provisioning/contactpoints_test.go +++ b/pkg/services/ngalert/provisioning/contactpoints_test.go @@ -114,16 +114,6 @@ func TestIntegrationContactPointService(t *testing.T) { require.Equal(t, customUID, cps[0].UID) }) - t.Run("it's not possible to use invalid UID", func(t *testing.T) { - customUID := strings.Repeat("1", util.MaxUIDLength+1) - sut := createContactPointServiceSut(t, secretsService) - newCp := createTestContactPoint() - newCp.UID = customUID - - _, err := sut.CreateContactPoint(context.Background(), 1, redactedUser, newCp, models.ProvenanceAPI) - require.ErrorIs(t, err, ErrValidation) - }) - t.Run("it's not possible to use the same uid twice", func(t *testing.T) { customUID := "1337" sut := createContactPointServiceSut(t, secretsService) @@ -137,14 +127,40 @@ func TestIntegrationContactPointService(t *testing.T) { require.Error(t, err) }) - t.Run("create rejects contact points that fail validation", func(t *testing.T) { + t.Run("create rejects invalid contact points", func(t *testing.T) { sut := createContactPointServiceSut(t, secretsService) - newCp := createTestContactPoint() - newCp.Type = "" + testCases := []struct { + name string + cp func(*definitions.EmbeddedContactPoint) + }{ + { + name: "empty type", + cp: func(cp *definitions.EmbeddedContactPoint) { + cp.Type = "" + }, + }, + { + name: "empty name", + cp: func(cp *definitions.EmbeddedContactPoint) { + cp.Name = "" + }, + }, + { + name: "invalid UID", + cp: func(cp *definitions.EmbeddedContactPoint) { + cp.UID = strings.Repeat("1", util.MaxUIDLength+1) + }, + }, + } - _, err := sut.CreateContactPoint(context.Background(), 1, redactedUser, newCp, models.ProvenanceAPI) - - require.ErrorIs(t, err, ErrValidation) + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + newCp := createTestContactPoint() + tc.cp(&newCp) + _, err := sut.CreateContactPoint(context.Background(), 1, redactedUser, newCp, models.ProvenanceAPI) + require.ErrorIs(t, err, ErrValidation) + }) + } }) t.Run("create accepts contact point with type in different cases", func(t *testing.T) { @@ -162,40 +178,57 @@ func TestIntegrationContactPointService(t *testing.T) { assert.EqualValues(t, slack.Type, got[0].Type) }) - t.Run("update rejects contact points with no settings", func(t *testing.T) { + t.Run("update rejects invalid contact points", func(t *testing.T) { + testCases := []struct { + name string + cp func(*definitions.EmbeddedContactPoint) + }{ + { + name: "empty type", + cp: func(cp *definitions.EmbeddedContactPoint) { + cp.Type = "" + }, + }, + { + name: "empty name", + cp: func(cp *definitions.EmbeddedContactPoint) { + cp.Name = "" + }, + }, + { + name: "nil settings", + cp: func(cp *definitions.EmbeddedContactPoint) { + cp.Settings = nil + }, + }, + { + name: "invalid settings after merge", + cp: func(cp *definitions.EmbeddedContactPoint) { + cp.Settings, _ = simplejson.NewJson([]byte(`{}`)) + }, + }, + } + sut := createContactPointServiceSut(t, secretsService) newCp := createTestContactPoint() newCp, err := sut.CreateContactPoint(context.Background(), 1, redactedUser, newCp, models.ProvenanceAPI) require.NoError(t, err) - newCp.Settings = nil - err = sut.UpdateContactPoint(context.Background(), 1, newCp, models.ProvenanceAPI) - - require.ErrorIs(t, err, ErrValidation) - }) - - t.Run("update rejects contact points with no type", func(t *testing.T) { - sut := createContactPointServiceSut(t, secretsService) - newCp := createTestContactPoint() - newCp, err := sut.CreateContactPoint(context.Background(), 1, redactedUser, newCp, models.ProvenanceAPI) - require.NoError(t, err) - newCp.Type = "" - - err = sut.UpdateContactPoint(context.Background(), 1, newCp, models.ProvenanceAPI) - - require.ErrorIs(t, err, ErrValidation) - }) - - t.Run("update rejects contact points which fail validation after merging", func(t *testing.T) { - sut := createContactPointServiceSut(t, secretsService) - newCp := createTestContactPoint() - newCp, err := sut.CreateContactPoint(context.Background(), 1, redactedUser, newCp, models.ProvenanceAPI) - require.NoError(t, err) - newCp.Settings, _ = simplejson.NewJson([]byte(`{}`)) - - err = sut.UpdateContactPoint(context.Background(), 1, newCp, models.ProvenanceAPI) - - require.ErrorIs(t, err, ErrValidation) + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + cp := definitions.EmbeddedContactPoint{ + UID: newCp.UID, + Name: newCp.Name, + Type: newCp.Type, + Settings: newCp.Settings.DeepCopy(), + DisableResolveMessage: newCp.DisableResolveMessage, + Provenance: newCp.Provenance, + } + tc.cp(&cp) + err = sut.UpdateContactPoint(context.Background(), 1, cp, models.ProvenanceAPI) + require.ErrorIs(t, err, ErrValidation) + }) + } }) t.Run("update accepts contact points with type in another case", func(t *testing.T) { @@ -592,7 +625,7 @@ func TestStitchReceivers(t *testing.T) { initial *definitions.PostableUserConfig new *definitions.PostableGrafanaReceiver expCfg definitions.PostableApiAlertingConfig - expOldReceiver string + expOldReceiver *string expCreatedReceiver bool expFullRemoval bool } @@ -603,7 +636,7 @@ func TestStitchReceivers(t *testing.T) { new: &definitions.PostableGrafanaReceiver{ UID: "does not exist", }, - expOldReceiver: "", + expOldReceiver: nil, expCfg: createTestConfigWithReceivers().AlertmanagerConfig, }, { @@ -613,7 +646,7 @@ func TestStitchReceivers(t *testing.T) { Name: "receiver-2", Type: "teams", }, - expOldReceiver: "receiver-2", + expOldReceiver: util.Pointer("receiver-2"), expCfg: definitions.PostableApiAlertingConfig{ Config: definitions.Config{ Route: &definitions.Route{ @@ -674,7 +707,7 @@ func TestStitchReceivers(t *testing.T) { Name: "new-receiver", Type: "slack", }, - expOldReceiver: "receiver-1", + expOldReceiver: util.Pointer("receiver-1"), expCreatedReceiver: true, expFullRemoval: true, expCfg: definitions.PostableApiAlertingConfig{ @@ -737,7 +770,7 @@ func TestStitchReceivers(t *testing.T) { Name: "receiver-1", Type: "slack", }, - expOldReceiver: "receiver-2", + expOldReceiver: util.Pointer("receiver-2"), expCreatedReceiver: false, expCfg: definitions.PostableApiAlertingConfig{ Config: definitions.Config{ @@ -858,7 +891,7 @@ func TestStitchReceivers(t *testing.T) { Name: "receiver-2", Type: "slack", }, - expOldReceiver: "receiver-1", + expOldReceiver: util.Pointer("receiver-1"), expCreatedReceiver: false, expCfg: definitions.PostableApiAlertingConfig{ Config: definitions.Config{ @@ -1002,7 +1035,7 @@ func TestStitchReceivers(t *testing.T) { Name: "receiver-4", Type: "slack", }, - expOldReceiver: "receiver-1", + expOldReceiver: util.Pointer("receiver-1"), expCreatedReceiver: false, expCfg: definitions.PostableApiAlertingConfig{ Config: definitions.Config{ @@ -1087,7 +1120,7 @@ func TestStitchReceivers(t *testing.T) { Name: "brand-new-group", Type: "opsgenie", }, - expOldReceiver: "receiver-2", + expOldReceiver: util.Pointer("receiver-2"), expCreatedReceiver: true, expCfg: definitions.PostableApiAlertingConfig{ Config: definitions.Config{ @@ -1159,7 +1192,7 @@ func TestStitchReceivers(t *testing.T) { Name: "brand-new-group", Type: "opsgenie", }, - expOldReceiver: "receiver-2", // Not the inconsistent receiver-3? + expOldReceiver: util.Pointer("receiver-2"), // Not the inconsistent receiver-3? expCreatedReceiver: true, expCfg: definitions.PostableApiAlertingConfig{ Config: definitions.Config{ @@ -1282,7 +1315,7 @@ func TestStitchReceivers(t *testing.T) { Name: "receiver-1", Type: "slack", }, - expOldReceiver: "receiver-2", + expOldReceiver: util.Pointer("receiver-2"), expCreatedReceiver: false, expFullRemoval: true, expCfg: definitions.PostableApiAlertingConfig{ @@ -1337,7 +1370,7 @@ func TestStitchReceivers(t *testing.T) { } renamedReceiver, fullRemoval, createdReceiver := stitchReceiver(cfg, c.new) - assert.Equalf(t, c.expOldReceiver, renamedReceiver, "expected old receiver to be %s, got %s", c.expOldReceiver, renamedReceiver) + assert.EqualValuesf(t, c.expOldReceiver, renamedReceiver, "expected old receiver to be %v, got %v", c.expOldReceiver, renamedReceiver) assert.Equalf(t, c.expFullRemoval, fullRemoval, "expected full removal to be %t, got %t", c.expFullRemoval, fullRemoval) assert.Equalf(t, c.expCreatedReceiver, createdReceiver, "expected created receiver to be %t, got %t", c.expCreatedReceiver, createdReceiver) require.Equal(t, c.expCfg, cfg.AlertmanagerConfig) From c0c31afdde9b327d7c96ca1205d49f5fa0d620f1 Mon Sep 17 00:00:00 2001 From: "grafana-pr-automation[bot]" <140550294+grafana-pr-automation[bot]@users.noreply.github.com> Date: Thu, 30 Oct 2025 00:40:00 +0000 Subject: [PATCH 107/378] I18n: Download translations from Crowdin (#113191) New Crowdin translations by GitHub Action Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- public/locales/cs-CZ/grafana.json | 31 ++++++++++++++++++++++++++--- public/locales/de-DE/grafana.json | 31 ++++++++++++++++++++++++++--- public/locales/es-ES/grafana.json | 31 ++++++++++++++++++++++++++--- public/locales/fr-FR/grafana.json | 31 ++++++++++++++++++++++++++--- public/locales/hu-HU/grafana.json | 31 ++++++++++++++++++++++++++--- public/locales/id-ID/grafana.json | 31 ++++++++++++++++++++++++++--- public/locales/it-IT/grafana.json | 31 ++++++++++++++++++++++++++--- public/locales/ja-JP/grafana.json | 31 ++++++++++++++++++++++++++--- public/locales/ko-KR/grafana.json | 31 ++++++++++++++++++++++++++--- public/locales/nl-NL/grafana.json | 31 ++++++++++++++++++++++++++--- public/locales/pl-PL/grafana.json | 31 ++++++++++++++++++++++++++--- public/locales/pt-BR/grafana.json | 31 ++++++++++++++++++++++++++--- public/locales/pt-PT/grafana.json | 31 ++++++++++++++++++++++++++--- public/locales/ru-RU/grafana.json | 31 ++++++++++++++++++++++++++--- public/locales/sv-SE/grafana.json | 31 ++++++++++++++++++++++++++--- public/locales/tr-TR/grafana.json | 31 ++++++++++++++++++++++++++--- public/locales/zh-Hans/grafana.json | 31 ++++++++++++++++++++++++++--- public/locales/zh-Hant/grafana.json | 31 ++++++++++++++++++++++++++--- 18 files changed, 504 insertions(+), 54 deletions(-) diff --git a/public/locales/cs-CZ/grafana.json b/public/locales/cs-CZ/grafana.json index 9abd78940c1..2a174ff7420 100644 --- a/public/locales/cs-CZ/grafana.json +++ b/public/locales/cs-CZ/grafana.json @@ -4197,6 +4197,7 @@ "cancel": "Zrušit", "clear": "Vymazat", "collapse": "Sbalit", + "disabled": "", "edit": "Upravit", "help": "Nápověda", "loading": "Načítání…", @@ -5175,6 +5176,19 @@ "aria-label-remove-override": "Odebrat přepsání", "tooltip-remove-override": "Odebrat přepsání" }, + "panel": { + "time-range-settings": { + "hide-time-info": "", + "hide-time-info-description": "", + "time-from": "", + "time-from-description": "", + "time-shift": "", + "time-shift-description": "", + "time-window-compare": "", + "time-window-compare-description": "", + "title": "" + } + }, "panel-edit": { "alerting-tab": { "dashboard-not-saved": "Před přidáním výstrahy musí být nástěnka uložena.", @@ -5730,6 +5744,11 @@ "open-in-new-tab": "Otevřít v nové záložce", "title-error-adding-the-panel": "Chyba při přidávání panelu" }, + "add-to-dashboard-form-exposed": { + "title": { + "new-panel": "" + } + }, "annotation-settings-edit": { "back-to-list": "Zpět na seznam", "delete": "Odstranit", @@ -7694,7 +7713,6 @@ } }, "folder-filter": { - "noOptionsMessage-no-folders-found": "Nebyly nalezeny žádné složky", "select-aria-label": "Filtr složky", "select-placeholder": "Filtrovat podle složky" }, @@ -10964,6 +10982,7 @@ "replace-library-panel": "Vyměnit panel knihovny", "share": "Sdílet", "show-legend": "Zobrazit legendu", + "time-settings": "", "unlink-library-panel": "Odpojit panel knihovny", "view": "Zobrazit" }, @@ -12400,8 +12419,6 @@ "title": "Vyberte rozsahy" }, "tree": { - "collapse": "", - "expand": "", "headline": { "noResults": "Nebyly nalezeny žádné výsledky pro váš dotaz", "recommended": "Doporučeno", @@ -13249,6 +13266,14 @@ "title": "Panel" } }, + "time-period": { + "1_day": "", + "1_hour": "", + "12_hours": "", + "30_days": "", + "6_hours": "", + "7_days": "" + }, "time-picker": { "absolute": { "recent-title": "Naposledy použité absolutní rozsahy", diff --git a/public/locales/de-DE/grafana.json b/public/locales/de-DE/grafana.json index 6aa5ee76432..b57ca0032d4 100644 --- a/public/locales/de-DE/grafana.json +++ b/public/locales/de-DE/grafana.json @@ -4157,6 +4157,7 @@ "cancel": "Abbrechen", "clear": "Löschen", "collapse": "Einklappen", + "disabled": "", "edit": "Bearbeiten", "help": "Hilfe", "loading": "Wird geladen ...", @@ -5133,6 +5134,19 @@ "aria-label-remove-override": "Überschreibung entfernen", "tooltip-remove-override": "Überschreibung entfernen" }, + "panel": { + "time-range-settings": { + "hide-time-info": "", + "hide-time-info-description": "", + "time-from": "", + "time-from-description": "", + "time-shift": "", + "time-shift-description": "", + "time-window-compare": "", + "time-window-compare-description": "", + "title": "" + } + }, "panel-edit": { "alerting-tab": { "dashboard-not-saved": "Das Dashboard muss gespeichert werden, bevor Warnungen hinzugefügt werden können.", @@ -5688,6 +5702,11 @@ "open-in-new-tab": "In neuem Tab öffnen", "title-error-adding-the-panel": "Fehler beim Hinzufügen des Panels" }, + "add-to-dashboard-form-exposed": { + "title": { + "new-panel": "" + } + }, "annotation-settings-edit": { "back-to-list": "Zurück zur Liste", "delete": "Löschen", @@ -7644,7 +7663,6 @@ } }, "folder-filter": { - "noOptionsMessage-no-folders-found": "Keine Ordner gefunden", "select-aria-label": "Ordnerfilter", "select-placeholder": "Nach Ordner filtern" }, @@ -10872,6 +10890,7 @@ "replace-library-panel": "Bibliotheks-Panel ersetzen", "share": "Teilen", "show-legend": "Legende anzeigen", + "time-settings": "", "unlink-library-panel": "Verknüpfung mit der Bibliotheksleiste aufheben", "view": "Anzeigen" }, @@ -12290,8 +12309,6 @@ "title": "Bereiche auswählen" }, "tree": { - "collapse": "", - "expand": "", "headline": { "noResults": "Keine Ergebnisse für deine Abfrage gefunden", "recommended": "Empfohlen", @@ -13135,6 +13152,14 @@ "title": "Panel" } }, + "time-period": { + "1_day": "", + "1_hour": "", + "12_hours": "", + "30_days": "", + "6_hours": "", + "7_days": "" + }, "time-picker": { "absolute": { "recent-title": "Kürzlich verwendete absolute Bereiche", diff --git a/public/locales/es-ES/grafana.json b/public/locales/es-ES/grafana.json index 6e93bc641b8..6503fc1080e 100644 --- a/public/locales/es-ES/grafana.json +++ b/public/locales/es-ES/grafana.json @@ -4157,6 +4157,7 @@ "cancel": "Cancelar", "clear": "Borrar", "collapse": "Contraer", + "disabled": "", "edit": "Editar", "help": "Ayuda", "loading": "Cargando...", @@ -5133,6 +5134,19 @@ "aria-label-remove-override": "Quitar anulación", "tooltip-remove-override": "Quitar anulación" }, + "panel": { + "time-range-settings": { + "hide-time-info": "", + "hide-time-info-description": "", + "time-from": "", + "time-from-description": "", + "time-shift": "", + "time-shift-description": "", + "time-window-compare": "", + "time-window-compare-description": "", + "title": "" + } + }, "panel-edit": { "alerting-tab": { "dashboard-not-saved": "El panel de control debe guardarse antes de poder añadir alertas.", @@ -5688,6 +5702,11 @@ "open-in-new-tab": "Abrir en pestaña nueva", "title-error-adding-the-panel": "Error al añadir el panel" }, + "add-to-dashboard-form-exposed": { + "title": { + "new-panel": "" + } + }, "annotation-settings-edit": { "back-to-list": "Regresar a la lista", "delete": "Eliminar", @@ -7644,7 +7663,6 @@ } }, "folder-filter": { - "noOptionsMessage-no-folders-found": "No se han encontrado carpetas", "select-aria-label": "Filtro de carpeta", "select-placeholder": "Filtrar por carpeta" }, @@ -10872,6 +10890,7 @@ "replace-library-panel": "Reemplazar panel de la biblioteca", "share": "Compartir", "show-legend": "Mostrar leyenda", + "time-settings": "", "unlink-library-panel": "Desvincular panel de librería", "view": "Vista" }, @@ -12290,8 +12309,6 @@ "title": "Seleccionar ámbitos" }, "tree": { - "collapse": "", - "expand": "", "headline": { "noResults": "No se han encontrado resultados para tu consulta", "recommended": "Recomendado", @@ -13135,6 +13152,14 @@ "title": "Panel" } }, + "time-period": { + "1_day": "", + "1_hour": "", + "12_hours": "", + "30_days": "", + "6_hours": "", + "7_days": "" + }, "time-picker": { "absolute": { "recent-title": "Intervalos absolutos utilizados recientemente", diff --git a/public/locales/fr-FR/grafana.json b/public/locales/fr-FR/grafana.json index 5f59f4eb023..7acded43c93 100644 --- a/public/locales/fr-FR/grafana.json +++ b/public/locales/fr-FR/grafana.json @@ -4157,6 +4157,7 @@ "cancel": "Annuler", "clear": "Effacer", "collapse": "Réduire", + "disabled": "", "edit": "Modifier", "help": "Aide", "loading": "Chargement en cours...", @@ -5133,6 +5134,19 @@ "aria-label-remove-override": "Retirer le remplacement", "tooltip-remove-override": "Retirer le remplacement" }, + "panel": { + "time-range-settings": { + "hide-time-info": "", + "hide-time-info-description": "", + "time-from": "", + "time-from-description": "", + "time-shift": "", + "time-shift-description": "", + "time-window-compare": "", + "time-window-compare-description": "", + "title": "" + } + }, "panel-edit": { "alerting-tab": { "dashboard-not-saved": "Le tableau de bord doit être enregistré avant de pouvoir ajouter des alertes.", @@ -5688,6 +5702,11 @@ "open-in-new-tab": "Ouvrir dans un nouvel onglet", "title-error-adding-the-panel": "Erreur lors de l’ajout du panneau" }, + "add-to-dashboard-form-exposed": { + "title": { + "new-panel": "" + } + }, "annotation-settings-edit": { "back-to-list": "Retour à la liste", "delete": "Supprimer", @@ -7644,7 +7663,6 @@ } }, "folder-filter": { - "noOptionsMessage-no-folders-found": "Aucun dossier trouvé", "select-aria-label": "Filtre de dossier", "select-placeholder": "Filtrer par dossier" }, @@ -10872,6 +10890,7 @@ "replace-library-panel": "Remplacer le panneau de bibliothèque", "share": "Partager", "show-legend": "Afficher la légende", + "time-settings": "", "unlink-library-panel": "Dissocier le panneau de la bibliothèque", "view": "Afficher" }, @@ -12290,8 +12309,6 @@ "title": "Sélectionner les portées" }, "tree": { - "collapse": "", - "expand": "", "headline": { "noResults": "Aucun résultat n'a été trouvé pour votre requête", "recommended": "Recommandé", @@ -13135,6 +13152,14 @@ "title": "Panneau" } }, + "time-period": { + "1_day": "", + "1_hour": "", + "12_hours": "", + "30_days": "", + "6_hours": "", + "7_days": "" + }, "time-picker": { "absolute": { "recent-title": "Périodes absolues récemment utilisées", diff --git a/public/locales/hu-HU/grafana.json b/public/locales/hu-HU/grafana.json index c18d53a7831..3da3dec91b9 100644 --- a/public/locales/hu-HU/grafana.json +++ b/public/locales/hu-HU/grafana.json @@ -4157,6 +4157,7 @@ "cancel": "Mégse", "clear": "Törlés", "collapse": "Összecsukás", + "disabled": "", "edit": "Szerkesztés", "help": "Súgó", "loading": "Betöltés...", @@ -5133,6 +5134,19 @@ "aria-label-remove-override": "Felülbírálás eltávolítása", "tooltip-remove-override": "Felülbírálás eltávolítása" }, + "panel": { + "time-range-settings": { + "hide-time-info": "", + "hide-time-info-description": "", + "time-from": "", + "time-from-description": "", + "time-shift": "", + "time-shift-description": "", + "time-window-compare": "", + "time-window-compare-description": "", + "title": "" + } + }, "panel-edit": { "alerting-tab": { "dashboard-not-saved": "Riasztások hozzáadása előtt menteni kell az irányítópultot.", @@ -5688,6 +5702,11 @@ "open-in-new-tab": "Megnyitás új lapon", "title-error-adding-the-panel": "Hiba történt a panel hozzáadásakor" }, + "add-to-dashboard-form-exposed": { + "title": { + "new-panel": "" + } + }, "annotation-settings-edit": { "back-to-list": "Vissza a listához", "delete": "Törlés", @@ -7644,7 +7663,6 @@ } }, "folder-filter": { - "noOptionsMessage-no-folders-found": "Nem található mappa", "select-aria-label": "Mappaszűrő", "select-placeholder": "Szűrés mappa alapján" }, @@ -10872,6 +10890,7 @@ "replace-library-panel": "Könyvtárpanel cseréje", "share": "Megosztás", "show-legend": "Jelmagyarázat megjelenítése", + "time-settings": "", "unlink-library-panel": "Könyvtárpanel leválasztása", "view": "Nézet" }, @@ -12290,8 +12309,6 @@ "title": "Hatókörök kijelölése" }, "tree": { - "collapse": "", - "expand": "", "headline": { "noResults": "Nincs találat a lekérdezésre", "recommended": "Ajánlott", @@ -13135,6 +13152,14 @@ "title": "Panel" } }, + "time-period": { + "1_day": "", + "1_hour": "", + "12_hours": "", + "30_days": "", + "6_hours": "", + "7_days": "" + }, "time-picker": { "absolute": { "recent-title": "Legutóbb használt abszolút tartományok", diff --git a/public/locales/id-ID/grafana.json b/public/locales/id-ID/grafana.json index 97627226a56..e7be931cea2 100644 --- a/public/locales/id-ID/grafana.json +++ b/public/locales/id-ID/grafana.json @@ -4137,6 +4137,7 @@ "cancel": "Batalkan", "clear": "Hapus", "collapse": "Ciutkan", + "disabled": "", "edit": "Edit", "help": "Bantuan", "loading": "Memuat...", @@ -5112,6 +5113,19 @@ "aria-label-remove-override": "Hapus penimpaan", "tooltip-remove-override": "Hapus penimpaan" }, + "panel": { + "time-range-settings": { + "hide-time-info": "", + "hide-time-info-description": "", + "time-from": "", + "time-from-description": "", + "time-shift": "", + "time-shift-description": "", + "time-window-compare": "", + "time-window-compare-description": "", + "title": "" + } + }, "panel-edit": { "alerting-tab": { "dashboard-not-saved": "Dasbor harus disimpan sebelum peringatan dapat ditambahkan.", @@ -5667,6 +5681,11 @@ "open-in-new-tab": "Buka di tab baru", "title-error-adding-the-panel": "Kesalahan saat menambahkan panel" }, + "add-to-dashboard-form-exposed": { + "title": { + "new-panel": "" + } + }, "annotation-settings-edit": { "back-to-list": "Kembali ke daftar", "delete": "Hapus", @@ -7619,7 +7638,6 @@ } }, "folder-filter": { - "noOptionsMessage-no-folders-found": "Folder tidak ditemukan", "select-aria-label": "Filter folder", "select-placeholder": "Filter berdasarkan folder" }, @@ -10826,6 +10844,7 @@ "replace-library-panel": "Ganti panel pustaka", "share": "Bagikan", "show-legend": "Tampilkan keterangan", + "time-settings": "", "unlink-library-panel": "Putuskan tautan panel pustaka", "view": "Lihat" }, @@ -12235,8 +12254,6 @@ "title": "Pilih cakupan" }, "tree": { - "collapse": "", - "expand": "", "headline": { "noResults": "Hasil untuk kueri Anda tidak ditemukan", "recommended": "Disarankan", @@ -13078,6 +13095,14 @@ "title": "Panel" } }, + "time-period": { + "1_day": "", + "1_hour": "", + "12_hours": "", + "30_days": "", + "6_hours": "", + "7_days": "" + }, "time-picker": { "absolute": { "recent-title": "Rentang absolut yang baru digunakan", diff --git a/public/locales/it-IT/grafana.json b/public/locales/it-IT/grafana.json index 4b5dc671573..76d6ebd06a5 100644 --- a/public/locales/it-IT/grafana.json +++ b/public/locales/it-IT/grafana.json @@ -4157,6 +4157,7 @@ "cancel": "Annulla", "clear": "Cancella", "collapse": "Riduci", + "disabled": "", "edit": "Modifica", "help": "Guida", "loading": "Caricamento in corso...", @@ -5133,6 +5134,19 @@ "aria-label-remove-override": "Rimuovi sovrascrittura", "tooltip-remove-override": "Rimuovi sovrascrittura" }, + "panel": { + "time-range-settings": { + "hide-time-info": "", + "hide-time-info-description": "", + "time-from": "", + "time-from-description": "", + "time-shift": "", + "time-shift-description": "", + "time-window-compare": "", + "time-window-compare-description": "", + "title": "" + } + }, "panel-edit": { "alerting-tab": { "dashboard-not-saved": "Il dashboard deve essere salvato prima di poter aggiungere avvisi.", @@ -5688,6 +5702,11 @@ "open-in-new-tab": "Apri in una nuova scheda", "title-error-adding-the-panel": "Errore durante l'aggiunta del pannello" }, + "add-to-dashboard-form-exposed": { + "title": { + "new-panel": "" + } + }, "annotation-settings-edit": { "back-to-list": "Torna all'elenco", "delete": "Elimina", @@ -7644,7 +7663,6 @@ } }, "folder-filter": { - "noOptionsMessage-no-folders-found": "Nessuna cartella trovata", "select-aria-label": "Filtro cartelle", "select-placeholder": "Filtra per cartella" }, @@ -10872,6 +10890,7 @@ "replace-library-panel": "Sostituisci il pannello della libreria", "share": "Condividi", "show-legend": "Mostra leggenda", + "time-settings": "", "unlink-library-panel": "Scollega pannello della libreria", "view": "Visualizza" }, @@ -12290,8 +12309,6 @@ "title": "Seleziona gli ambiti" }, "tree": { - "collapse": "", - "expand": "", "headline": { "noResults": "Nessun risultato trovato per la ricerca", "recommended": "Consigliato", @@ -13135,6 +13152,14 @@ "title": "Pannello" } }, + "time-period": { + "1_day": "", + "1_hour": "", + "12_hours": "", + "30_days": "", + "6_hours": "", + "7_days": "" + }, "time-picker": { "absolute": { "recent-title": "Intervalli assoluti utilizzati di recente", diff --git a/public/locales/ja-JP/grafana.json b/public/locales/ja-JP/grafana.json index 5b24acb3434..a41d40d75f8 100644 --- a/public/locales/ja-JP/grafana.json +++ b/public/locales/ja-JP/grafana.json @@ -4137,6 +4137,7 @@ "cancel": "キャンセル", "clear": "消去", "collapse": "折りたたみ表示", + "disabled": "", "edit": "編集", "help": "ヘルプ", "loading": "読み込み中...", @@ -5112,6 +5113,19 @@ "aria-label-remove-override": "オーバーライドを削除", "tooltip-remove-override": "オーバーライドを削除" }, + "panel": { + "time-range-settings": { + "hide-time-info": "", + "hide-time-info-description": "", + "time-from": "", + "time-from-description": "", + "time-shift": "", + "time-shift-description": "", + "time-window-compare": "", + "time-window-compare-description": "", + "title": "" + } + }, "panel-edit": { "alerting-tab": { "dashboard-not-saved": "アラートを追加する前に、ダッシュボードを保存する必要があります。", @@ -5667,6 +5681,11 @@ "open-in-new-tab": "新しいタブで開く", "title-error-adding-the-panel": "パネル追加時のエラー" }, + "add-to-dashboard-form-exposed": { + "title": { + "new-panel": "" + } + }, "annotation-settings-edit": { "back-to-list": "一覧に戻る", "delete": "削除", @@ -7619,7 +7638,6 @@ } }, "folder-filter": { - "noOptionsMessage-no-folders-found": "フォルダが見つかりません", "select-aria-label": "フォルダフィルター", "select-placeholder": "フォルダでフィルタリング" }, @@ -10826,6 +10844,7 @@ "replace-library-panel": "ライブラリパネルを置き換える", "share": "共有", "show-legend": "凡例を表示", + "time-settings": "", "unlink-library-panel": "ライブラリパネルのリンクを解除", "view": "表示" }, @@ -12235,8 +12254,6 @@ "title": "スコープを選択" }, "tree": { - "collapse": "", - "expand": "", "headline": { "noResults": "クエリに一致する結果が見つかりませんでした。", "recommended": "おすすめ", @@ -13078,6 +13095,14 @@ "title": "パネル" } }, + "time-period": { + "1_day": "", + "1_hour": "", + "12_hours": "", + "30_days": "", + "6_hours": "", + "7_days": "" + }, "time-picker": { "absolute": { "recent-title": "最近使用した絶対的な範囲", diff --git a/public/locales/ko-KR/grafana.json b/public/locales/ko-KR/grafana.json index 469989c8707..1f3be6553d3 100644 --- a/public/locales/ko-KR/grafana.json +++ b/public/locales/ko-KR/grafana.json @@ -4137,6 +4137,7 @@ "cancel": "취소", "clear": "초기화", "collapse": "접기", + "disabled": "", "edit": "편집", "help": "도움말", "loading": "로딩 중...", @@ -5112,6 +5113,19 @@ "aria-label-remove-override": "재정의 제거", "tooltip-remove-override": "재정의 제거" }, + "panel": { + "time-range-settings": { + "hide-time-info": "", + "hide-time-info-description": "", + "time-from": "", + "time-from-description": "", + "time-shift": "", + "time-shift-description": "", + "time-window-compare": "", + "time-window-compare-description": "", + "title": "" + } + }, "panel-edit": { "alerting-tab": { "dashboard-not-saved": "경고를 추가하기 전에 먼저 대시보드를 저장해야 합니다.", @@ -5667,6 +5681,11 @@ "open-in-new-tab": "새 탭에서 열기", "title-error-adding-the-panel": "패널 추가 중 오류 발생" }, + "add-to-dashboard-form-exposed": { + "title": { + "new-panel": "" + } + }, "annotation-settings-edit": { "back-to-list": "목록으로 돌아가기", "delete": "삭제", @@ -7619,7 +7638,6 @@ } }, "folder-filter": { - "noOptionsMessage-no-folders-found": "폴더를 찾을 수 없습니다", "select-aria-label": "폴더 필터", "select-placeholder": "폴더별로 필터링" }, @@ -10826,6 +10844,7 @@ "replace-library-panel": "라이브러리 패널 교체", "share": "공유", "show-legend": "범례 보기", + "time-settings": "", "unlink-library-panel": "라이브러리 패널 연결 해제", "view": "보기" }, @@ -12235,8 +12254,6 @@ "title": "범위 선택" }, "tree": { - "collapse": "", - "expand": "", "headline": { "noResults": "쿼리에 대해 찾은 결과 없음", "recommended": "권장", @@ -13078,6 +13095,14 @@ "title": "패널" } }, + "time-period": { + "1_day": "", + "1_hour": "", + "12_hours": "", + "30_days": "", + "6_hours": "", + "7_days": "" + }, "time-picker": { "absolute": { "recent-title": "최근에 사용한 절대 범위", diff --git a/public/locales/nl-NL/grafana.json b/public/locales/nl-NL/grafana.json index 9e46e64fb84..4c263008165 100644 --- a/public/locales/nl-NL/grafana.json +++ b/public/locales/nl-NL/grafana.json @@ -4157,6 +4157,7 @@ "cancel": "Annuleren", "clear": "Wissen", "collapse": "Samenvouwen", + "disabled": "", "edit": "Bewerken", "help": "Help", "loading": "Bezig met laden ...", @@ -5133,6 +5134,19 @@ "aria-label-remove-override": "Overschrijving verwijderen", "tooltip-remove-override": "Overschrijving verwijderen" }, + "panel": { + "time-range-settings": { + "hide-time-info": "", + "hide-time-info-description": "", + "time-from": "", + "time-from-description": "", + "time-shift": "", + "time-shift-description": "", + "time-window-compare": "", + "time-window-compare-description": "", + "title": "" + } + }, "panel-edit": { "alerting-tab": { "dashboard-not-saved": "Dashboard moet worden opgeslagen voordat waarschuwingen kunnen worden toegevoegd.", @@ -5688,6 +5702,11 @@ "open-in-new-tab": "In een nieuw tabblad openen", "title-error-adding-the-panel": "Er is een fout opgetreden bij het toevoegen van het paneel" }, + "add-to-dashboard-form-exposed": { + "title": { + "new-panel": "" + } + }, "annotation-settings-edit": { "back-to-list": "Terug naar lijst", "delete": "Verwijderen", @@ -7644,7 +7663,6 @@ } }, "folder-filter": { - "noOptionsMessage-no-folders-found": "Geen mappen gevonden", "select-aria-label": "Mapfilter", "select-placeholder": "Filteren op map" }, @@ -10872,6 +10890,7 @@ "replace-library-panel": "Bibliotheekpaneel vervangen", "share": "Delen", "show-legend": "Legenda tonen", + "time-settings": "", "unlink-library-panel": "Bibliotheekpaneel ontkoppelen", "view": "Weergave" }, @@ -12290,8 +12309,6 @@ "title": "Scopes selecteren" }, "tree": { - "collapse": "", - "expand": "", "headline": { "noResults": "Geen resultaten gevonden voor je zoekopdracht", "recommended": "Aanbevolen", @@ -13135,6 +13152,14 @@ "title": "Paneel" } }, + "time-period": { + "1_day": "", + "1_hour": "", + "12_hours": "", + "30_days": "", + "6_hours": "", + "7_days": "" + }, "time-picker": { "absolute": { "recent-title": "Recent gebruikte absolute bereiken", diff --git a/public/locales/pl-PL/grafana.json b/public/locales/pl-PL/grafana.json index ab686289d01..c308ccfeaf8 100644 --- a/public/locales/pl-PL/grafana.json +++ b/public/locales/pl-PL/grafana.json @@ -4197,6 +4197,7 @@ "cancel": "Anuluj", "clear": "Wyczyść", "collapse": "Zwiń", + "disabled": "", "edit": "Edytuj", "help": "Pomoc", "loading": "Ładowanie…", @@ -5175,6 +5176,19 @@ "aria-label-remove-override": "Usuń zastąpienie", "tooltip-remove-override": "Usuń zastąpienie" }, + "panel": { + "time-range-settings": { + "hide-time-info": "", + "hide-time-info-description": "", + "time-from": "", + "time-from-description": "", + "time-shift": "", + "time-shift-description": "", + "time-window-compare": "", + "time-window-compare-description": "", + "title": "" + } + }, "panel-edit": { "alerting-tab": { "dashboard-not-saved": "Przed dodaniem alertów należy zapisać pulpit.", @@ -5730,6 +5744,11 @@ "open-in-new-tab": "Otwórz w nowej karcie", "title-error-adding-the-panel": "Błąd dodawania panelu" }, + "add-to-dashboard-form-exposed": { + "title": { + "new-panel": "" + } + }, "annotation-settings-edit": { "back-to-list": "Powrót do listy", "delete": "Usuń", @@ -7694,7 +7713,6 @@ } }, "folder-filter": { - "noOptionsMessage-no-folders-found": "Nie znaleziono folderów", "select-aria-label": "Filtr folderów", "select-placeholder": "Filtruj wg folderu" }, @@ -10964,6 +10982,7 @@ "replace-library-panel": "Zastąp panel biblioteki", "share": "Udostępnij", "show-legend": "Pokaż legendę", + "time-settings": "", "unlink-library-panel": "Rozłącz panel biblioteki", "view": "Widok" }, @@ -12400,8 +12419,6 @@ "title": "Wybierz zakresy" }, "tree": { - "collapse": "", - "expand": "", "headline": { "noResults": "Nie znaleziono wyników dla tego zapytania", "recommended": "Zalecane", @@ -13249,6 +13266,14 @@ "title": "Panel" } }, + "time-period": { + "1_day": "", + "1_hour": "", + "12_hours": "", + "30_days": "", + "6_hours": "", + "7_days": "" + }, "time-picker": { "absolute": { "recent-title": "Ostatnio używane zakresy bezwzględne", diff --git a/public/locales/pt-BR/grafana.json b/public/locales/pt-BR/grafana.json index 9b2d4662786..2287cd91f81 100644 --- a/public/locales/pt-BR/grafana.json +++ b/public/locales/pt-BR/grafana.json @@ -4157,6 +4157,7 @@ "cancel": "Cancelar", "clear": "Limpar", "collapse": "Recolher", + "disabled": "", "edit": "Editar", "help": "Ajuda", "loading": "Carregando...", @@ -5133,6 +5134,19 @@ "aria-label-remove-override": "Remover substituição", "tooltip-remove-override": "Remover substituição" }, + "panel": { + "time-range-settings": { + "hide-time-info": "", + "hide-time-info-description": "", + "time-from": "", + "time-from-description": "", + "time-shift": "", + "time-shift-description": "", + "time-window-compare": "", + "time-window-compare-description": "", + "title": "" + } + }, "panel-edit": { "alerting-tab": { "dashboard-not-saved": "O painel de controle deve ser salvo para que os alertas possam ser adicionados.", @@ -5688,6 +5702,11 @@ "open-in-new-tab": "Abrir em nova aba", "title-error-adding-the-panel": "Erro ao adicionar o painel" }, + "add-to-dashboard-form-exposed": { + "title": { + "new-panel": "" + } + }, "annotation-settings-edit": { "back-to-list": "Voltar para a lista", "delete": "Excluir", @@ -7644,7 +7663,6 @@ } }, "folder-filter": { - "noOptionsMessage-no-folders-found": "Nenhuma pasta encontrada", "select-aria-label": "Filtro de pasta", "select-placeholder": "Filtrar por pasta" }, @@ -10872,6 +10890,7 @@ "replace-library-panel": "Substituir painel da biblioteca", "share": "Compartilhar", "show-legend": "Mostrar legenda", + "time-settings": "", "unlink-library-panel": "Desvincular painel de biblioteca", "view": "Visualizar" }, @@ -12290,8 +12309,6 @@ "title": "Selecionar escopos" }, "tree": { - "collapse": "", - "expand": "", "headline": { "noResults": "Nenhum resultado encontrado para sua consulta", "recommended": "Recomendado", @@ -13135,6 +13152,14 @@ "title": "Painel" } }, + "time-period": { + "1_day": "", + "1_hour": "", + "12_hours": "", + "30_days": "", + "6_hours": "", + "7_days": "" + }, "time-picker": { "absolute": { "recent-title": "Intervalos absolutos usados recentemente", diff --git a/public/locales/pt-PT/grafana.json b/public/locales/pt-PT/grafana.json index db0d3d98b1a..48b38a197d7 100644 --- a/public/locales/pt-PT/grafana.json +++ b/public/locales/pt-PT/grafana.json @@ -4157,6 +4157,7 @@ "cancel": "Cancelar", "clear": "Limpar", "collapse": "Recolher", + "disabled": "", "edit": "Editar", "help": "Ajuda", "loading": "A carregar...", @@ -5133,6 +5134,19 @@ "aria-label-remove-override": "Remover a substituição", "tooltip-remove-override": "Remover a substituição" }, + "panel": { + "time-range-settings": { + "hide-time-info": "", + "hide-time-info-description": "", + "time-from": "", + "time-from-description": "", + "time-shift": "", + "time-shift-description": "", + "time-window-compare": "", + "time-window-compare-description": "", + "title": "" + } + }, "panel-edit": { "alerting-tab": { "dashboard-not-saved": "O painel de controlo deve ser guardado antes de poderem ser adicionados alertas.", @@ -5688,6 +5702,11 @@ "open-in-new-tab": "Abrir num novo separador", "title-error-adding-the-panel": "Erro ao adicionar o painel" }, + "add-to-dashboard-form-exposed": { + "title": { + "new-panel": "" + } + }, "annotation-settings-edit": { "back-to-list": "Voltar à lista", "delete": "Eliminar", @@ -7644,7 +7663,6 @@ } }, "folder-filter": { - "noOptionsMessage-no-folders-found": "Nenhuma pasta encontrada", "select-aria-label": "Filtro de pastas", "select-placeholder": "Filtrar por pasta" }, @@ -10872,6 +10890,7 @@ "replace-library-panel": "Substituir painel de biblioteca", "share": "Partilhar", "show-legend": "Mostrar legenda", + "time-settings": "", "unlink-library-panel": "Desassociar painel de biblioteca", "view": "Ver" }, @@ -12290,8 +12309,6 @@ "title": "Selecionar âmbitos" }, "tree": { - "collapse": "", - "expand": "", "headline": { "noResults": "Não foram encontrados resultados para a sua consulta", "recommended": "Recomendado", @@ -13135,6 +13152,14 @@ "title": "Painel" } }, + "time-period": { + "1_day": "", + "1_hour": "", + "12_hours": "", + "30_days": "", + "6_hours": "", + "7_days": "" + }, "time-picker": { "absolute": { "recent-title": "Intervalos absolutos usados recentemente", diff --git a/public/locales/ru-RU/grafana.json b/public/locales/ru-RU/grafana.json index 51037975989..da5960489da 100644 --- a/public/locales/ru-RU/grafana.json +++ b/public/locales/ru-RU/grafana.json @@ -4197,6 +4197,7 @@ "cancel": "Отмена", "clear": "Очистить", "collapse": "Свернуть", + "disabled": "", "edit": "Редактировать", "help": "Справка", "loading": "Загрузка…", @@ -5175,6 +5176,19 @@ "aria-label-remove-override": "Удалить переопределение", "tooltip-remove-override": "Удалить переопределение" }, + "panel": { + "time-range-settings": { + "hide-time-info": "", + "hide-time-info-description": "", + "time-from": "", + "time-from-description": "", + "time-shift": "", + "time-shift-description": "", + "time-window-compare": "", + "time-window-compare-description": "", + "title": "" + } + }, "panel-edit": { "alerting-tab": { "dashboard-not-saved": "Перед добавлением оповещений необходимо сохранить дашборд.", @@ -5730,6 +5744,11 @@ "open-in-new-tab": "Открыть в новой вкладке", "title-error-adding-the-panel": "Ошибка при добавлении панели" }, + "add-to-dashboard-form-exposed": { + "title": { + "new-panel": "" + } + }, "annotation-settings-edit": { "back-to-list": "Назад к списку", "delete": "Удалить", @@ -7694,7 +7713,6 @@ } }, "folder-filter": { - "noOptionsMessage-no-folders-found": "Папки не найдены", "select-aria-label": "Фильтр папок", "select-placeholder": "Фильтровать по папкам" }, @@ -10964,6 +10982,7 @@ "replace-library-panel": "Заменить панель библиотеки", "share": "Общий доступ", "show-legend": "Показать условные обозначения", + "time-settings": "", "unlink-library-panel": "Отсоединить панель библиотеки", "view": "Просмотр" }, @@ -12400,8 +12419,6 @@ "title": "Выбор областей" }, "tree": { - "collapse": "", - "expand": "", "headline": { "noResults": "По вашему запросу ничего не найдено", "recommended": "Рекомендуемые", @@ -13249,6 +13266,14 @@ "title": "Панель" } }, + "time-period": { + "1_day": "", + "1_hour": "", + "12_hours": "", + "30_days": "", + "6_hours": "", + "7_days": "" + }, "time-picker": { "absolute": { "recent-title": "Последние использованные абсолютные диапазоны", diff --git a/public/locales/sv-SE/grafana.json b/public/locales/sv-SE/grafana.json index 5ede98266b1..8e96d2aaae8 100644 --- a/public/locales/sv-SE/grafana.json +++ b/public/locales/sv-SE/grafana.json @@ -4157,6 +4157,7 @@ "cancel": "Avbryt", "clear": "Rensa", "collapse": "Minimera", + "disabled": "", "edit": "Redigera", "help": "Hjälp", "loading": "Laddar …", @@ -5133,6 +5134,19 @@ "aria-label-remove-override": "Ta bort åsidosättning", "tooltip-remove-override": "Ta bort åsidosättning" }, + "panel": { + "time-range-settings": { + "hide-time-info": "", + "hide-time-info-description": "", + "time-from": "", + "time-from-description": "", + "time-shift": "", + "time-shift-description": "", + "time-window-compare": "", + "time-window-compare-description": "", + "title": "" + } + }, "panel-edit": { "alerting-tab": { "dashboard-not-saved": "Instrumentpanelen måste sparas innan varningar kan läggas till.", @@ -5688,6 +5702,11 @@ "open-in-new-tab": "Öppna i ny flik", "title-error-adding-the-panel": "Fel vid tillägg av panelen" }, + "add-to-dashboard-form-exposed": { + "title": { + "new-panel": "" + } + }, "annotation-settings-edit": { "back-to-list": "Tillbaka till listan", "delete": "Ta bort", @@ -7644,7 +7663,6 @@ } }, "folder-filter": { - "noOptionsMessage-no-folders-found": "Inga mappar hittades", "select-aria-label": "Mappfilter", "select-placeholder": "Filtrera efter mapp" }, @@ -10872,6 +10890,7 @@ "replace-library-panel": "Byt ut bibliotekspanel", "share": "Dela", "show-legend": "Visa förklaring", + "time-settings": "", "unlink-library-panel": "Ta bort länk till bibliotekspanel", "view": "Visa" }, @@ -12290,8 +12309,6 @@ "title": "Välj omfattningar" }, "tree": { - "collapse": "", - "expand": "", "headline": { "noResults": "Inga resultat hittades för din fråga", "recommended": "Rekommenderas", @@ -13135,6 +13152,14 @@ "title": "Panel" } }, + "time-period": { + "1_day": "", + "1_hour": "", + "12_hours": "", + "30_days": "", + "6_hours": "", + "7_days": "" + }, "time-picker": { "absolute": { "recent-title": "Nyligen använda absoluta intervall", diff --git a/public/locales/tr-TR/grafana.json b/public/locales/tr-TR/grafana.json index 432dfa7979f..e6682536014 100644 --- a/public/locales/tr-TR/grafana.json +++ b/public/locales/tr-TR/grafana.json @@ -4157,6 +4157,7 @@ "cancel": "İptal", "clear": "Temizle", "collapse": "Daralt", + "disabled": "", "edit": "Düzenle", "help": "Yardım", "loading": "Yükleniyor...", @@ -5133,6 +5134,19 @@ "aria-label-remove-override": "Geçersiz kılmayı kaldır", "tooltip-remove-override": "Geçersiz kılmayı kaldır" }, + "panel": { + "time-range-settings": { + "hide-time-info": "", + "hide-time-info-description": "", + "time-from": "", + "time-from-description": "", + "time-shift": "", + "time-shift-description": "", + "time-window-compare": "", + "time-window-compare-description": "", + "title": "" + } + }, "panel-edit": { "alerting-tab": { "dashboard-not-saved": "Uyarılar eklenmeden önce pano kaydedilmelidir.", @@ -5688,6 +5702,11 @@ "open-in-new-tab": "Yeni sekmede aç", "title-error-adding-the-panel": "Panel eklenirken hata oluştu" }, + "add-to-dashboard-form-exposed": { + "title": { + "new-panel": "" + } + }, "annotation-settings-edit": { "back-to-list": "Listeye geri dön", "delete": "Sil", @@ -7644,7 +7663,6 @@ } }, "folder-filter": { - "noOptionsMessage-no-folders-found": "Klasör bulunamadı", "select-aria-label": "Klasör filtresi", "select-placeholder": "Klasöre göre filtrele" }, @@ -10872,6 +10890,7 @@ "replace-library-panel": "Kütüphane panelini değiştir", "share": "Paylaş", "show-legend": "Açıklamayı göster", + "time-settings": "", "unlink-library-panel": "Kütüphane panelinin bağlantısını kaldır", "view": "Görüntüle" }, @@ -12290,8 +12309,6 @@ "title": "Kapsam seçin" }, "tree": { - "collapse": "", - "expand": "", "headline": { "noResults": "Sorgunuz için sonuç bulunamadı", "recommended": "Önerilen", @@ -13135,6 +13152,14 @@ "title": "Panel" } }, + "time-period": { + "1_day": "", + "1_hour": "", + "12_hours": "", + "30_days": "", + "6_hours": "", + "7_days": "" + }, "time-picker": { "absolute": { "recent-title": "Son kullanılan mutlak aralıklar", diff --git a/public/locales/zh-Hans/grafana.json b/public/locales/zh-Hans/grafana.json index 339ae6027eb..275f7cc605f 100644 --- a/public/locales/zh-Hans/grafana.json +++ b/public/locales/zh-Hans/grafana.json @@ -4137,6 +4137,7 @@ "cancel": "取消", "clear": "清除", "collapse": "收起", + "disabled": "", "edit": "编辑", "help": "帮助", "loading": "加载中...", @@ -5112,6 +5113,19 @@ "aria-label-remove-override": "移除覆盖", "tooltip-remove-override": "移除覆盖" }, + "panel": { + "time-range-settings": { + "hide-time-info": "", + "hide-time-info-description": "", + "time-from": "", + "time-from-description": "", + "time-shift": "", + "time-shift-description": "", + "time-window-compare": "", + "time-window-compare-description": "", + "title": "" + } + }, "panel-edit": { "alerting-tab": { "dashboard-not-saved": "必须先保存数据面板,然后才能添加提醒。", @@ -5667,6 +5681,11 @@ "open-in-new-tab": "在新标签页中打开", "title-error-adding-the-panel": "添加面板时出错" }, + "add-to-dashboard-form-exposed": { + "title": { + "new-panel": "" + } + }, "annotation-settings-edit": { "back-to-list": "回到列表", "delete": "删除", @@ -7619,7 +7638,6 @@ } }, "folder-filter": { - "noOptionsMessage-no-folders-found": "未找到文件夹", "select-aria-label": "文件夹筛选", "select-placeholder": "按文件夹筛选" }, @@ -10826,6 +10844,7 @@ "replace-library-panel": "替换库面板", "share": "分享", "show-legend": "显示图例", + "time-settings": "", "unlink-library-panel": "取消链接库面板", "view": "查看" }, @@ -12235,8 +12254,6 @@ "title": "选择范围" }, "tree": { - "collapse": "", - "expand": "", "headline": { "noResults": "未找到与您的查询相关的结果", "recommended": "推荐", @@ -13078,6 +13095,14 @@ "title": "面板" } }, + "time-period": { + "1_day": "", + "1_hour": "", + "12_hours": "", + "30_days": "", + "6_hours": "", + "7_days": "" + }, "time-picker": { "absolute": { "recent-title": "最近使用的绝对范围", diff --git a/public/locales/zh-Hant/grafana.json b/public/locales/zh-Hant/grafana.json index 176b57347ec..6173f865443 100644 --- a/public/locales/zh-Hant/grafana.json +++ b/public/locales/zh-Hant/grafana.json @@ -4137,6 +4137,7 @@ "cancel": "取消", "clear": "清除", "collapse": "收闔", + "disabled": "", "edit": "編輯", "help": "說明", "loading": "正在載入…", @@ -5112,6 +5113,19 @@ "aria-label-remove-override": "移除覆寫", "tooltip-remove-override": "移除覆寫" }, + "panel": { + "time-range-settings": { + "hide-time-info": "", + "hide-time-info-description": "", + "time-from": "", + "time-from-description": "", + "time-shift": "", + "time-shift-description": "", + "time-window-compare": "", + "time-window-compare-description": "", + "title": "" + } + }, "panel-edit": { "alerting-tab": { "dashboard-not-saved": "必須先儲存儀表板,然後才能新增警報。", @@ -5667,6 +5681,11 @@ "open-in-new-tab": "在新的分頁中開啟", "title-error-adding-the-panel": "新增面板時發生錯誤" }, + "add-to-dashboard-form-exposed": { + "title": { + "new-panel": "" + } + }, "annotation-settings-edit": { "back-to-list": "返回清單", "delete": "刪除", @@ -7619,7 +7638,6 @@ } }, "folder-filter": { - "noOptionsMessage-no-folders-found": "未找到資料夾", "select-aria-label": "資料夾篩選條件", "select-placeholder": "按資料夾篩選" }, @@ -10826,6 +10844,7 @@ "replace-library-panel": "取代資料庫面板", "share": "分享", "show-legend": "顯示圖例", + "time-settings": "", "unlink-library-panel": "取消連結資料庫面板", "view": "檢視" }, @@ -12235,8 +12254,6 @@ "title": "選取範圍" }, "tree": { - "collapse": "", - "expand": "", "headline": { "noResults": "未找到您的查詢結果", "recommended": "建議", @@ -13078,6 +13095,14 @@ "title": "面板" } }, + "time-period": { + "1_day": "", + "1_hour": "", + "12_hours": "", + "30_days": "", + "6_hours": "", + "7_days": "" + }, "time-picker": { "absolute": { "recent-title": "最近使用的絕對範圍", From 4c8c32a1d458b8b428ee4114565f9d2e3d27e10f Mon Sep 17 00:00:00 2001 From: Ryan McKinley Date: Thu, 30 Oct 2025 07:25:59 +0300 Subject: [PATCH 108/378] Chore: Update @playwright/test (#113179) --- package.json | 2 +- yarn.lock | 30 +++++++++++++++--------------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/package.json b/package.json index d74e091448d..373fca80b00 100644 --- a/package.json +++ b/package.json @@ -96,7 +96,7 @@ "@grafana/test-utils": "workspace:*", "@manypkg/get-packages": "^3.0.0", "@npmcli/package-json": "^6.0.0", - "@playwright/test": "1.55.1", + "@playwright/test": "1.56.1", "@pmmmwh/react-refresh-webpack-plugin": "0.6.1", "@react-types/button": "3.13.0", "@react-types/menu": "3.10.3", diff --git a/yarn.lock b/yarn.lock index 7480476abed..792fd086e36 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6476,14 +6476,14 @@ __metadata: languageName: node linkType: hard -"@playwright/test@npm:1.55.1": - version: 1.55.1 - resolution: "@playwright/test@npm:1.55.1" +"@playwright/test@npm:1.56.1": + version: 1.56.1 + resolution: "@playwright/test@npm:1.56.1" dependencies: - playwright: "npm:1.55.1" + playwright: "npm:1.56.1" bin: playwright: cli.js - checksum: 10/c67a46353c58aaeac551bce2654cdef0e9a0ad76b1667514832d34acd4b26ec72f35ea7595cd3fad4c4e1e039d5bb876b8d62c89af4525d455285f6fff9f0642 + checksum: 10/9933fa9f8eb9e775e792421b99c984c310b92092e65de57508ae1951a2589d87bbb5f1c4114bfdf7f69c15c0a3acb3f31259e143fa597aa28e97f4b223e37637 languageName: node linkType: hard @@ -18856,7 +18856,7 @@ __metadata: "@opentelemetry/api": "npm:1.9.0" "@opentelemetry/exporter-collector": "npm:0.25.0" "@opentelemetry/semantic-conventions": "npm:1.37.0" - "@playwright/test": "npm:1.55.1" + "@playwright/test": "npm:1.56.1" "@pmmmwh/react-refresh-webpack-plugin": "npm:0.6.1" "@popperjs/core": "npm:2.11.8" "@react-aria/dialog": "npm:3.5.31" @@ -26334,27 +26334,27 @@ __metadata: languageName: node linkType: hard -"playwright-core@npm:1.55.1": - version: 1.55.1 - resolution: "playwright-core@npm:1.55.1" +"playwright-core@npm:1.56.1": + version: 1.56.1 + resolution: "playwright-core@npm:1.56.1" bin: playwright-core: cli.js - checksum: 10/953a43039dbcca04513bd3138a9dee249a136d5377da00d49402ffcd24d33ca84dc1dc04636d1b76e9f8c9fd28a302b89cda1ae544d72b5d829c28e623bfcb0b + checksum: 10/df785eb3b3a8392b10dcde5f768e09b7fe459a7b06ed81180da69e048f2154b761f86d79572c2b62037a1f18a44e4ace72f5b6547f4f473b4ab13ab1d94007d2 languageName: node linkType: hard -"playwright@npm:1.55.1": - version: 1.55.1 - resolution: "playwright@npm:1.55.1" +"playwright@npm:1.56.1": + version: 1.56.1 + resolution: "playwright@npm:1.56.1" dependencies: fsevents: "npm:2.3.2" - playwright-core: "npm:1.55.1" + playwright-core: "npm:1.56.1" dependenciesMeta: fsevents: optional: true bin: playwright: cli.js - checksum: 10/5dcf9ce564cacf6c06ebc864bb2b1f709c641792560d49889ed4c98e230be54a963ec8aaafff11269735d8d22da4900bd2d4ef9f1748d132326ffda8fb1f3f20 + checksum: 10/f1743f93b26f1d497257771428d93f3c9ed2d75b00d935f0cd1556ff2dc61d47f2df8b381d752fbd2c47082b685f0ffe4cc4b7ba440d7b4ba3a08572aec58fba languageName: node linkType: hard From 0b566286222a9c1e167aab0982af007b5925109e Mon Sep 17 00:00:00 2001 From: Anna Urbiztondo Date: Thu, 30 Oct 2025 06:33:26 +0100 Subject: [PATCH 109/378] Docs: Plugins link to catalog (#113103) * Plugins link * Typo * Prettier * Edits * More edits --- .../sources/administration/plugin-management/_index.md | 10 ++++++---- .../sources/breaking-changes/breaking-changes-v11-0.md | 2 +- docs/sources/datasources/_index.md | 3 +-- docs/sources/setup-grafana/configure-grafana/_index.md | 2 +- docs/sources/whatsnew/whats-new-in-v8-0.md | 2 +- 5 files changed, 10 insertions(+), 9 deletions(-) diff --git a/docs/sources/administration/plugin-management/_index.md b/docs/sources/administration/plugin-management/_index.md index fce84ec643e..6736e15d176 100644 --- a/docs/sources/administration/plugin-management/_index.md +++ b/docs/sources/administration/plugin-management/_index.md @@ -20,7 +20,7 @@ Plugins enhance your Grafana experience with new ways to connect to and visualiz Read on for an overview on how to get started with plugins: -- Plugins are available in the [plugin catalog](#plugin-catalog). They can be built by Grafana Labs, commercial partners, our community, or you can [build a plugin yourself](/developers/plugin-tools). +- Plugins are available in the [plugin catalog](#access-the-plugin-catalog). They can be built by Grafana Labs, commercial partners, our community, or you can [build a plugin yourself](/developers/plugin-tools). - There are three [types of plugins](#types-of-plugins): panel, data source, and app plugins. - Learn [how to install](#install-a-plugin), [update](#update-a-plugin) and [verify](#verify-your-plugins) your plugins. @@ -40,11 +40,11 @@ Grafana supports three types of plugins: Read more in [Types of plugins](plugin-types). -## Plugin catalog +## Access the Plugin catalog -The Grafana plugin catalog allows you to browse and manage plugins from within Grafana. Only Grafana server administrators and Organization administrators can access and use the plugin catalog. For more information about Grafana roles and permissions, refer to [Roles and permissions](../roles-and-permissions/). +You can install and manage plugins from within Grafana. You need to have a Grafana Server administrator or Organization administrator role to access and use the plugin catalog. For more information about Grafana roles and permissions, refer to [Roles and permissions](../roles-and-permissions/). -The following access rules apply depending on the user role: +For app plugins, the following access rules apply: - If you are an **Org Admin**, you can configure app plugins, but you can't install, uninstall, or update them. - If you are a **Server Admin**, you can't configure app plugins, but you can install, uninstall, or update them. @@ -58,6 +58,8 @@ To browse for available plugins: 1. Use the search box to filter based on name, keywords, organization and other metadata. 1. Click the **Data sources**, **Panels**, or **Applications** buttons to filter by plugin type. +If you're not logged in, you can also access the list of available plugins in the [Plugin catalog](https://grafana.com/grafana/plugins/). + ## Manage your plugins We strongly recommend running the latest plugin version. Use [Grafana Advisor](https://grafana.com/docs/grafana//administration/grafana-advisor) to check the status of your data sources and plugins. diff --git a/docs/sources/breaking-changes/breaking-changes-v11-0.md b/docs/sources/breaking-changes/breaking-changes-v11-0.md index 313015b275d..898673c4be5 100644 --- a/docs/sources/breaking-changes/breaking-changes-v11-0.md +++ b/docs/sources/breaking-changes/breaking-changes-v11-0.md @@ -57,7 +57,7 @@ In Grafana v11, support for the deprecated AngularJS framework is turned off by #### Migration/mitigation -To avoid disruption, ensure all plugins are up to date and migrate from any remaining AngularJS plugins to a React-based alternative. If a plugin relies on AngularJS, a warning icon and message will be displayed in the [plugins catalog](https://grafana.com/docs/grafana//administration/plugin-management/#plugin-catalog) in Grafana and any dashboard panel where it's used. Additionally, a warning banner will appear in any impacted dashboards. A list of all impacted dashboards can also be generated using the [`detect-angular-dashboards`](https://github.com/grafana/detect-angular-dashboards) tool. +To avoid disruption, ensure all plugins are up to date and migrate from any remaining AngularJS plugins to a React-based alternative. If a plugin relies on AngularJS, a warning icon and message will be displayed in the [plugins catalog](https://grafana.com/docs/grafana//administration/plugin-management/#access-the-plugin-catalog) in Grafana and any dashboard panel where it's used. Additionally, a warning banner will appear in any impacted dashboards. A list of all impacted dashboards can also be generated using the [`detect-angular-dashboards`](https://github.com/grafana/detect-angular-dashboards) tool. Our [documentation](https://grafana.com/docs/grafana//developers/angular_deprecation/angular-plugins/) lists all known public plugins and provides migration advice when possible. diff --git a/docs/sources/datasources/_index.md b/docs/sources/datasources/_index.md index 7ba5e1756a5..e7da61ea2f5 100644 --- a/docs/sources/datasources/_index.md +++ b/docs/sources/datasources/_index.md @@ -71,9 +71,8 @@ After you add and configure a data source, you can use it as an input for many o This documentation describes how to manage data sources in general, and how to configure or query the built-in data sources. -For other data sources, refer to the list of [datasource plugins](/grafana/plugins/). -To develop a custom plugin, refer to [Create a data source plugin](#create-a-data-source-plugin). +For other available plugins, refer to the list of [documented plugins](https://grafana.com/docs/plugins/) or browse the [Plugin catalog](/grafana/plugins/). To develop a custom plugin, refer to [Create a data source plugin](#create-a-data-source-plugin). ## Manage data sources diff --git a/docs/sources/setup-grafana/configure-grafana/_index.md b/docs/sources/setup-grafana/configure-grafana/_index.md index f3d3dd89b45..ea83a3bb553 100644 --- a/docs/sources/setup-grafana/configure-grafana/_index.md +++ b/docs/sources/setup-grafana/configure-grafana/_index.md @@ -2559,7 +2559,7 @@ Available to Grafana administrators only, enables installing, uninstalling, and Set to `true` by default. Setting it to `false` hides the controls. -For more information, refer to [Plugin catalog](../../administration/plugin-management/#plugin-catalog). +For more information, refer to [Plugin catalog](../../administration/plugin-management/#access-the-plugin-catalog). #### `plugin_admin_external_manage_enabled` diff --git a/docs/sources/whatsnew/whats-new-in-v8-0.md b/docs/sources/whatsnew/whats-new-in-v8-0.md index cf3792d8a48..7559f646678 100644 --- a/docs/sources/whatsnew/whats-new-in-v8-0.md +++ b/docs/sources/whatsnew/whats-new-in-v8-0.md @@ -160,7 +160,7 @@ Log navigation in Explore has been significantly improved. We added pagination t You can now use the Plugin catalog app to easily manage your plugins from within Grafana. Install, update, and uninstall plugins without requiring a server restart. -[Plugin catalog](../../administration/plugin-management/#plugin-catalog) was added as a result of this feature. +[Plugin catalog](../../administration/plugin-management/#access-the-plugin-catalog) was added as a result of this feature. ### Performance improvements From 84edc45dee106efc33198b352ecaee03bdaf4238 Mon Sep 17 00:00:00 2001 From: Yunwen Zheng Date: Thu, 30 Oct 2025 01:49:15 -0400 Subject: [PATCH 110/378] PreviewBannerViewPR: Display branch info in preview banner (#113195) --- .../Dashboards/DashboardPreviewBanner.tsx | 22 ++++++++++---- .../components/Shared/PreviewBannerViewPR.tsx | 29 ++++++++++++++++--- .../provisioning/components/utils/url.ts | 17 +++++++++++ public/locales/en-US/grafana.json | 1 + 4 files changed, 59 insertions(+), 10 deletions(-) create mode 100644 public/app/features/provisioning/components/utils/url.ts diff --git a/public/app/features/provisioning/components/Dashboards/DashboardPreviewBanner.tsx b/public/app/features/provisioning/components/Dashboards/DashboardPreviewBanner.tsx index 77df93f0f8b..2f39623f29a 100644 --- a/public/app/features/provisioning/components/Dashboards/DashboardPreviewBanner.tsx +++ b/public/app/features/provisioning/components/Dashboards/DashboardPreviewBanner.tsx @@ -6,7 +6,8 @@ import { DashboardPageRouteSearchParams } from 'app/features/dashboard/container import { usePullRequestParam } from 'app/features/provisioning/hooks/usePullRequestParam'; import { DashboardRoutes } from 'app/types/dashboard'; -import { PreviewBannerViewPR } from '../Shared/PreviewBannerViewPR'; +import { useGetResourceRepositoryView } from '../../hooks/useGetResourceRepositoryView'; +import { PreviewBranchInfo, PreviewBannerViewPR } from '../Shared/PreviewBannerViewPR'; export interface CommonBannerProps { queryParams: DashboardPageRouteSearchParams; @@ -28,6 +29,15 @@ export const commonAlertProps = { function DashboardPreviewBannerContent({ queryParams, slug, path }: DashboardPreviewBannerContentProps) { const { prURL } = usePullRequestParam(); const file = useGetRepositoryFilesWithPathQuery({ name: slug, path, ref: queryParams.ref }); + const { repository } = useGetResourceRepositoryView({ name: slug }); + const targetRef = file.data?.ref; + const repoBaseUrl = file.data?.urls?.repositoryURL; + + const branchInfo: PreviewBranchInfo = { + targetBranch: targetRef, + configuredBranch: repository?.branch, + repoBaseUrl, + }; if (file.data?.errors) { return ( @@ -45,13 +55,13 @@ function DashboardPreviewBannerContent({ queryParams, slug, path }: DashboardPre // This page was loaded with a `pull_request_url` in the URL if (prURL?.length) { - return ; + return ; } - // Check if this is a repo link - const repoUrl = file.data?.urls?.newPullRequestURL ?? file.data?.urls?.compareURL; - if (repoUrl) { - return ; + // Check if pull request URLs are available from the repository file data + const prOrCompareUrl = file.data?.urls?.newPullRequestURL ?? file.data?.urls?.compareURL; + if (prOrCompareUrl) { + return ; } return ( diff --git a/public/app/features/provisioning/components/Shared/PreviewBannerViewPR.tsx b/public/app/features/provisioning/components/Shared/PreviewBannerViewPR.tsx index e9cddc16231..8a796ee049c 100644 --- a/public/app/features/provisioning/components/Shared/PreviewBannerViewPR.tsx +++ b/public/app/features/provisioning/components/Shared/PreviewBannerViewPR.tsx @@ -1,25 +1,32 @@ import { textUtil } from '@grafana/data'; import { Trans, t } from '@grafana/i18n'; -import { Alert, Icon, Stack } from '@grafana/ui'; +import { Alert, Box, Icon, Stack, TextLink } from '@grafana/ui'; import { RepoTypeDisplay, RepoType } from 'app/features/provisioning/Wizard/types'; import { usePullRequestParam } from 'app/features/provisioning/hooks/usePullRequestParam'; import { commonAlertProps } from '../Dashboards/DashboardPreviewBanner'; - -// TODO: We have this https://github.com/grafana/git-ui-sync-project/issues/166 to add more details about the PR. +import { getBranchUrl } from '../utils/url'; interface Props { prParam?: string; isNewPr?: boolean; behindBranch?: boolean; repoUrl?: string; + branchInfo?: PreviewBranchInfo; } +export type PreviewBranchInfo = { + targetBranch?: string; + configuredBranch?: string; + repoBaseUrl?: string; +}; + /** * @description This component is used to display a banner when a provisioned dashboard/folder is created or loaded from a new branch in repo. */ -export function PreviewBannerViewPR({ prParam, isNewPr, behindBranch, repoUrl }: Props) { +export function PreviewBannerViewPR({ prParam, isNewPr, behindBranch, repoUrl, branchInfo }: Props) { const { repoType } = usePullRequestParam(); + const { targetBranch, configuredBranch, repoBaseUrl } = branchInfo || {}; const capitalizedRepoType = isValidRepoType(repoType) ? RepoTypeDisplay[repoType] : 'repository'; @@ -96,6 +103,15 @@ export function PreviewBannerViewPR({ prParam, isNewPr, behindBranch, repoUrl }: The rest of Grafana users in your organization will still see the current version saved to configured default branch until this branch is merged + + {/* when repo type is not local, we show branch information */} + {showBranchInfo(repoType, branchInfo) && ( + + branch: + {targetBranch} {'\u2192'}{' '} + {configuredBranch} + + )} ); } @@ -106,3 +122,8 @@ export function isValidRepoType(repoType: string | undefined): repoType is RepoT } return repoType in RepoTypeDisplay; } + +function showBranchInfo(repoType: string | undefined, branchInfo?: PreviewBranchInfo): boolean { + const { targetBranch, configuredBranch, repoBaseUrl } = branchInfo || {}; + return repoType !== 'local' && !!targetBranch && !!configuredBranch && !!repoBaseUrl; +} diff --git a/public/app/features/provisioning/components/utils/url.ts b/public/app/features/provisioning/components/utils/url.ts new file mode 100644 index 00000000000..286235db636 --- /dev/null +++ b/public/app/features/provisioning/components/utils/url.ts @@ -0,0 +1,17 @@ +// repoType = string because this repoType is coming from URL param +export const getBranchUrl = (baseUrl: string, branch: string, repoType?: string): string => { + if (repoType === 'local') { + return ''; + } + + switch (repoType) { + case 'github': + return `${baseUrl}/tree/${branch}`; + case 'gitlab': + return `${baseUrl}/-/tree/${branch}`; + case 'bitbucket': + return `${baseUrl}/src/${branch}`; + default: + return ''; + } +}; diff --git a/public/locales/en-US/grafana.json b/public/locales/en-US/grafana.json index 3c0c17c7af2..4e435b87ed2 100644 --- a/public/locales/en-US/grafana.json +++ b/public/locales/en-US/grafana.json @@ -11370,6 +11370,7 @@ "provisioned-resource-preview-banner": { "preview-banner": { "behind-branch-text": "This resource is behind the branch in {{repoType}}.", + "branch-text": "branch:", "not-saved": "The rest of Grafana users in your organization will still see the current version saved to configured default branch until this branch is merged", "open-in-repo-button": "Open in {{repoType}}", "open-pull-request-in-repo": "Open pull request in {{repoType}}", From 209aa13ff75535dd548d62cdf3febfda26f955eb Mon Sep 17 00:00:00 2001 From: Dominik Prokop Date: Thu, 30 Oct 2025 07:25:55 +0100 Subject: [PATCH 111/378] Dashboard performance analytics system with Scenes integration (#112137) * Dashboard performance profiling architecture improvements - Create shared performanceUtils.ts with type-safe performance.memory access - Add standardized grouped logging utilities for structured console output - Convert observer methods to arrow functions eliminating constructor bindings - Implement DashboardAnalyticsAggregator for comprehensive panel metrics - Add ScenePerformanceLogger for performance marks and measurements - Create DashboardAnalyticsInitializerBehavior for automatic profiling setup - Update dashboard scene integration to use improved profiling system - Add numeric duration logging for better programmatic analysis - Fix localStorage usage to use @grafana/data store for consistency - Consolidate performance tracking logic into shared utilities * canary scenes * tests/lint * docs * performanceUtils namespace * Review and sync scenes * Only enable dashboard profiling when needed * docs update * update scenes --------- Co-authored-by: Victor Marin --- package.json | 4 +- .../DashboardAnalyticsInitializerBehavior.ts | 37 + .../pages/DashboardScenePageStateManager.ts | 31 + .../dashboard-scene/scene/DashboardScene.tsx | 4 + .../transformSaveModelSchemaV2ToScene.ts | 25 +- .../transformSaveModelToScene.ts | 31 +- .../PublicDashboardPageProxy.test.tsx | 3 + .../services/DashboardAnalyticsAggregator.ts | 373 ++++++++++ .../dashboard/services/DashboardProfiler.ts | 68 +- .../services/ScenePerformanceLogger.ts | 220 ++++++ .../dashboard-render-performance-profiling.md | 657 +++++++++++++----- .../services/performanceConstants.ts | 82 +++ .../dashboard/services/performanceUtils.ts | 139 ++++ .../scopes/selector/ScopesSelectorService.ts | 5 +- .../scopes/tests/dashboardReload.test.ts | 1 + yarn.lock | 80 +-- 16 files changed, 1483 insertions(+), 277 deletions(-) create mode 100644 public/app/features/dashboard-scene/behaviors/DashboardAnalyticsInitializerBehavior.ts create mode 100644 public/app/features/dashboard/services/DashboardAnalyticsAggregator.ts create mode 100644 public/app/features/dashboard/services/ScenePerformanceLogger.ts create mode 100644 public/app/features/dashboard/services/performanceConstants.ts create mode 100644 public/app/features/dashboard/services/performanceUtils.ts diff --git a/package.json b/package.json index 373fca80b00..a68dd4130c0 100644 --- a/package.json +++ b/package.json @@ -296,8 +296,8 @@ "@grafana/plugin-ui": "^0.10.10", "@grafana/prometheus": "workspace:*", "@grafana/runtime": "workspace:*", - "@grafana/scenes": "^6.40.1", - "@grafana/scenes-react": "^6.40.1", + "@grafana/scenes": "^6.41.0", + "@grafana/scenes-react": "^6.41.0", "@grafana/schema": "workspace:*", "@grafana/sql": "workspace:*", "@grafana/ui": "workspace:*", diff --git a/public/app/features/dashboard-scene/behaviors/DashboardAnalyticsInitializerBehavior.ts b/public/app/features/dashboard-scene/behaviors/DashboardAnalyticsInitializerBehavior.ts new file mode 100644 index 00000000000..2cc1e1138e0 --- /dev/null +++ b/public/app/features/dashboard-scene/behaviors/DashboardAnalyticsInitializerBehavior.ts @@ -0,0 +1,37 @@ +import { writePerformanceLog } from '@grafana/scenes'; + +import { getDashboardAnalyticsAggregator } from '../../dashboard/services/DashboardAnalyticsAggregator'; +import { DashboardScene } from '../scene/DashboardScene'; + +/** + * Scene behavior function that manages the dashboard-specific initialization + * of the global analytics aggregator for each dashboard session. + * + * Note: Both ScenePerformanceLogger and DashboardAnalyticsAggregator are now + * initialized globally to avoid timing issues. This behavior only sets + * dashboard-specific context. + */ +export function dashboardAnalyticsInitializer(dashboard: DashboardScene) { + const { uid, title } = dashboard.state; + + if (!uid) { + console.warn('dashboardAnalyticsInitializer: Dashboard UID is missing'); + return; + } + + writePerformanceLog('DAI', 'Setting dashboard context for analytics aggregator'); + + // Set dashboard context on the global aggregator (observer already registered) + const aggregator = getDashboardAnalyticsAggregator(); + aggregator.initialize(uid, title || 'Untitled Dashboard'); + + writePerformanceLog('DAI', 'Dashboard analytics aggregator context set:', { uid, title }); + + // Return cleanup function + return () => { + // Only clear dashboard state, keep observer registered for next dashboard + aggregator.destroy(); + + writePerformanceLog('DAI', 'Dashboard analytics aggregator context cleared'); + }; +} diff --git a/public/app/features/dashboard-scene/pages/DashboardScenePageStateManager.ts b/public/app/features/dashboard-scene/pages/DashboardScenePageStateManager.ts index 54dd386c619..e17f7e36cff 100644 --- a/public/app/features/dashboard-scene/pages/DashboardScenePageStateManager.ts +++ b/public/app/features/dashboard-scene/pages/DashboardScenePageStateManager.ts @@ -17,8 +17,11 @@ import { import { ensureV2Response, transformDashboardV2SpecToV1 } from 'app/features/dashboard/api/ResponseTransformers'; import { DashboardVersionError, DashboardWithAccessInfo } from 'app/features/dashboard/api/types'; import { isDashboardV2Resource, isDashboardV2Spec, isV2StoredVersion } from 'app/features/dashboard/api/utils'; +import { initializeDashboardAnalyticsAggregator } from 'app/features/dashboard/services/DashboardAnalyticsAggregator'; import { dashboardLoaderSrv, DashboardLoaderSrvV2 } from 'app/features/dashboard/services/DashboardLoaderSrv'; +import { getDashboardSceneProfiler } from 'app/features/dashboard/services/DashboardProfiler'; import { getDashboardSrv } from 'app/features/dashboard/services/DashboardSrv'; +import { initializeScenePerformanceLogger } from 'app/features/dashboard/services/ScenePerformanceLogger'; import { emitDashboardViewEvent } from 'app/features/dashboard/state/analyticsProcessor'; import { trackDashboardSceneLoaded } from 'app/features/dashboard-scene/utils/tracking'; import { playlistSrv } from 'app/features/playlist/PlaylistSrv'; @@ -41,6 +44,14 @@ import { restoreDashboardStateFromLocalStorage } from '../utils/dashboardSession import { processQueryParamsForDashboardLoad, updateNavModel } from './utils'; +/** + * Initialize both performance services to ensure they're ready before profiling starts + */ +function initializeDashboardPerformanceServices(): void { + initializeScenePerformanceLogger(); + initializeDashboardAnalyticsAggregator(); +} + export interface LoadError { status?: number; messageId?: string; @@ -296,6 +307,16 @@ abstract class DashboardScenePageStateManagerBase const queryController = sceneGraph.getQueryController(dashboard); trackDashboardSceneLoaded(dashboard, measure?.duration); + + const enableProfiling = + config.dashboardPerformanceMetrics.findIndex((uid) => uid === '*' || uid === options.uid) !== -1; + + if (enableProfiling) { + // Initialize both performance services before starting profiling to ensure observers are registered + initializeDashboardPerformanceServices(); + } + + // Start dashboard_view profiling (both services are now guaranteed to be listening) queryController?.startProfile('dashboard_view'); if (options.route !== DashboardRoutes.New) { @@ -409,6 +430,11 @@ export class DashboardScenePageStateManager extends DashboardScenePageStateManag fromCache.state.version === rsp?.dashboard.version && fromCache.state.meta.created === rsp?.meta.created ) { + const profiler = getDashboardSceneProfiler(); + profiler.setMetadata({ + dashboardUID: fromCache.state.uid, + dashboardTitle: fromCache.state.title, + }); return fromCache; } @@ -696,6 +722,11 @@ export class DashboardScenePageStateManagerV2 extends DashboardScenePageStateMan const fromCache = this.getSceneFromCache(options.uid); if (fromCache && fromCache.state.version === rsp?.metadata.generation) { + const profiler = getDashboardSceneProfiler(); + profiler.setMetadata({ + dashboardUID: fromCache.state.uid, + dashboardTitle: fromCache.state.title, + }); return fromCache; } diff --git a/public/app/features/dashboard-scene/scene/DashboardScene.tsx b/public/app/features/dashboard-scene/scene/DashboardScene.tsx index 748d3e7986e..087cd505fcd 100644 --- a/public/app/features/dashboard-scene/scene/DashboardScene.tsx +++ b/public/app/features/dashboard-scene/scene/DashboardScene.tsx @@ -25,6 +25,7 @@ import store from 'app/core/store'; import { sortedDeepCloneWithoutNulls } from 'app/core/utils/object'; import { DashboardWithAccessInfo } from 'app/features/dashboard/api/types'; import { SaveDashboardAsOptions } from 'app/features/dashboard/components/SaveDashboard/types'; +import { getDashboardSceneProfiler } from 'app/features/dashboard/services/DashboardProfiler'; import { getDashboardSrv } from 'app/features/dashboard/services/DashboardSrv'; import { DashboardModel, ScopeMeta } from 'app/features/dashboard/state/DashboardModel'; import { PanelModel } from 'app/features/dashboard/state/PanelModel'; @@ -625,7 +626,10 @@ export class DashboardScene extends SceneObjectBase impleme } public onCreateNewPanel(): VizPanel { + const profiler = getDashboardSceneProfiler(); const vizPanel = getDefaultVizPanel(); + profiler.attachProfilerToPanel(vizPanel); + this.addPanel(vizPanel); return vizPanel; } diff --git a/public/app/features/dashboard-scene/serialization/transformSaveModelSchemaV2ToScene.ts b/public/app/features/dashboard-scene/serialization/transformSaveModelSchemaV2ToScene.ts index ad94f404e68..7d57a2b087f 100644 --- a/public/app/features/dashboard-scene/serialization/transformSaveModelSchemaV2ToScene.ts +++ b/public/app/features/dashboard-scene/serialization/transformSaveModelSchemaV2ToScene.ts @@ -56,13 +56,14 @@ import { } from 'app/features/apiserver/types'; import { DashboardWithAccessInfo } from 'app/features/dashboard/api/types'; import { + getDashboardSceneProfilerWithMetadata, + enablePanelProfilingForDashboard, getDashboardComponentInteractionCallback, - getDashboardInteractionCallback, - getDashboardSceneProfiler, } from 'app/features/dashboard/services/DashboardProfiler'; import { DashboardMeta } from 'app/types/dashboard'; import { addPanelsOnLoadBehavior } from '../addToDashboard/addPanelsOnLoadBehavior'; +import { dashboardAnalyticsInitializer } from '../behaviors/DashboardAnalyticsInitializerBehavior'; import { DashboardAnnotationsDataLayer } from '../scene/DashboardAnnotationsDataLayer'; import { DashboardControls } from '../scene/DashboardControls'; import { DashboardDataLayerSet } from '../scene/DashboardDataLayerSet'; @@ -168,22 +169,24 @@ export function transformSaveModelSchemaV2ToScene(dto: DashboardWithAccessInfo uid === '*' || uid === metadata.name) !== -1; const queryController = new behaviors.SceneQueryController( { - enableProfiling: - config.dashboardPerformanceMetrics.findIndex((uid) => uid === '*' || uid === metadata.name) !== -1, - onProfileComplete: getDashboardInteractionCallback(metadata.name, dashboard.title), + enableProfiling, }, - getDashboardSceneProfiler() + dashboardProfiler ); const interactionTracker = new behaviors.SceneInteractionTracker( { - enableInteractionTracking: - config.dashboardPerformanceMetrics.findIndex((uid) => uid === '*' || uid === metadata.name) !== -1, + enableInteractionTracking: enableProfiling, onInteractionComplete: getDashboardComponentInteractionCallback(metadata.name, dashboard.title), }, - getDashboardSceneProfiler() + dashboardProfiler ); const dashboardScene = new DashboardScene( @@ -223,6 +226,7 @@ export function transformSaveModelSchemaV2ToScene(dto: DashboardWithAccessInfo uid === '*' || uid === oldModel.uid) !== -1; const queryController = new behaviors.SceneQueryController( { - enableProfiling: - config.dashboardPerformanceMetrics.findIndex((uid) => uid === '*' || uid === oldModel.uid) !== -1, - onProfileComplete: getDashboardInteractionCallback(oldModel.uid, oldModel.title), + enableProfiling, }, - getDashboardSceneProfiler() + dashboardProfiler ); const interactionTracker = new behaviors.SceneInteractionTracker( { - enableInteractionTracking: - config.dashboardPerformanceMetrics.findIndex((uid) => uid === '*' || uid === oldModel.uid) !== -1, + enableInteractionTracking: enableProfiling, onInteractionComplete: getDashboardComponentInteractionCallback(oldModel.uid, oldModel.title), }, - getDashboardSceneProfiler() + dashboardProfiler ); const behaviorList: SceneObjectState['$behaviors'] = [ @@ -330,6 +334,12 @@ export function createDashboardSceneFromDashboardModel(oldModel: DashboardModel, }), ]; + if (enableProfiling) { + // Analytics aggregator lifecycle management (initialization, observer registration, cleanup) + behaviorList.push(dashboardAnalyticsInitializer); + } + // Will be enabled in the dashboard creation below + let body: DashboardLayoutManager; if (config.featureToggles.dashboardNewLayouts && oldModel.panels.some((p) => p.type === 'row')) { @@ -385,6 +395,9 @@ export function createDashboardSceneFromDashboardModel(oldModel: DashboardModel, serializerVersion ); + // Enable panel profiling for this dashboard using the composed SceneRenderProfiler + enablePanelProfilingForDashboard(dashboardScene, uid); + return dashboardScene; } diff --git a/public/app/features/dashboard/containers/PublicDashboardPageProxy.test.tsx b/public/app/features/dashboard/containers/PublicDashboardPageProxy.test.tsx index b8ca09b1b4e..0bb44738440 100644 --- a/public/app/features/dashboard/containers/PublicDashboardPageProxy.test.tsx +++ b/public/app/features/dashboard/containers/PublicDashboardPageProxy.test.tsx @@ -51,6 +51,9 @@ describe('PublicDashboardPageProxy', () => { beforeEach(() => { config.featureToggles.publicDashboardsScene = false; + // Mock console methods to avoid jest-fail-on-console issues + jest.spyOn(console, 'warn').mockImplementation(); + // Mock the dashboard UID response so we don't get any refused connection errors // from this test (as the fetch polyfill means this logic would actually try and call the API) // eslint-disable-next-line @typescript-eslint/no-explicit-any diff --git a/public/app/features/dashboard/services/DashboardAnalyticsAggregator.ts b/public/app/features/dashboard/services/DashboardAnalyticsAggregator.ts new file mode 100644 index 00000000000..8671c2b13e5 --- /dev/null +++ b/public/app/features/dashboard/services/DashboardAnalyticsAggregator.ts @@ -0,0 +1,373 @@ +import { logMeasurement, reportInteraction } from '@grafana/runtime'; +import { performanceUtils } from '@grafana/scenes'; + +import { SLOW_OPERATION_THRESHOLD_MS } from './performanceConstants'; +import { + registerPerformanceObserver, + getPerformanceMemory, + writePerformanceGroupStart, + writePerformanceGroupLog, + writePerformanceGroupEnd, +} from './performanceUtils'; + +/** + * Panel metrics structure for analytics + */ +interface PanelAnalyticsMetrics { + panelId: string; + panelKey: string; + pluginId: string; + pluginVersion?: string; + totalQueryTime: number; + totalFieldConfigTime: number; + totalTransformationTime: number; + totalRenderTime: number; + pluginLoadTime: number; + queryOperations: Array<{ + duration: number; + timestamp: number; + queryType?: string; + seriesCount?: number; + dataPointsCount?: number; + }>; + fieldConfigOperations: Array<{ + duration: number; + timestamp: number; + }>; + transformationOperations: Array<{ + duration: number; + timestamp: number; + transformationId?: string; + success?: boolean; + outputSeriesCount?: number; + }>; + renderOperations: Array<{ + duration: number; + timestamp: number; + }>; +} + +/** + * Aggregates Scene performance events into analytics-ready panel metrics + */ +export class DashboardAnalyticsAggregator implements performanceUtils.ScenePerformanceObserver { + private panelMetrics = new Map(); + private dashboardUID = ''; + private dashboardTitle = ''; + + public initialize(uid: string, title: string) { + // Clear previous dashboard data and set new context + this.panelMetrics.clear(); + this.dashboardUID = uid; + this.dashboardTitle = title; + } + + public destroy() { + // Clear dashboard context + this.panelMetrics.clear(); + this.dashboardUID = ''; + this.dashboardTitle = ''; + } + + /** + * Clear all collected metrics (called on dashboard interaction start) + */ + public clearMetrics() { + this.panelMetrics.clear(); + } + + /** + * Get aggregated panel metrics for analytics + */ + public getPanelMetrics(): PanelAnalyticsMetrics[] { + return Array.from(this.panelMetrics.values()); + } + + // Dashboard-level events (we don't need to track these for panel analytics) + onDashboardInteractionStart = (data: performanceUtils.DashboardInteractionStartData): void => { + // Clear metrics when new dashboard interaction starts + this.clearMetrics(); + }; + + onDashboardInteractionMilestone = (_data: performanceUtils.DashboardInteractionMilestoneData): void => { + // No action needed for milestones in analytics + }; + + onDashboardInteractionComplete = (data: performanceUtils.DashboardInteractionCompleteData): void => { + // Send analytics report for dashboard interaction completion + this.sendAnalyticsReport(data); + }; + + // Panel-level events + onPanelOperationStart = (data: performanceUtils.PanelPerformanceData): void => { + // Start events don't need aggregation, just ensure panel exists + this.ensurePanelExists(data.panelKey, data.panelId, data.pluginId, data.pluginVersion); + }; + + onPanelOperationComplete = (data: performanceUtils.PanelPerformanceData): void => { + // Aggregate panel metrics without verbose logging (handled by ScenePerformanceLogger) + const panel = this.panelMetrics.get(data.panelKey); + if (!panel) { + console.warn('Panel not found for operation completion:', data.panelKey); + return; + } + + const duration = data.duration || 0; + + switch (data.operation) { + case 'fieldConfig': + panel.totalFieldConfigTime += duration; + panel.fieldConfigOperations.push({ + duration, + timestamp: data.timestamp, + }); + break; + + case 'transform': + panel.totalTransformationTime += duration; + panel.transformationOperations.push({ + duration, + timestamp: data.timestamp, + transformationId: data.metadata.transformationId, + success: data.metadata.success, + }); + break; + + case 'query': + panel.totalQueryTime += duration; + panel.queryOperations.push({ + duration, + timestamp: data.timestamp, + queryType: data.metadata.queryType, + }); + break; + + case 'render': + panel.totalRenderTime += duration; + panel.renderOperations.push({ + duration, + timestamp: data.timestamp, + }); + break; + + case 'plugin-load': + panel.pluginLoadTime += duration; + break; + } + }; + + // Query-level events + onQueryStart = (_data: performanceUtils.QueryPerformanceData): void => { + // no-op + }; + + onQueryComplete = (_data: performanceUtils.QueryPerformanceData): void => { + // no-op + }; + + /** + * Ensure a panel exists in our tracking map + */ + private ensurePanelExists( + panelKey: string, + panelId: string, + pluginId: string, + pluginVersion?: string + ): PanelAnalyticsMetrics { + let panel = this.panelMetrics.get(panelKey); + if (!panel) { + panel = { + panelId, + panelKey, + pluginId, + pluginVersion, + totalQueryTime: 0, + totalFieldConfigTime: 0, + totalTransformationTime: 0, + totalRenderTime: 0, + pluginLoadTime: 0, + queryOperations: [], + fieldConfigOperations: [], + transformationOperations: [], + renderOperations: [], + }; + this.panelMetrics.set(panelKey, panel); + } + return panel; + } + + /** + * Send analytics report for dashboard interactions + */ + private sendAnalyticsReport(data: performanceUtils.DashboardInteractionCompleteData): void { + const payload = { + duration: data.duration || 0, + networkDuration: data.networkDuration || 0, + startTs: data.timestamp, + endTs: data.timestamp + (data.duration || 0), + timeSinceBoot: performance.measure('time_since_boot', 'frontend_boot_js_done_time_seconds').duration, + longFramesCount: data.longFramesCount, + longFramesTotalTime: data.longFramesTotalTime, + ...getPerformanceMemory(), + }; + + const panelMetrics = this.getPanelMetrics(); + + this.logDashboardAnalyticsEvent(data, payload, panelMetrics); + + reportInteraction('dashboard_render', { + interactionType: data.interactionType, + uid: this.dashboardUID, + ...payload, + }); + + logMeasurement('dashboard_render', payload, { + interactionType: data.interactionType, + dashboard: this.dashboardUID, + title: this.dashboardTitle, + }); + } + + /** + * Log dashboard analytics event with panel metrics and performance insights + */ + private logDashboardAnalyticsEvent( + data: performanceUtils.DashboardInteractionCompleteData, + payload: Record, + panelMetrics: PanelAnalyticsMetrics[] | null + ): void { + const panelCount = panelMetrics?.length || 0; + const panelSummary = panelCount ? `${panelCount} panels analyzed` : 'No panel metrics'; + + // Main analytics summary + const slowPanelCount = + panelMetrics?.filter( + (p) => + p.totalQueryTime + p.totalTransformationTime + p.totalRenderTime + p.totalFieldConfigTime + p.pluginLoadTime > + SLOW_OPERATION_THRESHOLD_MS + ).length || 0; + + writePerformanceGroupStart( + 'DAA', + `[ANALYTICS] ${data.interactionType} | ${panelSummary}${slowPanelCount > 0 ? ` | ${slowPanelCount} slow panels ⚠️` : ''}` + ); + + // Dashboard overview + writePerformanceGroupLog('DAA', '📊 Dashboard (ms):', { + duration: Math.round((data.duration || 0) * 10) / 10, + network: Math.round((data.networkDuration || 0) * 10) / 10, + interactionType: data.interactionType, + slowPanels: slowPanelCount, + }); + + // Analytics payload + writePerformanceGroupLog('DAA', '📈 Analytics payload:', payload); + + // Individual collapsible panel logs with detailed breakdown + if (panelMetrics && panelMetrics.length > 0) { + panelMetrics.forEach((panel) => { + const totalPanelTime = + panel.totalQueryTime + + panel.totalTransformationTime + + panel.totalRenderTime + + panel.totalFieldConfigTime + + panel.pluginLoadTime; + + const isSlowPanel = totalPanelTime > SLOW_OPERATION_THRESHOLD_MS; + const slowWarning = isSlowPanel ? ' ⚠️ SLOW' : ''; + + writePerformanceGroupStart( + 'DAA', + `🎨 Panel ${panel.pluginId}-${panel.panelId}: ${totalPanelTime.toFixed(1)}ms total${slowWarning}` + ); + + writePerformanceGroupLog('DAA', '🔧 Plugin:', { + id: panel.pluginId, + version: panel.pluginVersion || 'unknown', + panelId: panel.panelId, + panelKey: panel.panelKey, + }); + + writePerformanceGroupLog('DAA', '⚡ Performance (ms):', { + totalTime: Math.round(totalPanelTime * 10) / 10, // Round to 1 decimal + isSlowPanel: isSlowPanel, + breakdown: { + query: Math.round(panel.totalQueryTime * 10) / 10, + transform: Math.round(panel.totalTransformationTime * 10) / 10, + render: Math.round(panel.totalRenderTime * 10) / 10, + fieldConfig: Math.round(panel.totalFieldConfigTime * 10) / 10, + pluginLoad: Math.round(panel.pluginLoadTime * 10) / 10, + }, + }); + + if (panel.queryOperations.length > 0) { + writePerformanceGroupLog('DAA', '📊 Queries:', { + count: panel.queryOperations.length, + details: panel.queryOperations.map((op, index) => ({ + operation: index + 1, + duration: Math.round(op.duration * 10) / 10, + timestamp: op.timestamp, + queryType: op.queryType || 'unknown', + })), + }); + } + + if (panel.transformationOperations.length > 0) { + writePerformanceGroupLog('DAA', '🔄 Transformations:', { + count: panel.transformationOperations.length, + details: panel.transformationOperations.map((op, index) => ({ + operation: index + 1, + duration: Math.round(op.duration * 10) / 10, + timestamp: op.timestamp, + transformationId: op.transformationId || 'unknown', + success: op.success !== false, + })), + }); + } + + if (panel.renderOperations.length > 0) { + writePerformanceGroupLog('DAA', '🎨 Renders:', { + count: panel.renderOperations.length, + details: panel.renderOperations.map((op, index) => ({ + operation: index + 1, + duration: Math.round(op.duration * 10) / 10, + timestamp: op.timestamp, + })), + }); + } + + if (panel.fieldConfigOperations.length > 0) { + writePerformanceGroupLog('DAA', '⚙️ FieldConfigs:', { + count: panel.fieldConfigOperations.length, + details: panel.fieldConfigOperations.map((op, index) => ({ + operation: index + 1, + duration: Math.round(op.duration * 10) / 10, + timestamp: op.timestamp, + })), + }); + } + + writePerformanceGroupEnd(); + }); + } + + writePerformanceGroupEnd(); + } +} + +// Global singleton instance with lazy initialization +let dashboardAnalyticsAggregator: DashboardAnalyticsAggregator | null = null; + +export function initializeDashboardAnalyticsAggregator(): DashboardAnalyticsAggregator { + if (!dashboardAnalyticsAggregator) { + dashboardAnalyticsAggregator = new DashboardAnalyticsAggregator(); + + // Register as global performance observer + registerPerformanceObserver(dashboardAnalyticsAggregator, 'DAA'); + } + return dashboardAnalyticsAggregator; +} + +export function getDashboardAnalyticsAggregator(): DashboardAnalyticsAggregator { + return initializeDashboardAnalyticsAggregator(); +} diff --git a/public/app/features/dashboard/services/DashboardProfiler.ts b/public/app/features/dashboard/services/DashboardProfiler.ts index 1be6cfd1f1c..01fe67eb451 100644 --- a/public/app/features/dashboard/services/DashboardProfiler.ts +++ b/public/app/features/dashboard/services/DashboardProfiler.ts @@ -1,11 +1,24 @@ -import { logMeasurement, reportInteraction } from '@grafana/runtime'; -import { SceneInteractionProfileEvent, SceneRenderProfiler } from '@grafana/scenes'; +import { logMeasurement, reportInteraction, config } from '@grafana/runtime'; +import { performanceUtils, type SceneObject } from '@grafana/scenes'; -let dashboardSceneProfiler: SceneRenderProfiler | undefined; +interface SceneInteractionProfileEvent { + origin: string; + duration: number; + networkDuration: number; + startTs: number; + endTs: number; +} + +let dashboardSceneProfiler: performanceUtils.SceneRenderProfiler | undefined; export function getDashboardSceneProfiler() { if (!dashboardSceneProfiler) { - dashboardSceneProfiler = new SceneRenderProfiler(); + // Create panel profiling configuration + const panelProfilingConfig = { + watchStateKey: 'body', // Watch dashboard body changes for panel structure changes + }; + + dashboardSceneProfiler = new performanceUtils.SceneRenderProfiler(panelProfilingConfig); } return dashboardSceneProfiler; } @@ -30,28 +43,31 @@ export function getDashboardComponentInteractionCallback(uid: string, title: str }; } -export function getDashboardInteractionCallback(uid: string, title: string) { - return (e: SceneInteractionProfileEvent) => { - const payload = { - duration: e.duration, - networkDuration: e.networkDuration, - processingTime: e.duration - e.networkDuration, - startTs: e.startTs, - endTs: e.endTs, - totalJSHeapSize: e.totalJSHeapSize, - usedJSHeapSize: e.usedJSHeapSize, - jsHeapSizeLimit: e.jsHeapSizeLimit, - longFramesCount: e.longFramesCount, - longFramesTotalTime: e.longFramesTotalTime, - timeSinceBoot: performance.measure('time_since_boot', 'frontend_boot_js_done_time_seconds').duration, - }; +// Enhanced function to create profiler with dashboard metadata +export function getDashboardSceneProfilerWithMetadata(uid: string, title: string) { + const profiler = getDashboardSceneProfiler(); - reportInteraction('dashboard_render', { - interactionType: e.origin, - uid, - ...payload, - }); + // Set metadata for observer notifications + profiler.setMetadata({ + dashboardUID: uid, + dashboardTitle: title, + }); - logMeasurement(`dashboard_render`, payload, { interactionType: e.origin, dashboard: uid, title: title }); - }; + // Note: Analytics aggregator initialization and observer registration + // is now handled by DashboardAnalyticsInitializerBehavior + + return profiler; +} + +// Function to enable panel profiling for a specific dashboard +export function enablePanelProfilingForDashboard(dashboard: SceneObject, uid: string) { + // Check if panel profiling should be enabled for this dashboard + const shouldEnablePanelProfiling = + config.dashboardPerformanceMetrics.findIndex((configUid) => configUid === '*' || configUid === uid) !== -1; + + if (shouldEnablePanelProfiling) { + const profiler = getDashboardSceneProfiler(); + // Attach panel profiling to this dashboard + profiler.attachPanelProfiling(dashboard); + } } diff --git a/public/app/features/dashboard/services/ScenePerformanceLogger.ts b/public/app/features/dashboard/services/ScenePerformanceLogger.ts new file mode 100644 index 00000000000..79b0bceb402 --- /dev/null +++ b/public/app/features/dashboard/services/ScenePerformanceLogger.ts @@ -0,0 +1,220 @@ +import { performanceUtils, writePerformanceLog } from '@grafana/scenes'; + +import { PERFORMANCE_MARKS, PERFORMANCE_MEASURES, SLOW_OPERATION_THRESHOLD_MS } from './performanceConstants'; +import { registerPerformanceObserver, createPerformanceMark, createPerformanceMeasure } from './performanceUtils'; + +/** + * Grafana logger that subscribes to Scene performance events + * and logs them to console with Chrome DevTools performance marks and measurements for debugging. + */ +export class ScenePerformanceLogger implements performanceUtils.ScenePerformanceObserver { + private panelGroupsOpen = new Set(); // Track which panels we've seen + + public initialize() { + writePerformanceLog('SPL', 'Performance logger ready'); + } + + public destroy() { + this.panelGroupsOpen.clear(); + writePerformanceLog('SPL', 'Performance logger state cleared'); + } + + // Dashboard-level events + onDashboardInteractionStart = (data: performanceUtils.DashboardInteractionStartData): void => { + const dashboardStartMark = PERFORMANCE_MARKS.DASHBOARD_INTERACTION_START(data.operationId); + createPerformanceMark(dashboardStartMark, data.timestamp); + + const title = data.metadata?.dashboardTitle || 'Unknown Dashboard'; + + writePerformanceLog('SPL', `[DASHBOARD] ${data.interactionType} started: ${title}`); + }; + + onDashboardInteractionMilestone = (data: performanceUtils.DashboardInteractionMilestoneData): void => { + const milestone = data.milestone || 'unknown'; + const dashboardMilestoneMark = PERFORMANCE_MARKS.DASHBOARD_MILESTONE(data.operationId, milestone); + createPerformanceMark(dashboardMilestoneMark, data.timestamp); + }; + + onDashboardInteractionComplete = (data: performanceUtils.DashboardInteractionCompleteData): void => { + const dashboardEndMark = PERFORMANCE_MARKS.DASHBOARD_INTERACTION_END(data.operationId); + const dashboardStartMark = PERFORMANCE_MARKS.DASHBOARD_INTERACTION_START(data.operationId); + const dashboardMeasureName = PERFORMANCE_MEASURES.DASHBOARD_INTERACTION(data.operationId); + + createPerformanceMark(dashboardEndMark, data.timestamp); + createPerformanceMeasure(dashboardMeasureName, dashboardStartMark, dashboardEndMark); + + this.panelGroupsOpen.clear(); + }; + + onPanelOperationStart = (data: performanceUtils.PanelPerformanceData): void => { + this.createStandardizedPanelMark(data, 'start'); + + // Track panel for summary logging later + this.panelGroupsOpen.add(data.panelKey); + }; + + onPanelOperationComplete = (data: performanceUtils.PanelPerformanceData): void => { + this.createStandardizedPanelMark(data, 'end'); + this.createStandardizedPanelMeasure(data); + + const duration = (data.duration || 0).toFixed(1); + const slowWarning = (data.duration || 0) > SLOW_OPERATION_THRESHOLD_MS ? ' ⚠️ SLOW' : ''; + + // For query operations, include the queryId for correlation + let operationDisplay: string = data.operation; + if (data.operation === 'query') { + operationDisplay = `${data.operation} [${data.metadata.queryId}]`; + } + + writePerformanceLog( + 'SPL', + `[PANEL] ${data.pluginId}-${data.panelId} ${operationDisplay}: ${duration}ms${slowWarning}` + ); + }; + + // Query-level events + onQueryStart = (data: performanceUtils.QueryPerformanceData): void => { + const queryStartMark = PERFORMANCE_MARKS.QUERY_START(data.origin, data.queryId); + createPerformanceMark(queryStartMark, data.timestamp); + }; + + onQueryComplete = (data: performanceUtils.QueryPerformanceData): void => { + const queryEndMark = PERFORMANCE_MARKS.QUERY_END(data.origin, data.queryId); + const queryStartMark = PERFORMANCE_MARKS.QUERY_START(data.origin, data.queryId); + const queryMeasureName = PERFORMANCE_MEASURES.QUERY(data.origin, data.queryId); + + createPerformanceMark(queryEndMark, data.timestamp); + createPerformanceMeasure(queryMeasureName, queryStartMark, queryEndMark); + + const duration = (data.duration || 0).toFixed(1); + const slowWarning = (data.duration || 0) > SLOW_OPERATION_THRESHOLD_MS ? ' ⚠️ SLOW' : ''; + + const queryType = data.queryType.replace(/^(getDataSource\/|AnnotationsDataLayer\/)/, ''); // Remove prefixes + writePerformanceLog('SPL', `[QUERY ${data.origin}] ${queryType} [${data.queryId}]: ${duration}ms${slowWarning}`); + }; + + private createStandardizedPanelMark(data: performanceUtils.PanelPerformanceData, phase: 'start' | 'end'): void { + const { operation, panelKey, operationId } = data; + + switch (operation) { + case 'query': + const markName = + phase === 'start' + ? PERFORMANCE_MARKS.PANEL_QUERY_START(panelKey, operationId) + : PERFORMANCE_MARKS.PANEL_QUERY_END(panelKey, operationId); + createPerformanceMark(markName, data.timestamp); + break; + + case 'plugin-load': + const pluginMarkName = + phase === 'start' + ? PERFORMANCE_MARKS.PANEL_PLUGIN_LOAD_START(panelKey, operationId) + : PERFORMANCE_MARKS.PANEL_PLUGIN_LOAD_END(panelKey, operationId); + createPerformanceMark(pluginMarkName, data.timestamp); + break; + + case 'fieldConfig': + const fieldConfigMarkName = + phase === 'start' + ? PERFORMANCE_MARKS.PANEL_FIELD_CONFIG_START(panelKey, operationId) + : PERFORMANCE_MARKS.PANEL_FIELD_CONFIG_END(panelKey, operationId); + createPerformanceMark(fieldConfigMarkName, data.timestamp); + break; + + case 'render': + const renderMarkName = + phase === 'start' + ? PERFORMANCE_MARKS.PANEL_RENDER_START(panelKey, operationId) + : PERFORMANCE_MARKS.PANEL_RENDER_END(panelKey, operationId); + createPerformanceMark(renderMarkName, data.timestamp); + break; + + case 'transform': + const transformationId = data.metadata.transformationId; + if (phase === 'start') { + createPerformanceMark( + PERFORMANCE_MARKS.PANEL_TRANSFORM_START(panelKey, transformationId, operationId), + data.timestamp + ); + } else { + const isError = data.metadata.error || data.metadata.success === false; + const transformEndMarkName = isError + ? PERFORMANCE_MARKS.PANEL_TRANSFORM_ERROR(panelKey, transformationId, operationId) + : PERFORMANCE_MARKS.PANEL_TRANSFORM_END(panelKey, transformationId, operationId); + createPerformanceMark(transformEndMarkName, data.timestamp); + } + break; + + default: + break; + } + } + + private createStandardizedPanelMeasure(data: performanceUtils.PanelPerformanceData): void { + const { operation, panelKey, operationId } = data; + + switch (operation) { + case 'query': + const startMark = PERFORMANCE_MARKS.PANEL_QUERY_START(panelKey, operationId); + const endMark = PERFORMANCE_MARKS.PANEL_QUERY_END(panelKey, operationId); + const measureName = PERFORMANCE_MEASURES.PANEL_QUERY(panelKey, operationId); + createPerformanceMeasure(measureName, startMark, endMark); + break; + + case 'plugin-load': + const pluginStartMark = PERFORMANCE_MARKS.PANEL_PLUGIN_LOAD_START(panelKey, operationId); + const pluginEndMark = PERFORMANCE_MARKS.PANEL_PLUGIN_LOAD_END(panelKey, operationId); + const pluginMeasureName = PERFORMANCE_MEASURES.PANEL_PLUGIN_LOAD(panelKey, operationId); + createPerformanceMeasure(pluginMeasureName, pluginStartMark, pluginEndMark); + break; + + case 'fieldConfig': + const fieldConfigStartMark = PERFORMANCE_MARKS.PANEL_FIELD_CONFIG_START(panelKey, operationId); + const fieldConfigEndMark = PERFORMANCE_MARKS.PANEL_FIELD_CONFIG_END(panelKey, operationId); + const fieldConfigMeasureName = PERFORMANCE_MEASURES.PANEL_FIELD_CONFIG(panelKey, operationId); + createPerformanceMeasure(fieldConfigMeasureName, fieldConfigStartMark, fieldConfigEndMark); + break; + + case 'render': + const renderStartMark = PERFORMANCE_MARKS.PANEL_RENDER_START(panelKey, operationId); + const renderEndMark = PERFORMANCE_MARKS.PANEL_RENDER_END(panelKey, operationId); + const renderMeasureName = PERFORMANCE_MEASURES.PANEL_RENDER(panelKey, operationId); + createPerformanceMeasure(renderMeasureName, renderStartMark, renderEndMark); + break; + + case 'transform': + const transformationId = data.metadata.transformationId; + const transformStartMark = PERFORMANCE_MARKS.PANEL_TRANSFORM_START(panelKey, transformationId, operationId); + + const isError = data.metadata.error || data.metadata.success === false; + const transformEndMark = isError + ? PERFORMANCE_MARKS.PANEL_TRANSFORM_ERROR(panelKey, transformationId, operationId) + : PERFORMANCE_MARKS.PANEL_TRANSFORM_END(panelKey, transformationId, operationId); + + const transformMeasureName = PERFORMANCE_MEASURES.PANEL_TRANSFORM(panelKey, transformationId, operationId); + createPerformanceMeasure(transformMeasureName, transformStartMark, transformEndMark); + break; + + default: + break; + } + } +} + +// Global singleton instance with lazy initialization +let scenePerformanceLogger: ScenePerformanceLogger | null = null; + +export function initializeScenePerformanceLogger(): ScenePerformanceLogger { + if (!scenePerformanceLogger) { + scenePerformanceLogger = new ScenePerformanceLogger(); + scenePerformanceLogger.initialize(); + + // Register as global performance observer + registerPerformanceObserver(scenePerformanceLogger, 'SPL'); + } + return scenePerformanceLogger; +} + +export function getScenePerformanceLogger(): ScenePerformanceLogger { + return initializeScenePerformanceLogger(); +} diff --git a/public/app/features/dashboard/services/dashboard-render-performance-profiling.md b/public/app/features/dashboard/services/dashboard-render-performance-profiling.md index 80f6fc522f6..cbef48d7411 100644 --- a/public/app/features/dashboard/services/dashboard-render-performance-profiling.md +++ b/public/app/features/dashboard/services/dashboard-render-performance-profiling.md @@ -10,25 +10,34 @@ This documentation describes the dashboard render performance metrics exposed fr - [Tracked Interactions](#tracked-interactions) - [Core Performance-Tracked Interactions](#core-performance-tracked-interactions) - [Interaction Origin Mapping](#interaction-origin-mapping) +- [Panel-Level Performance Attribution](#panel-level-performance-attribution) + - [Overview](#panel-level-overview) + - [Panel Operations Tracked](#panel-operations-tracked) + - [Performance Observer Architecture](#performance-observer-architecture) - [Profiling Implementation](#profiling-implementation) - [Profile Data Structure](#profile-data-structure) - [Collected Metrics](#collected-metrics) -- [Debugging and Development](#debugging-and-development) - - [Enable Profiler Debug Logging](#enable-profiler-debug-logging) - - [Enable Echo Service Debug Logging](#enable-echo-service-debug-logging) - - [Browser Performance Profiler](#browser-performance-profiler) -- [Analytics Integration](#analytics-integration) - - [Interaction Reporting](#interaction-reporting) - - [Data Collection](#data-collection) -- [Implementation Details](#implementation-details) - [Long Frame Detection](#long-frame-detection) +- [Analytics Integration](#analytics-integration) + - [Analytics Components](#analytics-components) + - [Chrome DevTools Integration](#chrome-devtools-integration) + - [Data Collection](#data-collection) +- [Debugging and Development](#debugging-and-development) + - [Enable Performance Debug Logging](#enable-performance-debug-logging) + - [Console Output Examples](#console-output-examples) + - [Browser Performance Profiler](#browser-performance-profiler) +- [Implementation Details](#implementation-details) + - [Architecture Overview](#architecture-overview) - [Tab Inactivity Handling](#tab-inactivity-handling) + - [Profile Isolation](#profile-isolation) - [Related Documentation](#related-documentation) ## Overview The exposed dashboard performance metrics feature provides comprehensive tracking and profiling of dashboard interactions, allowing administrators and developers to analyze dashboard render performance, user interactions, and identify performance bottlenecks. +The system includes **panel-level performance attribution** through an observer pattern architecture, providing visibility into individual panel operations within dashboard interactions. This enables identification of performance bottlenecks at both dashboard and panel levels, with comprehensive analytics reporting and Chrome DevTools integration. + ## Configuration ### Enabling Performance Metrics @@ -110,6 +119,102 @@ logMeasurement(`dashboard_render`, payload, { interactionType: e.origin, dashboa The profiling system uses profiler event's `origin` directly as the `interactionType`, providing direct mapping between user actions and performance measurements. +## Panel-Level Performance Attribution + +### Panel-Level Overview + +The panel-level performance attribution system uses a observer pattern architecture built around `ScenePerformanceTracker` to provide comprehensive visibility into individual panel operations. When dashboard profiling is enabled, `VizPanelRenderProfiler` instances are automatically attached to all panels, providing granular tracking of panel lifecycle operations. + +**Key Features:** + +- **Complete lifecycle tracking**: Monitors plugin load, query execution, data transformation, field configuration, and rendering phases +- **Sub-millisecond precision timing**: Chrome DevTools integration via performance marks and measurements +- **Operation ID correlation**: UUID-based operation IDs with crypto fallback for cross-environment compatibility +- **Observer pattern architecture**: Clean separation between performance tracking and business logic with extensible observer support +- **Real-time analytics aggregation**: Structured data format ready for analytics reporting +- **Conditional profiling**: Analytics aggregator only initialized when profiling is enabled +- **Type-safe interfaces**: Comprehensive TypeScript support with event-specific interfaces + +### Panel Operations Tracked + +The system tracks the following panel operations: + +| Operation | Description | When Tracked | +| ------------- | --------------------- | ----------------------------------------------- | +| `plugin-load` | Plugin initialization | When panel plugin is loaded | +| `query` | Data source queries | When panel executes queries | +| `transform` | Data transformations | When data is transformed (SceneDataTransformer) | +| `fieldConfig` | Field configuration | When field configurations are applied | +| `render` | Panel rendering | When panel is rendered | + +Each operation is tracked with: + +- **Operation ID**: UUID-based unique identifier for correlating start/complete events (e.g., `query-a1b2c3d4-e5f6-7890-abcd-ef1234567890`) +- **Timing**: High-precision start and end timestamps with sub-millisecond duration calculation +- **Metadata**: Operation-specific data (query types, transformation IDs, plugin information, etc.) + +### Operation ID Format + +The system generates unique operation IDs using a standardized format: + +``` +- +``` + +**Examples:** + +- `plugin-load-550e8400-e29b-41d4-a716-446655440000` +- `query-a1b2c3d4-e5f6-7890-abcd-ef1234567890` +- `transform-b2c3d4e5-f6g7-8901-bcde-f23456789012` +- `fieldConfig-c3d4e5f6-g7h8-9012-cdef-345678901234` +- `render-d4e5f6g7-h8i9-0123-def0-456789012345` + +**Benefits:** + +- **Global Uniqueness**: UUIDs prevent ID collisions across dashboard sessions +- **Cross-Environment Compatibility**: Crypto fallback ensures operation in all environments +- **Operation Correlation**: Enables precise tracking of start/complete event pairs +- **Debugging**: Human-readable prefixes make log analysis easier + +### Performance Observer Architecture + +The system uses `ScenePerformanceTracker` as a centralized coordinator that manages performance observers through an event-driven architecture. The performance utilities are organized under the `performanceUtils` namespace. + +```typescript +// Import performance utilities from scenes +import { performanceUtils } from '@grafana/scenes'; + +// Observer interface implemented by analytics components +interface ScenePerformanceObserver { + onDashboardInteractionStart?(data: performanceUtils.DashboardInteractionStartData): void; + onDashboardInteractionMilestone?(data: performanceUtils.DashboardInteractionMilestoneData): void; + onDashboardInteractionComplete?(data: performanceUtils.DashboardInteractionCompleteData): void; + onPanelOperationStart?(data: performanceUtils.PanelPerformanceData): void; + onPanelOperationComplete?(data: performanceUtils.PanelPerformanceData): void; + onQueryStart?(data: performanceUtils.QueryPerformanceData): void; + onQueryComplete?(data: performanceUtils.QueryPerformanceData): void; +} + +// Register observers with the performance tracker +const tracker = performanceUtils.getScenePerformanceTracker(); +tracker.addObserver(myObserver); +``` + +**Operation ID Generation:** + +The system generates unique operation IDs for correlating start/complete events using UUID with fallback support: + +```typescript +// Uses crypto.randomUUID() when available, Math.random() fallback for compatibility +const operationId = performanceUtils.generateOperationId('panel-query'); +// Result: "panel-query-550e8400-e29b-41d4-a716-446655440000" +``` + +**Registered Observers:** + +- **`DashboardAnalyticsAggregator`**: Aggregates panel metrics for analytics reporting (conditionally initialized) +- **`ScenePerformanceLogger`**: Creates Chrome DevTools performance marks and console logs + ## Profiling Implementation ### Profile Data Structure @@ -153,42 +258,274 @@ The performance metrics provide detailed insights into where time is spent durin - **Total Duration (`duration`)**: Complete time from interaction start to completion - **Network Time (`networkDuration`)**: Time spent waiting for server responses (data source queries, API calls) - **Processing Time (`processingTime`)**: Time spent on client-side operations (rendering, computations, DOM updates) -- **Long Frames (`longFramesCount` & `longFramesTotalTime`)**: Frames exceeding 50ms threshold indicate potential UI jank or performance issues. These metrics help identify interactions causing poor user experience: - - `longFramesCount`: The number of frames that exceeded the 50ms threshold - - `longFramesTotalTime`: The total accumulated time of all long frames, indicating the severity of performance issues - - **Detection Method**: Automatically uses Long Animation Frame API when available (Chrome 123+), falls back to manual tracking for broader browser support +- **Long Frames (`longFramesCount` & `longFramesTotalTime`)**: Frames exceeding 50ms threshold indicate potential UI jank or performance issues + +### Long Frame Detection + +The profiler includes sophisticated long frame detection using the Long Animation Frame (LoAF) API when available, with automatic fallback to manual frame tracking: + +#### Detection Methods + +1. **Long Animation Frame API (Primary)** + - **Browser Support**: Chrome 123+ (automatically detected) + - **Threshold**: 50ms (standard LoAF threshold) + - **Benefits**: Browser-level accuracy, script attribution, automatic buffering control + +2. **Manual Frame Tracking (Fallback)** + - **Browser Support**: All browsers + - **Threshold**: 50ms (same as LoAF) + - **Implementation**: Uses requestAnimationFrame for frame monitoring + +#### Metrics Collected + +- **`longFramesCount`**: Number of frames exceeding the 50ms threshold +- **`longFramesTotalTime`**: Cumulative duration of all long frames during interaction + +This helps identify: + +- Rendering performance issues impacting user experience +- Interactions causing UI jank or frame drops +- Performance optimization opportunities + +## Analytics Integration + +### Analytics Components + +The performance tracking system integrates with Grafana's analytics through two main components: + +#### DashboardAnalyticsAggregator + +Aggregates panel-level performance metrics for analytics reporting: + +- Collects and aggregates metrics for all panel operations +- Tracks operation counts and total time spent per panel +- Sends comprehensive analytics reports via `reportInteraction` and `logMeasurement` +- Provides detailed panel breakdowns including slow panel detection + +#### ScenePerformanceLogger + +Creates Chrome DevTools performance marks and measurements for debugging: + +- Generates performance marks for all dashboard and panel operations +- Creates performance measurements for timing visualization +- Provides console logging for real-time debugging +- Integrates with Chrome DevTools Performance timeline + +### Chrome DevTools Integration + +Performance operations are recorded as marks and measurements in the Chrome DevTools Performance timeline: + +**Dashboard-level marks:** + +``` +Dashboard Interaction Start: +Dashboard Interaction End: +Dashboard Milestone: : +``` + +**Panel-level marks:** + +``` +Panel Query Start: : +Panel Query End: : +Panel Render Start: : +Panel Render End: : +``` + +### Data Collection + +The system collects and reports data at two levels: + +#### Dashboard Interaction Data + +Reported for each interaction via `reportInteraction` and `logMeasurement`: + +```typescript +{ + interactionType: string, // Type of interaction + uid: string, // Dashboard UID + duration: number, // Total duration + networkDuration: number, // Network time + processingTime: number, // Client-side processing time + startTs: number, // Profile start timestamp + endTs: number, // Profile end timestamp + longFramesCount: number, // Number of long frames + longFramesTotalTime: number, // Total time of long frames + totalJSHeapSize: number, // Memory metrics + usedJSHeapSize: number, + jsHeapSizeLimit: number, + timeSinceBoot: number // Time since frontend boot +} +``` + +#### Panel-Level Metrics + +Aggregated by `DashboardAnalyticsAggregator` for each panel with detailed operation tracking: + +```typescript +{ + panelId: string, // Panel identifier + pluginId: string, // Plugin type (e.g., 'timeseries', 'stat') + pluginVersion?: string, // Plugin version + totalQueryTime: number, // Total time spent in queries + totalTransformationTime: number, // Total time in transformations + totalRenderTime: number, // Total render time + totalFieldConfigTime: number, // Total field config time + pluginLoadTime: number, // Plugin initialization time + + // Individual operations with UUID-based operation IDs + pluginLoadOperations: Array<{ + operationId: string, // e.g., "plugin-load-550e8400-e29b-41d4-a716-446655440000" + duration: number, + timestamp: number + }>, + queryOperations: Array<{ // Individual query operations + operationId: string, // e.g., "query-a1b2c3d4-e5f6-7890-abcd-ef1234567890" + duration: number, + timestamp: number, + queryType?: string + }>, + transformationOperations: Array<{ + duration: number, + timestamp: number, + transformationType?: string + }>, + fieldConfigOperations: Array<{ + duration: number, + timestamp: number + }>, + renderOperations: Array<{ // Individual render operations + duration: number, + timestamp: number + }>, + + // Performance analysis + isSlowPanel: boolean, // true if total time > SLOW_OPERATION_THRESHOLD_MS (500ms) + slowOperationThreshold: number, // Current threshold value (500ms) + totalPanelTime: number // Sum of all operation times +} +``` ## Debugging and Development -### Enable Profiler Debug Logging +### Enable Performance Debug Logging -To observe profiling events in the browser console: +To observe performance profiling events in the browser console: ```javascript -localStorage.setItem('grafana.debug.scenes', 'true'); +// Enable performance debug logging +localStorage.setItem('grafana.debug.sceneProfiling', 'true'); ``` -#### Console Output +### Performance Threshold Configuration -When debug logging is enabled, you'll see console logs for each profiling event: +The system uses a const threshold to identify slow operations: + +- **Default Threshold**: `SLOW_OPERATION_THRESHOLD_MS = 500` milliseconds +- **Applies to**: Individual panel operations and total panel performance +- **Slow Panel Detection**: Panels exceeding threshold display ⚠️ warnings in logs +- **Analytics Integration**: Slow panel count included in dashboard analytics reports + +**Example Slow Operation Warning:** + +```javascript +SPL: [PANEL] timeseries-panel-1 query [query-abc123]: 125.3ms ⚠️ SLOW +DAA: 🎨 Panel timeseries-panel-1: 125.3ms total ⚠️ SLOW +``` + +### Console Output Examples + +With debug logging enabled, you'll see detailed performance logs: + +#### Dashboard Interaction Logs ``` -SceneRenderProfiler: Profile started[clean] - ├─ Origin: dashboard_view - └─ Timestamp: 1072.5ms -LongFrameDetector: Started tracking with LoAF API method, threshold: 50ms -... // intermediate steps adding profile crumbs -LongFrameDetector: Long frame detected (LoAF): 67.4ms at 1071.5ms -LongFrameDetector: Long frame detected (LoAF): 76.3ms at 1139.8ms -... // more long frame detections -SceneRenderProfiler: Profile completed - ├─ Timestamp: 3530.6ms - ├─ Total time: 156.8ms - ├─ Slow frames: 16.3ms (1 frames) - └─ Long frames: 143.7ms (2 frames) -SceneRenderProfiler: Stopped long frame detection - profile complete at 3530.6ms +SRP: [PROFILER] dashboard_view started (clean) +LFD: Started tracking with LoAF API method, threshold: 50ms +SPL: [DASHBOARD] dashboard_view started: My Dashboard +SRP: [PROFILER] dashboard_view completed + ├─ Duration: 156.8ms + ├─ Long frames: 143.7ms (2 frames) + └─ Network time: 45.2ms ``` +#### Panel Operation Logs + +``` +SPL: [PANEL] timeseries-panel-1 plugin-load: 39.0ms +SPL: [PANEL] timeseries-panel-1 query [query-a1b2c3d4-e5f6-7890-abcd]: 45.2ms +SPL: [PANEL] timeseries-panel-1 transform: 12.3ms +SPL: [PANEL] timeseries-panel-1 fieldConfig: 5.0ms +SPL: [PANEL] timeseries-panel-1 render: 23.8ms ⚠️ SLOW +``` + +#### VizPanelRenderProfiler Logs + +The `VizPanelRenderProfiler` provides lifecycle and error logging (only visible with scenes debug logging enabled): + +``` +VizPanelRenderProfiler [My Dashboard Panel]: Plugin changed to timeseries +VizPanelRenderProfiler [My Dashboard Panel]: Cleaned up +VizPanelRenderProfiler: Not attached to a VizPanel +VizPanelRenderProfiler: Panel has no key, skipping tracking +``` + +#### Analytics Aggregator Summary + +The `DashboardAnalyticsAggregator` creates structured **collapsible console groups** for detailed analysis. Each panel gets its own expandable group in the browser console: + +``` +DAA: [ANALYTICS] dashboard_view | 4 panels analyzed | 1 slow panels ⚠️ + DAA: 📊 Dashboard (ms): { + duration: 156.8, + network: 45.2, + interactionType: "dashboard_view", + slowPanels: 1 + } + DAA: 📈 Analytics payload: { /* comprehensive analytics data */ } + + // Per-panel detailed breakdown (console group for each panel) + DAA: 🎨 Panel timeseries-panel-1: 125.3ms total ⚠️ SLOW + DAA: 🔧 Plugin: { + id: "timeseries", + version: "10.0.0", + panelId: "panel-1", + panelKey: "panel-1" + } + DAA: ⚡ Performance (ms): { + totalTime: 125.3, + isSlowPanel: true, + breakdown: { + query: 45.2, + transform: 12.3, + render: 23.8, + fieldConfig: 5.0, + pluginLoad: 39.0 + } + } + DAA: 📊 Queries: { + count: 2, + details: [ + { operation: 1, duration: 25.1, timestamp: 1729692845100.123 }, + { operation: 2, duration: 20.1, timestamp: 1729692845125.456 } + ] + } + DAA: 🔄 Transformations: { + count: 1, + details: [ + { operation: 1, duration: 12.3, timestamp: 1729692845150.789 } + ] + } + DAA: 🎨 Renders: { + count: 1, + details: [ + { operation: 1, duration: 23.8, timestamp: 1729692845163.012 } + ] + } +``` + +**Note**: The indentation shows the **console group hierarchy**. In the browser console, each panel creates a collapsible group that can be expanded to see detailed operation breakdowns. The main dashboard analytics group contains nested panel groups for organized analysis. + ### Enable Echo Service Debug Logging To observe Echo events in the browser console: @@ -207,99 +544,79 @@ When Echo debug logging is enabled, you'll see console logs for each profiling e ### Browser Performance Profiler -Dashboard interactions can be recorded in the browser's performance profiler, where they appear as: +Dashboard and panel operations are recorded in the Chrome DevTools Performance timeline with detailed marks and measurements: + +**Dashboard Marks:** ``` -Dashboard Interaction +Dashboard Interaction Start: dashboard-550e8400-e29b-41d4-a716-446655440000 +Dashboard Interaction End: dashboard-550e8400-e29b-41d4-a716-446655440000 +Dashboard Milestone: dashboard-550e8400-e29b-41d4-a716-446655440000:queries_complete +Dashboard Milestone: dashboard-550e8400-e29b-41d4-a716-446655440000:actual_interaction_complete ``` -## Analytics Integration +**Panel Marks:** -### Interaction Reporting - -Performance data is integrated with Grafana's analytics system through: - -- **`reportInteraction`**: Reports interaction events to Echo service with performance data -- **`logMeasurement`**: Records Faro's performance measurements with metadata - -### Data Collection - -The system reports the following data for each interaction: - -```typescript -{ - interactionType: string, // Type of interaction - uid: string, // Dashboard UID - duration: number, // Total duration - networkDuration: number, // Network time - processingTime: number, // Client-side processing time (duration - networkDuration) - startTs: number, // Profile start timestamp - endTs: number, // Profile end timestamp - totalJSHeapSize: number, // Memory metrics - usedJSHeapSize: number, - jsHeapSizeLimit: number, - longFramesCount: number, // Number of long frames (>50ms threshold) - longFramesTotalTime: number, // Total time of all long frames - timeSinceBoot: number // Time since frontend boot -} ``` +Panel Plugin Load Start: panel-1:plugin-load-a1b2c3d4-e5f6-7890-abcd-ef1234567890 +Panel Plugin Load End: panel-1:plugin-load-a1b2c3d4-e5f6-7890-abcd-ef1234567890 +Panel Query Start: panel-1:query-b2c3d4e5-f6g7-8901-bcde-f23456789012 +Panel Query End: panel-1:query-b2c3d4e5-f6g7-8901-bcde-f23456789012 +Panel Transform Start: panel-1:transform-c3d4e5f6-g7h8-9012-cdef-345678901234 +Panel Transform End: panel-1:transform-c3d4e5f6-g7h8-9012-cdef-345678901234 +Panel Field Config Start: panel-1:fieldConfig-d4e5f6g7-h8i9-0123-def0-456789012345 +Panel Field Config End: panel-1:fieldConfig-d4e5f6g7-h8i9-0123-def0-456789012345 +Panel Render Start: panel-1:render-e5f6g7h8-i9j0-1234-ef01-567890123456 +Panel Render End: panel-1:render-e5f6g7h8-i9j0-1234-ef01-567890123456 +``` + +These marks enable visual timeline analysis of: + +- Overall dashboard interaction timing +- Individual panel operation performance +- Parallel vs sequential operations +- Performance bottlenecks ## Implementation Details -The profiler is integrated into dashboard creation paths and uses a singleton pattern to share profiler instances across dashboard reloads. The performance tracking is implemented using the `SceneRenderProfiler` from the `@grafana/scenes` library. +### Architecture Overview -### Long Frame Detection +The performance tracking system consists of multiple integrated components with observer pattern architecture: -The profiler uses the Long Animation Frame (LoAF) API when available to monitor frame rendering performance during dashboard interactions: +1. **SceneRenderProfiler** (Scenes library - `performanceUtils` namespace) + - Singleton profiler instance shared across dashboard reloads + - Tracks dashboard interactions and manages long frame detection + - Integrates with VizPanelRenderProfiler for comprehensive panel-level tracking -#### Primary Method: Long Animation Frame API +2. **ScenePerformanceTracker** (Scenes library - `performanceUtils` namespace) + - Central coordinator implementing observer pattern architecture + - Distributes performance events to registered observers without coupling + - Provides type-safe interfaces for different event types + - Supports extensible observer registration with clean separation of concerns -- **Browser Support**: Chrome 123+ (automatically detected) -- **Threshold**: 50ms (standard LoAF threshold) -- **Benefits**: - - Browser-level accuracy and performance - - Standards-based implementation - - More efficient than manual tracking - - Automatic buffering control for real-time detection +3. **VizPanelRenderProfiler** (Scenes library - `performanceUtils` namespace) + - Automatically attached to individual panels when profiling is enabled + - Tracks complete panel lifecycle: plugin-load, query, transform, fieldConfig, render + - Uses UUID-based operation IDs with crypto fallback for cross-environment compatibility + - Reports structured performance data to ScenePerformanceTracker -#### Fallback Method: Manual Frame Tracking +4. **DashboardAnalyticsAggregator** (Grafana) + - **Conditionally initialized**: Only activated when `enableProfiling` is true + - Aggregates panel metrics for analytics reporting with slow panel detection + - Uses configurable threshold (SLOW_OPERATION_THRESHOLD_MS = 100ms) + - Sends comprehensive reports via reportInteraction and logMeasurement -- **Browser Support**: All browsers -- **Threshold**: 50ms (same as LoAF threshold) -- **Used when**: LoAF API is not available -- **Implementation**: Uses requestAnimationFrame for frame monitoring - -Both methods track: - -- **Count**: Number of frames exceeding the threshold -- **Total Time**: Cumulative duration of all long frames - -#### Debug Output - -With LoAF API: - -``` -LongFrameDetector: Long frame detected (LoAF): 67.4ms at 1234.5ms -``` - -With manual fallback: - -``` -LongFrameDetector: Long frame detected (manual): 38.2ms (threshold: 50ms) -``` - -This metric is particularly valuable for: - -- Detecting rendering performance issues that impact user experience -- Identifying when interactions cause UI jank or frame drops -- Measuring the impact of performance optimizations on frame rendering -- Comparing performance across different browsers and environments +5. **ScenePerformanceLogger** (Grafana) + - Creates Chrome DevTools performance marks and measurements + - Provides structured console logging for debugging with localStorage controls + - Maps operations to standardized performance mark names + - Integrates with browser Performance Timeline API ### Tab Inactivity Handling To prevent meaningless profiling data when users switch browser tabs, the `SceneRenderProfiler` implements dual protection mechanisms: -#### Primary Protection: Page Visibility API +#### Page Visibility API The profiler automatically cancels active profiling sessions when the browser tab becomes inactive: @@ -313,109 +630,71 @@ document.addEventListener('visibilitychange', () => { This provides immediate response to tab switches using the browser's native visibility change events. -#### Fallback Protection: Frame Length Detection +#### Frame Length Measurement for Performance Analysis -As a backup mechanism, the profiler detects tab inactivity by monitoring frame duration: +The profiler measures frame lengths during the post-interaction recording window for performance analysis: ```javascript -if (frameLength > TAB_INACTIVE_THRESHOLD) { - // 1000ms - this.cancelProfile(); - return; -} +const frameLength = currentFrameTime - lastFrameTime; +this.#recordedTrailingSpans.push(frameLength); ``` -This fallback catches cases where visibility events might be missed and prevents recording of artificially long frame times (hours instead of milliseconds) that occur when `requestAnimationFrame` callbacks resume after tab reactivation. +**Note**: Frame length measurement is used for performance analytics only. The profiler does **not** use frame length thresholds for tab inactivity detection. Tab inactivity protection relies exclusively on the Page Visibility API for accurate and immediate response to tab changes. -### Profile Isolation and Overlapping Interactions +### Profile Isolation -To ensure accurate performance measurements, the `SceneRenderProfiler` implements profile isolation to handle rapid user interactions: +To ensure accurate performance measurements, the profiler implements automatic profile cancellation when handling rapid user interactions: -#### Understanding Trailing Frame Recording +**Trailing Frame Recording**: After an interaction completes, the profiler continues recording for 2 seconds (POST_STORM_WINDOW) to capture delayed rendering effects. -After the main interaction completes, the profiler continues to record "trailing frames" for 2 seconds (POST_STORM_WINDOW) to capture any delayed rendering effects. This ensures complete performance measurement including: - -- Delayed DOM updates -- Asynchronous rendering operations -- Secondary effects from the initial interaction - -#### Problem: Mixed Performance Data - -When users perform rapid interactions during this 2-second trailing frame window (e.g., quickly changing time ranges or triggering a refresh), the performance data from multiple actions could be mixed into a single profile. This led to: - -- Inaccurate performance measurements -- Profile events that never completed -- Crumbs from different interactions being combined -- Trailing frames from one interaction being attributed to another - -#### Solution: Automatic Profile Cancellation - -Starting with `@grafana/scenes` v6.30.4, the profiler automatically cancels the current profile when a new interaction begins while trailing frames are still being recorded: +**Automatic Cancellation**: When a new interaction begins during trailing frame recording, the current profile is cancelled to prevent mixing performance data: ```javascript -// When new profile is requested while still recording trailing frames if (this.#trailAnimationFrameId) { this.cancelProfile(); - this._startNewProfile(name, true); // true = forced profile -} else { - this.addCrumb(name); + this._startNewProfile(name, true); // forced profile } ``` -This ensures: +**Profile Types**: -- Each interaction gets its own isolated measurement -- No mixing of performance data between different user actions -- Clean separation of interaction metrics +- **Clean Start**: No active profile when starting +- **Forced Start**: Previous profile cancelled for new interaction -#### Profile Start Types - -The profiler now distinguishes between two types of profile starts: - -1. **Clean Start**: Profile started when no other profile is active -2. **Forced Start (Interrupted)**: Profile started by cancelling a previous active profile - -This information is logged in debug mode: - -``` -SceneRenderProfiler: Profile started[forced]: {origin: "refresh", crumbs: []} -SceneRenderProfiler: Profile started[clean]: {origin: "dashboard_view", crumbs: []} -``` - -Additionally, when a profile is cancelled due to overlapping interactions: - -``` -SceneRenderProfiler: Cancelled recording frames, new profile started -``` - -#### Example Scenario - -1. User changes time range (profile starts) -2. Dashboard finishes loading after 500ms (main profile complete) -3. Profiler continues recording trailing frames to capture delayed effects -4. At 1 second, user clicks refresh button -5. Without this fix: Refresh would be added as a crumb to the time range profile -6. With this fix: Time range profile is cancelled, new refresh profile starts cleanly - -This fix is particularly important for dashboards with: - -- Auto-refresh enabled -- Slow API responses -- Rapid user interactions - -Without profile isolation, these scenarios could result in profiles that never complete and mix data from multiple unrelated interactions. +This ensures each interaction gets isolated measurements, preventing data contamination from overlapping operations. ## Related Documentation -- [PR #858 - Add SceneRenderProfiler to scenes](https://github.com/grafana/scenes/pull/858) -- [PR #99629 - Dashboard render performance metrics](https://github.com/grafana/grafana/pull/99629) -- [PR #108658 - Dashboard: Tweak interaction tracking](https://github.com/grafana/grafana/pull/108658) -- [PR #1195 - Enhance SceneRenderProfiler with additional interaction tracking](https://github.com/grafana/scenes/pull/1195) -- [PR #1198 - Make SceneRenderProfiler optional and injectable](https://github.com/grafana/scenes/pull/1198) -- [PR #1199 - SceneRenderProfiler: add start and end timestamps to profile events](https://github.com/grafana/scenes/pull/1199) -- [PR #1205 - SceneRenderProfiler: Handle tab inactivity](https://github.com/grafana/scenes/pull/1205) -- [PR #1209 - SceneRenderProfiler: Only capture network requests within measurement window](https://github.com/grafana/scenes/pull/1209) -- [PR #1211 - SceneRenderProfiler: Improve profiler accuracy by adding cancellation and skipping inactive tabs](https://github.com/grafana/scenes/pull/1211) -- [PR #1212 - SceneQueryController: Fix profiler query controller registration on scene re-activation](https://github.com/grafana/scenes/pull/1212) -- [PR #1225 - SceneRenderProfiler: Handle overlapping profiles by cancelling previous profile](https://github.com/grafana/scenes/pull/1225) -- [PR #1235 - Implement long frame detection with LoAF API and manual fallback](https://github.com/grafana/scenes/pull/1235) +### Foundational Performance System + +- [PR #858 - Add SceneRenderProfiler to scenes](https://github.com/grafana/scenes/pull/858) ✅ Merged +- [PR #99629 - Dashboard render performance metrics](https://github.com/grafana/grafana/pull/99629) ✅ Merged +- [PR #108658 - Dashboard: Tweak interaction tracking](https://github.com/grafana/grafana/pull/108658) ✅ Merged + +### Enhanced Profiling Features + +- [PR #1195 - Enhance SceneRenderProfiler with additional interaction tracking](https://github.com/grafana/scenes/pull/1195) ✅ Merged +- [PR #1198 - Make SceneRenderProfiler optional and injectable](https://github.com/grafana/scenes/pull/1198) ✅ Merged +- [PR #1199 - SceneRenderProfiler: add start and end timestamps to profile events](https://github.com/grafana/scenes/pull/1199) ✅ Merged +- [PR #1205 - SceneRenderProfiler: Handle tab inactivity](https://github.com/grafana/scenes/pull/1205) ✅ Merged +- [PR #1209 - SceneRenderProfiler: Only capture network requests within measurement window](https://github.com/grafana/scenes/pull/1209) ✅ Merged +- [PR #1211 - SceneRenderProfiler: Improve profiler accuracy by adding cancellation and skipping inactive tabs](https://github.com/grafana/scenes/pull/1211) ✅ Merged +- [PR #1212 - SceneQueryController: Fix profiler query controller registration on scene re-activation](https://github.com/grafana/scenes/pull/1212) ✅ Merged +- [PR #1225 - SceneRenderProfiler: Handle overlapping profiles by cancelling previous profile](https://github.com/grafana/scenes/pull/1225) ✅ Merged +- [PR #1235 - Implement long frame detection with LoAF API and manual fallback](https://github.com/grafana/scenes/pull/1235) ✅ Merged + +### Panel-Level Performance Attribution System + +- [PR #1265 - Panel-level performance attribution system](https://github.com/grafana/scenes/pull/1265) 🔄 **In Review** + - Modern observer pattern architecture with ScenePerformanceTracker + - Complete panel lifecycle tracking (plugin-load, query, transform, fieldConfig, render) + - UUID-based operation IDs with crypto fallback for cross-environment compatibility + - performanceUtils namespace organization for clean API separation + - Type-safe performance interfaces with comprehensive TypeScript support + - Chrome DevTools integration via performance marks and measurements +- [PR #112137 - Dashboard performance analytics system with Scenes integration](https://github.com/grafana/grafana/pull/112137) 🔄 **In Review** + - DashboardAnalyticsAggregator with conditional initialization + - ScenePerformanceLogger for debugging and Chrome DevTools integration + - Configurable performance thresholds (SLOW_OPERATION_THRESHOLD_MS) + - Comprehensive analytics reporting via reportInteraction and logMeasurement + - Integration with the panel-level performance attribution system from PR #1265 diff --git a/public/app/features/dashboard/services/performanceConstants.ts b/public/app/features/dashboard/services/performanceConstants.ts new file mode 100644 index 00000000000..c5ae3474d33 --- /dev/null +++ b/public/app/features/dashboard/services/performanceConstants.ts @@ -0,0 +1,82 @@ +// Standardized performance mark names for Scene operations +export const PERFORMANCE_MARKS = { + // Panel operations + PANEL_QUERY_START: (panelKey: string, operationId?: string) => + operationId ? `scenes.panel.query.start.${panelKey}.${operationId}` : `scenes.panel.query.start.${panelKey}`, + PANEL_QUERY_END: (panelKey: string, operationId?: string) => + operationId ? `scenes.panel.query.end.${panelKey}.${operationId}` : `scenes.panel.query.end.${panelKey}`, + PANEL_PLUGIN_LOAD_START: (panelKey: string, operationId?: string) => + operationId + ? `scenes.panel.pluginLoad.start.${panelKey}.${operationId}` + : `scenes.panel.pluginLoad.start.${panelKey}`, + PANEL_PLUGIN_LOAD_END: (panelKey: string, operationId?: string) => + operationId ? `scenes.panel.pluginLoad.end.${panelKey}.${operationId}` : `scenes.panel.pluginLoad.end.${panelKey}`, + PANEL_FIELD_CONFIG_START: (panelKey: string, operationId?: string) => + operationId + ? `scenes.panel.fieldConfig.start.${panelKey}.${operationId}` + : `scenes.panel.fieldConfig.start.${panelKey}`, + PANEL_FIELD_CONFIG_END: (panelKey: string, operationId?: string) => + operationId + ? `scenes.panel.fieldConfig.end.${panelKey}.${operationId}` + : `scenes.panel.fieldConfig.end.${panelKey}`, + PANEL_RENDER_START: (panelKey: string, operationId?: string) => + operationId ? `scenes.panel.render.start.${panelKey}.${operationId}` : `scenes.panel.render.start.${panelKey}`, + PANEL_RENDER_END: (panelKey: string, operationId?: string) => + operationId ? `scenes.panel.render.end.${panelKey}.${operationId}` : `scenes.panel.render.end.${panelKey}`, + PANEL_TRANSFORM_START: (panelKey: string, transformationId: string, operationId?: string) => + operationId + ? `scenes.panel.transform.start.${panelKey}.${transformationId}.${operationId}` + : `scenes.panel.transform.start.${panelKey}.${transformationId}`, + PANEL_TRANSFORM_END: (panelKey: string, transformationId: string, operationId?: string) => + operationId + ? `scenes.panel.transform.end.${panelKey}.${transformationId}.${operationId}` + : `scenes.panel.transform.end.${panelKey}.${transformationId}`, + PANEL_TRANSFORM_ERROR: (panelKey: string, transformationId: string, operationId?: string) => + operationId + ? `scenes.panel.transform.error.${panelKey}.${transformationId}.${operationId}` + : `scenes.panel.transform.error.${panelKey}.${transformationId}`, + + // Dashboard operations + DASHBOARD_INTERACTION_START: (operationId: string) => `scenes.dashboard.interaction.start.${operationId}`, + DASHBOARD_INTERACTION_END: (operationId: string) => `scenes.dashboard.interaction.end.${operationId}`, + DASHBOARD_MILESTONE: (operationId: string, milestone: string) => + `scenes.dashboard.milestone.${milestone}.${operationId}`, + + // Query operations + QUERY_START: (panelId: string, queryId: string) => `scenes.query.start.${panelId}.${queryId}`, + QUERY_END: (panelId: string, queryId: string) => `scenes.query.end.${panelId}.${queryId}`, +}; + +// Standardized performance measure names +export const PERFORMANCE_MEASURES = { + // Panel operations + PANEL_QUERY: (panelKey: string, operationId?: string) => + operationId ? `scenes.panel.query.duration.${panelKey}.${operationId}` : `scenes.panel.query.duration.${panelKey}`, + PANEL_PLUGIN_LOAD: (panelKey: string, operationId?: string) => + operationId + ? `scenes.panel.pluginLoad.duration.${panelKey}.${operationId}` + : `scenes.panel.pluginLoad.duration.${panelKey}`, + PANEL_FIELD_CONFIG: (panelKey: string, operationId?: string) => + operationId + ? `scenes.panel.fieldConfig.duration.${panelKey}.${operationId}` + : `scenes.panel.fieldConfig.duration.${panelKey}`, + PANEL_RENDER: (panelKey: string, operationId?: string) => + operationId + ? `scenes.panel.render.duration.${panelKey}.${operationId}` + : `scenes.panel.render.duration.${panelKey}`, + PANEL_TRANSFORM: (panelKey: string, transformationId: string, operationId?: string) => + operationId + ? `scenes.panel.transform.duration.${panelKey}.${transformationId}.${operationId}` + : `scenes.panel.transform.duration.${panelKey}.${transformationId}`, + + // Dashboard operations + DASHBOARD_INTERACTION: (operationId: string) => `scenes.dashboard.interaction.duration.${operationId}`, + + // Query operations + QUERY: (panelId: string, queryId: string) => `scenes.query.duration.${panelId}.${queryId}`, +}; + +/** + * Threshold in milliseconds for determining slow operations (panels, queries, transformations, etc.) + */ +export const SLOW_OPERATION_THRESHOLD_MS = 500; diff --git a/public/app/features/dashboard/services/performanceUtils.ts b/public/app/features/dashboard/services/performanceUtils.ts new file mode 100644 index 00000000000..a09096b513c --- /dev/null +++ b/public/app/features/dashboard/services/performanceUtils.ts @@ -0,0 +1,139 @@ +import { store } from '@grafana/data'; +import { performanceUtils, writePerformanceLog } from '@grafana/scenes'; + +/** + * Utility function to register a performance observer with the global tracker + * Reduces duplication between ScenePerformanceLogger and DashboardAnalyticsAggregator + */ +export function registerPerformanceObserver( + observer: performanceUtils.ScenePerformanceObserver, + loggerName: string +): void { + const tracker = performanceUtils.getScenePerformanceTracker(); + tracker.addObserver(observer); + + writePerformanceLog(loggerName, 'Initialized globally and registered as performance observer'); +} + +/** + * Chrome-specific performance.memory interface (non-standard) + */ +export interface PerformanceMemory { + totalJSHeapSize: number; + usedJSHeapSize: number; + jsHeapSizeLimit: number; +} + +/** + * Extended Performance interface with Chrome's memory property + */ +export interface PerformanceWithMemory extends Performance { + memory?: PerformanceMemory; +} + +/** + * Type guard to check if performance has memory property (Chrome-specific) + */ +function hasPerformanceMemory(perf: Performance): perf is PerformanceWithMemory { + return 'memory' in perf; +} + +/** + * Safely get performance memory metrics (Chrome-specific, non-standard) + * Returns zero values for browsers without performance.memory support + */ +export function getPerformanceMemory(): PerformanceMemory { + if (hasPerformanceMemory(performance)) { + return { + totalJSHeapSize: performance.memory?.totalJSHeapSize || 0, + usedJSHeapSize: performance.memory?.usedJSHeapSize || 0, + jsHeapSizeLimit: performance.memory?.jsHeapSizeLimit || 0, + }; + } + + // Fallback for browsers without performance.memory + return { + totalJSHeapSize: 0, + usedJSHeapSize: 0, + jsHeapSizeLimit: 0, + }; +} + +/** + * Check if performance logging is enabled via localStorage + */ +function isPerformanceLoggingEnabled(): boolean { + if (typeof window !== 'undefined') { + return store.get('grafana.debug.sceneProfiling') === 'true'; + } + return false; +} + +/** + * Write a collapsible performance log group (follows writePerformanceLog pattern) + */ +export function writePerformanceGroupStart(logger: string, message: string): void { + if (isPerformanceLoggingEnabled()) { + // eslint-disable-next-line no-console + console.groupCollapsed(`${logger}: ${message}`); + } +} + +/** + * Write a performance log within a group (follows writePerformanceLog pattern) + */ +export function writePerformanceGroupLog(logger: string, message: string, data?: unknown): void { + if (isPerformanceLoggingEnabled()) { + if (data) { + // eslint-disable-next-line no-console + console.log(message, data); + } else { + // eslint-disable-next-line no-console + console.log(message); + } + } +} + +/** + * End a performance log group (follows writePerformanceLog pattern) + */ +export function writePerformanceGroupEnd(): void { + if (isPerformanceLoggingEnabled()) { + // eslint-disable-next-line no-console + console.groupEnd(); + } +} + +/** + * Safely creates a performance mark, ignoring errors if the Performance API is not available. + */ +export function createPerformanceMark(name: string, timestamp?: number): void { + try { + if (typeof performance !== 'undefined' && performance.mark) { + if (timestamp !== undefined) { + performance.mark(name, { startTime: timestamp }); + } else { + performance.mark(name); + } + } + } catch (error) { + console.error(`❌ Failed to create performance mark: ${name}`, { timestamp, error }); + } +} + +/** + * Safely creates a performance measure, ignoring errors if the Performance API is not available. + */ +export function createPerformanceMeasure(name: string, startMark: string, endMark?: string): void { + try { + if (typeof performance !== 'undefined' && performance.measure) { + if (endMark) { + performance.measure(name, startMark, endMark); + } else { + performance.measure(name, startMark); + } + } + } catch (error) { + console.error(`❌ Failed to create performance measure: ${name}`, { startMark, endMark, error }); + } +} diff --git a/public/app/features/scopes/selector/ScopesSelectorService.ts b/public/app/features/scopes/selector/ScopesSelectorService.ts index 370258d4785..b7c502de5bd 100644 --- a/public/app/features/scopes/selector/ScopesSelectorService.ts +++ b/public/app/features/scopes/selector/ScopesSelectorService.ts @@ -1,6 +1,6 @@ import { Scope, ScopeNode, store as storeImpl } from '@grafana/data'; import { config, locationService } from '@grafana/runtime'; -import { SceneRenderProfiler } from '@grafana/scenes'; +import { performanceUtils } from '@grafana/scenes'; import { getDashboardSceneProfiler } from 'app/features/dashboard/services/DashboardProfiler'; import { ScopesApiClient } from '../ScopesApiClient'; @@ -54,7 +54,8 @@ export class ScopesSelectorService extends ScopesServiceBase { let dashboardReloadSpy: jest.SpyInstance; beforeEach(() => { jest.spyOn(console, 'log').mockImplementation(); + jest.spyOn(console, 'warn').mockImplementation(); }); beforeAll(() => { config.featureToggles.scopeFilters = true; diff --git a/yarn.lock b/yarn.lock index 792fd086e36..12c677dba68 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2324,15 +2324,15 @@ __metadata: languageName: node linkType: hard -"@formatjs/ecma402-abstract@npm:2.3.6": - version: 2.3.6 - resolution: "@formatjs/ecma402-abstract@npm:2.3.6" +"@formatjs/ecma402-abstract@npm:2.3.4": + version: 2.3.4 + resolution: "@formatjs/ecma402-abstract@npm:2.3.4" dependencies: "@formatjs/fast-memoize": "npm:2.2.7" - "@formatjs/intl-localematcher": "npm:0.6.2" + "@formatjs/intl-localematcher": "npm:0.6.1" decimal.js: "npm:^10.4.3" tslib: "npm:^2.8.0" - checksum: 10/30b1b5cd6b62ba46245f934429936592df5500bc1b089dc92dd49c826757b873dd92c305dcfe370701e4df6b057bf007782113abb9b65db550d73be4961718bc + checksum: 10/573971ffc291096a4b9fcc80b4708124e89bf2e3ac50e0f78b41eb797e9aa1b842f4dc3665e4467a853c738386821769d9e40408a1d25bc73323a1f057a16cf2 languageName: node linkType: hard @@ -2376,13 +2376,13 @@ __metadata: linkType: hard "@formatjs/intl-durationformat@npm:^0.7.0": - version: 0.7.6 - resolution: "@formatjs/intl-durationformat@npm:0.7.6" + version: 0.7.4 + resolution: "@formatjs/intl-durationformat@npm:0.7.4" dependencies: - "@formatjs/ecma402-abstract": "npm:2.3.6" - "@formatjs/intl-localematcher": "npm:0.6.2" + "@formatjs/ecma402-abstract": "npm:2.3.4" + "@formatjs/intl-localematcher": "npm:0.6.1" tslib: "npm:^2.8.0" - checksum: 10/442236ba85bcd9cb7296c43a708271fa09f110b1ca9d5899066d00812fc2965eaeaec6b5240be421b80daba62860352131088449ba0fcd2061f671cec6240f0b + checksum: 10/d62273ecd635475ca91e9b501301f3f396403fa91b584c550734b19b2d194ba1316b27303fed985c1d42ae933d54eb220da6540edfdf376b0d9371ecfd0d4e15 languageName: node linkType: hard @@ -2395,12 +2395,12 @@ __metadata: languageName: node linkType: hard -"@formatjs/intl-localematcher@npm:0.6.2": - version: 0.6.2 - resolution: "@formatjs/intl-localematcher@npm:0.6.2" +"@formatjs/intl-localematcher@npm:0.6.1": + version: 0.6.1 + resolution: "@formatjs/intl-localematcher@npm:0.6.1" dependencies: tslib: "npm:^2.8.0" - checksum: 10/eb12a7f5367bbecdfafc20d7f005559ce840f420e970f425c5213d35e94e86dfe75bde03464971a26494bf8427d4961269db22ecad2834f2a19d888b5d9cc064 + checksum: 10/c7b3bc8395d18670677f207b2fd107561fff5d6394a9b4273c29e0bea920300ec3a2eefead600ebb7761c04a770cada28f78ac059f84d00520bfb57a9db36998 languageName: node linkType: hard @@ -3555,11 +3555,11 @@ __metadata: languageName: unknown linkType: soft -"@grafana/scenes-react@npm:^6.40.1": - version: 6.40.1 - resolution: "@grafana/scenes-react@npm:6.40.1" +"@grafana/scenes-react@npm:^6.41.0": + version: 6.42.0 + resolution: "@grafana/scenes-react@npm:6.42.0" dependencies: - "@grafana/scenes": "npm:6.40.1" + "@grafana/scenes": "npm:6.42.0" lru-cache: "npm:^10.2.2" react-use: "npm:^17.4.0" peerDependencies: @@ -3571,7 +3571,7 @@ __metadata: react: ^18.0.0 react-dom: ^18.0.0 react-router-dom: ^6.28.0 - checksum: 10/4515d53609d7b49e234bbc5c3da8131406c20b8ac0e54b1a5ca3ce3d1d42220ff08db65d31c83c9796188ef9d76e9a24fef170badb793a56b44bbabd31302575 + checksum: 10/05db719566e8499b2f9f46ac7da83b2c669bc29d3169b42cb800ad0bb099ad7d5dead4109975d5c65bb711a98965f4c8eb20ea3e60d8f46c958be0508346f84e languageName: node linkType: hard @@ -3601,9 +3601,9 @@ __metadata: languageName: node linkType: hard -"@grafana/scenes@npm:6.40.1, @grafana/scenes@npm:^6.40.1": - version: 6.40.1 - resolution: "@grafana/scenes@npm:6.40.1" +"@grafana/scenes@npm:6.42.0, @grafana/scenes@npm:^6.41.0": + version: 6.42.0 + resolution: "@grafana/scenes@npm:6.42.0" dependencies: "@floating-ui/react": "npm:^0.26.16" "@leeoniya/ufuzzy": "npm:^1.0.16" @@ -3623,7 +3623,7 @@ __metadata: react: ^18.0.0 react-dom: ^18.0.0 react-router-dom: ^6.28.0 - checksum: 10/f3f33d58bca9d05cf8d9527564e2f6bd9f164b44531382972c2b1ed0a54f54e29a6130fcab5797cd5dbba673e5d678ae5d1ef9c01ce6fe7895ee0f0c9408bc10 + checksum: 10/790afb142b6aa78a8a4f1359ec363e5a6c6c198873eafd39398b125d65881fb37514cf0c2f424e020dedca53a11a378f1dc87bab8ebc69fa76f5d10d59837e9f languageName: node linkType: hard @@ -6029,9 +6029,9 @@ __metadata: linkType: hard "@openfeature/core@npm:^1.9.0": - version: 1.9.1 - resolution: "@openfeature/core@npm:1.9.1" - checksum: 10/6099e16b1b4cd6e3c45c05ab4acd44c9cb4ab501b676ab6f3e77f0be1b56abc7506c5629187381333a02975d315d831e0905582435b356d9676255e72a465899 + version: 1.9.0 + resolution: "@openfeature/core@npm:1.9.0" + checksum: 10/c6d20edc09053afd99752fe46d8328158680950bca4b86679f67f79249d7226eea127b31fffdc38e26ecb729f2bab5a4a5a7c1db708ae76b7fbbac68cd56f094 languageName: node linkType: hard @@ -6056,11 +6056,11 @@ __metadata: linkType: hard "@openfeature/web-sdk@npm:^1.6.1": - version: 1.6.2 - resolution: "@openfeature/web-sdk@npm:1.6.2" + version: 1.6.1 + resolution: "@openfeature/web-sdk@npm:1.6.1" peerDependencies: "@openfeature/core": ^1.9.0 - checksum: 10/0fcc0ef76ff51d4725a00ff07755b21941b647f775d1ff04fc3d973143e78c909ccba485f582fcbc7f6201f42c795c85bcb103c43d64924fedf13ea517f625ac + checksum: 10/8bd7d1ea386e21cdd7492cab2fd1d2b138b4e6a376a4c0a40244633e5955f6452039bc2633fc5230bd7b494506a4137ba7210d40850634f9618f77a0ee435f9d languageName: node linkType: hard @@ -18832,8 +18832,8 @@ __metadata: "@grafana/plugin-ui": "npm:^0.10.10" "@grafana/prometheus": "workspace:*" "@grafana/runtime": "workspace:*" - "@grafana/scenes": "npm:^6.40.1" - "@grafana/scenes-react": "npm:^6.40.1" + "@grafana/scenes": "npm:^6.41.0" + "@grafana/scenes-react": "npm:^6.41.0" "@grafana/schema": "workspace:*" "@grafana/sql": "workspace:*" "@grafana/test-utils": "workspace:*" @@ -23060,9 +23060,9 @@ __metadata: linkType: hard "lossless-json@npm:^4.1.1": - version: 4.3.0 - resolution: "lossless-json@npm:4.3.0" - checksum: 10/a984a882c79b6e62a917d0202518472c17587bdee002f1427d7ec61115f9fbdeb5f0baa9f0e9fff8d9dbacd17da6b6c910012b2dcab69dd33d151cb7c13d5a37 + version: 4.2.0 + resolution: "lossless-json@npm:4.2.0" + checksum: 10/b29cbf9a90b8f3108219ff410223a90a3a6ad14cf902eed4038571d9421c69ade7077fb59737e1ca20f3f404ddd68fad69be11365b0d79b4b61421b054759551 languageName: node linkType: hard @@ -23530,9 +23530,9 @@ __metadata: linkType: hard "micro-memoize@npm:^4.1.2": - version: 4.2.0 - resolution: "micro-memoize@npm:4.2.0" - checksum: 10/260e27a5c15809f7dc435a89a424d93e49ccca62b743fa96ee72f254264df58c95edacbd847a2899a6d7f8ad0daef188548a8b12add5ccff83e88869a50a762c + version: 4.1.3 + resolution: "micro-memoize@npm:4.1.3" + checksum: 10/4e9c7767911cc76ae9c9779584ec87844437af9446b295a01774640a732c2c7f91944794027f44625031f7330ab7f9147740d0a9fb612680d1d2d858dad43402 languageName: node linkType: hard @@ -24230,11 +24230,11 @@ __metadata: linkType: hard "nanoid@npm:^5.0.9": - version: 5.1.6 - resolution: "nanoid@npm:5.1.6" + version: 5.1.5 + resolution: "nanoid@npm:5.1.5" bin: nanoid: bin/nanoid.js - checksum: 10/4109dbcf596d7f297a9b42f459b8f01694a03ebbdd2f41408d963ad54e5ec7234cbe7b4acad137751f31add11bb4fb3415a3e688082516745812811f05570014 + checksum: 10/6de2d006b51c983be385ef7ee285f7f2a57bd96f8c0ca881c4111461644bd81fafc2544f8e07cb834ca0f3e0f3f676c1fe78052183f008b0809efe6e273119f5 languageName: node linkType: hard From 31a2d2aff41c8884882a0e5409706b8cdbf7b298 Mon Sep 17 00:00:00 2001 From: Alex Khomenko Date: Thu, 30 Oct 2025 09:20:41 +0200 Subject: [PATCH 112/378] Provisioning: Show last and preview branches in the branch dropdown (#113148) * Provisioning: Show configured and last used branches * Remove unused var * Add hooks * Extract branch logic * remove type assertion * fix tests * Memoize descriptions --- eslint-suppressions.json | 5 -- .../provisioning/File/FileStatusPage.tsx | 22 +++-- .../DeleteProvisionedDashboardForm.tsx | 2 + .../MoveProvisionedDashboardForm.tsx | 2 + .../SaveProvisionedDashboardForm.test.tsx | 12 +++ .../SaveProvisionedDashboardForm.tsx | 11 +-- .../Folders/DeleteProvisionedFolderForm.tsx | 2 + .../Folders/NewProvisionedFolderForm.test.tsx | 12 +++ .../Folders/NewProvisionedFolderForm.tsx | 1 + .../ResourceEditFormSharedFields.test.tsx | 12 +++ .../Shared/ResourceEditFormSharedFields.tsx | 39 +++------ .../hooks/useBranchDropdownOptions.ts | 84 +++++++++++++++++++ .../provisioning/hooks/useLastBranch.ts | 35 ++++++++ .../provisioning/hooks/usePRBranch.ts | 13 +++ .../hooks/useProvisionedRequestHandler.ts | 27 +++++- public/locales/en-US/grafana.json | 4 +- 16 files changed, 232 insertions(+), 51 deletions(-) create mode 100644 public/app/features/provisioning/hooks/useBranchDropdownOptions.ts create mode 100644 public/app/features/provisioning/hooks/useLastBranch.ts create mode 100644 public/app/features/provisioning/hooks/usePRBranch.ts diff --git a/eslint-suppressions.json b/eslint-suppressions.json index c704beaefc3..2d84e04dadf 100644 --- a/eslint-suppressions.json +++ b/eslint-suppressions.json @@ -3374,11 +3374,6 @@ "count": 2 } }, - "public/app/features/provisioning/File/FileStatusPage.tsx": { - "@typescript-eslint/consistent-type-assertions": { - "count": 2 - } - }, "public/app/features/provisioning/Shared/BranchValidationError.tsx": { "react/no-unescaped-entities": { "count": 26 diff --git a/public/app/features/provisioning/File/FileStatusPage.tsx b/public/app/features/provisioning/File/FileStatusPage.tsx index 5a946122e11..9b32521a5fb 100644 --- a/public/app/features/provisioning/File/FileStatusPage.tsx +++ b/public/app/features/provisioning/File/FileStatusPage.tsx @@ -18,12 +18,24 @@ import { useQueryParams } from 'app/core/hooks/useQueryParams'; import { PROVISIONING_URL } from '../constants'; import { useGetResourceRepositoryView } from '../hooks/useGetResourceRepositoryView'; +import { usePRBranch } from '../hooks/usePRBranch'; + +enum TabSelection { + File = 'file', + Existing = 'existing', + DryRun = 'dryRun', +} + +function isTabSelection(value: unknown): value is TabSelection { + return value === TabSelection.File || value === TabSelection.Existing || value === TabSelection.DryRun; +} export default function FileStatusPage() { const params = useParams(); const [queryParams] = useQueryParams(); - const ref = (queryParams['ref'] as string) ?? undefined; - const tab = (queryParams['tab'] as TabSelection) ?? TabSelection.File; + const ref = usePRBranch(); + const tabParam = queryParams['tab']; + const tab = isTabSelection(tabParam) ? tabParam : TabSelection.File; const name = params['name'] ?? ''; const path = params['*'] ?? ''; const file = useGetRepositoryFilesWithPathQuery({ name, path, ref }); @@ -52,12 +64,6 @@ export default function FileStatusPage() { ); } -enum TabSelection { - File = 'file', - Existing = 'existing', - DryRun = 'dryRun', -} - interface Props { wrap: ResourceWrapper; repo: string; diff --git a/public/app/features/provisioning/components/Dashboards/DeleteProvisionedDashboardForm.tsx b/public/app/features/provisioning/components/Dashboards/DeleteProvisionedDashboardForm.tsx index 743975947a0..87948f5f555 100644 --- a/public/app/features/provisioning/components/Dashboards/DeleteProvisionedDashboardForm.tsx +++ b/public/app/features/provisioning/components/Dashboards/DeleteProvisionedDashboardForm.tsx @@ -166,6 +166,8 @@ export function DeleteProvisionedDashboardForm({ request, workflow, resourceType: 'dashboard', + repository, + selectedBranch: ref || loadedFromRef, successMessage: t( 'dashboard-scene.delete-provisioned-dashboard-form.success-message', 'Dashboard deleted successfully' diff --git a/public/app/features/provisioning/components/Dashboards/MoveProvisionedDashboardForm.tsx b/public/app/features/provisioning/components/Dashboards/MoveProvisionedDashboardForm.tsx index 637d0861882..abdd4a74eae 100644 --- a/public/app/features/provisioning/components/Dashboards/MoveProvisionedDashboardForm.tsx +++ b/public/app/features/provisioning/components/Dashboards/MoveProvisionedDashboardForm.tsx @@ -225,6 +225,8 @@ export function MoveProvisionedDashboardForm({ request: moveRequest, workflow, resourceType: 'dashboard', + repository, + selectedBranch: ref || loadedFromRef, successMessage: t( 'dashboard-scene.move-provisioned-dashboard-form.success-message', 'Dashboard moved successfully' diff --git a/public/app/features/provisioning/components/Dashboards/SaveProvisionedDashboardForm.test.tsx b/public/app/features/provisioning/components/Dashboards/SaveProvisionedDashboardForm.test.tsx index 0f3029c51df..f74f7ddd949 100644 --- a/public/app/features/provisioning/components/Dashboards/SaveProvisionedDashboardForm.test.tsx +++ b/public/app/features/provisioning/components/Dashboards/SaveProvisionedDashboardForm.test.tsx @@ -77,6 +77,18 @@ jest.mock('app/api/clients/provisioning/v0alpha1', () => ({ useGetRepositoryRefsQuery: jest.fn().mockReturnValue({ data: { items: [] }, isLoading: false, error: null }), })); +// Mock the new hooks that depend on router context +jest.mock('../../hooks/usePRBranch', () => ({ + usePRBranch: jest.fn().mockReturnValue(undefined), +})); + +jest.mock('../../hooks/useLastBranch', () => ({ + useLastBranch: jest.fn().mockReturnValue({ + getLastBranch: jest.fn().mockReturnValue(undefined), + setLastBranch: jest.fn(), + }), +})); + jest.mock('app/features/dashboard-scene/saving/SaveDashboardForm', () => { const actual = jest.requireActual('app/features/dashboard-scene/saving/SaveDashboardForm'); return { diff --git a/public/app/features/provisioning/components/Dashboards/SaveProvisionedDashboardForm.tsx b/public/app/features/provisioning/components/Dashboards/SaveProvisionedDashboardForm.tsx index bffaab79a73..a807ada4911 100644 --- a/public/app/features/provisioning/components/Dashboards/SaveProvisionedDashboardForm.tsx +++ b/public/app/features/provisioning/components/Dashboards/SaveProvisionedDashboardForm.tsx @@ -148,6 +148,7 @@ export function SaveProvisionedDashboardForm({ workflow, resourceType: 'dashboard', repository, + selectedBranch: methods.getValues().ref, handlers: { onBranchSuccess: ({ ref, path }, info, resource) => onBranchSuccess(ref, path, info, resource), onWriteSuccess, @@ -156,15 +157,7 @@ export function SaveProvisionedDashboardForm({ }); // Submit handler for saving the form data - const handleFormSubmit = async ({ - title, - description, - repo, - path, - comment, - ref, - folder, - }: ProvisionedDashboardFormData) => { + const handleFormSubmit = async ({ title, description, repo, path, comment, ref }: ProvisionedDashboardFormData) => { // Validate required fields if (!repo || !path) { console.error('Missing required fields for saving:', { repo, path }); diff --git a/public/app/features/provisioning/components/Folders/DeleteProvisionedFolderForm.tsx b/public/app/features/provisioning/components/Folders/DeleteProvisionedFolderForm.tsx index 102cacbf7d4..6682d21af88 100644 --- a/public/app/features/provisioning/components/Folders/DeleteProvisionedFolderForm.tsx +++ b/public/app/features/provisioning/components/Folders/DeleteProvisionedFolderForm.tsx @@ -143,6 +143,8 @@ function FormContent({ initialValues, parentFolder, repository, workflowOptions, request, workflow, resourceType: 'folder', + repository, + selectedBranch: ref, successMessage: t( 'browse-dashboards.delete-provisioned-folder-form.success-message', 'Folder deleted successfully' diff --git a/public/app/features/provisioning/components/Folders/NewProvisionedFolderForm.test.tsx b/public/app/features/provisioning/components/Folders/NewProvisionedFolderForm.test.tsx index 0bd80b282a9..1aa011c708c 100644 --- a/public/app/features/provisioning/components/Folders/NewProvisionedFolderForm.test.tsx +++ b/public/app/features/provisioning/components/Folders/NewProvisionedFolderForm.test.tsx @@ -51,6 +51,18 @@ jest.mock('app/api/clients/provisioning/v0alpha1', () => { }; }); +// Mock the new hooks that depend on router context +jest.mock('../../hooks/usePRBranch', () => ({ + usePRBranch: jest.fn().mockReturnValue(undefined), +})); + +jest.mock('../../hooks/useLastBranch', () => ({ + useLastBranch: jest.fn().mockReturnValue({ + getLastBranch: jest.fn().mockReturnValue(undefined), + setLastBranch: jest.fn(), + }), +})); + jest.mock('../../hooks/useProvisionedFolderFormData', () => { return { useProvisionedFolderFormData: jest.fn(), diff --git a/public/app/features/provisioning/components/Folders/NewProvisionedFolderForm.tsx b/public/app/features/provisioning/components/Folders/NewProvisionedFolderForm.tsx index 109277d38a7..367bcd25860 100644 --- a/public/app/features/provisioning/components/Folders/NewProvisionedFolderForm.tsx +++ b/public/app/features/provisioning/components/Folders/NewProvisionedFolderForm.tsx @@ -89,6 +89,7 @@ function FormContent({ initialValues, repository, workflowOptions, folder, onDis workflow, repository, resourceType: 'folder', + selectedBranch: methods.getValues().ref, handlers: { onDismiss, onBranchSuccess, diff --git a/public/app/features/provisioning/components/Shared/ResourceEditFormSharedFields.test.tsx b/public/app/features/provisioning/components/Shared/ResourceEditFormSharedFields.test.tsx index 306571926c1..0df03fab5a4 100644 --- a/public/app/features/provisioning/components/Shared/ResourceEditFormSharedFields.test.tsx +++ b/public/app/features/provisioning/components/Shared/ResourceEditFormSharedFields.test.tsx @@ -13,6 +13,18 @@ jest.mock('app/api/clients/provisioning/v0alpha1', () => ({ useGetRepositoryRefsQuery: jest.fn().mockReturnValue({ data: { items: [] }, isLoading: false, error: null }), })); +// Mock the new hooks that depend on router context +jest.mock('../../hooks/usePRBranch', () => ({ + usePRBranch: jest.fn().mockReturnValue(undefined), +})); + +jest.mock('../../hooks/useLastBranch', () => ({ + useLastBranch: jest.fn().mockReturnValue({ + getLastBranch: jest.fn().mockReturnValue(undefined), + setLastBranch: jest.fn(), + }), +})); + const mockRepo: { github: RepositoryView; local: RepositoryView } = { github: { type: 'github', diff --git a/public/app/features/provisioning/components/Shared/ResourceEditFormSharedFields.tsx b/public/app/features/provisioning/components/Shared/ResourceEditFormSharedFields.tsx index da05af72fa2..ecad626dbba 100644 --- a/public/app/features/provisioning/components/Shared/ResourceEditFormSharedFields.tsx +++ b/public/app/features/provisioning/components/Shared/ResourceEditFormSharedFields.tsx @@ -10,6 +10,9 @@ import { WorkflowOption } from 'app/features/provisioning/types'; import { validateBranchName } from 'app/features/provisioning/utils/git'; import { isGitProvider } from 'app/features/provisioning/utils/repositoryTypes'; +import { useBranchDropdownOptions } from '../../hooks/useBranchDropdownOptions'; +import { useLastBranch } from '../../hooks/useLastBranch'; +import { usePRBranch } from '../../hooks/usePRBranch'; import { generateNewBranchName } from '../utils/newBranchName'; interface DashboardEditFormSharedFieldsProps { @@ -40,34 +43,16 @@ export const ResourceEditFormSharedFields = memo { - const options: Array<{ label: string; value: string; description?: string }> = []; + const { getLastBranch } = useLastBranch(); + const prBranch = usePRBranch(); + const lastBranch = getLastBranch(repository?.name); - const configuredBranch = repository?.branch; - const prefix = t( - 'provisioned-resource-form.save-or-delete-resource-shared-fields.suffix-configured-branch', - 'Configured branch' - ); - // Show the configured branch first in the list - if (configuredBranch) { - options.push({ - label: `${configuredBranch}`, - value: configuredBranch, - description: prefix, - }); - } - - // Create combobox options - if (branchData?.items) { - for (const ref of branchData.items) { - if (ref.name !== configuredBranch) { - options.push({ label: ref.name, value: ref.name }); - } - } - } - - return options; - }, [branchData?.items, repository?.branch]); + const branchOptions = useBranchDropdownOptions({ + repository, + prBranch, + lastBranch, + branchData, + }); const newBranchDefaultName = useMemo(() => generateNewBranchName(resourceType), [resourceType]); diff --git a/public/app/features/provisioning/hooks/useBranchDropdownOptions.ts b/public/app/features/provisioning/hooks/useBranchDropdownOptions.ts new file mode 100644 index 00000000000..4302cabf92b --- /dev/null +++ b/public/app/features/provisioning/hooks/useBranchDropdownOptions.ts @@ -0,0 +1,84 @@ +import { useMemo } from 'react'; + +import { t } from '@grafana/i18n'; +import { GetRepositoryRefsApiResponse, RepositoryView } from 'app/api/clients/provisioning/v0alpha1'; + +interface UseBranchDropdownOptionsParams { + repository?: RepositoryView; + prBranch?: string; + lastBranch?: string; + branchData?: GetRepositoryRefsApiResponse; +} + +interface BranchOption { + label: string; + value: string; + description?: string; +} + +function getBranchDescriptions() { + return { + configured: t( + 'provisioned-resource-form.save-or-delete-resource-shared-fields.suffix-configured-branch', + 'Configured branch' + ), + pr: t('provisioned-resource-form.save-or-delete-resource-shared-fields.suffix-pr-branch', 'Pull request branch'), + lastUsed: t('provisioned-resource-form.save-or-delete-resource-shared-fields.suffix-last-used', 'Last branch'), + }; +} + +/** + * Hook to generate branch dropdown options with proper ordering and deduplication. + * Order: Configured branch → PR branch → Last used branch → Other branches + */ +export const useBranchDropdownOptions = ({ + repository, + prBranch, + lastBranch, + branchData, +}: UseBranchDropdownOptionsParams): BranchOption[] => { + const descriptions = useMemo(() => getBranchDescriptions(), []); + + const options: BranchOption[] = []; + const addedBranches = new Set(); + + const configuredBranch = repository?.branch; + + if (configuredBranch) { + options.push({ + label: `${configuredBranch}`, + value: configuredBranch, + description: descriptions.configured, + }); + addedBranches.add(configuredBranch); + } + + if (prBranch && !addedBranches.has(prBranch)) { + options.push({ + label: prBranch, + value: prBranch, + description: descriptions.pr, + }); + addedBranches.add(prBranch); + } + + if (lastBranch && !addedBranches.has(lastBranch)) { + options.push({ + label: lastBranch, + value: lastBranch, + description: descriptions.lastUsed, + }); + addedBranches.add(lastBranch); + } + + if (branchData?.items) { + for (const ref of branchData.items) { + if (!addedBranches.has(ref.name)) { + options.push({ label: ref.name, value: ref.name }); + addedBranches.add(ref.name); + } + } + } + + return options; +}; diff --git a/public/app/features/provisioning/hooks/useLastBranch.ts b/public/app/features/provisioning/hooks/useLastBranch.ts new file mode 100644 index 00000000000..ca977362cc4 --- /dev/null +++ b/public/app/features/provisioning/hooks/useLastBranch.ts @@ -0,0 +1,35 @@ +import { useCallback } from 'react'; + +import { store } from '@grafana/data'; + +const LAST_BRANCH_KEY_PREFIX = 'grafana.provisioning.lastBranch'; + +/** + * Get the local storage key for a repository's last used branch + */ +const getStorageKey = (repositoryName: string) => { + return `${LAST_BRANCH_KEY_PREFIX}.${repositoryName}`; +}; + +/** + * Hook to manage the last used branch per repository in local storage + */ +export const useLastBranch = () => { + const getLastBranch = useCallback((repositoryName: string | undefined): string | undefined => { + if (!repositoryName) { + return undefined; + } + const key = getStorageKey(repositoryName); + return store.get(key) || undefined; + }, []); + + const setLastBranch = useCallback((repositoryName: string | undefined, branch: string | undefined) => { + if (!repositoryName || !branch) { + return; + } + const key = getStorageKey(repositoryName); + store.set(key, branch); + }, []); + + return { getLastBranch, setLastBranch }; +}; diff --git a/public/app/features/provisioning/hooks/usePRBranch.ts b/public/app/features/provisioning/hooks/usePRBranch.ts new file mode 100644 index 00000000000..ba31e94f132 --- /dev/null +++ b/public/app/features/provisioning/hooks/usePRBranch.ts @@ -0,0 +1,13 @@ +import { useQueryParams } from 'app/core/hooks/useQueryParams'; + +/** + * Hook to get a properly typed URL ref param + */ +export const usePRBranch = () => { + const [queryParams] = useQueryParams(); + const ref = queryParams['ref']; + if (typeof ref !== 'string') { + return undefined; + } + return ref; +}; diff --git a/public/app/features/provisioning/hooks/useProvisionedRequestHandler.ts b/public/app/features/provisioning/hooks/useProvisionedRequestHandler.ts index 188f6218950..528e3ee49be 100644 --- a/public/app/features/provisioning/hooks/useProvisionedRequestHandler.ts +++ b/public/app/features/provisioning/hooks/useProvisionedRequestHandler.ts @@ -14,6 +14,8 @@ import { refetchChildren } from 'app/features/browse-dashboards/state/actions'; import { RepoType } from 'app/features/provisioning/Wizard/types'; import { useDispatch } from 'app/types/store'; +import { useLastBranch } from './useLastBranch'; + type ResourceType = 'dashboard' | 'folder'; // Add more as needed, e.g., 'alert', etc. // Information object that gets passed to all handlers @@ -56,6 +58,7 @@ interface Props { successMessage?: string; repository?: RepositoryView; resourceType?: ResourceType; + selectedBranch?: string; // The branch selected by the user in the form } /** @@ -72,10 +75,12 @@ export function useProvisionedRequestHandler({ successMessage, repository, resourceType, + selectedBranch, }: Props) { const dispatch = useDispatch(); // useRef to ensure handlers are only called once per request const hasHandled = useRef(false); + const { setLastBranch } = useLastBranch(); useEffect(() => { const repoType = repository?.type || 'git'; @@ -97,6 +102,15 @@ export function useProvisionedRequestHandler({ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions const resourceData = resource.upsert as Resource; + // Save the last used branch to local storage + if (workflow === 'branch' && ref) { + // For branch workflow, save the ref from the response + setLastBranch(repository?.name, ref); + } else if (workflow === 'write') { + // For write workflow, save the selectedBranch or fall back to repository branch + setLastBranch(repository?.name, selectedBranch || repository?.branch); + } + // Success message const message = successMessage || getContextualSuccessMessage(info); getAppEvents().publish({ @@ -121,7 +135,18 @@ export function useProvisionedRequestHandler({ handlers.onDismiss?.(); } - }, [request, workflow, handlers, successMessage, repository, resourceType, folderUID, dispatch]); + }, [ + request, + workflow, + handlers, + successMessage, + repository, + resourceType, + folderUID, + dispatch, + selectedBranch, + setLastBranch, + ]); } function getContextualSuccessMessage(info: ProvisionedOperationInfo): string { diff --git a/public/locales/en-US/grafana.json b/public/locales/en-US/grafana.json index 4e435b87ed2..62cf6c11a10 100644 --- a/public/locales/en-US/grafana.json +++ b/public/locales/en-US/grafana.json @@ -11364,7 +11364,9 @@ "label-workflow": "Workflow", "placeholder-branch": "Select or enter branch name", "placeholder-new-branch": "Enter new branch name", - "suffix-configured-branch": "Configured branch" + "suffix-configured-branch": "Configured branch", + "suffix-last-used": "Last branch", + "suffix-pr-branch": "Pull request branch" } }, "provisioned-resource-preview-banner": { From 5dce711680759e775ba2eaf002417db0925a82d6 Mon Sep 17 00:00:00 2001 From: antonio <45235678+tonypowa@users.noreply.github.com> Date: Thu, 30 Oct 2025 09:36:44 +0100 Subject: [PATCH 113/378] add feedback survey to contributing related docs (#113168) * add feedback survey to contributing related docs * removed deprecated drone logo and link * all pretty, no pity * removed indentation --- CONTRIBUTING.md | 4 +++- README.md | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c1f5d9ddace..c62e18c754e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,7 +2,9 @@ Thank you for your interest in contributing to Grafana! We welcome all people who want to contribute in a healthy and constructive manner within our community. To help us create a safe and positive community experience for all, we require all participants to adhere to the [Code of Conduct](CODE_OF_CONDUCT.md). -This document is a guide to help you through the process of contributing to Grafana. Be sure to check out the [Grafana Champions program](https://grafana.com/community/champions/?src=github&camp=community-cross-platform-engagement) as you start to contribute. It’s designed to recognize and empower individuals who are actively contributing to the growth and success of the Grafana ecosystem. +This document is a guide to help you through the process of contributing to Grafana. Be sure to check out the [Grafana Champions program](https://grafana.com/community/champions/?src=github&camp=community-cross-platform-engagement) as you start to contribute. It's designed to recognize and empower individuals who are actively contributing to the growth and success of the Grafana ecosystem. + +> **Help us improve!** We'd love to hear about your contributor experience. Take a moment to share your feedback in our [Open Source Contributor Experience Survey](https://gra.fan/ome). Your input helps us make contributing to Grafana better for everyone. Whether you're a new contributor or a seasoned veteran, we hope these resources help you connect with the community. diff --git a/README.md b/README.md index 033ebdc1ea6..d92844ed9aa 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,6 @@ The open-source platform for monitoring and observability [![License](https://img.shields.io/github/license/grafana/grafana)](LICENSE) -[![Drone](https://drone.grafana.net/api/badges/grafana/grafana/status.svg)](https://drone.grafana.net/grafana/grafana) [![Go Report Card](https://goreportcard.com/badge/github.com/grafana/grafana)](https://goreportcard.com/report/github.com/grafana/grafana) Grafana allows you to query, visualize, alert on and understand your metrics no matter where they are stored. Create, explore, and share dashboards with your team and foster a data-driven culture: @@ -36,6 +35,8 @@ If you're interested in contributing to the Grafana project: - Explore our [beginner-friendly issues](https://github.com/grafana/grafana/issues?q=is%3Aopen+is%3Aissue+label%3A%22beginner+friendly%22). - Look through our [style guide and Storybook](https://developers.grafana.com/ui/latest/index.html). +> Share your contributor experience in our [feedback survey](https://gra.fan/ome) to help us improve. + ## Get involved - Follow [@grafana on X (formerly Twitter)](https://x.com/grafana/). From f9ef1b6bd0f9049ad007524589f3a2b2020adbd8 Mon Sep 17 00:00:00 2001 From: Levente Balogh Date: Thu, 30 Oct 2025 10:08:10 +0100 Subject: [PATCH 114/378] Switch variable: Stop allowing identical values (#113166) * fix: don't allow identical values for enabled and disabled states * fix: add missing translation --- .../components/SwitchVariableForm.test.tsx | 61 +++++++++++++++++++ .../components/SwitchVariableForm.tsx | 43 +++++++++++-- public/locales/en-US/grafana.json | 1 + 3 files changed, 101 insertions(+), 4 deletions(-) diff --git a/public/app/features/dashboard-scene/settings/variables/components/SwitchVariableForm.test.tsx b/public/app/features/dashboard-scene/settings/variables/components/SwitchVariableForm.test.tsx index a5561a5ecd6..70c06cc2e35 100644 --- a/public/app/features/dashboard-scene/settings/variables/components/SwitchVariableForm.test.tsx +++ b/public/app/features/dashboard-scene/settings/variables/components/SwitchVariableForm.test.tsx @@ -128,4 +128,65 @@ describe('SwitchVariableForm', () => { unmount(); }); }); + + it('should show error when enabled value matches disabled value', async () => { + const user = userEvent.setup(); + renderForm({ + enabledValue: 'on', + disabledValue: 'off', + }); + + const enabledInput = screen.getByTestId( + selectors.pages.Dashboard.Settings.Variables.Edit.SwitchVariable.enabledValueInput + ); + + await user.clear(enabledInput); + await user.type(enabledInput, 'off'); + + expect(screen.getByText('Enabled and disabled values cannot be the same')).toBeInTheDocument(); + expect(onEnabledValueChange).not.toHaveBeenCalledWith('off'); + }); + + it('should show error when disabled value matches enabled value', async () => { + const user = userEvent.setup(); + renderForm({ + enabledValue: 'on', + disabledValue: 'off', + }); + + const disabledInput = screen.getByTestId( + selectors.pages.Dashboard.Settings.Variables.Edit.SwitchVariable.disabledValueInput + ); + + await user.clear(disabledInput); + await user.type(disabledInput, 'on'); + + expect(screen.getByText('Enabled and disabled values cannot be the same')).toBeInTheDocument(); + expect(onDisabledValueChange).not.toHaveBeenCalledWith('on'); + }); + + it('should clear the error when the values are update to not be the same', async () => { + const user = userEvent.setup(); + renderForm({ + enabledValue: 'on', + disabledValue: 'off', + }); + + const enabledInput = screen.getByTestId( + selectors.pages.Dashboard.Settings.Variables.Edit.SwitchVariable.enabledValueInput + ); + const disabledInput = screen.getByTestId( + selectors.pages.Dashboard.Settings.Variables.Edit.SwitchVariable.disabledValueInput + ); + + // First make disabled value same as enabled + await user.clear(disabledInput); + await user.type(disabledInput, 'on'); + expect(screen.getByText('Enabled and disabled values cannot be the same')).toBeInTheDocument(); + + // Then change enabled value to something that is not identical + await user.clear(enabledInput); + await user.type(enabledInput, 'new'); + expect(screen.queryByText('Enabled and disabled values cannot be the same')).not.toBeInTheDocument(); + }); }); diff --git a/public/app/features/dashboard-scene/settings/variables/components/SwitchVariableForm.tsx b/public/app/features/dashboard-scene/settings/variables/components/SwitchVariableForm.tsx index a14824ab84e..2f00b67f161 100644 --- a/public/app/features/dashboard-scene/settings/variables/components/SwitchVariableForm.tsx +++ b/public/app/features/dashboard-scene/settings/variables/components/SwitchVariableForm.tsx @@ -28,12 +28,21 @@ export function SwitchVariableForm({ }: SwitchVariableFormProps) { const currentValuePairType = getCurrentValuePairType(enabledValue, disabledValue); const [isCustomValuePairType, setIsCustomValuePairType] = useState(currentValuePairType === 'custom'); + const [enabledValueInvalid, setEnabledValueInvalid] = useState(false); + const [disabledValueInvalid, setDisabledValueInvalid] = useState(false); + const identicalValuesErrorMessage = t( + 'dashboard-scene.switch-variable-form.same-values-error', + 'Enabled and disabled values cannot be the same' + ); const onValuePairTypeChange = (selection: ComboboxOption | null) => { if (!selection?.value) { return; } + setEnabledValueInvalid(false); + setDisabledValueInvalid(false); + switch (selection.value) { case 'boolean': onEnabledValueChange('true'); @@ -56,6 +65,28 @@ export function SwitchVariableForm({ } }; + const handleEnabledValueChange = (newEnabledValue: string) => { + const isInvalid = newEnabledValue === disabledValue; + + setEnabledValueInvalid(isInvalid); + setDisabledValueInvalid(false); + + if (!isInvalid) { + onEnabledValueChange(newEnabledValue); + } + }; + + const handleDisabledValueChange = (newDisabledValue: string) => { + const isInvalid = newDisabledValue === enabledValue; + + setDisabledValueInvalid(isInvalid); + setEnabledValueInvalid(false); + + if (!isInvalid) { + onDisabledValueChange(newDisabledValue); + } + }; + return ( <> @@ -90,12 +121,14 @@ export function SwitchVariableForm({ 'dashboard-scene.switch-variable-form.enabled-value-description', 'Value when switch is enabled' )} + error={enabledValueInvalid && identicalValuesErrorMessage} + invalid={enabledValueInvalid} > { - onEnabledValueChange(event.currentTarget.value); + handleEnabledValueChange(event.currentTarget.value); }} placeholder={t( 'dashboard-scene.switch-variable-form.enabled-value-placeholder', @@ -112,11 +145,13 @@ export function SwitchVariableForm({ 'dashboard-scene.switch-variable-form.disabled-value-description', 'Value when switch is disabled' )} + error={disabledValueInvalid && identicalValuesErrorMessage} + invalid={disabledValueInvalid} > onDisabledValueChange(event.currentTarget.value)} + defaultValue={disabledValue} + onChange={(event) => handleDisabledValueChange(event.currentTarget.value)} placeholder={t( 'dashboard-scene.switch-variable-form.disabled-value-placeholder', 'e.g. Off, Disabled, Inactive' diff --git a/public/locales/en-US/grafana.json b/public/locales/en-US/grafana.json index 62cf6c11a10..dcbf60af7b5 100644 --- a/public/locales/en-US/grafana.json +++ b/public/locales/en-US/grafana.json @@ -6269,6 +6269,7 @@ "enabled-value": "Enabled value", "enabled-value-description": "Value when switch is enabled", "enabled-value-placeholder": "e.g. On, Enabled, Active", + "same-values-error": "Enabled and disabled values cannot be the same", "switch-options": "Switch options", "value-pair-type": "Value pair type", "value-pair-type-description": "Choose the type of values for the switch states" From 58098f93397ec2416fd7fed9c796d0e3876737ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mustafa=20Sencer=20=C3=96zcan?= <32759850+mustafasencer@users.noreply.github.com> Date: Thu, 30 Oct 2025 10:12:29 +0100 Subject: [PATCH 115/378] chore: improve unified dual writer logging (#113203) chore: improve dual writer logging --- pkg/storage/legacysql/dualwrite/dualwriter.go | 41 +++++++++++-------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/pkg/storage/legacysql/dualwrite/dualwriter.go b/pkg/storage/legacysql/dualwrite/dualwriter.go index 72c05d5ed4d..cefaf923efc 100644 --- a/pkg/storage/legacysql/dualwrite/dualwriter.go +++ b/pkg/storage/legacysql/dualwrite/dualwriter.go @@ -37,6 +37,7 @@ type dualWriter struct { } func (d *dualWriter) Get(ctx context.Context, name string, options *metav1.GetOptions) (runtime.Object, error) { + log := logging.FromContext(ctx).With("method", "Get", "name", name) // If we read from unified, we can just do that and return. if d.readUnified { return d.unified.Get(ctx, name, options) @@ -44,6 +45,7 @@ func (d *dualWriter) Get(ctx context.Context, name string, options *metav1.GetOp // If legacy is still our main store, lets first read from it. legacyGet, err := d.legacy.Get(ctx, name, options) if err != nil { + log.Error("failed to get object from legacy storage", "err", err) return nil, err } // Once we have successfully read from legacy, we can check if we want to fail on a unified read. @@ -52,7 +54,6 @@ func (d *dualWriter) Get(ctx context.Context, name string, options *metav1.GetOp go func(ctxBg context.Context, cancel context.CancelFunc) { defer cancel() if _, err := d.unified.Get(ctxBg, name, options); err != nil { - log := logging.FromContext(ctxBg).With("method", "Get") log.Error("failed background GET to unified", "err", err) } }(context.WithTimeout(context.WithoutCancel(ctx), backgroundReqTimeout)) @@ -61,6 +62,7 @@ func (d *dualWriter) Get(ctx context.Context, name string, options *metav1.GetOp // If it's not okay to fail, we have to check it in the foreground. _, unifiedErr := d.unified.Get(ctx, name, options) if unifiedErr != nil && !apierrors.IsNotFound(unifiedErr) { + log.Error("failed to get object from unified storage", "err", unifiedErr) return nil, unifiedErr } return legacyGet, nil @@ -71,7 +73,7 @@ func (d *dualWriter) List(ctx context.Context, options *metainternalversion.List var ( legacyOptions = options.DeepCopy() unifiedOptions = options.DeepCopy() - log = logging.FromContext(ctx).With("method", "List") + log = logging.FromContext(ctx).With("method", "List", "options", options) ) legacyToken, unifiedToken, err := parseContinueTokens(options.Continue) @@ -86,6 +88,7 @@ func (d *dualWriter) List(ctx context.Context, options *metainternalversion.List if d.readUnified { unifiedList, err := d.unified.List(ctx, unifiedOptions) if err != nil { + log.Error("failed to list objects from unified storage", "err", err) return nil, err } unifiedMeta, err := meta.ListAccessor(unifiedList) @@ -115,6 +118,7 @@ func (d *dualWriter) List(ctx context.Context, options *metainternalversion.List // If legacy is still the main store, lets first read from it. legacyList, err := d.legacy.List(ctx, legacyOptions) if err != nil { + log.Error("failed to list objects from legacy storage", "err", err) return nil, err } legacyMeta, err := meta.ListAccessor(legacyList) @@ -158,6 +162,7 @@ func (d *dualWriter) List(ctx context.Context, options *metainternalversion.List // If it's not okay to fail, we have to check it in the foreground. unifiedList, err := d.unified.List(ctx, unifiedOptions) if err != nil { + log.Error("failed to list objects from unified storage", "err", err) return nil, err } unifiedMeta, err := meta.ListAccessor(unifiedList) @@ -207,7 +212,7 @@ func (d *dualWriter) Create(ctx context.Context, in runtime.Object, createValida // will try to cleanup the object in legacy. createdFromLegacy, err := d.legacy.Create(ctx, in, createValidation, options) if err != nil { - log.Error("unable to create object in legacy storage", "err", err) + log.With("object", in).Error("failed to CREATE object in legacy storage", "err", err) return nil, err } @@ -234,11 +239,11 @@ func (d *dualWriter) Create(ctx context.Context, in runtime.Object, createValida if d.readUnified { storageObj, errObjectSt := d.unified.Create(ctx, createdCopy, createValidation, options) if errObjectSt != nil { - log.Error("unable to create object in unified storage", "err", errObjectSt) + log.With("object", createdCopy).Error("failed to CREATE object in unified storage", "err", errObjectSt) // If we cannot create in unified storage, attempt to clean up legacy. _, _, err = d.legacy.Delete(ctx, accCreated.GetName(), nil, &metav1.DeleteOptions{}) if err != nil { - log.Error("unable to cleanup object in legacy storage", "err", err) + log.With("name", accCreated.GetName()).Error("failed to CLEANUP object in legacy storage", "err", err) } return nil, errObjectSt } @@ -248,13 +253,13 @@ func (d *dualWriter) Create(ctx context.Context, in runtime.Object, createValida go func(ctxBg context.Context, cancel context.CancelFunc) { defer cancel() if _, err := d.unified.Create(ctxBg, createdCopy, createValidation, options); err != nil { - log.Error("unable to create object in unified storage", "err", err) + log.With("object", createdCopy).Error("failed to CREATE object in unified storage", "err", err) } }(context.WithTimeout(context.WithoutCancel(ctx), backgroundReqTimeout)) } else { // Otherwise let's create it in the foreground and return any error. if _, err := d.unified.Create(ctx, createdCopy, createValidation, options); err != nil { - log.Error("unable to create object in unified storage", "err", err) + log.With("object", createdCopy).Error("failed to CREATE object in unified storage", "err", err) if d.errorIsOK { return createdFromLegacy, nil } @@ -262,7 +267,7 @@ func (d *dualWriter) Create(ctx context.Context, in runtime.Object, createValida // If we cannot create in unified storage, attempt to clean up legacy. _, _, errLegacy := d.legacy.Delete(ctx, accCreated.GetName(), nil, &metav1.DeleteOptions{}) if errLegacy != nil { - log.Error("unable to cleanup object in legacy storage", "err", errLegacy) + log.With("name", accCreated.GetName()).Error("failed to CLEANUP object in legacy storage", "err", errLegacy) } return nil, err } @@ -281,10 +286,12 @@ func (d *dualWriter) Delete(ctx context.Context, name string, deleteValidation r // By setting RemovePermissions to false in the context, we will skip the deletion of permissions // in the legacy store. This is needed as otherwise the permissions would be missing when executing // the delete operation in the unified storage store. + log := logging.FromContext(ctx).With("method", "Delete", "name", name) ctx = utils.SetFolderRemovePermissions(ctx, false) objFromLegacy, asyncLegacy, err := d.legacy.Delete(ctx, name, deleteValidation, options) if err != nil && (!d.readUnified || !d.errorIsOK && !apierrors.IsNotFound(err)) { + log.Error("failed to DELETE object in legacy storage", "err", err) return nil, false, err } @@ -295,6 +302,7 @@ func (d *dualWriter) Delete(ctx context.Context, name string, deleteValidation r if d.readUnified { objFromStorage, asyncStorage, err := d.unified.Delete(ctx, name, deleteValidation, options) if err != nil && !apierrors.IsNotFound(err) && !d.errorIsOK { + log.Error("failed to DELETE object in unified storage", "err", err) return nil, false, err } return objFromStorage, asyncStorage, nil @@ -304,7 +312,6 @@ func (d *dualWriter) Delete(ctx context.Context, name string, deleteValidation r defer cancel() _, _, err := d.unified.Delete(ctxBg, name, deleteValidation, options) if err != nil && !apierrors.IsNotFound(err) && !d.errorIsOK { - log := logging.FromContext(ctxBg).With("method", "Delete") log.Error("failed background DELETE in unified storage", "err", err) } }(context.WithTimeout(context.WithoutCancel(ctx), backgroundReqTimeout)) @@ -312,6 +319,7 @@ func (d *dualWriter) Delete(ctx context.Context, name string, deleteValidation r // Otherwise we just run it in the foreground and return an error if any might happen. _, _, err = d.unified.Delete(ctx, name, deleteValidation, options) if err != nil && !apierrors.IsNotFound(err) && !d.errorIsOK { + log.Error("failed to DELETE object in unified storage", "err", err) return nil, false, err } return objFromLegacy, asyncLegacy, nil @@ -319,7 +327,7 @@ func (d *dualWriter) Delete(ctx context.Context, name string, deleteValidation r // Update overrides the behavior of the generic DualWriter and writes first to Storage and then to LegacyStorage. func (d *dualWriter) Update(ctx context.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc, forceAllowCreate bool, options *metav1.UpdateOptions) (runtime.Object, bool, error) { - log := logging.FromContext(ctx).With("method", "Update") + log := logging.FromContext(ctx).With("method", "Update", "name", name, "objInfo", objInfo) // update in legacy first, and then unistore. Will return a failure if either fails. // @@ -341,7 +349,7 @@ func (d *dualWriter) Update(ctx context.Context, name string, objInfo rest.Updat objFromLegacy, createdLegacy, err := d.legacy.Update(ctx, name, legacyInfo, createValidation, updateValidation, legacyForceCreate, options) if err != nil { - log.With("object", objFromLegacy).Error("could not update in legacy storage", "err", err) + log.Error("failed to UPDATE in legacy storage", "err", err) return nil, false, err } @@ -350,7 +358,7 @@ func (d *dualWriter) Update(ctx context.Context, name string, objInfo rest.Updat if createdLegacy { legacyMeta, err := utils.MetaAccessor(objFromLegacy) if err != nil { - log.With("object", objFromLegacy).Error("could not get meta accessor for legacy object", "err", err) + log.Error("failed to get meta accessor for legacy object", "err", err) return nil, false, err } unifiedInfo = &wrappedUpdateInfo{ @@ -374,6 +382,7 @@ func (d *dualWriter) Update(ctx context.Context, name string, objInfo rest.Updat } // If we want to check unified errors just run it in foreground. if _, _, err := d.unified.Update(ctx, name, unifiedInfo, createValidation, updateValidation, unifiedForceCreate, options); err != nil { + log.Error("failed to UPDATE in unified storage", "err", err) return nil, false, err } return objFromLegacy, createdLegacy, nil @@ -391,7 +400,7 @@ func (d *dualWriter) DeleteCollection(ctx context.Context, deleteValidation rest deletedLegacy, err := d.legacy.DeleteCollection(ctx, deleteValidation, options, listOptions) if err != nil { - log.With("deleted", deletedLegacy).Error("failed to delete collection successfully from legacy storage", "err", err) + log.With("options", options).Error("failed to DELETE collection successfully from legacy storage", "err", err) return nil, err } @@ -403,14 +412,14 @@ func (d *dualWriter) DeleteCollection(ctx context.Context, deleteValidation rest go func(ctxBg context.Context, cancel context.CancelFunc) { defer cancel() if _, err := d.unified.DeleteCollection(ctxBg, deleteValidation, options, listOptions); err != nil { - log.Error("failed background DELETE collection to unified storage", "err", err) + log.With("object", deletedLegacy).Error("failed background DELETE collection to unified storage", "err", err) } }(context.WithTimeout(context.WithoutCancel(ctx), backgroundReqTimeout)) return deletedLegacy, nil } // Otherwise we have to check the error and run it in the foreground. - if deletedStorage, err := d.unified.DeleteCollection(ctx, deleteValidation, options, listOptions); err != nil { - log.With("deleted", deletedStorage).Error("failed to delete collection successfully from Storage", "err", err) + if _, err := d.unified.DeleteCollection(ctx, deleteValidation, options, listOptions); err != nil { + log.With("object", deletedLegacy).Error("failed to DELETE collection successfully from Storage", "err", err) return nil, err } return deletedLegacy, nil From 8b31ec5040c4b15fca4f3ae9fe28780ccebb3e9a Mon Sep 17 00:00:00 2001 From: Ashley Harrison Date: Thu, 30 Oct 2025 09:23:21 +0000 Subject: [PATCH 116/378] Chore: Convert to functional components (#112951) * refactor ErrorBoundary so it doesn't trigger the lint rule * refactor ErrorBoundaryAlert to functional component * convert StatPanel to a functional component * convert ServiceAccountPicker to a functional component * convert UserPicker to a functional component * don't need displayName when not memoized * convert TimelineChart to a functional component * convert UserLdapSyncInfo to a functional component * convert UserOrgs to functional component * convert OrgRow to a functional component * convert UserSessions to a functional component * convert TimePickerSettings to a functional component * convert DataSourcePluginSettings to a functional component * convert ExploreTimeControls to a functional component * convert SearchBarInput to a functional component * convert LiveConnectionWarning to a functional component * convert ConcatenateTransformerEditor * convert ConstantVariableEditor a functional component * convert VariableInput to a functional component * convert ConfigEditor to a functional component * convert CSVWavesEditor to a functional component --- eslint-suppressions.json | 86 +---- .../src/components/ErrorBoundary.tsx | 10 +- .../ErrorBoundary/ErrorBoundary.tsx | 23 +- .../Select/ServiceAccountPicker.tsx | 110 +++---- .../app/core/components/Select/UserPicker.tsx | 104 +++--- .../TimelineChart/TimelineChart.tsx | 121 +++---- .../app/features/admin/UserLdapSyncInfo.tsx | 138 ++++---- public/app/features/admin/UserOrgs.tsx | 300 ++++++++---------- public/app/features/admin/UserSessions.tsx | 195 ++++++------ .../DashboardSettings/TimePickerSettings.tsx | 113 ++++--- .../components/DataSourcePluginSettings.tsx | 51 ++- .../features/explore/ExploreTimeControls.tsx | 88 +++-- .../components/common/SearchBarInput.test.tsx | 5 +- .../components/common/SearchBarInput.tsx | 65 ++-- .../features/live/LiveConnectionWarning.tsx | 97 +++--- .../editors/ConcatenateTransformerEditor.tsx | 116 +++---- .../constant/ConstantVariableEditor.tsx | 15 +- .../pickers/shared/VariableInput.tsx | 57 ++-- .../components/ConfigEditor/ConfigEditor.tsx | 62 ++-- .../components/CSVWaveEditor.tsx | 63 ++-- public/app/plugins/panel/stat/StatPanel.tsx | 206 ++++++------ public/locales/en-US/grafana.json | 3 + 22 files changed, 924 insertions(+), 1104 deletions(-) diff --git a/eslint-suppressions.json b/eslint-suppressions.json index 2d84e04dadf..e068ca60eff 100644 --- a/eslint-suppressions.json +++ b/eslint-suppressions.json @@ -539,11 +539,6 @@ "count": 2 } }, - "packages/grafana-sql/src/components/ErrorBoundary.tsx": { - "react-prefer-function-component/react-prefer-function-component": { - "count": 1 - } - }, "packages/grafana-sql/src/components/configuration/ConnectionLimits.tsx": { "no-restricted-syntax": { "count": 2 @@ -666,11 +661,6 @@ "count": 3 } }, - "packages/grafana-ui/src/components/ErrorBoundary/ErrorBoundary.tsx": { - "react-prefer-function-component/react-prefer-function-component": { - "count": 1 - } - }, "packages/grafana-ui/src/components/FormField/FormField.tsx": { "no-restricted-syntax": { "count": 1 @@ -1278,21 +1268,11 @@ "count": 1 } }, - "public/app/core/components/Select/ServiceAccountPicker.tsx": { - "react-prefer-function-component/react-prefer-function-component": { - "count": 1 - } - }, "public/app/core/components/Select/TeamPicker.tsx": { "react-prefer-function-component/react-prefer-function-component": { "count": 1 } }, - "public/app/core/components/Select/UserPicker.tsx": { - "react-prefer-function-component/react-prefer-function-component": { - "count": 1 - } - }, "public/app/core/components/SharedPreferences/SharedPreferences.tsx": { "no-restricted-syntax": { "count": 8 @@ -1342,11 +1322,6 @@ "count": 2 } }, - "public/app/core/components/TimelineChart/TimelineChart.tsx": { - "react-prefer-function-component/react-prefer-function-component": { - "count": 1 - } - }, "public/app/core/config.ts": { "no-barrel-files/no-barrel-files": { "count": 2 @@ -1483,25 +1458,17 @@ "public/app/features/admin/UserLdapSyncInfo.tsx": { "no-restricted-syntax": { "count": 3 - }, - "react-prefer-function-component/react-prefer-function-component": { - "count": 1 } }, "public/app/features/admin/UserOrgs.tsx": { "no-restricted-syntax": { "count": 2 }, - "react-prefer-function-component/react-prefer-function-component": { - "count": 3 - } - }, - "public/app/features/admin/UserProfile.tsx": { "react-prefer-function-component/react-prefer-function-component": { "count": 1 } }, - "public/app/features/admin/UserSessions.tsx": { + "public/app/features/admin/UserProfile.tsx": { "react-prefer-function-component/react-prefer-function-component": { "count": 1 } @@ -2399,9 +2366,6 @@ "public/app/features/dashboard/components/DashboardSettings/TimePickerSettings.tsx": { "no-restricted-syntax": { "count": 5 - }, - "react-prefer-function-component/react-prefer-function-component": { - "count": 1 } }, "public/app/features/dashboard/components/DashboardSettings/VersionsSettings.tsx": { @@ -2752,11 +2716,6 @@ "count": 1 } }, - "public/app/features/datasources/components/DataSourcePluginSettings.tsx": { - "react-prefer-function-component/react-prefer-function-component": { - "count": 1 - } - }, "public/app/features/datasources/components/DataSourcePluginState.tsx": { "no-restricted-syntax": { "count": 3 @@ -2872,11 +2831,6 @@ "count": 1 } }, - "public/app/features/explore/ExploreTimeControls.tsx": { - "react-prefer-function-component/react-prefer-function-component": { - "count": 1 - } - }, "public/app/features/explore/Logs/LiveLogs.tsx": { "react-prefer-function-component/react-prefer-function-component": { "count": 1 @@ -2977,11 +2931,6 @@ "count": 1 } }, - "public/app/features/explore/TraceView/components/common/SearchBarInput.tsx": { - "react-prefer-function-component/react-prefer-function-component": { - "count": 1 - } - }, "public/app/features/explore/TraceView/components/demo/trace-generators.ts": { "@typescript-eslint/consistent-type-assertions": { "count": 1 @@ -3118,11 +3067,6 @@ "count": 2 } }, - "public/app/features/live/LiveConnectionWarning.tsx": { - "react-prefer-function-component/react-prefer-function-component": { - "count": 1 - } - }, "public/app/features/live/centrifuge/LiveDataStream.ts": { "@typescript-eslint/consistent-type-assertions": { "count": 1 @@ -3578,11 +3522,6 @@ "count": 1 } }, - "public/app/features/transformers/editors/ConcatenateTransformerEditor.tsx": { - "react-prefer-function-component/react-prefer-function-component": { - "count": 1 - } - }, "public/app/features/transformers/editors/ConvertFieldTypeTransformerEditor.tsx": { "@typescript-eslint/consistent-type-assertions": { "count": 1 @@ -3700,11 +3639,6 @@ "count": 2 } }, - "public/app/features/variables/constant/ConstantVariableEditor.tsx": { - "react-prefer-function-component/react-prefer-function-component": { - "count": 1 - } - }, "public/app/features/variables/constant/reducer.ts": { "@typescript-eslint/consistent-type-assertions": { "count": 1 @@ -3787,9 +3721,6 @@ "public/app/features/variables/pickers/shared/VariableInput.tsx": { "no-restricted-syntax": { "count": 1 - }, - "react-prefer-function-component/react-prefer-function-component": { - "count": 1 } }, "public/app/features/variables/pickers/shared/VariableOptions.tsx": { @@ -4004,11 +3935,6 @@ "count": 1 } }, - "public/app/plugins/datasource/cloud-monitoring/components/ConfigEditor/ConfigEditor.tsx": { - "react-prefer-function-component/react-prefer-function-component": { - "count": 1 - } - }, "public/app/plugins/datasource/cloud-monitoring/components/Fields.tsx": { "no-restricted-syntax": { "count": 1 @@ -4207,11 +4133,6 @@ "count": 1 } }, - "public/app/plugins/datasource/grafana-testdata-datasource/components/CSVWaveEditor.tsx": { - "react-prefer-function-component/react-prefer-function-component": { - "count": 1 - } - }, "public/app/plugins/datasource/grafana-testdata-datasource/components/RandomWalkEditor.tsx": { "@typescript-eslint/consistent-type-assertions": { "count": 2 @@ -4920,11 +4841,6 @@ "count": 1 } }, - "public/app/plugins/panel/stat/StatPanel.tsx": { - "react-prefer-function-component/react-prefer-function-component": { - "count": 1 - } - }, "public/app/plugins/panel/state-timeline/migrations.ts": { "@typescript-eslint/no-explicit-any": { "count": 2 diff --git a/packages/grafana-sql/src/components/ErrorBoundary.tsx b/packages/grafana-sql/src/components/ErrorBoundary.tsx index f7991415795..8500fb68fdf 100644 --- a/packages/grafana-sql/src/components/ErrorBoundary.tsx +++ b/packages/grafana-sql/src/components/ErrorBoundary.tsx @@ -1,4 +1,4 @@ -import * as React from 'react'; +import { Component, ErrorInfo, PropsWithChildren } from 'react'; import { Trans } from '@grafana/i18n'; @@ -6,14 +6,14 @@ type Props = { fallBackComponent?: React.ReactNode; }; -export class ErrorBoundary extends React.Component, { hasError: boolean }> { - constructor(props: React.PropsWithChildren) { +export class ErrorBoundary extends Component, { hasError: boolean }> { + constructor(props: PropsWithChildren) { super(props); this.state = { hasError: false }; } - static getDerivedStateFromError() { - return { hasError: true }; + componentDidCatch(error: Error, errorInfo: ErrorInfo) { + this.setState({ hasError: true }); } render() { diff --git a/packages/grafana-ui/src/components/ErrorBoundary/ErrorBoundary.tsx b/packages/grafana-ui/src/components/ErrorBoundary/ErrorBoundary.tsx index dd49f34b985..818e919710c 100644 --- a/packages/grafana-ui/src/components/ErrorBoundary/ErrorBoundary.tsx +++ b/packages/grafana-ui/src/components/ErrorBoundary/ErrorBoundary.tsx @@ -1,6 +1,7 @@ -import { PureComponent, ReactNode, ComponentType, ErrorInfo } from 'react'; +import { PureComponent, ReactNode, ComponentType, ErrorInfo, memo } from 'react'; import { faro } from '@grafana/faro-web-sdk'; +import { t } from '@grafana/i18n'; import { Alert } from '../Alert/Alert'; @@ -116,15 +117,9 @@ export interface ErrorBoundaryAlertProps { errorLogger?: (error: Error) => void; } -export class ErrorBoundaryAlert extends PureComponent { - static defaultProps: Partial = { - title: 'An unexpected error happened', - style: 'alertbox', - }; - - render() { - const { title, children, style, dependencies, errorLogger, boundaryName } = this.props; - +export const ErrorBoundaryAlert = memo( + ({ title, children, style = 'alertbox', dependencies, errorLogger, boundaryName }: ErrorBoundaryAlertProps) => { + const alertTitle = title ?? t('grafana-ui.error-boundary.title', 'An unexpected error happened'); return ( {({ error, errorInfo }) => { @@ -134,7 +129,7 @@ export class ErrorBoundaryAlert extends PureComponent { if (style === 'alertbox') { return ( - +
{error && error.toString()}
@@ -144,12 +139,14 @@ export class ErrorBoundaryAlert extends PureComponent { ); } - return ; + return ; }} ); } -} +); + +ErrorBoundaryAlert.displayName = 'ErrorBoundaryAlert'; /** * HOC for wrapping a component in an error boundary. diff --git a/public/app/core/components/Select/ServiceAccountPicker.tsx b/public/app/core/components/Select/ServiceAccountPicker.tsx index 037404dcb2b..e9b200a4cb0 100644 --- a/public/app/core/components/Select/ServiceAccountPicker.tsx +++ b/public/app/core/components/Select/ServiceAccountPicker.tsx @@ -1,6 +1,6 @@ import debounce from 'debounce-promise'; import { isNil } from 'lodash'; -import { Component } from 'react'; +import { useMemo, useState } from 'react'; import { SelectableValue } from '@grafana/data'; import { t } from '@grafana/i18n'; @@ -14,66 +14,58 @@ export interface Props { inputId?: string; } -export interface State { - isLoading: boolean; -} +export const ServiceAccountPicker = ({ className, onSelected, inputId }: Props) => { + const [isLoading, setIsLoading] = useState(false); -export class ServiceAccountPicker extends Component { - constructor(props: Props) { - super(props); - this.state = { isLoading: false }; - } + const search = useMemo( + () => + debounce( + async (query?: string) => { + setIsLoading(true); - search = debounce( - async (query?: string) => { - this.setState({ isLoading: true }); + if (isNil(query)) { + query = ''; + } - if (isNil(query)) { - query = ''; - } - - return getBackendSrv() - .get(`/api/serviceaccounts/search?query=${query}&perpage=100`) - .then((result: ServiceAccountsState) => { - return result.serviceAccounts.map((sa) => ({ - id: sa.id, - uid: sa.uid, - value: sa, - label: sa.login, - imgUrl: sa.avatarUrl, - login: sa.login, - })); - }) - .finally(() => { - this.setState({ isLoading: false }); - }); - }, - 300, - { leading: true } + return getBackendSrv() + .get(`/api/serviceaccounts/search?query=${query}&perpage=100`) + .then((result: ServiceAccountsState) => { + return result.serviceAccounts.map((sa) => ({ + id: sa.id, + uid: sa.uid, + value: sa, + label: sa.login, + imgUrl: sa.avatarUrl, + login: sa.login, + })); + }) + .finally(() => { + setIsLoading(false); + }); + }, + 300, + { leading: true } + ), + [] ); - render() { - const { className, onSelected, inputId } = this.props; - const { isLoading } = this.state; - - return ( -
- -
- ); - } -} + return ( +
+ +
+ ); +}; diff --git a/public/app/core/components/Select/UserPicker.tsx b/public/app/core/components/Select/UserPicker.tsx index 5284cbeca5f..e7d4110d09b 100644 --- a/public/app/core/components/Select/UserPicker.tsx +++ b/public/app/core/components/Select/UserPicker.tsx @@ -1,6 +1,6 @@ import debounce from 'debounce-promise'; import { isNil } from 'lodash'; -import { Component } from 'react'; +import { useMemo, useState } from 'react'; import { SelectableValue } from '@grafana/data'; import { t } from '@grafana/i18n'; @@ -14,63 +14,55 @@ export interface Props { inputId?: string; } -export interface State { - isLoading: boolean; -} +export const UserPicker = ({ className, onSelected, inputId }: Props) => { + const [isLoading, setIsLoading] = useState(false); -export class UserPicker extends Component { - constructor(props: Props) { - super(props); - this.state = { isLoading: false }; - } + const search = useMemo( + () => + debounce( + async (query?: string) => { + setIsLoading(true); - search = debounce( - async (query?: string) => { - this.setState({ isLoading: true }); + if (isNil(query)) { + query = ''; + } - if (isNil(query)) { - query = ''; - } - - return getBackendSrv() - .get(`/api/org/users/lookup?query=${query}&limit=100`) - .then((result: OrgUser[]) => { - return result.map((user) => ({ - id: user.userId, - uid: user.uid, - value: user, - label: user.login, - imgUrl: user.avatarUrl, - login: user.login, - })); - }) - .finally(() => { - this.setState({ isLoading: false }); - }); - }, - 300, - { leading: true } + return getBackendSrv() + .get(`/api/org/users/lookup?query=${query}&limit=100`) + .then((result: OrgUser[]) => { + return result.map((user) => ({ + id: user.userId, + uid: user.uid, + value: user, + label: user.login, + imgUrl: user.avatarUrl, + login: user.login, + })); + }) + .finally(() => { + setIsLoading(false); + }); + }, + 300, + { leading: true } + ), + [] ); - render() { - const { className, onSelected, inputId } = this.props; - const { isLoading } = this.state; - - return ( -
- -
- ); - } -} + return ( +
+ +
+ ); +}; diff --git a/public/app/core/components/TimelineChart/TimelineChart.tsx b/public/app/core/components/TimelineChart/TimelineChart.tsx index f4317a127b7..ce6e4a1f4c1 100644 --- a/public/app/core/components/TimelineChart/TimelineChart.tsx +++ b/public/app/core/components/TimelineChart/TimelineChart.tsx @@ -1,4 +1,4 @@ -import { Component } from 'react'; +import { useCallback } from 'react'; import { DataFrame, FALLBACK_COLOR, FieldType, TimeRange } from '@grafana/data'; import { VisibilityMode, TimelineValueAlignment, TooltipDisplayMode, VizTooltipOptions } from '@grafana/schema'; @@ -25,69 +25,76 @@ export interface TimelineProps extends Omit { - getValueColor = (frameIdx: number, fieldIdx: number, value: unknown) => { - const field = this.props.frames[frameIdx]?.fields[fieldIdx]; +export const TimelineChart = (props: TimelineProps) => { + const { frames, timeZone, rowHeight, tooltip, legend, legendItems } = props; - if (field?.display) { - const disp = field.display(value); // will apply color modes - if (disp.color) { - return disp.color; + const getValueColor = useCallback( + (frameIdx: number, fieldIdx: number, value: unknown) => { + const field = frames[frameIdx]?.fields[fieldIdx]; + + if (field?.display) { + const disp = field.display(value); // will apply color modes + if (disp.color) { + return disp.color; + } } - } - return FALLBACK_COLOR; - }; + return FALLBACK_COLOR; + }, + [frames] + ); - prepConfig = (alignedFrame: DataFrame, allFrames: DataFrame[], getTimeRange: () => TimeRange) => { - return preparePlotConfigBuilder({ - frame: alignedFrame, - getTimeRange, - allFrames: this.props.frames, - ...this.props, + const prepConfig = useCallback( + (alignedFrame: DataFrame, allFrames: DataFrame[], getTimeRange: () => TimeRange) => { + return preparePlotConfigBuilder({ + frame: alignedFrame, + getTimeRange, + allFrames: frames, + ...props, - // Ensure timezones is passed as an array - timeZones: Array.isArray(this.props.timeZone) ? this.props.timeZone : [this.props.timeZone], + // Ensure timezones is passed as an array + timeZones: Array.isArray(timeZone) ? timeZone : [timeZone], - // When there is only one row, use the full space - rowHeight: alignedFrame.fields.length > 2 ? this.props.rowHeight : 1, - getValueColor: this.getValueColor, + // When there is only one row, use the full space + rowHeight: alignedFrame.fields.length > 2 ? rowHeight : 1, + getValueColor: getValueColor, - hoverMulti: this.props.tooltip?.mode === TooltipDisplayMode.Multi, - }); - }; + hoverMulti: tooltip?.mode === TooltipDisplayMode.Multi, + }); + }, + [frames, props, timeZone, rowHeight, getValueColor, tooltip] + ); - renderLegend = (config: UPlotConfigBuilder) => { - const { legend, legendItems } = this.props; + const renderLegend = useCallback( + (config: UPlotConfigBuilder) => { + if (!config || !legendItems || !legend || legend.showLegend === false) { + return null; + } - if (!config || !legendItems || !legend || legend.showLegend === false) { - return null; - } + return ( + + + + ); + }, + [legend, legendItems] + ); - return ( - - - - ); - }; - - render() { - return ( - f.type === FieldType.time, - y: (f) => - f.type === FieldType.number || - f.type === FieldType.boolean || - f.type === FieldType.string || - f.type === FieldType.enum, - }} - prepConfig={this.prepConfig} - propsToDiff={propsToDiff} - renderLegend={this.renderLegend} - omitHideFromViz={true} - /> - ); - } -} + return ( + f.type === FieldType.time, + y: (f) => + f.type === FieldType.number || + f.type === FieldType.boolean || + f.type === FieldType.string || + f.type === FieldType.enum, + }} + prepConfig={prepConfig} + propsToDiff={propsToDiff} + renderLegend={renderLegend} + omitHideFromViz={true} + /> + ); +}; diff --git a/public/app/features/admin/UserLdapSyncInfo.tsx b/public/app/features/admin/UserLdapSyncInfo.tsx index 1baf9e219a2..4277fa4c814 100644 --- a/public/app/features/admin/UserLdapSyncInfo.tsx +++ b/public/app/features/admin/UserLdapSyncInfo.tsx @@ -1,4 +1,4 @@ -import { PureComponent } from 'react'; +import { memo } from 'react'; import { dateTimeFormat } from '@grafana/data'; import { Trans, t } from '@grafana/i18n'; @@ -16,80 +16,72 @@ interface Props { onUserSync: () => void; } -interface State {} - const format = 'dddd YYYY-MM-DD HH:mm zz'; const debugLDAPMappingBaseURL = '/admin/authentication/ldap'; -export class UserLdapSyncInfo extends PureComponent { - onUserSync = () => { - this.props.onUserSync(); - }; +export const UserLdapSyncInfo = memo(({ ldapSyncInfo, user, onUserSync }: Props) => { + const nextSyncSuccessful = ldapSyncInfo && ldapSyncInfo.nextSync; + const nextSyncTime = nextSyncSuccessful ? dateTimeFormat(ldapSyncInfo.nextSync, { format }) : ''; + const debugLDAPMappingURL = `${debugLDAPMappingBaseURL}?username=${user && user.login}`; + const canReadLDAPUser = contextSrv.hasPermission(AccessControlAction.LDAPUsersRead); + const canSyncLDAPUser = contextSrv.hasPermission(AccessControlAction.LDAPUsersSync); - render() { - const { ldapSyncInfo, user } = this.props; - const nextSyncSuccessful = ldapSyncInfo && ldapSyncInfo.nextSync; - const nextSyncTime = nextSyncSuccessful ? dateTimeFormat(ldapSyncInfo.nextSync, { format }) : ''; - const debugLDAPMappingURL = `${debugLDAPMappingBaseURL}?username=${user && user.login}`; - const canReadLDAPUser = contextSrv.hasPermission(AccessControlAction.LDAPUsersRead); - const canSyncLDAPUser = contextSrv.hasPermission(AccessControlAction.LDAPUsersSync); - - return ( - <> -

- LDAP Synchronisation -

-
-
-
- - - - - - - - - - - -
- External sync - - - User synced via LDAP. Some changes must be done in LDAP or mappings. - - - -
- Next scheduled synchronization - - {ldapSyncInfo.enabled ? ( - nextSyncTime - ) : ( - Not enabled - )} -
-
-
- {canSyncLDAPUser && ( - - )} - {canReadLDAPUser && ( - - Debug LDAP Mapping - - )} -
+ return ( + <> +

+ LDAP Synchronisation +

+
+
+ + + + + + + + + + + + +
+ External sync + + + User synced via LDAP. Some changes must be done in LDAP or mappings. + + + +
+ Next scheduled synchronization + + {ldapSyncInfo.enabled ? ( + nextSyncTime + ) : ( + Not enabled + )} +
- - ); - } -} +
+ {canSyncLDAPUser && ( + + )} + {canReadLDAPUser && ( + + Debug LDAP Mapping + + )} +
+
+ + ); +}); +UserLdapSyncInfo.displayName = 'UserLdapSyncInfo'; diff --git a/public/app/features/admin/UserOrgs.tsx b/public/app/features/admin/UserOrgs.tsx index b7083bf7051..a0169a1022a 100644 --- a/public/app/features/admin/UserOrgs.tsx +++ b/public/app/features/admin/UserOrgs.tsx @@ -1,5 +1,5 @@ import { css, cx } from '@emotion/css'; -import { createRef, PureComponent, ReactElement } from 'react'; +import { memo, PureComponent, ReactElement, useEffect, useRef, useState } from 'react'; import { GrafanaTheme2, OrgRole } from '@grafana/data'; import { Trans, t } from '@grafana/i18n'; @@ -10,10 +10,8 @@ import { Icon, Modal, stylesFactory, - Themeable2, Tooltip, useStyles2, - withTheme2, Stack, TextLink, } from '@grafana/ui'; @@ -37,73 +35,63 @@ interface Props { onOrgAdd: (orgId: number, role: OrgRole) => void; } -interface State { - showAddOrgModal: boolean; -} +export const UserOrgs = memo(({ user, orgs, isExternalUser, onOrgRoleChange, onOrgRemove, onOrgAdd }: Props) => { + const [showAddOrgModal, setShowAddOrgModal] = useState(false); + const addToOrgButtonRef = useRef(null); -export class UserOrgs extends PureComponent { - addToOrgButtonRef = createRef(); - state = { - showAddOrgModal: false, + const showOrgAddModal = () => { + setShowAddOrgModal(true); }; - showOrgAddModal = () => { - this.setState({ showAddOrgModal: true }); + const dismissOrgAddModal = () => { + setShowAddOrgModal(false); + addToOrgButtonRef.current?.focus(); }; - dismissOrgAddModal = () => { - this.setState({ showAddOrgModal: false }, () => { - this.addToOrgButtonRef.current?.focus(); - }); - }; + const canAddToOrg = contextSrv.hasPermission(AccessControlAction.OrgUsersAdd) && !isExternalUser; - render() { - const { user, orgs, isExternalUser, onOrgRoleChange, onOrgRemove, onOrgAdd } = this.props; - const { showAddOrgModal } = this.state; + return ( +
+

+ Organizations +

+ + + + {orgs.map((org, index) => ( + + ))} + +
- const canAddToOrg = contextSrv.hasPermission(AccessControlAction.OrgUsersAdd) && !isExternalUser; - return ( -
-

- Organizations -

- - - - {orgs.map((org, index) => ( - - ))} - -
+
+ {canAddToOrg && ( + + )} +
+ +
+
+ ); +}); +UserOrgs.displayName = 'UserOrgs'; -
- {canAddToOrg && ( - - )} -
- -
-
- ); - } -} - -const getOrgRowStyles = stylesFactory((theme: GrafanaTheme2) => { +const getOrgRowStyles = (theme: GrafanaTheme2) => { return { removeButton: css({ marginRight: '0.6rem', @@ -130,9 +118,9 @@ const getOrgRowStyles = stylesFactory((theme: GrafanaTheme2) => { marginRight: theme.spacing(1), }), }; -}); +}; -interface OrgRowProps extends Themeable2 { +interface OrgRowProps { user?: UserDTO; org: UserOrg; isExternalUser?: boolean; @@ -140,124 +128,116 @@ interface OrgRowProps extends Themeable2 { onOrgRoleChange: (orgId: number, newRole: OrgRole) => void; } -class UnThemedOrgRow extends PureComponent { - state = { - currentRole: this.props.org.role, - isChangingRole: false, - roleOptions: [], - }; +const OrgRow = memo(({ user, org, isExternalUser, onOrgRemove, onOrgRoleChange }: OrgRowProps) => { + const [currentRole, setCurrentRole] = useState(org.role); + const [isChangingRole, setIsChangingRole] = useState(false); + const [roleOptions, setRoleOptions] = useState([]); + const styles = useStyles2(getOrgRowStyles); - componentDidMount() { + useEffect(() => { if (contextSrv.licensedAccessControlEnabled()) { if (contextSrv.hasPermission(AccessControlAction.ActionRolesList)) { - fetchRoleOptions(this.props.org.orgId) - .then((roles) => this.setState({ roleOptions: roles })) + fetchRoleOptions(org.orgId) + .then((roles) => setRoleOptions(roles)) .catch((e) => console.error(e)); } } - } + }, [org.orgId]); - onOrgRemove = async () => { - const { org } = this.props; - this.props.onOrgRemove(org.orgId); + const handleOrgRemove = async () => { + onOrgRemove(org.orgId); }; - onChangeRoleClick = () => { - const { org } = this.props; - this.setState({ isChangingRole: true, currentRole: org.role }); + const handleChangeRoleClick = () => { + setIsChangingRole(true); + setCurrentRole(org.role); }; - onOrgRoleChange = (newRole: OrgRole) => { - this.setState({ currentRole: newRole }); + const handleOrgRoleChange = (newRole: OrgRole) => { + setCurrentRole(newRole); }; - onOrgRoleSave = () => { - this.props.onOrgRoleChange(this.props.org.orgId, this.state.currentRole); + const handleOrgRoleSave = () => { + onOrgRoleChange(org.orgId, currentRole); }; - onCancelClick = () => { - this.setState({ isChangingRole: false }); + const handleCancelClick = () => { + setIsChangingRole(false); }; - onBasicRoleChange = (newRole: OrgRole) => { - this.props.onOrgRoleChange(this.props.org.orgId, newRole); + const handleBasicRoleChange = (newRole: OrgRole) => { + onOrgRoleChange(org.orgId, newRole); }; - render() { - const { user, org, isExternalUser, theme } = this.props; - const authSource = user?.authLabels?.length && user?.authLabels[0]; - const lockMessage = authSource ? `Synced via ${authSource}` : ''; - const { currentRole, isChangingRole } = this.state; - const styles = getOrgRowStyles(theme); - const labelClass = cx('width-16', styles.label); - const canChangeRole = contextSrv.hasPermission(AccessControlAction.OrgUsersWrite); - const canRemoveFromOrg = contextSrv.hasPermission(AccessControlAction.OrgUsersRemove) && !isExternalUser; - const rolePickerDisabled = isExternalUser || !canChangeRole; + const authSource = user?.authLabels?.length && user?.authLabels[0]; + const lockMessage = authSource ? `Synced via ${authSource}` : ''; + const labelClass = cx('width-16', styles.label); + const canChangeRole = contextSrv.hasPermission(AccessControlAction.OrgUsersWrite); + const canRemoveFromOrg = contextSrv.hasPermission(AccessControlAction.OrgUsersRemove) && !isExternalUser; + const rolePickerDisabled = isExternalUser || !canChangeRole; - const inputId = `${org.name}-input`; - return ( - - - - - {contextSrv.licensedAccessControlEnabled() ? ( - -
-
- -
- {isExternalUser && } + const inputId = `${org.name}-input`; + return ( + + + + + {contextSrv.licensedAccessControlEnabled() ? ( + +
+
+
- - ) : ( - <> - {isChangingRole ? ( - - - - ) : ( - {org.role} - )} - - {canChangeRole && ( - - )} - - - )} - - {canRemoveFromOrg && ( - - {t('admin.user-orgs.remove-button', 'Remove from organization')} - - )} + {isExternalUser && } +
- - ); - } -} - -const OrgRow = withTheme2(UnThemedOrgRow); + ) : ( + <> + {isChangingRole ? ( + + + + ) : ( + {org.role} + )} + + {canChangeRole && ( + + )} + + + )} + + {canRemoveFromOrg && ( + + {t('admin.user-orgs.remove-button', 'Remove from organization')} + + )} + + + ); +}); +OrgRow.displayName = 'OrgRow'; const getAddToOrgModalStyles = stylesFactory(() => ({ modal: css({ diff --git a/public/app/features/admin/UserSessions.tsx b/public/app/features/admin/UserSessions.tsx index f05278d7884..16fadaa8313 100644 --- a/public/app/features/admin/UserSessions.tsx +++ b/public/app/features/admin/UserSessions.tsx @@ -1,4 +1,4 @@ -import { createRef, PureComponent } from 'react'; +import { memo, useRef, useState } from 'react'; import { Trans, t } from '@grafana/i18n'; import { ConfirmButton, ConfirmModal, Button, Stack } from '@grafana/ui'; @@ -15,120 +15,107 @@ interface Props { onAllSessionsRevoke: () => void; } -interface State { - showLogoutModal: boolean; -} +export const UserSessions = memo(({ sessions, onSessionRevoke, onAllSessionsRevoke }: Props) => { + const [showLogoutModal, setShowLogoutModal] = useState(false); + const forceAllLogoutButton = useRef(null); -class BaseUserSessions extends PureComponent { - forceAllLogoutButton = createRef(); - state: State = { - showLogoutModal: false, + const showLogoutConfirmationModal = () => { + setShowLogoutModal(true); }; - showLogoutConfirmationModal = () => { - this.setState({ showLogoutModal: true }); + const dismissLogoutConfirmationModal = () => { + setShowLogoutModal(false); + forceAllLogoutButton.current?.focus(); }; - dismissLogoutConfirmationModal = () => { - this.setState({ showLogoutModal: false }, () => { - this.forceAllLogoutButton.current?.focus(); - }); - }; - - onSessionRevoke = (id: number) => { + const handleSessionRevoke = (id: number) => { return () => { - this.props.onSessionRevoke(id); + onSessionRevoke(id); }; }; - onAllSessionsRevoke = () => { - this.setState({ showLogoutModal: false }); - this.props.onAllSessionsRevoke(); + const handleAllSessionsRevoke = () => { + setShowLogoutModal(false); + onAllSessionsRevoke(); }; - render() { - const { sessions } = this.props; - const { showLogoutModal } = this.state; + const canLogout = contextSrv.hasPermission(AccessControlAction.UsersLogout); - const canLogout = contextSrv.hasPermission(AccessControlAction.UsersLogout); + return ( +
+

+ Sessions +

+ +
+ + + + + + + + + + + + {sessions && + sessions.map((session, index) => ( + + + + + + + + + ))} + +
+ Last seen + + Logged on + + IP address + + Browser and OS + + Identity Provider +
{session.isActive ? t('admin.user-sessions.now', 'Now') : session.seenAt}{formatDate(session.createdAt, { dateStyle: 'long' })}{session.clientIp}{`${session.browser} on ${session.os} ${session.osVersion}`} + {session.authModule && } + + {canLogout && ( + + {t('admin.user-sessions.force-logout-button', 'Force logout')} + + )} +
+
- return ( -
-

- Sessions -

- -
- - - - - - - - - - - - {sessions && - sessions.map((session, index) => ( - - - - - - - - - ))} - -
- Last seen - - Logged on - - IP address - - Browser and OS - - Identity Provider -
{session.isActive ? t('admin.user-sessions.now', 'Now') : session.seenAt}{formatDate(session.createdAt, { dateStyle: 'long' })}{session.clientIp}{`${session.browser} on ${session.os} ${session.osVersion}`} - {session.authModule && } - - {canLogout && ( - - {t('admin.user-sessions.force-logout-button', 'Force logout')} - - )} -
-
- -
- {canLogout && sessions.length > 0 && ( - +
+ {canLogout && sessions.length > 0 && ( + + )} + -
- -
- ); - } -} - -export const UserSessions = BaseUserSessions; + confirmText={t('admin.base-user-sessions.confirmText-force-logout', 'Force logout')} + onConfirm={handleAllSessionsRevoke} + onDismiss={dismissLogoutConfirmationModal} + /> +
+
+
+ ); +}); +UserSessions.displayName = 'UserSessions'; diff --git a/public/app/features/dashboard/components/DashboardSettings/TimePickerSettings.tsx b/public/app/features/dashboard/components/DashboardSettings/TimePickerSettings.tsx index bfcd9a5e66d..ba88db1e1bf 100644 --- a/public/app/features/dashboard/components/DashboardSettings/TimePickerSettings.tsx +++ b/public/app/features/dashboard/components/DashboardSettings/TimePickerSettings.tsx @@ -1,6 +1,5 @@ import { isEmpty } from 'lodash'; -import { PureComponent } from 'react'; -import * as React from 'react'; +import { FormEvent, memo, useState } from 'react'; import { rangeUtil, TimeZone } from '@grafana/data'; import { selectors } from '@grafana/e2e-selectors'; @@ -24,49 +23,58 @@ interface Props { liveNow?: boolean; } -interface State { - isNowDelayValid: boolean; -} +export const TimePickerSettings = memo( + ({ + onWeekStartChange, + onTimeZoneChange, + onRefreshIntervalChange, + onNowDelayChange, + onHideTimePickerChange, + onLiveNowChange, + refreshIntervals, + timePickerHidden, + nowDelay, + timezone, + weekStart, + liveNow, + }: Props) => { + const [isNowDelayValid, setIsNowDelayValid] = useState(true); -export class TimePickerSettings extends PureComponent { - state: State = { isNowDelayValid: true }; + const handleNowDelayChange = (event: FormEvent) => { + const value = event.currentTarget.value; - onNowDelayChange = (event: React.FormEvent) => { - const value = event.currentTarget.value; + if (isEmpty(value)) { + setIsNowDelayValid(true); + return onNowDelayChange(value); + } - if (isEmpty(value)) { - this.setState({ isNowDelayValid: true }); - return this.props.onNowDelayChange(value); - } + if (rangeUtil.isValidTimeSpan(value)) { + setIsNowDelayValid(true); + return onNowDelayChange(value); + } - if (rangeUtil.isValidTimeSpan(value)) { - this.setState({ isNowDelayValid: true }); - return this.props.onNowDelayChange(value); - } + setIsNowDelayValid(false); + }; - this.setState({ isNowDelayValid: false }); - }; + const handleHideTimePickerChange = () => { + onHideTimePickerChange(!timePickerHidden); + }; - onHideTimePickerChange = () => { - this.props.onHideTimePickerChange(!this.props.timePickerHidden); - }; + const handleLiveNowChange = () => { + onLiveNowChange(!liveNow); + }; - onLiveNowChange = () => { - this.props.onLiveNowChange(!this.props.liveNow); - }; + const handleTimeZoneChange = (timeZone?: string) => { + if (typeof timeZone !== 'string') { + return; + } + onTimeZoneChange(timeZone); + }; - onTimeZoneChange = (timeZone?: string) => { - if (typeof timeZone !== 'string') { - return; - } - this.props.onTimeZoneChange(timeZone); - }; + const handleWeekStartChange = (weekStart?: WeekStart) => { + onWeekStartChange(weekStart); + }; - onWeekStartChange = (weekStart?: WeekStart) => { - this.props.onWeekStartChange(weekStart); - }; - - render() { return ( { @@ -85,17 +93,9 @@ export class TimePickerSettings extends PureComponent { label={t('dashboard-settings.time-picker.week-start-label', 'Week start')} data-testid={selectors.components.WeekStartPicker.containerV2} > - + - + { > - + { 'Continuously update panels when the time range includes the current time' )} > - + ); } -} +); +TimePickerSettings.displayName = 'TimePickerSettings'; diff --git a/public/app/features/datasources/components/DataSourcePluginSettings.tsx b/public/app/features/datasources/components/DataSourcePluginSettings.tsx index f920837275b..556896147fe 100644 --- a/public/app/features/datasources/components/DataSourcePluginSettings.tsx +++ b/public/app/features/datasources/components/DataSourcePluginSettings.tsx @@ -1,4 +1,4 @@ -import { createElement, PureComponent } from 'react'; +import { createElement, memo } from 'react'; import { DataSourcePluginMeta, DataSourceSettings } from '@grafana/data'; import { writableProxy } from 'app/features/plugins/extensions/utils'; @@ -12,36 +12,23 @@ export interface Props { onModelChange: (dataSource: DataSourceSettings) => void; } -export class DataSourcePluginSettings extends PureComponent { - constructor(props: Props) { - super(props); - - this.onModelChanged = this.onModelChanged.bind(this); +export const DataSourcePluginSettings = memo(({ plugin, dataSource, onModelChange }: Props) => { + if (!plugin) { + return null; } - onModelChanged = (dataSource: DataSourceSettings) => { - this.props.onModelChange(dataSource); - }; - - render() { - const { plugin, dataSource } = this.props; - - if (!plugin) { - return null; - } - - return ( -
- {plugin.components.ConfigEditor && - createElement(plugin.components.ConfigEditor, { - options: writableProxy(dataSource, { - source: 'datasource', - pluginId: plugin.meta?.id, - pluginVersion: plugin.meta?.info?.version, - }), - onOptionsChange: this.onModelChanged, - })} -
- ); - } -} + return ( +
+ {plugin.components.ConfigEditor && + createElement(plugin.components.ConfigEditor, { + options: writableProxy(dataSource, { + source: 'datasource', + pluginId: plugin.meta?.id, + pluginVersion: plugin.meta?.info?.version, + }), + onOptionsChange: onModelChange, + })} +
+ ); +}); +DataSourcePluginSettings.displayName = 'DataSourcePluginSettings'; diff --git a/public/app/features/explore/ExploreTimeControls.tsx b/public/app/features/explore/ExploreTimeControls.tsx index 07c92e8fba5..ef616131b6e 100644 --- a/public/app/features/explore/ExploreTimeControls.tsx +++ b/public/app/features/explore/ExploreTimeControls.tsx @@ -1,5 +1,3 @@ -import { Component } from 'react'; - import { TimeRange, RawTimeRange, dateTimeForTimeZone, dateMath } from '@grafana/data'; import { reportInteraction } from '@grafana/runtime'; import { TimeZone } from '@grafana/schema'; @@ -22,9 +20,19 @@ export interface Props { onChangeFiscalYearStartMonth: (fiscalYearStartMonth: number) => void; } -export class ExploreTimeControls extends Component { - onMoveTimePicker = (direction: number) => { - const { range, onChangeTime, timeZone } = this.props; +export const ExploreTimeControls = ({ + range, + timeZone, + fiscalYearStartMonth, + splitted, + syncedTimes, + onChangeTimeSync, + hideText, + onChangeTimeZone, + onChangeFiscalYearStartMonth, + onChangeTime, +}: Props) => { + const onMoveTimePicker = (direction: number) => { const { from, to } = getShiftedTimeRange(direction, range); const nextTimeRange = { from: dateTimeForTimeZone(timeZone, from), @@ -34,14 +42,14 @@ export class ExploreTimeControls extends Component { onChangeTime(nextTimeRange); }; - onMoveForward = () => this.onMoveTimePicker(1); - onMoveBack = () => this.onMoveTimePicker(-1); + const onMoveForward = () => onMoveTimePicker(1); + const onMoveBack = () => onMoveTimePicker(-1); - onChangeTimePicker = (timeRange: TimeRange) => { + const onChangeTimePicker = (timeRange: TimeRange) => { const adjustedFrom = dateMath.isMathString(timeRange.raw.from) ? timeRange.raw.from : timeRange.from; const adjustedTo = dateMath.isMathString(timeRange.raw.to) ? timeRange.raw.to : timeRange.to; - this.props.onChangeTime({ + onChangeTime({ from: adjustedFrom, to: adjustedTo, }); @@ -52,8 +60,7 @@ export class ExploreTimeControls extends Component { }); }; - onZoom = () => { - const { range, onChangeTime, timeZone } = this.props; + const onZoom = () => { const { from, to } = getZoomedTimeRange(range, 2); const nextTimeRange = { from: dateTimeForTimeZone(timeZone, from), @@ -63,40 +70,27 @@ export class ExploreTimeControls extends Component { onChangeTime(nextTimeRange); }; - render() { - const { - range, - timeZone, - fiscalYearStartMonth, - splitted, - syncedTimes, - onChangeTimeSync, - hideText, - onChangeTimeZone, - onChangeFiscalYearStartMonth, - } = this.props; - const timeSyncButton = splitted ? : undefined; - const timePickerCommonProps = { - value: range, - timeZone, - fiscalYearStartMonth, - onMoveBackward: this.onMoveBack, - onMoveForward: this.onMoveForward, - onZoom: this.onZoom, - hideText, - }; + const timeSyncButton = splitted ? : undefined; + const timePickerCommonProps = { + value: range, + timeZone, + fiscalYearStartMonth, + onMoveBackward: onMoveBack, + onMoveForward: onMoveForward, + onZoom: onZoom, + hideText, + }; - return ( - - ); - } -} + return ( + + ); +}; diff --git a/public/app/features/explore/TraceView/components/common/SearchBarInput.test.tsx b/public/app/features/explore/TraceView/components/common/SearchBarInput.test.tsx index e613c07fcfc..6e7b590a016 100644 --- a/public/app/features/explore/TraceView/components/common/SearchBarInput.test.tsx +++ b/public/app/features/explore/TraceView/components/common/SearchBarInput.test.tsx @@ -18,15 +18,16 @@ import SearchBarInput from './SearchBarInput'; describe('SearchBarInput', () => { describe('rendering', () => { + const onChange = jest.fn(); it('renders as expected with no value', () => { - render(); + render(); const searchBarInput = screen.queryByPlaceholderText('Find...'); expect(searchBarInput).toBeInTheDocument(); expect(searchBarInput?.getAttribute('value')).toEqual(''); }); it('renders as expected with value', () => { - render(); + render(); const searchBarInput = screen.queryByPlaceholderText('Find...'); expect(searchBarInput).toBeInTheDocument(); expect(searchBarInput?.getAttribute('value')).toEqual('value'); diff --git a/public/app/features/explore/TraceView/components/common/SearchBarInput.tsx b/public/app/features/explore/TraceView/components/common/SearchBarInput.tsx index 58db71fd862..a6527ca1c0e 100644 --- a/public/app/features/explore/TraceView/components/common/SearchBarInput.tsx +++ b/public/app/features/explore/TraceView/components/common/SearchBarInput.tsx @@ -12,49 +12,44 @@ // See the License for the specific language governing permissions and // limitations under the License. -import * as React from 'react'; +import { memo } from 'react'; import { t } from '@grafana/i18n'; import { IconButton, Input } from '@grafana/ui'; type Props = { - value: string | undefined; + value?: string; onChange: (value: string) => void; }; -export default class SearchBarInput extends React.PureComponent { - static defaultProps: Partial = { - value: undefined, +const SearchBarInput = memo(({ value, onChange }: Props) => { + const clearUiFind = () => { + onChange(''); }; - clearUiFind = () => { - this.props.onChange(''); - }; - - render() { - const { value } = this.props; - - const suffix = ( - <> - {value && value.length && ( - - )} - - ); - - return ( -
- this.props.onChange(e.currentTarget.value)} - suffix={suffix} - value={value} + const suffix = ( + <> + {value && value.length && ( + -
- ); - } -} + )} + + ); + + return ( +
+ onChange(e.currentTarget.value)} + suffix={suffix} + value={value} + /> +
+ ); +}); +SearchBarInput.displayName = 'SearchBarInput'; + +export default SearchBarInput; diff --git a/public/app/features/live/LiveConnectionWarning.tsx b/public/app/features/live/LiveConnectionWarning.tsx index 27595f0b908..2f78ebd22db 100644 --- a/public/app/features/live/LiveConnectionWarning.tsx +++ b/public/app/features/live/LiveConnectionWarning.tsx @@ -1,72 +1,63 @@ import { css } from '@emotion/css'; -import { PureComponent } from 'react'; +import { memo, useEffect, useRef, useState } from 'react'; import { Unsubscribable } from 'rxjs'; import { GrafanaTheme2, OrgRole } from '@grafana/data'; import { t } from '@grafana/i18n'; import { config, getGrafanaLiveSrv } from '@grafana/runtime'; -import { Alert, stylesFactory } from '@grafana/ui'; +import { Alert, useStyles2 } from '@grafana/ui'; import { contextSrv } from 'app/core/services/context_srv'; export interface Props {} -export interface State { - show?: boolean; -} +export const LiveConnectionWarning = memo(function LiveConnectionWarning() { + const [show, setShow] = useState(undefined); + const subscriptionRef = useRef(); + const styles = useStyles2(getStyle); -export class LiveConnectionWarning extends PureComponent { - subscription?: Unsubscribable; - styles = getStyle(config.theme2); - state: State = {}; - - componentDidMount() { + useEffect(() => { // Only show the error in development mode if (process.env.NODE_ENV === 'development') { // Wait a second to listen for server errors - setTimeout(this.initListener, 1500); + const timer = setTimeout(() => { + const live = getGrafanaLiveSrv(); + if (live) { + subscriptionRef.current = live.getConnectionState().subscribe({ + next: (v) => { + setShow(!v); + }, + }); + } + }, 1500); + + return () => { + clearTimeout(timer); + if (subscriptionRef.current) { + subscriptionRef.current.unsubscribe(); + } + }; } + + return undefined; + }, []); + + if (show) { + if (!contextSrv.isSignedIn || !config.liveEnabled || contextSrv.user.orgRole === OrgRole.None) { + return null; // do not show the warning for anonymous users or ones with no org (and /login page etc) + } + + return ( + + ); } + return null; +}); - initListener = () => { - const live = getGrafanaLiveSrv(); - if (live) { - this.subscription = live.getConnectionState().subscribe({ - next: (v) => { - this.setState({ show: !v }); - }, - }); - } - }; - - componentWillUnmount() { - if (this.subscription) { - this.subscription.unsubscribe(); - } - } - - render() { - const { show } = this.state; - if (show) { - if (!contextSrv.isSignedIn || !config.liveEnabled || contextSrv.user.orgRole === OrgRole.None) { - return null; // do not show the warning for anonymous users or ones with no org (and /login page etc) - } - - return ( - - ); - } - return null; - } -} - -const getStyle = stylesFactory((theme: GrafanaTheme2) => ({ +const getStyle = (theme: GrafanaTheme2) => ({ warn: css({ position: 'fixed', bottom: 0, @@ -76,4 +67,4 @@ const getStyle = stylesFactory((theme: GrafanaTheme2) => ({ zIndex: theme.zIndex.portal, cursor: 'wait', }), -})); +}); diff --git a/public/app/features/transformers/editors/ConcatenateTransformerEditor.tsx b/public/app/features/transformers/editors/ConcatenateTransformerEditor.tsx index e31ea83a565..91bcb2c1542 100644 --- a/public/app/features/transformers/editors/ConcatenateTransformerEditor.tsx +++ b/public/app/features/transformers/editors/ConcatenateTransformerEditor.tsx @@ -1,4 +1,4 @@ -import { PureComponent, ChangeEvent } from 'react'; +import { memo, ChangeEvent } from 'react'; import { DataTransformerID, @@ -18,13 +18,8 @@ import lightImage from '../images/light/concatenate.svg'; interface ConcatenateTransformerEditorProps extends TransformerUIProps {} -export class ConcatenateTransformerEditor extends PureComponent { - constructor(props: ConcatenateTransformerEditorProps) { - super(props); - } - - onModeChanged = (value: SelectableValue) => { - const { options, onChange } = this.props; +export const ConcatenateTransformerEditor = memo(({ options, onChange }: ConcatenateTransformerEditorProps) => { + const onModeChanged = (value: SelectableValue) => { const frameNameMode = value.value ?? ConcatenateFrameNameMode.FieldName; onChange({ ...options, @@ -32,74 +27,63 @@ export class ConcatenateTransformerEditor extends PureComponent) => { - const { options } = this.props; - this.props.onChange({ + const onLabelChanged = (evt: ChangeEvent) => { + onChange({ ...options, frameNameLabel: evt.target.value, }); }; - //--------------------------------------------------------- - // Render - //--------------------------------------------------------- + const nameModes: Array> = [ + { + value: ConcatenateFrameNameMode.FieldName, + label: t( + 'transformers.concatenate-transformer-editor.name-modes.label.copy-frame-name-to-field', + 'Copy frame name to field name' + ), + }, + { + value: ConcatenateFrameNameMode.Label, + label: t( + 'transformers.concatenate-transformer-editor.name-modes.label.label-frame', + 'Add a label with the frame name' + ), + }, + { + value: ConcatenateFrameNameMode.Drop, + label: t( + 'transformers.concatenate-transformer-editor.name-modes.label.ignore-the-frame-name', + 'Ignore the frame name' + ), + }, + ]; - render() { - const { options } = this.props; - const nameModes: Array> = [ - { - value: ConcatenateFrameNameMode.FieldName, - label: t( - 'transformers.concatenate-transformer-editor.name-modes.label.copy-frame-name-to-field', - 'Copy frame name to field name' - ), - }, - { - value: ConcatenateFrameNameMode.Label, - label: t( - 'transformers.concatenate-transformer-editor.name-modes.label.label-frame', - 'Add a label with the frame name' - ), - }, - { - value: ConcatenateFrameNameMode.Drop, - label: t( - 'transformers.concatenate-transformer-editor.name-modes.label.ignore-the-frame-name', - 'Ignore the frame name' - ), - }, - ]; + const frameNameMode = options.frameNameMode ?? ConcatenateFrameNameMode.FieldName; - const frameNameMode = options.frameNameMode ?? ConcatenateFrameNameMode.FieldName; - - return ( -
- - v.value === frameNameMode)} + onChange={onModeChanged} + /> + + {frameNameMode === ConcatenateFrameNameMode.Label && ( + + v.value === frameNameMode)} - onChange={this.onModeChanged} + value={options.frameNameLabel ?? ''} + placeholder={t('transformers.concatenate-transformer-editor.placeholder-frame', 'Frame')} + onChange={onLabelChanged} /> - {frameNameMode === ConcatenateFrameNameMode.Label && ( - - - - )} -
- ); - } -} + )} +
+ ); +}); +ConcatenateTransformerEditor.displayName = 'ConcatenateTransformerEditor'; export const getConcatenateTransformRegistryItem: () => TransformerRegistryItem = () => ({ diff --git a/public/app/features/variables/constant/ConstantVariableEditor.tsx b/public/app/features/variables/constant/ConstantVariableEditor.tsx index 6325ef2890c..5eb7a1f352d 100644 --- a/public/app/features/variables/constant/ConstantVariableEditor.tsx +++ b/public/app/features/variables/constant/ConstantVariableEditor.tsx @@ -1,4 +1,4 @@ -import { FormEvent, PureComponent } from 'react'; +import { FormEvent, memo } from 'react'; import { ConstantVariableModel } from '@grafana/data'; import { ConstantVariableForm } from 'app/features/dashboard-scene/settings/variables/components/ConstantVariableForm'; @@ -7,16 +7,15 @@ import { VariableEditorProps } from '../editor/types'; export interface Props extends VariableEditorProps {} -export class ConstantVariableEditor extends PureComponent { - onChange = (event: FormEvent) => { - this.props.onPropChange({ +export const ConstantVariableEditor = memo(({ variable, onPropChange }: Props) => { + const onChange = (event: FormEvent) => { + onPropChange({ propName: 'query', propValue: event.currentTarget.value, updateOptions: true, }); }; - render() { - return ; - } -} + return ; +}); +ConstantVariableEditor.displayName = 'ConstantVariableEditor'; diff --git a/public/app/features/variables/pickers/shared/VariableInput.tsx b/public/app/features/variables/pickers/shared/VariableInput.tsx index 7ff43d04657..8f577ac5da5 100644 --- a/public/app/features/variables/pickers/shared/VariableInput.tsx +++ b/public/app/features/variables/pickers/shared/VariableInput.tsx @@ -1,48 +1,45 @@ -import { PureComponent } from 'react'; -import * as React from 'react'; +import { memo, type KeyboardEvent, type HTMLProps } from 'react'; import { t } from '@grafana/i18n'; import { NavigationKey } from '../types'; -export interface Props extends Omit, 'onChange' | 'value'> { +export interface Props extends Omit, 'onChange' | 'value'> { onChange: (value: string) => void; onNavigate: (key: NavigationKey, clearOthers: boolean) => void; value: string | null; } -export class VariableInput extends PureComponent { - onKeyDown = (event: React.KeyboardEvent) => { +export const VariableInput = memo(({ value, id, onNavigate, onChange, ...restProps }: Props) => { + const onKeyDown = (event: KeyboardEvent) => { if (NavigationKey[event.keyCode] && event.keyCode !== NavigationKey.select) { const clearOthers = event.ctrlKey || event.metaKey || event.shiftKey; - this.props.onNavigate(event.keyCode, clearOthers); + onNavigate(event.keyCode, clearOthers); event.preventDefault(); } }; - onChange = (event: React.ChangeEvent) => { - this.props.onChange(event.target.value); + const handleChange = (event: React.ChangeEvent) => { + onChange(event.target.value); }; - render() { - const { value, id, onNavigate, ...restProps } = this.props; - return ( - { - if (instance) { - instance.focus(); - instance.setAttribute('style', `width:${Math.max(instance.width, 150)}px`); - } - }} - id={id} - type="text" - className="gf-form-input" - value={value ?? ''} - onChange={this.onChange} - onKeyDown={this.onKeyDown} - placeholder={t('variable.dropdown.placeholder', 'Enter variable value')} - /> - ); - } -} + return ( + { + if (instance) { + instance.focus(); + instance.setAttribute('style', `width:${Math.max(instance.width, 150)}px`); + } + }} + id={id} + type="text" + className="gf-form-input" + value={value ?? ''} + onChange={handleChange} + onKeyDown={onKeyDown} + placeholder={t('variable.dropdown.placeholder', 'Enter variable value')} + /> + ); +}); +VariableInput.displayName = 'VariableInput'; diff --git a/public/app/plugins/datasource/cloud-monitoring/components/ConfigEditor/ConfigEditor.tsx b/public/app/plugins/datasource/cloud-monitoring/components/ConfigEditor/ConfigEditor.tsx index 9889693efae..d866ad49185 100644 --- a/public/app/plugins/datasource/cloud-monitoring/components/ConfigEditor/ConfigEditor.tsx +++ b/public/app/plugins/datasource/cloud-monitoring/components/ConfigEditor/ConfigEditor.tsx @@ -1,4 +1,4 @@ -import { PureComponent } from 'react'; +import { memo } from 'react'; import { DataSourcePluginOptionsEditorProps } from '@grafana/data'; import { ConnectionConfig } from '@grafana/google-sdk'; @@ -10,8 +10,8 @@ import { CloudMonitoringOptions, CloudMonitoringSecureJsonData } from '../../typ export type Props = DataSourcePluginOptionsEditorProps; -export class ConfigEditor extends PureComponent { - handleOnOptionsChange = (options: Props['options']) => { +export const ConfigEditor = memo(({ options, onOptionsChange }: Props) => { + const handleOnOptionsChange = (options: Props['options']) => { if (options.jsonData.privateKeyPath || options.secureJsonFields['privateKey']) { reportInteraction('grafana_cloud_monitoring_config_changed', { authenticationType: 'JWT', @@ -19,34 +19,32 @@ export class ConfigEditor extends PureComponent { privateKeyPath: !!options.jsonData.privateKeyPath, }); } - this.props.onOptionsChange(options); + onOptionsChange(options); }; - render() { - const { options, onOptionsChange } = this.props; - return ( - <> - - - - {config.secureSocksDSProxyEnabled && ( - <> - - - - - - )} - - ); - } -} + return ( + <> + + + + {config.secureSocksDSProxyEnabled && ( + <> + + + + + + )} + + ); +}); +ConfigEditor.displayName = 'ConfigEditor'; diff --git a/public/app/plugins/datasource/grafana-testdata-datasource/components/CSVWaveEditor.tsx b/public/app/plugins/datasource/grafana-testdata-datasource/components/CSVWaveEditor.tsx index ac2a9a2a779..1643cc0e9bd 100644 --- a/public/app/plugins/datasource/grafana-testdata-datasource/components/CSVWaveEditor.tsx +++ b/public/app/plugins/datasource/grafana-testdata-datasource/components/CSVWaveEditor.tsx @@ -1,4 +1,4 @@ -import { PureComponent, useState } from 'react'; +import { memo, useState } from 'react'; import * as React from 'react'; import { Button, InlineField, InlineFieldRow, Input } from '@grafana/ui'; @@ -93,43 +93,42 @@ const CSVWaveEditor = (props: WaveProps) => { ); }; -export class CSVWavesEditor extends PureComponent { - onChange = (index: number, wave?: CSVWave) => { - let waves = [...(this.props.waves ?? defaultCSVWaveQuery)]; +export const CSVWavesEditor = memo(({ waves, onChange }: WavesProps) => { + const handleChange = (index: number, wave?: CSVWave) => { + let wavesArray = [...(waves ?? defaultCSVWaveQuery)]; if (wave) { - waves[index] = { ...wave }; + wavesArray[index] = { ...wave }; } else { // remove the element - waves.splice(index, 1); + wavesArray.splice(index, 1); } - this.props.onChange(waves); + onChange(wavesArray); }; - onAdd = () => { - const waves = [...(this.props.waves ?? defaultCSVWaveQuery)]; - waves.push({ ...defaultCSVWaveQuery[0] }); - this.props.onChange(waves); + const onAdd = () => { + const wavesArray = [...(waves ?? defaultCSVWaveQuery)]; + wavesArray.push({ ...defaultCSVWaveQuery[0] }); + onChange(wavesArray); }; - render() { - let waves = this.props.waves ?? defaultCSVWaveQuery; - if (!waves.length) { - waves = defaultCSVWaveQuery; - } - - return ( - <> - {waves.map((wave, index) => ( - - ))} - - ); + let wavesArray = waves ?? defaultCSVWaveQuery; + if (!wavesArray.length) { + wavesArray = defaultCSVWaveQuery; } -} + + return ( + <> + {wavesArray.map((wave, index) => ( + + ))} + + ); +}); +CSVWavesEditor.displayName = 'CSVWavesEditor'; diff --git a/public/app/plugins/panel/stat/StatPanel.tsx b/public/app/plugins/panel/stat/StatPanel.tsx index 6d1c35cc63a..055fc4adc93 100644 --- a/public/app/plugins/panel/stat/StatPanel.tsx +++ b/public/app/plugins/panel/stat/StatPanel.tsx @@ -1,5 +1,5 @@ import { isNumber } from 'lodash'; -import { PureComponent } from 'react'; +import { memo, useCallback } from 'react'; import { DisplayValueAlignmentFactors, @@ -12,120 +12,131 @@ import { } from '@grafana/data'; import { findNumericFieldMinMax } from '@grafana/data/internal'; import { BigValueTextMode, BigValueGraphMode } from '@grafana/schema'; -import { BigValue, DataLinksContextMenu, VizRepeater, VizRepeaterRenderValueProps } from '@grafana/ui'; +import { BigValue, DataLinksContextMenu, useTheme2, VizRepeater, VizRepeaterRenderValueProps } from '@grafana/ui'; import { DataLinksContextMenuApi } from '@grafana/ui/internal'; -import { config } from 'app/core/config'; import { Options } from './panelcfg.gen'; -export class StatPanel extends PureComponent> { - renderComponent = ( - valueProps: VizRepeaterRenderValueProps, - menuProps: DataLinksContextMenuApi - ): JSX.Element => { - const { timeRange, options } = this.props; - const { value, alignmentFactors, width, height, count } = valueProps; - const { openMenu, targetClassName } = menuProps; - let sparkline = value.sparkline; - if (sparkline) { - sparkline.timeRange = timeRange; - } +export const StatPanel = memo( + ({ + timeRange, + options, + fieldConfig, + title, + data, + replaceVariables, + timeZone, + height, + width, + renderCounter, + }: PanelProps) => { + const theme = useTheme2(); - return ( - + const getTextMode = useCallback(() => { + // If we have manually set displayName or panel title switch text mode to value and name + if (options.textMode === BigValueTextMode.Auto && (fieldConfig.defaults.displayName || !title)) { + return BigValueTextMode.ValueAndName; + } + + return options.textMode; + }, [options.textMode, fieldConfig.defaults.displayName, title]); + + const renderComponent = useCallback( + ( + valueProps: VizRepeaterRenderValueProps, + menuProps: DataLinksContextMenuApi + ): JSX.Element => { + const { value, alignmentFactors, width, height, count } = valueProps; + const { openMenu, targetClassName } = menuProps; + let sparkline = value.sparkline; + if (sparkline) { + sparkline.timeRange = timeRange; + } + + return ( + + ); + }, + [theme, timeRange, options, getTextMode] ); - }; - getTextMode() { - const { options, fieldConfig, title } = this.props; + const renderValue = useCallback( + (valueProps: VizRepeaterRenderValueProps): JSX.Element => { + const { value } = valueProps; + const { getLinks, hasLinks } = value; - // If we have manually set displayName or panel title switch text mode to value and name - if (options.textMode === BigValueTextMode.Auto && (fieldConfig.defaults.displayName || !title)) { - return BigValueTextMode.ValueAndName; - } + if (hasLinks && getLinks) { + return ( + + {(api) => { + return renderComponent(valueProps, api); + }} + + ); + } - return options.textMode; - } + return renderComponent(valueProps, {}); + }, + [renderComponent] + ); - renderValue = (valueProps: VizRepeaterRenderValueProps): JSX.Element => { - const { value } = valueProps; - const { getLinks, hasLinks } = value; + const getValues = useCallback((): FieldDisplay[] => { + let globalRange: NumericRange | undefined = undefined; - if (hasLinks && getLinks) { - return ( - - {(api) => { - return this.renderComponent(valueProps, api); - }} - - ); - } - - return this.renderComponent(valueProps, {}); - }; - - getValues = (): FieldDisplay[] => { - const { data, options, replaceVariables, fieldConfig, timeZone } = this.props; - - let globalRange: NumericRange | undefined = undefined; - - for (let frame of data.series) { - for (let field of frame.fields) { - let { config } = field; - // mostly copied from fieldOverrides, since they are skipped during streaming - // Set the Min/Max value automatically - if (field.type === FieldType.number) { - if (field.state?.range) { - continue; + for (let frame of data.series) { + for (let field of frame.fields) { + let { config } = field; + // mostly copied from fieldOverrides, since they are skipped during streaming + // Set the Min/Max value automatically + if (field.type === FieldType.number) { + if (field.state?.range) { + continue; + } + if (!globalRange && (!isNumber(config.min) || !isNumber(config.max))) { + globalRange = findNumericFieldMinMax(data.series); + } + const min = config.min ?? globalRange!.min; + const max = config.max ?? globalRange!.max; + field.state = field.state ?? {}; + field.state.range = { min, max, delta: max! - min! }; } - if (!globalRange && (!isNumber(config.min) || !isNumber(config.max))) { - globalRange = findNumericFieldMinMax(data.series); - } - const min = config.min ?? globalRange!.min; - const max = config.max ?? globalRange!.max; - field.state = field.state ?? {}; - field.state.range = { min, max, delta: max! - min! }; } } - } - return getFieldDisplayValues({ - fieldConfig, - reduceOptions: options.reduceOptions, - replaceVariables, - theme: config.theme2, - data: data.series, - sparkline: options.graphMode !== BigValueGraphMode.None, - percentChange: options.showPercentChange, - timeZone, - }); - }; - - render() { - const { height, options, width, data, renderCounter } = this.props; + return getFieldDisplayValues({ + fieldConfig, + reduceOptions: options.reduceOptions, + replaceVariables, + theme, + data: data.series, + sparkline: options.graphMode !== BigValueGraphMode.None, + percentChange: options.showPercentChange, + timeZone, + }); + }, [data, fieldConfig, theme, options, replaceVariables, timeZone]); return ( > { /> ); } -} +); +StatPanel.displayName = 'StatPanel'; diff --git a/public/locales/en-US/grafana.json b/public/locales/en-US/grafana.json index dcbf60af7b5..2d5bd426837 100644 --- a/public/locales/en-US/grafana.json +++ b/public/locales/en-US/grafana.json @@ -8782,6 +8782,9 @@ "drawer": { "close": "Close" }, + "error-boundary": { + "title": "An unexpected error happened" + }, "feature-badge": { "experimental": "Experimental", "new": "New!", From d399f116b805ba210e09040e5fdc6c008a0e9b5e Mon Sep 17 00:00:00 2001 From: Konrad Lalik Date: Thu, 30 Oct 2025 10:28:15 +0100 Subject: [PATCH 117/378] Alerting: Improve instance details drawer in Alerts (#113106) * Add alert instance breadcrumbs, change instance drawer title * Update translations * Add instance drawer title component and unify its usage --- .../InstanceDetailsDrawer.tsx | 37 +++++++++++++----- .../InstanceDetailsDrawerTitle.tsx | 39 +++++++++++++++++++ public/locales/en-US/grafana.json | 7 ++-- 3 files changed, 69 insertions(+), 14 deletions(-) create mode 100644 public/app/features/alerting/unified/triage/instance-details/InstanceDetailsDrawerTitle.tsx diff --git a/public/app/features/alerting/unified/triage/instance-details/InstanceDetailsDrawer.tsx b/public/app/features/alerting/unified/triage/instance-details/InstanceDetailsDrawer.tsx index 704c4d54c47..7ce7e9ae6f7 100644 --- a/public/app/features/alerting/unified/triage/instance-details/InstanceDetailsDrawer.tsx +++ b/public/app/features/alerting/unified/triage/instance-details/InstanceDetailsDrawer.tsx @@ -3,12 +3,11 @@ import { orderBy } from 'lodash'; import { Fragment, useMemo } from 'react'; import { useMeasure } from 'react-use'; -import { AlertLabels } from '@grafana/alerting/unstable'; import { GrafanaTheme2, Labels } from '@grafana/data'; import { t } from '@grafana/i18n'; import { isFetchError } from '@grafana/runtime'; import { TimeRangePicker, useTimeRange } from '@grafana/scenes-react'; -import { Alert, Box, Drawer, Icon, LoadingBar, Stack, Text, useStyles2 } from '@grafana/ui'; +import { Alert, Box, Drawer, Icon, LoadingBar, LoadingPlaceholder, Stack, Text, useStyles2 } from '@grafana/ui'; import { AlertQuery, GrafanaRuleDefinition } from 'app/types/unified-alerting-dto'; import { alertRuleApi } from '../../api/alertRuleApi'; @@ -19,6 +18,7 @@ import { LogRecord, historyDataFrameToLogRecords } from '../../components/rules/ import { isAlertQueryOfAlertData } from '../../rule-editor/formProcessing'; import { stringifyErrorLike } from '../../utils/misc'; +import { InstanceDetailsDrawerTitle } from './InstanceDetailsDrawerTitle'; import { QueryVisualization } from './QueryVisualization'; import { convertStateHistoryToAnnotations } from './stateHistoryUtils'; @@ -66,7 +66,7 @@ export function InstanceDetailsDrawer({ ruleUID, instanceLabels, onClose }: Inst if (error) { return ( - + } onClose={onClose} size="md"> ); @@ -74,15 +74,15 @@ export function InstanceDetailsDrawer({ ruleUID, instanceLabels, onClose }: Inst if (loading || !rule) { return ( - -
{t('alerting.common.loading', 'Loading...')}
+ } onClose={onClose} size="md"> + ); } return ( } onClose={onClose} size="lg" > @@ -106,10 +106,6 @@ export function InstanceDetailsDrawer({ ruleUID, instanceLabels, onClose }: Inst )} - - - - {t('alerting.instance-details.state-history', 'Recent State Changes')} {stateHistoryFetching && } @@ -139,6 +135,27 @@ export function InstanceDetailsDrawer({ ruleUID, instanceLabels, onClose }: Inst ); } +export interface InstanceLocationProps { + folderTitle: string; + groupName: string; + ruleName: string; +} + +export function InstanceLocation({ folderTitle, groupName, ruleName }: InstanceLocationProps) { + return ( + + + + {folderTitle} + + {groupName} + + {ruleName} + + + ); +} + function extractQueryDetails(rule: GrafanaRuleDefinition) { const dataQueries = rule.data.filter((query: AlertQuery) => isAlertQueryOfAlertData(query)); diff --git a/public/app/features/alerting/unified/triage/instance-details/InstanceDetailsDrawerTitle.tsx b/public/app/features/alerting/unified/triage/instance-details/InstanceDetailsDrawerTitle.tsx new file mode 100644 index 00000000000..1b07cdb284f --- /dev/null +++ b/public/app/features/alerting/unified/triage/instance-details/InstanceDetailsDrawerTitle.tsx @@ -0,0 +1,39 @@ +import { AlertLabels } from '@grafana/alerting/unstable'; +import { Labels } from '@grafana/data'; +import { Trans, t } from '@grafana/i18n'; +import { Box, Stack, Text } from '@grafana/ui'; +import { GrafanaRuleDefinition } from 'app/types/unified-alerting-dto'; + +import { stringifyFolder, useFolder } from '../../hooks/useFolder'; + +import { InstanceLocation } from './InstanceDetailsDrawer'; + +interface InstanceDetailsDrawerTitleProps { + instanceLabels: Labels; + rule?: GrafanaRuleDefinition; +} + +export function InstanceDetailsDrawerTitle({ instanceLabels, rule }: InstanceDetailsDrawerTitleProps) { + const { folder } = useFolder(rule?.namespace_uid); + + return ( + + + Instance details + + + + {Object.keys(instanceLabels).length > 0 ? ( + + ) : ( + {t('alerting.triage.no-labels', 'No labels')} + )} + + + + {folder && rule && ( + + )} + + ); +} diff --git a/public/locales/en-US/grafana.json b/public/locales/en-US/grafana.json index 2d5bd426837..b687292e3ad 100644 --- a/public/locales/en-US/grafana.json +++ b/public/locales/en-US/grafana.json @@ -1662,9 +1662,6 @@ "no-history": "No recent state changes", "state-history": "Recent State Changes" }, - "instance-details-drawer": { - "title-instance-details": "Instance Details" - }, "instance-match": { "non-matching-labels": "Non-matching labels", "notification-policy": "View route" @@ -2950,7 +2947,9 @@ "alert-instances": "Alert instances", "error-loading-rule": "Error loading rule", "firing-instances-count": "{{firingCount}} firing instances", - "instance-details": "Instance Details", + "instance-details-drawer": { + "instance-details": "Instance details" + }, "no-instances-found": "No alert instances found for rule: {{ruleUID}}", "no-labels": "No labels", "open-in-sidebar": "Open in sidebar", From ee62a8d431c00e510b1664f899d9bbef06f11ba2 Mon Sep 17 00:00:00 2001 From: Konrad Lalik Date: Thu, 30 Oct 2025 10:43:13 +0100 Subject: [PATCH 118/378] Alerting: Alerts page improvements (#113172) * Remove column header from Triage workbench * Use md size for details Drawers * Fix top workbench border * Fix query filter for alert instances * Remove the default grouping * Update translations --- .../alerting/unified/triage/Timeline.tsx | 37 ------------------- .../alerting/unified/triage/Workbench.tsx | 9 ----- .../InstanceDetailsDrawer.tsx | 2 +- .../unified/triage/rows/GenericRow.tsx | 5 +-- .../triage/rule-details/RuleDetailsDrawer.tsx | 7 ++-- .../triage/scene/AlertRuleInstances.tsx | 6 ++- .../unified/triage/scene/TriageScene.tsx | 1 - public/locales/en-US/grafana.json | 3 -- 8 files changed, 9 insertions(+), 61 deletions(-) delete mode 100644 public/app/features/alerting/unified/triage/Timeline.tsx diff --git a/public/app/features/alerting/unified/triage/Timeline.tsx b/public/app/features/alerting/unified/triage/Timeline.tsx deleted file mode 100644 index 3bde44c91b9..00000000000 --- a/public/app/features/alerting/unified/triage/Timeline.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import { scaleTime } from 'd3-scale'; -import { useMemo } from 'react'; -import { useMeasure } from 'react-use'; - -import { Stack, Text } from '@grafana/ui'; - -import { Domain } from './types'; - -interface TimelineProps { - domain: Domain; -} - -export const TimelineHeader = ({ domain }: TimelineProps) => { - const [ref, { width }] = useMeasure(); - - const ticks = useMemo(() => { - const xScale = scaleTime().domain(domain).range([0, width]).nice(0); - const tickFormatter = xScale.tickFormat(); - - return xScale.ticks(5).map((value) => ({ - value: tickFormatter(value), - xOffset: xScale(value), - })); - }, [domain, width]); - - return ( -
- - {ticks.map((tick) => ( - - {tick.value} - - ))} - -
- ); -}; diff --git a/public/app/features/alerting/unified/triage/Workbench.tsx b/public/app/features/alerting/unified/triage/Workbench.tsx index 85a4788a706..ceb4196ad7f 100644 --- a/public/app/features/alerting/unified/triage/Workbench.tsx +++ b/public/app/features/alerting/unified/triage/Workbench.tsx @@ -4,15 +4,12 @@ import { useState } from 'react'; import { useMeasure } from 'react-use'; import { GrafanaTheme2 } from '@grafana/data'; -import { t } from '@grafana/i18n'; import { SceneQueryRunner } from '@grafana/scenes'; import { ScrollContainer, useSplitter, useStyles2 } from '@grafana/ui'; import { DEFAULT_PER_PAGE_PAGINATION } from 'app/core/constants'; -import { EditorColumnHeader } from '../components/EditorColumnHeader'; import LoadMoreHelper from '../rule-list/LoadMoreHelper'; -import { TimelineHeader } from './Timeline'; import { WorkbenchProvider } from './WorkbenchContext'; import { AlertRuleRow } from './rows/AlertRuleRow'; import { FolderGroupRow } from './rows/FolderGroupRow'; @@ -141,12 +138,6 @@ export function Workbench({ domain, data, queryRunner }: WorkbenchProps) {
-
- - - - -
{/* Render actual data */}
diff --git a/public/app/features/alerting/unified/triage/instance-details/InstanceDetailsDrawer.tsx b/public/app/features/alerting/unified/triage/instance-details/InstanceDetailsDrawer.tsx index 7ce7e9ae6f7..617f097ce89 100644 --- a/public/app/features/alerting/unified/triage/instance-details/InstanceDetailsDrawer.tsx +++ b/public/app/features/alerting/unified/triage/instance-details/InstanceDetailsDrawer.tsx @@ -84,7 +84,7 @@ export function InstanceDetailsDrawer({ ruleUID, instanceLabels, onClose }: Inst } onClose={onClose} - size="lg" + size="md" > diff --git a/public/app/features/alerting/unified/triage/rows/GenericRow.tsx b/public/app/features/alerting/unified/triage/rows/GenericRow.tsx index 904687a4dbf..edc475fbfe1 100644 --- a/public/app/features/alerting/unified/triage/rows/GenericRow.tsx +++ b/public/app/features/alerting/unified/triage/rows/GenericRow.tsx @@ -108,10 +108,7 @@ export const getStyles = (theme: GrafanaTheme2) => { display: 'flex', position: 'relative', flexBasis: 0, - border: 'solid 1px transparent', - borderBottom: `1px solid ${theme.colors.border.medium}`, - borderLeft: `1px solid ${theme.colors.border.medium}`, - borderRight: `1px solid ${theme.colors.border.medium}`, + border: `1px solid ${theme.colors.border.medium}`, }), leftColumn: css({ overflow: 'hidden', diff --git a/public/app/features/alerting/unified/triage/rule-details/RuleDetailsDrawer.tsx b/public/app/features/alerting/unified/triage/rule-details/RuleDetailsDrawer.tsx index 69687456341..980f8272f43 100644 --- a/public/app/features/alerting/unified/triage/rule-details/RuleDetailsDrawer.tsx +++ b/public/app/features/alerting/unified/triage/rule-details/RuleDetailsDrawer.tsx @@ -48,7 +48,7 @@ export function RuleDetailsDrawer({ ruleUID, onClose }: RuleDetailsDrawerProps) if (error) { return ( - + ); @@ -56,7 +56,7 @@ export function RuleDetailsDrawer({ ruleUID, onClose }: RuleDetailsDrawerProps) if (loading || !rule) { return ( - +
{t('alerting.common.loading', 'Loading...')}
); @@ -69,7 +69,6 @@ export function RuleDetailsDrawer({ ruleUID, onClose }: RuleDetailsDrawerProps) return ( @@ -104,7 +103,7 @@ export function RuleDetailsDrawer({ ruleUID, onClose }: RuleDetailsDrawerProps) {t('alerting.triage.rule-details.subtitle', 'Rule details and conditions')} } - size="lg" + size="md" tabs={ Date: Thu, 30 Oct 2025 10:49:54 +0100 Subject: [PATCH 119/378] PanelEditor: Fixes double top border around Queries (#112865) * PanelEditor: Fixes double top border around Queries * Fixes --- .../PanelDataPane/PanelDataPane.tsx | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataPane.tsx b/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataPane.tsx index 943637d2722..4e7d10fa22f 100644 --- a/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataPane.tsx +++ b/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataPane.tsx @@ -80,14 +80,16 @@ function PanelDataPaneRendered({ model }: SceneComponentProps) { return (
- + {tabs.map((t) => t.renderTab({ active: t.tabId === tab, onChangeTab: () => model.onChangeTab(t) }))} - - - {currentTab && } - - +
+ + + {currentTab && } + + +
); } @@ -116,13 +118,18 @@ function getStyles(theme: GrafanaTheme2) { height: '100%', width: '100%', }), - tabContent: css({ - padding: theme.spacing(2), + tabBorder: css({ + background: theme.colors.background.primary, border: `1px solid ${theme.colors.border.weak}`, borderLeft: 'none', borderBottom: 'none', borderTopRightRadius: theme.shape.radius.default, flexGrow: 1, + overflow: 'hidden', + }), + tabContent: css({ + padding: theme.spacing(2), + height: '100%', }), tabsBar: css({ flexShrink: 0, From 344fc5606fa27146613d5406628a95ccd70808a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Thu, 30 Oct 2025 10:50:05 +0100 Subject: [PATCH 120/378] PanelTimeCompare: Support saving time compare window (#113150) * PanelTimeCompare: Support saving time compare window * fix indentation * Fix merge issue * Update * Update * make gen-cue --------- Co-authored-by: oscarkilhed --- apps/dashboard/kinds/v2beta1/dashboard_spec.cue | 1 + .../pkg/apis/dashboard/v0alpha1/dashboard_kind.cue | 4 ++++ .../dashboard/pkg/apis/dashboard/v1beta1/dashboard_kind.cue | 4 ++++ .../dashboard/pkg/apis/dashboard/v2beta1/dashboard_spec.cue | 1 + .../pkg/apis/dashboard/v2beta1/dashboard_spec_gen.go | 1 + .../pkg/apis/dashboard/v2beta1/zz_generated.openapi.go | 6 ++++++ kinds/dashboard/dashboard_kind.cue | 4 ++++ .../src/raw/dashboard/x/dashboard_types.gen.ts | 5 +++++ .../src/schema/dashboard/v2alpha0/dashboard.schema.cue | 1 + .../src/schema/dashboard/v2beta1/types.spec.gen.ts | 1 + pkg/kinds/dashboard/dashboard_spec_gen.go | 3 +++ .../serialization/transformSaveModelToScene.ts | 3 ++- .../serialization/transformSceneToSaveModel.ts | 1 + .../serialization/transformSceneToSaveModelSchemaV2.ts | 1 + public/app/features/dashboard/state/PanelModel.ts | 1 + 15 files changed, 36 insertions(+), 1 deletion(-) diff --git a/apps/dashboard/kinds/v2beta1/dashboard_spec.cue b/apps/dashboard/kinds/v2beta1/dashboard_spec.cue index f0278fc431c..ef1490091c2 100644 --- a/apps/dashboard/kinds/v2beta1/dashboard_spec.cue +++ b/apps/dashboard/kinds/v2beta1/dashboard_spec.cue @@ -452,6 +452,7 @@ QueryOptionsSpec: { interval?: string cacheTimeout?: string hideTimeOverride?: bool + timeCompare?: string } DataQueryKind: { diff --git a/apps/dashboard/pkg/apis/dashboard/v0alpha1/dashboard_kind.cue b/apps/dashboard/pkg/apis/dashboard/v0alpha1/dashboard_kind.cue index 526ddba3bfc..7d8a0e551bf 100644 --- a/apps/dashboard/pkg/apis/dashboard/v0alpha1/dashboard_kind.cue +++ b/apps/dashboard/pkg/apis/dashboard/v0alpha1/dashboard_kind.cue @@ -670,6 +670,10 @@ lineage: schemas: [{ // Controls if the timeFrom or timeShift overrides are shown in the panel header hideTimeOverride?: bool + // Compare the current time range with a previous period + // For example "1d" to compare current period but shifted back 1 day + timeCompare?: string + // Dynamically load the panel libraryPanel?: #LibraryPanelRef diff --git a/apps/dashboard/pkg/apis/dashboard/v1beta1/dashboard_kind.cue b/apps/dashboard/pkg/apis/dashboard/v1beta1/dashboard_kind.cue index 526ddba3bfc..7d8a0e551bf 100644 --- a/apps/dashboard/pkg/apis/dashboard/v1beta1/dashboard_kind.cue +++ b/apps/dashboard/pkg/apis/dashboard/v1beta1/dashboard_kind.cue @@ -670,6 +670,10 @@ lineage: schemas: [{ // Controls if the timeFrom or timeShift overrides are shown in the panel header hideTimeOverride?: bool + // Compare the current time range with a previous period + // For example "1d" to compare current period but shifted back 1 day + timeCompare?: string + // Dynamically load the panel libraryPanel?: #LibraryPanelRef diff --git a/apps/dashboard/pkg/apis/dashboard/v2beta1/dashboard_spec.cue b/apps/dashboard/pkg/apis/dashboard/v2beta1/dashboard_spec.cue index fb46afb5c76..31603c6240b 100644 --- a/apps/dashboard/pkg/apis/dashboard/v2beta1/dashboard_spec.cue +++ b/apps/dashboard/pkg/apis/dashboard/v2beta1/dashboard_spec.cue @@ -456,6 +456,7 @@ QueryOptionsSpec: { interval?: string cacheTimeout?: string hideTimeOverride?: bool + timeCompare?: string } DataQueryKind: { diff --git a/apps/dashboard/pkg/apis/dashboard/v2beta1/dashboard_spec_gen.go b/apps/dashboard/pkg/apis/dashboard/v2beta1/dashboard_spec_gen.go index 35674997511..4229e5765d1 100644 --- a/apps/dashboard/pkg/apis/dashboard/v2beta1/dashboard_spec_gen.go +++ b/apps/dashboard/pkg/apis/dashboard/v2beta1/dashboard_spec_gen.go @@ -278,6 +278,7 @@ type DashboardQueryOptionsSpec struct { Interval *string `json:"interval,omitempty"` CacheTimeout *string `json:"cacheTimeout,omitempty"` HideTimeOverride *bool `json:"hideTimeOverride,omitempty"` + TimeCompare *string `json:"timeCompare,omitempty"` } // NewDashboardQueryOptionsSpec creates a new DashboardQueryOptionsSpec object. diff --git a/apps/dashboard/pkg/apis/dashboard/v2beta1/zz_generated.openapi.go b/apps/dashboard/pkg/apis/dashboard/v2beta1/zz_generated.openapi.go index 5e51134e80c..97fb1c10326 100644 --- a/apps/dashboard/pkg/apis/dashboard/v2beta1/zz_generated.openapi.go +++ b/apps/dashboard/pkg/apis/dashboard/v2beta1/zz_generated.openapi.go @@ -3426,6 +3426,12 @@ func schema_pkg_apis_dashboard_v2beta1_DashboardQueryOptionsSpec(ref common.Refe Format: "", }, }, + "timeCompare": { + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + Format: "", + }, + }, }, }, }, diff --git a/kinds/dashboard/dashboard_kind.cue b/kinds/dashboard/dashboard_kind.cue index 13c2b4f25f6..e32b8b6725e 100644 --- a/kinds/dashboard/dashboard_kind.cue +++ b/kinds/dashboard/dashboard_kind.cue @@ -666,6 +666,10 @@ lineage: schemas: [{ // Controls if the timeFrom or timeShift overrides are shown in the panel header hideTimeOverride?: bool + // Compare the current time range with a previous period + // For example "1d" to compare current period but shifted back 1 day + timeCompare?: string + // Dynamically load the panel libraryPanel?: #LibraryPanelRef diff --git a/packages/grafana-schema/src/raw/dashboard/x/dashboard_types.gen.ts b/packages/grafana-schema/src/raw/dashboard/x/dashboard_types.gen.ts index b370fc6206c..973f10bfb21 100644 --- a/packages/grafana-schema/src/raw/dashboard/x/dashboard_types.gen.ts +++ b/packages/grafana-schema/src/raw/dashboard/x/dashboard_types.gen.ts @@ -885,6 +885,11 @@ export interface Panel { * Depends on the panel plugin. See the plugin documentation for details. */ targets?: Array>; + /** + * Compare the current time range with a previous period + * For example "1d" to compare current period but shifted back 1 day + */ + timeCompare?: string; /** * Overrides the relative time range for individual panels, * which causes them to be different than what is selected in diff --git a/packages/grafana-schema/src/schema/dashboard/v2alpha0/dashboard.schema.cue b/packages/grafana-schema/src/schema/dashboard/v2alpha0/dashboard.schema.cue index 5369503d6f2..ba637656ed8 100644 --- a/packages/grafana-schema/src/schema/dashboard/v2alpha0/dashboard.schema.cue +++ b/packages/grafana-schema/src/schema/dashboard/v2alpha0/dashboard.schema.cue @@ -409,6 +409,7 @@ QueryOptionsSpec: { interval?: string cacheTimeout?: string hideTimeOverride?: bool + timeCompare?: string } DataQueryKind: { diff --git a/packages/grafana-schema/src/schema/dashboard/v2beta1/types.spec.gen.ts b/packages/grafana-schema/src/schema/dashboard/v2beta1/types.spec.gen.ts index 19c324f1cd9..e9cbe9e649a 100644 --- a/packages/grafana-schema/src/schema/dashboard/v2beta1/types.spec.gen.ts +++ b/packages/grafana-schema/src/schema/dashboard/v2beta1/types.spec.gen.ts @@ -219,6 +219,7 @@ export interface QueryOptionsSpec { interval?: string; cacheTimeout?: string; hideTimeOverride?: boolean; + timeCompare?: string; } export const defaultQueryOptionsSpec = (): QueryOptionsSpec => ({ diff --git a/pkg/kinds/dashboard/dashboard_spec_gen.go b/pkg/kinds/dashboard/dashboard_spec_gen.go index 2ebe81760c9..43877fbca7b 100644 --- a/pkg/kinds/dashboard/dashboard_spec_gen.go +++ b/pkg/kinds/dashboard/dashboard_spec_gen.go @@ -191,6 +191,9 @@ type Panel struct { TimeShift *string `json:"timeShift,omitempty"` // Controls if the timeFrom or timeShift overrides are shown in the panel header HideTimeOverride *bool `json:"hideTimeOverride,omitempty"` + // Compare the current time range with a previous period + // For example "1d" to compare current period but shifted back 1 day + TimeCompare *string `json:"timeCompare,omitempty"` // Dynamically load the panel LibraryPanel *LibraryPanelRef `json:"libraryPanel,omitempty"` // Sets panel queries cache timeout. diff --git a/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.ts b/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.ts index aab1f181854..7646b7df68c 100644 --- a/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.ts +++ b/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.ts @@ -456,11 +456,12 @@ export function buildGridItemForPanel(panel: PanelModel): DashboardGridItem { }); } - if (panel.timeFrom || panel.timeShift) { + if (panel.timeFrom || panel.timeShift || panel.timeCompare) { vizPanelState.$timeRange = new PanelTimeRange({ timeFrom: panel.timeFrom, timeShift: panel.timeShift, hideTimeOverride: panel.hideTimeOverride, + compareWith: panel.timeCompare, }); } diff --git a/public/app/features/dashboard-scene/serialization/transformSceneToSaveModel.ts b/public/app/features/dashboard-scene/serialization/transformSceneToSaveModel.ts index 16b3957435f..bd5a1139848 100644 --- a/public/app/features/dashboard-scene/serialization/transformSceneToSaveModel.ts +++ b/public/app/features/dashboard-scene/serialization/transformSceneToSaveModel.ts @@ -232,6 +232,7 @@ export function vizPanelToPanel( panel.timeFrom = panelTime.state.timeFrom; panel.timeShift = panelTime.state.timeShift; panel.hideTimeOverride = panelTime.state.hideTimeOverride; + panel.timeCompare = panelTime.state.compareWith; } if (gridItem instanceof DashboardGridItem) { diff --git a/public/app/features/dashboard-scene/serialization/transformSceneToSaveModelSchemaV2.ts b/public/app/features/dashboard-scene/serialization/transformSceneToSaveModelSchemaV2.ts index da7e19d3a41..85cd9e8ee7b 100644 --- a/public/app/features/dashboard-scene/serialization/transformSceneToSaveModelSchemaV2.ts +++ b/public/app/features/dashboard-scene/serialization/transformSceneToSaveModelSchemaV2.ts @@ -387,6 +387,7 @@ function getVizPanelQueryOptions(vizPanel: VizPanel): QueryOptionsSpec { queryOptions.timeFrom = panelTime.state.timeFrom; queryOptions.timeShift = panelTime.state.timeShift; queryOptions.hideTimeOverride = panelTime.state.hideTimeOverride; + queryOptions.timeCompare = panelTime.state.compareWith; } return queryOptions; } diff --git a/public/app/features/dashboard/state/PanelModel.ts b/public/app/features/dashboard/state/PanelModel.ts index 7e67a270ed4..4b06df7c8bc 100644 --- a/public/app/features/dashboard/state/PanelModel.ts +++ b/public/app/features/dashboard/state/PanelModel.ts @@ -170,6 +170,7 @@ export class PanelModel implements DataConfigSource, IPanelModel { timeFrom?: any; timeShift?: any; hideTimeOverride?: boolean; + timeCompare?: string; declare options: { [key: string]: any; }; From cb86be2e32d0aef062e3d313addf99ff156e8cf3 Mon Sep 17 00:00:00 2001 From: maicon Date: Thu, 30 Oct 2025 07:51:31 -0300 Subject: [PATCH 121/378] Unistore: ensure dashboard DeleteInFolders work on both storages (#113197) Signed-off-by: Maicon Costa --- .../dashboards/service/dashboard_service.go | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/pkg/services/dashboards/service/dashboard_service.go b/pkg/services/dashboards/service/dashboard_service.go index 3d26169edd7..f59416924de 100644 --- a/pkg/services/dashboards/service/dashboard_service.go +++ b/pkg/services/dashboards/service/dashboard_service.go @@ -1638,12 +1638,14 @@ func (dr *DashboardServiceImpl) DeleteInFolders(ctx context.Context, orgID int64 defer span.End() // We need a list of dashboard uids inside the folder to delete related public dashboards - dashes, err := dr.dashboardStore.FindDashboards(ctx, &dashboards.FindPersistedDashboardsQuery{ + dashes, err := dr.searchDashboardsThroughK8s(ctx, &dashboards.FindPersistedDashboardsQuery{ SignedInUser: u, - FolderUIDs: folderUIDs, - OrgId: orgID, Type: searchstore.TypeDashboard, + Limit: 100000, + OrgId: orgID, + FolderUIDs: folderUIDs, }) + if err != nil { return folder.ErrInternal.Errorf("failed to fetch dashboards: %w", err) } @@ -1658,7 +1660,14 @@ func (dr *DashboardServiceImpl) DeleteInFolders(ctx context.Context, orgID int64 return err } - return dr.dashboardStore.DeleteDashboardsInFolders(ctx, &dashboards.DeleteDashboardsInFolderRequest{FolderUIDs: folderUIDs, OrgID: orgID}) + for _, dash := range dashes { + errDel := dr.DeleteDashboard(ctx, dash.ID, dash.UID, orgID) + if errDel != nil { + dr.log.Error("failed to delete dashboard inside folder", "dashboardUID", dash.UID, "folderUIDs", folderUIDs, "error", errDel) + } + } + + return err } func (dr *DashboardServiceImpl) Kind() string { return entity.StandardKindDashboard } From bbfb8268d1502bb33dbe7cd7bcf07c4f79fead68 Mon Sep 17 00:00:00 2001 From: Costa Alexoglou Date: Thu, 30 Oct 2025 11:55:36 +0100 Subject: [PATCH 122/378] Provisioning: concurrent deletes in finalizers and 404 handling (#113155) * fix: concurrent deletes in finalizers and 404 handling * chore: feedback review * fix: broken tests --- .../apis/dashboard/cuevalidator/validator.go | 29 +++ .../pkg/apis/dashboard/v0alpha1/validation.go | 15 +- .../pkg/apis/dashboard/v1beta1/validation.go | 15 +- .../pkg/apis/dashboard/v2alpha1/validation.go | 16 +- .../pkg/apis/dashboard/v2beta1/validation.go | 16 +- pkg/operators/provisioning/repo_operator.go | 3 + .../provisioning/controller/finalizers.go | 64 +++++- .../controller/finalizers_test.go | 182 ++++++++++++++++-- .../provisioning/controller/repository.go | 2 + pkg/registry/apis/provisioning/register.go | 1 + 10 files changed, 290 insertions(+), 53 deletions(-) create mode 100644 apps/dashboard/pkg/apis/dashboard/cuevalidator/validator.go diff --git a/apps/dashboard/pkg/apis/dashboard/cuevalidator/validator.go b/apps/dashboard/pkg/apis/dashboard/cuevalidator/validator.go new file mode 100644 index 00000000000..38792ade026 --- /dev/null +++ b/apps/dashboard/pkg/apis/dashboard/cuevalidator/validator.go @@ -0,0 +1,29 @@ +package cuevalidator + +import ( + "sync" + + "cuelang.org/go/cue" + cuejson "cuelang.org/go/encoding/json" +) + +// Validator provides thread-safe CUE schema validation. +// +// CUE is not safe for concurrent use: https://github.com/cue-lang/cue/discussions/1205#discussioncomment-1189238 +// This validator uses a mutex to protect concurrent access to the underlying CUE validation. +type Validator struct { + schema cue.Value + mu sync.Mutex +} + +func NewValidator(schema cue.Value) *Validator { + return &Validator{ + schema: schema, + } +} + +func (v *Validator) Validate(data []byte) error { + v.mu.Lock() + defer v.mu.Unlock() + return cuejson.Validate(data, v.schema) +} diff --git a/apps/dashboard/pkg/apis/dashboard/v0alpha1/validation.go b/apps/dashboard/pkg/apis/dashboard/v0alpha1/validation.go index 6fdf1dd4515..7c5573f600a 100644 --- a/apps/dashboard/pkg/apis/dashboard/v0alpha1/validation.go +++ b/apps/dashboard/pkg/apis/dashboard/v0alpha1/validation.go @@ -7,13 +7,13 @@ import ( "strings" "sync" + "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/cuevalidator" "github.com/grafana/grafana/apps/dashboard/pkg/migration/schemaversion" "k8s.io/apimachinery/pkg/util/validation/field" "cuelang.org/go/cue" "cuelang.org/go/cue/cuecontext" "cuelang.org/go/cue/errors" - cuejson "cuelang.org/go/encoding/json" ) func ValidateDashboardSpec(obj *Dashboard, forceValidation bool) (field.ErrorList, field.ErrorList) { @@ -33,7 +33,7 @@ func ValidateDashboardSpec(obj *Dashboard, forceValidation bool) (field.ErrorLis }, schemaVersionError } - if err := cuejson.Validate(data, getCueSchema()); err != nil { + if err := getValidator().Validate(data); err != nil { errs := field.ErrorList{} for _, e := range errors.Errors(err) { @@ -71,20 +71,21 @@ func formatErrorPath(path []string) string { } var ( - compiledSchema cue.Value - getSchemaOnce sync.Once + validator *cuevalidator.Validator + getSchemaOnce sync.Once ) //go:embed dashboard_kind.cue var schemaSource string -func getCueSchema() cue.Value { +func getValidator() *cuevalidator.Validator { getSchemaOnce.Do(func() { cueCtx := cuecontext.New() - compiledSchema = cueCtx.CompileString(schemaSource).LookupPath( + compiledSchema := cueCtx.CompileString(schemaSource).LookupPath( cue.ParsePath("lineage.schemas[0].schema.spec"), ) + validator = cuevalidator.NewValidator(compiledSchema) }) - return compiledSchema + return validator } diff --git a/apps/dashboard/pkg/apis/dashboard/v1beta1/validation.go b/apps/dashboard/pkg/apis/dashboard/v1beta1/validation.go index 7020aa46b90..b48e38ffd7b 100644 --- a/apps/dashboard/pkg/apis/dashboard/v1beta1/validation.go +++ b/apps/dashboard/pkg/apis/dashboard/v1beta1/validation.go @@ -12,8 +12,8 @@ import ( "cuelang.org/go/cue" "cuelang.org/go/cue/cuecontext" "cuelang.org/go/cue/errors" - cuejson "cuelang.org/go/encoding/json" + "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/cuevalidator" "github.com/grafana/grafana/apps/dashboard/pkg/migration/schemaversion" ) @@ -34,7 +34,7 @@ func ValidateDashboardSpec(obj *Dashboard, forceValidation bool) (field.ErrorLis }, schemaVersionError } - if err := cuejson.Validate(data, getCueSchema()); err != nil { + if err := getValidator().Validate(data); err != nil { errs := field.ErrorList{} for _, e := range errors.Errors(err) { @@ -72,20 +72,21 @@ func formatErrorPath(path []string) string { } var ( - compiledSchema cue.Value - getSchemaOnce sync.Once + validator *cuevalidator.Validator + getSchemaOnce sync.Once ) //go:embed dashboard_kind.cue var schemaSource string -func getCueSchema() cue.Value { +func getValidator() *cuevalidator.Validator { getSchemaOnce.Do(func() { cueCtx := cuecontext.New() - compiledSchema = cueCtx.CompileString(schemaSource).LookupPath( + compiledSchema := cueCtx.CompileString(schemaSource).LookupPath( cue.ParsePath("lineage.schemas[0].schema.spec"), ) + validator = cuevalidator.NewValidator(compiledSchema) }) - return compiledSchema + return validator } diff --git a/apps/dashboard/pkg/apis/dashboard/v2alpha1/validation.go b/apps/dashboard/pkg/apis/dashboard/v2alpha1/validation.go index 7c61faa8924..ca9dcd3e514 100644 --- a/apps/dashboard/pkg/apis/dashboard/v2alpha1/validation.go +++ b/apps/dashboard/pkg/apis/dashboard/v2alpha1/validation.go @@ -12,7 +12,8 @@ import ( "cuelang.org/go/cue" "cuelang.org/go/cue/cuecontext" "cuelang.org/go/cue/errors" - cuejson "cuelang.org/go/encoding/json" + + "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/cuevalidator" ) func ValidateDashboardSpec(obj *Dashboard) field.ErrorList { @@ -26,7 +27,7 @@ func ValidateDashboardSpec(obj *Dashboard) field.ErrorList { // Custom validation for action query params and headers validateAndTrimActionArrays(obj) - if err := cuejson.Validate(data, getCueSchema()); err != nil { + if err := getValidator().Validate(data); err != nil { errs := field.ErrorList{} for _, e := range errors.Errors(err) { @@ -123,20 +124,21 @@ func formatErrorPath(path []string) string { } var ( - compiledSchema cue.Value - getSchemaOnce sync.Once + validator *cuevalidator.Validator + getSchemaOnce sync.Once ) //go:embed dashboard_spec.cue var schemaSource string -func getCueSchema() cue.Value { +func getValidator() *cuevalidator.Validator { getSchemaOnce.Do(func() { cueCtx := cuecontext.New() - compiledSchema = cueCtx.CompileString(schemaSource).LookupPath( + compiledSchema := cueCtx.CompileString(schemaSource).LookupPath( cue.ParsePath("DashboardSpec"), ) + validator = cuevalidator.NewValidator(compiledSchema) }) - return compiledSchema + return validator } diff --git a/apps/dashboard/pkg/apis/dashboard/v2beta1/validation.go b/apps/dashboard/pkg/apis/dashboard/v2beta1/validation.go index 7c859626b98..518c133bcd7 100644 --- a/apps/dashboard/pkg/apis/dashboard/v2beta1/validation.go +++ b/apps/dashboard/pkg/apis/dashboard/v2beta1/validation.go @@ -12,7 +12,8 @@ import ( "cuelang.org/go/cue" "cuelang.org/go/cue/cuecontext" "cuelang.org/go/cue/errors" - cuejson "cuelang.org/go/encoding/json" + + "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/cuevalidator" ) func ValidateDashboardSpec(obj *Dashboard) field.ErrorList { @@ -26,7 +27,7 @@ func ValidateDashboardSpec(obj *Dashboard) field.ErrorList { // Custom validation for action query params and headers validateAndTrimActionArrays(obj) - if err := cuejson.Validate(data, getCueSchema()); err != nil { + if err := getValidator().Validate(data); err != nil { errs := field.ErrorList{} for _, e := range errors.Errors(err) { @@ -123,20 +124,21 @@ func formatErrorPath(path []string) string { } var ( - compiledSchema cue.Value - getSchemaOnce sync.Once + validator *cuevalidator.Validator + getSchemaOnce sync.Once ) //go:embed dashboard_spec.cue var schemaSource string -func getCueSchema() cue.Value { +func getValidator() *cuevalidator.Validator { getSchemaOnce.Do(func() { cueCtx := cuecontext.New() - compiledSchema = cueCtx.CompileString(schemaSource).LookupPath( + compiledSchema := cueCtx.CompileString(schemaSource).LookupPath( cue.ParsePath("DashboardSpec"), ) + validator = cuevalidator.NewValidator(compiledSchema) }) - return compiledSchema + return validator } diff --git a/pkg/operators/provisioning/repo_operator.go b/pkg/operators/provisioning/repo_operator.go index f96653a1d87..1651a126ffe 100644 --- a/pkg/operators/provisioning/repo_operator.go +++ b/pkg/operators/provisioning/repo_operator.go @@ -90,6 +90,7 @@ func RunRepoController(deps server.OperatorDependencies) error { statusPatcher, deps.Registerer, tracer, + controllerCfg.parallelOperations, ) if err != nil { return fmt.Errorf("failed to create repository controller: %w", err) @@ -107,6 +108,7 @@ func RunRepoController(deps server.OperatorDependencies) error { type repoControllerConfig struct { provisioningControllerConfig workerCount int + parallelOperations int allowedTargets []string allowImageRendering bool minSyncInterval time.Duration @@ -128,6 +130,7 @@ func getRepoControllerConfig(cfg *setting.Cfg, registry prometheus.Registerer) ( provisioningControllerConfig: *controllerCfg, allowedTargets: allowedTargets, workerCount: cfg.SectionWithEnvOverrides("operator").Key("worker_count").MustInt(1), + parallelOperations: cfg.SectionWithEnvOverrides("operator").Key("parallel_operations").MustInt(10), allowImageRendering: cfg.SectionWithEnvOverrides("provisioning").Key("allow_image_rendering").MustBool(false), minSyncInterval: cfg.SectionWithEnvOverrides("provisioning").Key("min_sync_interval").MustDuration(1 * time.Minute), }, nil diff --git a/pkg/registry/apis/provisioning/controller/finalizers.go b/pkg/registry/apis/provisioning/controller/finalizers.go index d9c41ee4c15..5bd468fe660 100644 --- a/pkg/registry/apis/provisioning/controller/finalizers.go +++ b/pkg/registry/apis/provisioning/controller/finalizers.go @@ -7,8 +7,11 @@ import ( "slices" "sort" "strings" + "sync/atomic" "time" + "github.com/grafana/dskit/concurrency" + "k8s.io/apimachinery/pkg/api/errors" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/types" @@ -27,6 +30,7 @@ type finalizer struct { lister resources.ResourceLister clientFactory resources.ClientFactory metrics *finalizerMetrics + maxWorkers int } func (f *finalizer) process(ctx context.Context, @@ -113,27 +117,73 @@ func (f *finalizer) processExistingItems( // Safe deletion order sortResourceListForDeletion(items) - count := 0 + var dashboards, folderItems []*provisioning.ResourceListItem for _, item := range items.Items { - res, _, err := clients.ForResource(ctx, schema.GroupVersionResource{ + if item.Group == folders.GroupVersion.Group { + folderItems = append(folderItems, &item) + } else { + dashboards = append(dashboards, &item) + } + } + + processItem := func(jobCtx context.Context, item *provisioning.ResourceListItem) error { + res, _, err := clients.ForResource(jobCtx, schema.GroupVersionResource{ Group: item.Group, Resource: item.Resource, }) if err != nil { logger.Error("error getting client for resource", "resource", item.Resource, "error", err) - return count, err + return err } - err = cb(res, &item) + err = cb(res, item) if err != nil { + if errors.IsNotFound(err) { + logger.Info("resource not found, skipping", "name", item.Name, "group", item.Group, "resource", item.Resource) + return nil + } logger.Error("error processing item", "name", item.Name, "error", err) - return count, fmt.Errorf("processing item: %w", err) - } else { + return fmt.Errorf("processing item: %w", err) + } + return nil + } + + processGroup := func(group []*provisioning.ResourceListItem) (int, error) { + var processed int64 + err := concurrency.ForEachJob(ctx, len(group), f.maxWorkers, func(ctx context.Context, idx int) error { + jobCtx, cancel := context.WithTimeout(ctx, 15*time.Second) + defer cancel() + item := group[idx] + if err := processItem(jobCtx, item); err != nil { + return err + } + atomic.AddInt64(&processed, 1) + return nil + }) + return int(processed), err + } + + count := 0 + + if len(dashboards) > 0 { + processed, err := processGroup(dashboards) + if err != nil { + return processed, err + } + count += processed + } + + if len(folderItems) > 0 { + for _, item := range folderItems { + if err := processItem(ctx, item); err != nil { + return count, err + } count++ } } - logger.Info("processed orphan items", "items", count) + + logger.Info("processed items", "items", count) return count, nil } diff --git a/pkg/registry/apis/provisioning/controller/finalizers_test.go b/pkg/registry/apis/provisioning/controller/finalizers_test.go index 140363a0507..4df89107bbe 100644 --- a/pkg/registry/apis/provisioning/controller/finalizers_test.go +++ b/pkg/registry/apis/provisioning/controller/finalizers_test.go @@ -2,10 +2,15 @@ package controller import ( "context" + "fmt" + "sync" + "sync/atomic" "testing" + "time" "github.com/prometheus/client_golang/prometheus" "github.com/stretchr/testify/assert" + mock "github.com/stretchr/testify/mock" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime/schema" @@ -14,6 +19,8 @@ import ( "k8s.io/apimachinery/pkg/watch" "k8s.io/client-go/dynamic" + "github.com/grafana/grafana-app-sdk/logging" + folders "github.com/grafana/grafana/apps/folder/pkg/apis/folder/v1beta1" provisioning "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1" "github.com/grafana/grafana/apps/provisioning/pkg/repository" "github.com/grafana/grafana/pkg/registry/apis/provisioning/resources" @@ -140,7 +147,7 @@ func TestFinalizer_process(t *testing.T) { resourceLister := resources.NewMockResourceLister(t) resourceLister. - On("List", context.Background(), "default", "my-repo"). + On("List", mock.Anything, "default", "my-repo"). Once(). Return(&provisioning.ResourceList{ Items: []provisioning.ResourceListItem{ @@ -164,12 +171,12 @@ func TestFinalizer_process(t *testing.T) { } clientFactory. - On("Clients", context.Background(), "default"). + On("Clients", mock.Anything, "default"). Once(). Return(clients, nil) clients. - On("ForResource", context.Background(), schema.GroupVersionResource{ + On("ForResource", mock.Anything, schema.GroupVersionResource{ Group: "dashboard.grafana.app", Resource: "dashboards", }). @@ -196,7 +203,7 @@ func TestFinalizer_process(t *testing.T) { resourceLister := resources.NewMockResourceLister(t) resourceLister. - On("List", context.Background(), "default", "my-repo"). + On("List", mock.Anything, "default", "my-repo"). Once(). Return(&provisioning.ResourceList{ Items: []provisioning.ResourceListItem{ @@ -220,12 +227,12 @@ func TestFinalizer_process(t *testing.T) { } clientFactory. - On("Clients", context.Background(), "default"). + On("Clients", mock.Anything, "default"). Once(). Return(clients, nil) clients. - On("ForResource", context.Background(), schema.GroupVersionResource{ + On("ForResource", mock.Anything, schema.GroupVersionResource{ Group: "dashboard.grafana.app", Resource: "dashboards", }). @@ -253,7 +260,7 @@ func TestFinalizer_process(t *testing.T) { clientFactory := resources.NewMockClientFactory(t) clientFactory. - On("Clients", context.Background(), "default"). + On("Clients", mock.Anything, "default"). Once(). Return(nil, assert.AnError) @@ -275,7 +282,7 @@ func TestFinalizer_process(t *testing.T) { resourceLister := resources.NewMockResourceLister(t) resourceLister. - On("List", context.Background(), "default", "my-repo"). + On("List", mock.Anything, "default", "my-repo"). Once(). Return(nil, assert.AnError) @@ -286,7 +293,7 @@ func TestFinalizer_process(t *testing.T) { clients := resources.NewMockResourceClients(t) clientFactory. - On("Clients", context.Background(), "default"). + On("Clients", mock.Anything, "default"). Once(). Return(clients, nil) @@ -308,7 +315,7 @@ func TestFinalizer_process(t *testing.T) { resourceLister := resources.NewMockResourceLister(t) resourceLister. - On("List", context.Background(), "default", "my-repo"). + On("List", mock.Anything, "default", "my-repo"). Once(). Return(&provisioning.ResourceList{ Items: []provisioning.ResourceListItem{ @@ -327,12 +334,12 @@ func TestFinalizer_process(t *testing.T) { clients := resources.NewMockResourceClients(t) clientFactory. - On("Clients", context.Background(), "default"). + On("Clients", mock.Anything, "default"). Once(). Return(clients, nil) clients. - On("ForResource", context.Background(), schema.GroupVersionResource{ + On("ForResource", mock.Anything, schema.GroupVersionResource{ Group: "dashboard.grafana.app", Resource: "dashboards", }). @@ -357,7 +364,7 @@ func TestFinalizer_process(t *testing.T) { resourceLister := resources.NewMockResourceLister(t) resourceLister. - On("List", context.Background(), "default", "my-repo"). + On("List", mock.Anything, "default", "my-repo"). Once(). Return(&provisioning.ResourceList{ Items: []provisioning.ResourceListItem{ @@ -381,12 +388,12 @@ func TestFinalizer_process(t *testing.T) { } clientFactory. - On("Clients", context.Background(), "default"). + On("Clients", mock.Anything, "default"). Once(). Return(clients, nil) clients. - On("ForResource", context.Background(), schema.GroupVersionResource{ + On("ForResource", mock.Anything, schema.GroupVersionResource{ Group: "dashboard.grafana.app", Resource: "dashboards", }). @@ -414,7 +421,7 @@ func TestFinalizer_process(t *testing.T) { resourceLister := resources.NewMockResourceLister(t) resourceLister. - On("List", context.Background(), "default", "my-repo"). + On("List", mock.Anything, "default", "my-repo"). Once(). Return(&provisioning.ResourceList{ Items: []provisioning.ResourceListItem{ @@ -438,12 +445,12 @@ func TestFinalizer_process(t *testing.T) { } clientFactory. - On("Clients", context.Background(), "default"). + On("Clients", mock.Anything, "default"). Once(). Return(clients, nil) clients. - On("ForResource", context.Background(), schema.GroupVersionResource{ + On("ForResource", mock.Anything, schema.GroupVersionResource{ Group: "dashboard.grafana.app", Resource: "dashboards", }). @@ -560,3 +567,142 @@ func TestSortResourceListForDeletion(t *testing.T) { }) } } + +func TestFinalizer_processExistingItems_Concurrency(t *testing.T) { + testCases := []struct { + name string + dashboardCount int + folderCount int + maxWorkers int + expectedConcurrency bool + }{ + { + name: "Multiple dashboards processed concurrently", + dashboardCount: 10, + folderCount: 0, + maxWorkers: 5, + expectedConcurrency: true, + }, + { + name: "Single worker processes dashboards sequentially", + dashboardCount: 5, + folderCount: 0, + maxWorkers: 1, + expectedConcurrency: false, + }, + { + name: "Folders processed sequentially regardless of maxWorkers", + dashboardCount: 0, + folderCount: 5, + maxWorkers: 10, + expectedConcurrency: false, + }, + { + name: "Mixed dashboards and folders - dashboards concurrent, folders sequential", + dashboardCount: 10, + folderCount: 3, + maxWorkers: 5, + expectedConcurrency: true, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + // Will be used to track concurrent executions + var ( + concurrentCount int64 + maxConcurrent int64 + mu sync.Mutex + ) + + items := provisioning.ResourceList{Items: []provisioning.ResourceListItem{}} + + for i := 0; i < tc.dashboardCount; i++ { + items.Items = append(items.Items, provisioning.ResourceListItem{ + Group: "dashboard.grafana.app", + Resource: "dashboards", + Name: fmt.Sprintf("dashboard-%d", i), + }) + } + + for i := 0; i < tc.folderCount; i++ { + items.Items = append(items.Items, provisioning.ResourceListItem{ + Group: folders.GroupVersion.Group, + Resource: "folders", + Name: fmt.Sprintf("folder-%d", i), + }) + } + + resourceLister := resources.NewMockResourceLister(t) + resourceLister. + On("List", mock.Anything, "default", "my-repo"). + Return(&items, nil) + + clientFactory := resources.NewMockClientFactory(t) + clients := resources.NewMockResourceClients(t) + + client := &mockDynamicClient{ + deleteFunc: func(ctx context.Context, name string, options metav1.DeleteOptions, subresources ...string) error { + // Track concurrent executions + current := atomic.AddInt64(&concurrentCount, 1) + defer atomic.AddInt64(&concurrentCount, -1) + + mu.Lock() + if current > maxConcurrent { + maxConcurrent = current + } + mu.Unlock() + + // Simulate slow client to allow concurrency to build up + time.Sleep(1 * time.Second) + + return nil + }, + } + + clientFactory. + On("Clients", mock.Anything, "default"). + Return(clients, nil) + + clients. + On("ForResource", mock.Anything, mock.Anything). + Return(client, schema.GroupVersionKind{}, nil) + + metrics := registerFinalizerMetrics(prometheus.NewRegistry()) + f := &finalizer{ + lister: resourceLister, + clientFactory: clientFactory, + metrics: &metrics, + maxWorkers: tc.maxWorkers, + } + + repo := &provisioning.Repository{ + ObjectMeta: metav1.ObjectMeta{ + Name: "my-repo", + Namespace: "default", + }, + } + + count, err := f.processExistingItems( + context.Background(), + repo, + f.removeResources(context.Background(), logging.DefaultLogger), + ) + + assert.NoError(t, err) + assert.Equal(t, tc.dashboardCount+tc.folderCount, count) + + if tc.expectedConcurrency { + // When concurrent, max concurrent should be > 1 + assert.Greater(t, maxConcurrent, int64(1), + "Expected concurrent execution but maxConcurrent was %d", maxConcurrent) + // Should not exceed maxWorkers + assert.LessOrEqual(t, maxConcurrent, int64(tc.maxWorkers)) + } else { + // When sequential, max concurrent should be 1 + assert.Equal(t, int64(1), maxConcurrent, + "Expected sequential execution but maxConcurrent was %d", maxConcurrent) + } + }) + } +} diff --git a/pkg/registry/apis/provisioning/controller/repository.go b/pkg/registry/apis/provisioning/controller/repository.go index 70e5c3b4a87..681619711e1 100644 --- a/pkg/registry/apis/provisioning/controller/repository.go +++ b/pkg/registry/apis/provisioning/controller/repository.go @@ -84,6 +84,7 @@ func NewRepositoryController( statusPatcher StatusPatcher, registry prometheus.Registerer, tracer tracing.Tracer, + parallelOperations int, ) (*RepositoryController, error) { finalizerMetrics := registerFinalizerMetrics(registry) @@ -104,6 +105,7 @@ func NewRepositoryController( lister: resourceLister, clientFactory: clients, metrics: &finalizerMetrics, + maxWorkers: parallelOperations, }, jobs: jobs, logger: logging.DefaultLogger.With("logger", loggerName), diff --git a/pkg/registry/apis/provisioning/register.go b/pkg/registry/apis/provisioning/register.go index 8797d940408..485f6bfe5d5 100644 --- a/pkg/registry/apis/provisioning/register.go +++ b/pkg/registry/apis/provisioning/register.go @@ -798,6 +798,7 @@ func (b *APIBuilder) GetPostStartHooks() (map[string]genericapiserver.PostStartH b.statusPatcher, b.registry, b.tracer, + 10, ) if err != nil { return err From 5f2074e84ce339de098e1afa40a8c2487e242e04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Jamr=C3=B3z?= Date: Thu, 30 Oct 2025 12:55:06 +0100 Subject: [PATCH 123/378] Explore: Use compact mode only when targeting Tempo (#113037) * Explore: Use compact mode only when targeting Tempo * Fix checking ds type when data source is not in the query object --- public/app/features/explore/Explore.tsx | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/public/app/features/explore/Explore.tsx b/public/app/features/explore/Explore.tsx index 5673fdbbbb9..f8bd275930b 100644 --- a/public/app/features/explore/Explore.tsx +++ b/public/app/features/explore/Explore.tsx @@ -312,16 +312,20 @@ export class Explore extends PureComponent { */ onSplitOpen = (panelType: string) => { return async (options?: SplitOpenOptions) => { - let compact = true; + let compact = false; /** * Temporary fix grafana-clickhouse-datasource as it requires the query editor to be fully rendered to update the query * Proposed fixes: * - https://github.com/grafana/clickhouse-datasource/issues/1363 - handle query update in data source * - https://github.com/grafana/grafana/issues/110868 - allow data links to provide meta info if the link can be handled in compact mode (default to false) + * Update: + * More data source may struggle with this setting: https://github.com/grafana/grafana/issues/112075 + * We're making it enabled for tempo only and will try to make it optional for other data sources in the future. */ - if (options?.queries?.some((q) => q.datasource?.type === 'grafana-clickhouse-datasource')) { - compact = false; + const dsType = getDataSourceSrv().getInstanceSettings({ uid: options?.datasourceUid })?.type; + if (dsType === 'tempo' || options?.queries?.every((q) => q.datasource?.type === 'tempo')) { + compact = true; } this.props.splitOpen(options ? { ...options, compact } : options); From 80d5cfa1844df4358415c48176970a5e6c325ea1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ida=20=C5=A0tambuk?= Date: Thu, 30 Oct 2025 13:10:00 +0100 Subject: [PATCH 124/378] CloudWatch: Add tracking for logs anomalies (#113181) - Fix tracking for new logs queries with logGroups field --- .../mocks/dashboardOnLoadedEvent.ts | 30 ++++++++++++++++++- .../datasource/cloudwatch/tracking.test.ts | 5 ++-- .../plugins/datasource/cloudwatch/tracking.ts | 27 ++++++++++++----- 3 files changed, 51 insertions(+), 11 deletions(-) diff --git a/public/app/plugins/datasource/cloudwatch/mocks/dashboardOnLoadedEvent.ts b/public/app/plugins/datasource/cloudwatch/mocks/dashboardOnLoadedEvent.ts index ebe3dcaf1f0..f2095b5c4f2 100644 --- a/public/app/plugins/datasource/cloudwatch/mocks/dashboardOnLoadedEvent.ts +++ b/public/app/plugins/datasource/cloudwatch/mocks/dashboardOnLoadedEvent.ts @@ -2,7 +2,7 @@ import { DashboardLoadedEvent } from '@grafana/data'; import { CloudWatchQuery } from '../types'; -const baseLogsQuery = { +const baseLegacyLogsQuery = { datasource: { type: 'cloudwatch', uid: 'P7DC3E4760CFAC4AP', @@ -17,6 +17,15 @@ const baseLogsQuery = { statsGroups: [], }; +const baseLogsQuery = { + ...baseLegacyLogsQuery, + logGroups: [ + { arn: 'arn:test', name: 'log-group-1' }, + { arn: 'arn:test2', name: 'log-group-2' }, + ], + logGroupNames: undefined, +}; + export const CloudWatchDashboardLoadedEvent = new DashboardLoadedEvent({ dashboardId: 'dashboard123', orgId: 1, @@ -474,6 +483,9 @@ export const CloudWatchDashboardLoadedEvent = new DashboardLoadedEvent({ sqlExpression: '', statistic: 'Average', }, + { + ...baseLegacyLogsQuery, + }, { ...baseLogsQuery, }, @@ -779,6 +791,22 @@ export const CloudWatchDashboardLoadedEvent = new DashboardLoadedEvent({ sqlExpression: '', statistic: '', }, + { + refId: 'A', + region: 'default', + queryMode: 'Logs', + logsMode: 'Anomalies', + anomalyDetectionARN: '', + suppressionState: 'suppressed', + }, + { + refId: 'A', + region: 'default', + queryMode: 'Logs', + logsMode: 'Anomalies', + anomalyDetectionARN: '', + suppressionState: 'all', + }, ] as CloudWatchQuery[], }, }); diff --git a/public/app/plugins/datasource/cloudwatch/tracking.test.ts b/public/app/plugins/datasource/cloudwatch/tracking.test.ts index 822cf07a5d1..f66f0a2ad25 100644 --- a/public/app/plugins/datasource/cloudwatch/tracking.test.ts +++ b/public/app/plugins/datasource/cloudwatch/tracking.test.ts @@ -27,10 +27,11 @@ describe('onDashboardLoadedHandler', () => { dashboard_id: 'dashboard123', grafana_version: 'v9.0.0', org_id: 1, - logs_queries_count: 5, - logs_cwli_queries_count: 2, + logs_queries_count: 8, + logs_cwli_queries_count: 3, logs_sql_queries_count: 1, logs_ppl_queries_count: 2, + log_anomalies_queries_count: 2, metrics_queries_count: 21, metrics_query_builder_count: 3, metrics_query_code_count: 4, diff --git a/public/app/plugins/datasource/cloudwatch/tracking.ts b/public/app/plugins/datasource/cloudwatch/tracking.ts index 4bf91191f1e..51a4559ee1e 100644 --- a/public/app/plugins/datasource/cloudwatch/tracking.ts +++ b/public/app/plugins/datasource/cloudwatch/tracking.ts @@ -1,13 +1,15 @@ import { DashboardLoadedEvent } from '@grafana/data'; import { config, reportInteraction } from '@grafana/runtime'; -import { isCloudWatchLogsQuery, isCloudWatchMetricsQuery } from './guards'; +import { isCloudWatchLogsQuery, isCloudWatchMetricsQuery, isLogsAnomaliesQuery } from './guards'; import { migrateMetricQuery } from './migrations/metricQueryMigrations'; import pluginJson from './plugin.json'; import { + CloudWatchLogsAnomaliesQuery, CloudWatchLogsQuery, CloudWatchMetricsQuery, CloudWatchQuery, + LogsMode, LogsQueryLanguage, MetricEditorMode, MetricQueryType, @@ -31,6 +33,9 @@ type CloudWatchOnDashboardLoadedTrackingEvent = { /* The number of Logs queries that use PPL language */ logs_ppl_queries_count: number; + /* The number of log anomalies queries */ + log_anomalies_queries_count: number; + /* The number of CloudWatch metrics queries present in the dashboard*/ metrics_queries_count: number; @@ -77,7 +82,8 @@ export const onDashboardLoadedHandler = ({ return; } - let logsQueries: CloudWatchLogsQuery[] = []; + let logsInsightsQueries: CloudWatchLogsQuery[] = []; + let logAnomaliesQueries: CloudWatchLogsAnomaliesQuery[] = []; let metricsQueries: CloudWatchMetricsQuery[] = []; for (const query of cloudWatchQueries) { @@ -85,8 +91,12 @@ export const onDashboardLoadedHandler = ({ continue; } - if (isCloudWatchLogsQuery(query)) { - query.logGroupNames?.length && logsQueries.push(query); + const isLogsInsightsQuery = + isCloudWatchLogsQuery(query) && (!query.logsMode || query.logsMode === LogsMode.Insights); + if (isLogsInsightsQuery) { + (query.logGroupNames?.length || query.logGroups?.length) && logsInsightsQueries.push(query); + } else if (isLogsAnomaliesQuery(query)) { + logAnomaliesQueries.push(query); } else if (isCloudWatchMetricsQuery(query)) { const migratedQuery = migrateMetricQuery(query); filterMetricsQuery(migratedQuery) && metricsQueries.push(query); @@ -97,12 +107,13 @@ export const onDashboardLoadedHandler = ({ grafana_version: grafanaVersion, dashboard_id: dashboardId, org_id: orgId, - logs_queries_count: logsQueries?.length, - logs_cwli_queries_count: logsQueries?.filter( + logs_queries_count: logsInsightsQueries?.length + logAnomaliesQueries.length, + logs_cwli_queries_count: logsInsightsQueries?.filter( (q) => !q.queryLanguage || q.queryLanguage === LogsQueryLanguage.CWLI ).length, - logs_sql_queries_count: logsQueries?.filter((q) => q.queryLanguage === LogsQueryLanguage.SQL).length, - logs_ppl_queries_count: logsQueries?.filter((q) => q.queryLanguage === LogsQueryLanguage.PPL).length, + logs_sql_queries_count: logsInsightsQueries?.filter((q) => q.queryLanguage === LogsQueryLanguage.SQL).length, + logs_ppl_queries_count: logsInsightsQueries?.filter((q) => q.queryLanguage === LogsQueryLanguage.PPL).length, + log_anomalies_queries_count: logAnomaliesQueries.length, metrics_queries_count: metricsQueries?.length, metrics_search_count: 0, metrics_search_builder_count: 0, From f185377c68bb2f0a943e9974034ba00d04d6511f Mon Sep 17 00:00:00 2001 From: Ezequiel Victorero Date: Thu, 30 Oct 2025 09:29:40 -0300 Subject: [PATCH 125/378] ShortURL: Use RTK api for creation (#113185) --- public/app/core/utils/shortLinks.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/public/app/core/utils/shortLinks.ts b/public/app/core/utils/shortLinks.ts index c01988d2262..011b5c66baa 100644 --- a/public/app/core/utils/shortLinks.ts +++ b/public/app/core/utils/shortLinks.ts @@ -1,10 +1,10 @@ import memoizeOne from 'memoize-one'; -import { generatedAPI } from '@grafana/api-clients/rtkq/shorturl/v1alpha1'; import { AbsoluteTimeRange, LogRowModel, UrlQueryMap } from '@grafana/data'; import { t } from '@grafana/i18n'; import { getBackendSrv, config, locationService } from '@grafana/runtime'; import { sceneGraph, SceneTimeRangeLike, VizPanel } from '@grafana/scenes'; +import { shortURLAPIv1alpha1 } from 'app/api/clients/shorturl/v1alpha1'; import { notifyApp } from 'app/core/actions'; import { createErrorNotification, createSuccessNotification } from 'app/core/copy/appNotification'; import { DashboardScene } from 'app/features/dashboard-scene/scene/DashboardScene'; @@ -46,7 +46,7 @@ export const createShortLink = async function (path: string) { if (config.featureToggles.useKubernetesShortURLsAPI) { // Use RTK API - it handles caching/failures/retries automatically const result = await dispatch( - generatedAPI.endpoints.createShortUrl.initiate({ + shortURLAPIv1alpha1.endpoints.createShortUrl.initiate({ shortUrl: { apiVersion: 'shorturl.grafana.app/v1alpha1', kind: 'ShortURL', From d303746ff90563669cfbeae7f6d1041770c7bec6 Mon Sep 17 00:00:00 2001 From: Ryan McKinley Date: Thu, 30 Oct 2025 15:57:03 +0300 Subject: [PATCH 126/378] ShortURL: Use UpdateStatus client (#111170) --- apps/shorturl/pkg/app/app.go | 14 ++- pkg/api/short_url_test.go | 9 +- pkg/registry/apps/shorturl/conversions.go | 9 +- pkg/registry/apps/shorturl/legacy_storage.go | 52 +------- pkg/registry/apps/shorturl/register.go | 16 +++ pkg/registry/apps/shorturl/status.go | 111 ++++++++++++++++++ .../apiserver/appinstaller/installer.go | 10 +- pkg/services/apiserver/appinstaller/server.go | 52 +++++--- pkg/services/shorturls/shorturl.go | 6 +- .../shorturls/shorturlimpl/shorturl.go | 10 +- pkg/services/shorturls/shorturlimpl/store.go | 8 +- pkg/tests/apis/shorturl/shorturl_test.go | 83 ++++++------- 12 files changed, 250 insertions(+), 130 deletions(-) create mode 100644 pkg/registry/apps/shorturl/status.go diff --git a/apps/shorturl/pkg/app/app.go b/apps/shorturl/pkg/app/app.go index 4c85ef97435..bb97db78a93 100644 --- a/apps/shorturl/pkg/app/app.go +++ b/apps/shorturl/pkg/app/app.go @@ -30,11 +30,12 @@ var ( func New(cfg app.Config) (app.App, error) { cfg.KubeConfig.APIPath = "apis" - client, err := k8s.NewClientRegistry(cfg.KubeConfig, k8s.DefaultClientConfig()). + tmp, err := k8s.NewClientRegistry(cfg.KubeConfig, k8s.DefaultClientConfig()). ClientFor(shorturlv1alpha1.ShortURLKind()) if err != nil { return nil, fmt.Errorf("unable to create client") } + client := shorturlv1alpha1.NewShortURLClient(tmp) simpleConfig := simple.AppConfig{ Name: "shorturl", @@ -81,8 +82,8 @@ func New(cfg app.Config) (app.App, error) { Name: req.ResourceIdentifier.Name, } - info := &shorturlv1alpha1.ShortURL{} - if err := client.GetInto(ctx, id, info); err != nil { + info, err := client.Get(ctx, id) + if err != nil { return err } @@ -93,7 +94,12 @@ func New(cfg app.Config) (app.App, error) { if err != nil { logging.FromContext(ctx).Warn("unable to create background identity", "err", err) } else { - _, _ = client.Update(ctx, id, info, resource.UpdateOptions{}) + _, err = client.UpdateStatus(ctx, id, info.Status, resource.UpdateOptions{ + ResourceVersion: info.ResourceVersion, + }) + if err != nil { + logging.FromContext(ctx).Warn("unable to update status", "err", err) + } } }() diff --git a/pkg/api/short_url_test.go b/pkg/api/short_url_test.go index 6d3da5fbe0c..116d4f70328 100644 --- a/pkg/api/short_url_test.go +++ b/pkg/api/short_url_test.go @@ -11,6 +11,7 @@ import ( "github.com/grafana/grafana/pkg/api/dtos" "github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/api/routing" + "github.com/grafana/grafana/pkg/apimachinery/identity" "github.com/grafana/grafana/pkg/infra/log" contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model" "github.com/grafana/grafana/pkg/services/shorturls" @@ -31,7 +32,7 @@ func TestShortURLAPIEndpoint(t *testing.T) { Path: cmd.Path, } service := &fakeShortURLService{ - createShortURLFunc: func(ctx context.Context, user *user.SignedInUser, cmd *dtos.CreateShortURLCmd) (*shorturls.ShortUrl, error) { + createShortURLFunc: func(ctx context.Context, user identity.Requester, cmd *dtos.CreateShortURLCmd) (*shorturls.ShortUrl, error) { return createResp, nil }, createConvertShortURLToDTO: func(shortURL *shorturls.ShortUrl, appURL string) *dtos.ShortURL { @@ -81,7 +82,7 @@ func createShortURLScenario(t *testing.T, desc string, url string, routePattern } type fakeShortURLService struct { - createShortURLFunc func(ctx context.Context, user *user.SignedInUser, cmd *dtos.CreateShortURLCmd) (*shorturls.ShortUrl, error) + createShortURLFunc func(ctx context.Context, user identity.Requester, cmd *dtos.CreateShortURLCmd) (*shorturls.ShortUrl, error) createConvertShortURLToDTO func(shortURL *shorturls.ShortUrl, appURL string) *dtos.ShortURL } @@ -89,11 +90,11 @@ func (s *fakeShortURLService) List(ctx context.Context, orgID int64) ([]*shortur return nil, nil } -func (s *fakeShortURLService) GetShortURLByUID(ctx context.Context, user *user.SignedInUser, uid string) (*shorturls.ShortUrl, error) { +func (s *fakeShortURLService) GetShortURLByUID(ctx context.Context, user identity.Requester, uid string) (*shorturls.ShortUrl, error) { return nil, nil } -func (s *fakeShortURLService) CreateShortURL(ctx context.Context, user *user.SignedInUser, cmd *dtos.CreateShortURLCmd) (*shorturls.ShortUrl, error) { +func (s *fakeShortURLService) CreateShortURL(ctx context.Context, user identity.Requester, cmd *dtos.CreateShortURLCmd) (*shorturls.ShortUrl, error) { if s.createShortURLFunc != nil { return s.createShortURLFunc(ctx, user, cmd) } diff --git a/pkg/registry/apps/shorturl/conversions.go b/pkg/registry/apps/shorturl/conversions.go index 979106d3bda..c23f014adbd 100644 --- a/pkg/registry/apps/shorturl/conversions.go +++ b/pkg/registry/apps/shorturl/conversions.go @@ -21,10 +21,17 @@ func convertToK8sResource(v *shorturls.ShortUrl, namespacer request.NamespaceMap status := shorturl.ShortURLStatus{ LastSeenAt: v.LastSeenAt, } + + // resourceVersion can't be 0, since we are using the lastSeenAt value, when it's zero we default to current time + resourceVersion := fmt.Sprintf("%d", v.LastSeenAt) + if v.LastSeenAt == 0 { + resourceVersion = fmt.Sprintf("%d", time.Now().UnixMilli()) + } + p := &shorturl.ShortURL{ ObjectMeta: metav1.ObjectMeta{ Name: v.Uid, - ResourceVersion: fmt.Sprintf("%d", v.LastSeenAt), + ResourceVersion: resourceVersion, CreationTimestamp: metav1.NewTime(time.UnixMilli(v.CreatedAt)), Namespace: namespacer(v.OrgId), }, diff --git a/pkg/registry/apps/shorturl/legacy_storage.go b/pkg/registry/apps/shorturl/legacy_storage.go index c9462359236..de36560b679 100644 --- a/pkg/registry/apps/shorturl/legacy_storage.go +++ b/pkg/registry/apps/shorturl/legacy_storage.go @@ -16,9 +16,7 @@ import ( "github.com/grafana/grafana/pkg/api/dtos" "github.com/grafana/grafana/pkg/apimachinery/identity" "github.com/grafana/grafana/pkg/services/apiserver/endpoints/request" - "github.com/grafana/grafana/pkg/services/authn" "github.com/grafana/grafana/pkg/services/shorturls" - "github.com/grafana/grafana/pkg/services/user" ) var ( @@ -87,13 +85,7 @@ func (s *legacyStorage) Get(ctx context.Context, name string, options *metav1.Ge return nil, err } - // Convert any identity.Requester to *user.SignedInUser - signedInUser, err := convertRequesterToSignedInUser(requester) - if err != nil { - return nil, fmt.Errorf("failed to convert requester: %w", err) - } - - dto, err := s.service.GetShortURLByUID(ctx, signedInUser, name) + dto, err := s.service.GetShortURLByUID(ctx, requester, name) if err != nil || dto == nil { if errors.Is(err, shorturls.ErrShortURLNotFound) || err == nil { err = k8serrors.NewNotFound(shorturl.ShortURLKind().GroupVersionResource().GroupResource(), name) @@ -114,12 +106,6 @@ func (s *legacyStorage) Create(ctx context.Context, return nil, err } - // Convert any identity.Requester to *user.SignedInUser - signedInUser, err := convertRequesterToSignedInUser(requester) - if err != nil { - return nil, fmt.Errorf("failed to convert requester: %w", err) - } - if createValidation != nil { if err := createValidation(ctx, obj.DeepCopyObject()); err != nil { return nil, err @@ -133,7 +119,7 @@ func (s *legacyStorage) Create(ctx context.Context, Path: p.Spec.Path, UID: p.Name, } - out, err := s.service.CreateShortURL(ctx, signedInUser, cmd) + out, err := s.service.CreateShortURL(ctx, requester, cmd) if err != nil { return nil, err } @@ -154,13 +140,7 @@ func (s *legacyStorage) Update(ctx context.Context, return nil, false, err } - // Convert any identity.Requester to *user.SignedInUser - signedInUser, err := convertRequesterToSignedInUser(requester) - if err != nil { - return nil, false, fmt.Errorf("failed to convert requester: %w", err) - } - - shortURL, err := s.service.GetShortURLByUID(ctx, signedInUser, name) + shortURL, err := s.service.GetShortURLByUID(ctx, requester, name) if err != nil || shortURL == nil { if errors.Is(err, shorturls.ErrShortURLNotFound) || err == nil { err = k8serrors.NewNotFound(shorturl.ShortURLKind().GroupVersionResource().GroupResource(), name) @@ -173,7 +153,7 @@ func (s *legacyStorage) Update(ctx context.Context, return nil, false, err } // Fetch the updated short URL to return - updatedLegacyShortURL, err := s.service.GetShortURLByUID(ctx, signedInUser, name) + updatedLegacyShortURL, err := s.service.GetShortURLByUID(ctx, requester, name) if err != nil { return nil, false, err } @@ -199,27 +179,3 @@ func (s *legacyStorage) Delete(ctx context.Context, name string, deleteValidatio func (s *legacyStorage) DeleteCollection(ctx context.Context, deleteValidation rest.ValidateObjectFunc, options *metav1.DeleteOptions, listOptions *internalversion.ListOptions) (runtime.Object, error) { return nil, fmt.Errorf("DeleteCollection for shorturl not implemented") } - -// convertRequesterToSignedInUser converts any identity.Requester to *user.SignedInUser -// This is needed because some legacy shorturls service methods still expect SignedInUser -func convertRequesterToSignedInUser(requester identity.Requester) (*user.SignedInUser, error) { - // If it's already a SignedInUser, return it directly - if signedInUser, ok := requester.(*user.SignedInUser); ok { - return signedInUser, nil - } - - // If it's a StaticRequester (service identity), convert it - if staticRequester, ok := requester.(*identity.StaticRequester); ok { - return &user.SignedInUser{ - UserID: staticRequester.UserID, // Used for CreatedBy field - OrgID: staticRequester.OrgID, // Used in SQL queries - }, nil - } - - // If it's an authn.Identity, use its SignedInUser method - if authnIdentity, ok := requester.(*authn.Identity); ok { - return authnIdentity.SignedInUser(), nil - } - - return nil, fmt.Errorf("unsupported identity type") -} diff --git a/pkg/registry/apps/shorturl/register.go b/pkg/registry/apps/shorturl/register.go index a44593ceabe..423eae92073 100644 --- a/pkg/registry/apps/shorturl/register.go +++ b/pkg/registry/apps/shorturl/register.go @@ -5,6 +5,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apiserver/pkg/registry/rest" restclient "k8s.io/client-go/rest" "github.com/grafana/grafana-app-sdk/app" @@ -86,3 +87,18 @@ func (s *ShortURLAppInstaller) GetLegacyStorage(requested schema.GroupVersionRes ) return legacyStore } + +func (s *ShortURLAppInstaller) GetLegacyStatus(requested schema.GroupVersionResource, unified *appsdkapiserver.StatusREST) rest.Storage { + gvr := shorturl.ShortURLKind().GroupVersionResource() + if requested.String() != gvr.String() { + return nil + } + return &statusDualWriter{ + gv: gvr.GroupVersion(), + status: unified, + legacy: &legacyStorage{ + service: s.service, + namespacer: s.namespacer, + }, + } +} diff --git a/pkg/registry/apps/shorturl/status.go b/pkg/registry/apps/shorturl/status.go new file mode 100644 index 00000000000..ed9fe063a98 --- /dev/null +++ b/pkg/registry/apps/shorturl/status.go @@ -0,0 +1,111 @@ +package shorturl + +import ( + "context" + "errors" + "fmt" + + k8serrors "k8s.io/apimachinery/pkg/api/errors" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apiserver/pkg/registry/rest" + "sigs.k8s.io/structured-merge-diff/v6/fieldpath" + + "github.com/grafana/grafana-app-sdk/k8s/apiserver" + "github.com/grafana/grafana-app-sdk/logging" + shorturl "github.com/grafana/grafana/apps/shorturl/pkg/apis/shorturl/v1alpha1" + "github.com/grafana/grafana/pkg/apimachinery/identity" + "github.com/grafana/grafana/pkg/services/shorturls" +) + +type statusDualWriter struct { + gv schema.GroupVersion + status *apiserver.StatusREST + legacy *legacyStorage +} + +var ( + _ rest.Patcher = (*statusDualWriter)(nil) + _ rest.Storage = (*statusDualWriter)(nil) + _ rest.ResetFieldsStrategy = (*statusDualWriter)(nil) +) + +// Destroy implements rest.Storage. +func (s *statusDualWriter) Destroy() {} + +// New implements rest.Storage. +func (s *statusDualWriter) New() runtime.Object { + return s.legacy.New() +} + +// Get implements rest.Patcher. +func (s *statusDualWriter) Get(ctx context.Context, name string, options *v1.GetOptions) (runtime.Object, error) { + return s.legacy.Get(ctx, name, options) +} + +// Update implements rest.Patcher. +func (s *statusDualWriter) Update(ctx context.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc, forceAllowCreate bool, options *v1.UpdateOptions) (runtime.Object, bool, error) { + requester, err := identity.GetRequester(ctx) + if err != nil { + return nil, false, err + } + + shortURL, err := s.legacy.service.GetShortURLByUID(ctx, requester, name) + if err != nil || shortURL == nil { + if errors.Is(err, shorturls.ErrShortURLNotFound) || err == nil { + err = k8serrors.NewNotFound(shorturl.ShortURLKind().GroupVersionResource().GroupResource(), name) + } + return nil, false, err + } + + // This ignores the incoming and updates it directly + err = s.legacy.service.UpdateLastSeenAt(ctx, shortURL) + if err != nil { + return nil, false, err + } + + getter := func(getter rest.Getter) (*shorturl.ShortURL, error) { + obj, err := getter.Get(ctx, name, &v1.GetOptions{}) + if err != nil { + return nil, err + } + val, ok := obj.(*shorturl.ShortURL) + if !ok { + return nil, fmt.Errorf("expected ShortURL but got %T", obj) + } + return val, nil + } + + legacy, err := getter(s.legacy) + if err != nil { + return nil, false, err // unable to get legacy object + } + + unified, err := getter(s.status) + if err != nil { + logging.FromContext(ctx).Warn("unable to read unified status", "error", err) + return legacy, false, nil + } + + // Use the same status from legacy in unified + unified.Status = legacy.Status + + _, _, err = s.status.Update(ctx, name, rest.DefaultUpdatedObjectInfo(unified), createValidation, updateValidation, false, options) + if err != nil { + logging.FromContext(ctx).Warn("error updating unified status", "error", err) + } + + return legacy, false, err +} + +// GetResetFields implements rest.ResetFieldsStrategy +func (s *statusDualWriter) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set { + fields := map[fieldpath.APIVersion]*fieldpath.Set{ + fieldpath.APIVersion(s.gv.String()): fieldpath.NewSet( + fieldpath.MakePathOrDie("spec"), + fieldpath.MakePathOrDie("metadata"), + ), + } + return fields +} diff --git a/pkg/services/apiserver/appinstaller/installer.go b/pkg/services/apiserver/appinstaller/installer.go index a89d2b84f9a..d7742eedf12 100644 --- a/pkg/services/apiserver/appinstaller/installer.go +++ b/pkg/services/apiserver/appinstaller/installer.go @@ -12,18 +12,18 @@ import ( "k8s.io/apiserver/pkg/admission" "k8s.io/apiserver/pkg/authorization/authorizer" "k8s.io/apiserver/pkg/registry/generic" + "k8s.io/apiserver/pkg/registry/rest" genericapiserver "k8s.io/apiserver/pkg/server" serverstore "k8s.io/apiserver/pkg/server/storage" "k8s.io/kube-openapi/pkg/common" appsdkapiserver "github.com/grafana/grafana-app-sdk/k8s/apiserver" "github.com/grafana/grafana-app-sdk/logging" - "github.com/grafana/grafana/pkg/storage/legacysql/dualwrite" - grafanarest "github.com/grafana/grafana/pkg/apiserver/rest" "github.com/grafana/grafana/pkg/services/apiserver/builder" "github.com/grafana/grafana/pkg/services/apiserver/endpoints/request" grafanaapiserveroptions "github.com/grafana/grafana/pkg/services/apiserver/options" + "github.com/grafana/grafana/pkg/storage/legacysql/dualwrite" ) type LegacyStorageGetterFunc func(schema.GroupVersionResource) grafanarest.Storage @@ -32,6 +32,12 @@ type LegacyStorageProvider interface { GetLegacyStorage(schema.GroupVersionResource) grafanarest.Storage } +// In the rare case that that legacy needs to support the status subresource +// Unlike resource storage, dual writing must be managed explicitly +type LegacyStatusProvider interface { + GetLegacyStatus(schema.GroupVersionResource, *appsdkapiserver.StatusREST) rest.Storage +} + type AuthorizerProvider interface { GetAuthorizer() authorizer.Authorizer } diff --git a/pkg/services/apiserver/appinstaller/server.go b/pkg/services/apiserver/appinstaller/server.go index 2e5d46b2b3d..ab688a46fb9 100644 --- a/pkg/services/apiserver/appinstaller/server.go +++ b/pkg/services/apiserver/appinstaller/server.go @@ -60,25 +60,41 @@ func (s *serverWrapper) InstallAPIGroup(apiGroupInfo *genericapiserver.APIGroupI continue } storage := s.configureStorage(gr, dualWriteSupported, restStorage) - if unifiedStorage, ok := storage.(grafanarest.Storage); ok && dualWriteSupported { - log.Debug("Configuring dual writer for storage", "resource", gr.String(), "version", v, "storagePath", storagePath) - dw, err := NewDualWriter( - s.ctx, - gr, - s.storageOpts, - legacyProvider.GetLegacyStorage(gr.WithVersion(v)), - unifiedStorage, - s.kvStore, - s.lock, - s.namespaceMapper, - s.dualWriteService, - s.dualWriterMetrics, - s.builderMetrics, - ) - if err != nil { - return err + if dualWriteSupported { + if unifiedStorage, ok := storage.(grafanarest.Storage); ok { + log.Debug("Configuring dual writer for storage", "resource", gr.String(), "version", v, "storagePath", storagePath) + storage, err = NewDualWriter( + s.ctx, + gr, + s.storageOpts, + legacyProvider.GetLegacyStorage(gr.WithVersion(v)), + unifiedStorage, + s.kvStore, + s.lock, + s.namespaceMapper, + s.dualWriteService, + s.dualWriterMetrics, + s.builderMetrics, + ) + if err != nil { + return err + } + } else if statusRest, ok := storage.(*appsdkapiserver.StatusREST); ok { + parentPath := strings.TrimSuffix(storagePath, "/status") + parentStore, ok := apiGroupInfo.VersionedResourcesStorageMap[v][parentPath] + if ok { + if _, isMode4or5 := parentStore.(*genericregistry.Store); !isMode4or5 { + // When legacy resources have status, the dual writing must be handled explicitly + if statusProvider, ok := s.installer.(LegacyStatusProvider); ok { + storage = statusProvider.GetLegacyStatus(gr.WithVersion(v), statusRest) + } else { + log.Warn("skipped registering status sub-resource that does not support dual writing", + "resource", gr.String(), "version", v, "storagePath", storagePath) + continue + } + } + } } - storage = dw } apiGroupInfo.VersionedResourcesStorageMap[v][storagePath] = storage } diff --git a/pkg/services/shorturls/shorturl.go b/pkg/services/shorturls/shorturl.go index d62f469f85c..99040011f50 100644 --- a/pkg/services/shorturls/shorturl.go +++ b/pkg/services/shorturls/shorturl.go @@ -4,12 +4,12 @@ import ( "context" "github.com/grafana/grafana/pkg/api/dtos" - "github.com/grafana/grafana/pkg/services/user" + "github.com/grafana/grafana/pkg/apimachinery/identity" ) type Service interface { - GetShortURLByUID(ctx context.Context, user *user.SignedInUser, uid string) (*ShortUrl, error) - CreateShortURL(ctx context.Context, user *user.SignedInUser, cmd *dtos.CreateShortURLCmd) (*ShortUrl, error) + GetShortURLByUID(ctx context.Context, user identity.Requester, uid string) (*ShortUrl, error) + CreateShortURL(ctx context.Context, user identity.Requester, cmd *dtos.CreateShortURLCmd) (*ShortUrl, error) UpdateLastSeenAt(ctx context.Context, shortURL *ShortUrl) error DeleteStaleShortURLs(ctx context.Context, cmd *DeleteShortUrlCommand) error ConvertShortURLToDTO(shortURL *ShortUrl, appURL string) *dtos.ShortURL diff --git a/pkg/services/shorturls/shorturlimpl/shorturl.go b/pkg/services/shorturls/shorturlimpl/shorturl.go index 51753b74c6e..a363a4d7627 100644 --- a/pkg/services/shorturls/shorturlimpl/shorturl.go +++ b/pkg/services/shorturls/shorturlimpl/shorturl.go @@ -8,9 +8,9 @@ import ( "time" "github.com/grafana/grafana/pkg/api/dtos" + "github.com/grafana/grafana/pkg/apimachinery/identity" "github.com/grafana/grafana/pkg/infra/db" "github.com/grafana/grafana/pkg/services/shorturls" - "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/util" ) @@ -28,7 +28,7 @@ func ProvideService(db db.DB) *ShortURLService { } } -func (s ShortURLService) GetShortURLByUID(ctx context.Context, user *user.SignedInUser, uid string) (*shorturls.ShortUrl, error) { +func (s ShortURLService) GetShortURLByUID(ctx context.Context, user identity.Requester, uid string) (*shorturls.ShortUrl, error) { return s.SQLStore.Get(ctx, user, uid) } @@ -40,7 +40,7 @@ func (s ShortURLService) List(ctx context.Context, orgID int64) ([]*shorturls.Sh return s.SQLStore.List(ctx, orgID) } -func (s ShortURLService) CreateShortURL(ctx context.Context, user *user.SignedInUser, cmd *dtos.CreateShortURLCmd) (*shorturls.ShortUrl, error) { +func (s ShortURLService) CreateShortURL(ctx context.Context, user identity.Requester, cmd *dtos.CreateShortURLCmd) (*shorturls.ShortUrl, error) { relPath := strings.TrimSpace(cmd.Path) if path.IsAbs(relPath) { @@ -74,12 +74,12 @@ func (s ShortURLService) CreateShortURL(ctx context.Context, user *user.SignedIn now := time.Now().Unix() shortURL := shorturls.ShortUrl{ - OrgId: user.OrgID, + OrgId: user.GetOrgID(), Uid: uid, Path: relPath, - CreatedBy: user.UserID, CreatedAt: now, } + shortURL.CreatedBy, _ = user.GetInternalID() if err := s.SQLStore.Insert(ctx, &shortURL); err != nil { return nil, shorturls.ErrShortURLInternal.Errorf("failed to insert shorturl: %w", err) diff --git a/pkg/services/shorturls/shorturlimpl/store.go b/pkg/services/shorturls/shorturlimpl/store.go index 6e0a072d23c..ad74b269d45 100644 --- a/pkg/services/shorturls/shorturlimpl/store.go +++ b/pkg/services/shorturls/shorturlimpl/store.go @@ -3,13 +3,13 @@ package shorturlimpl import ( "context" + "github.com/grafana/grafana/pkg/apimachinery/identity" "github.com/grafana/grafana/pkg/infra/db" "github.com/grafana/grafana/pkg/services/shorturls" - "github.com/grafana/grafana/pkg/services/user" ) type store interface { - Get(ctx context.Context, user *user.SignedInUser, uid string) (*shorturls.ShortUrl, error) + Get(ctx context.Context, user identity.Requester, uid string) (*shorturls.ShortUrl, error) Update(ctx context.Context, shortURL *shorturls.ShortUrl) error Insert(ctx context.Context, shortURL *shorturls.ShortUrl) error Delete(ctx context.Context, cmd *shorturls.DeleteShortUrlCommand) error @@ -20,10 +20,10 @@ type sqlStore struct { db db.DB } -func (s sqlStore) Get(ctx context.Context, user *user.SignedInUser, uid string) (*shorturls.ShortUrl, error) { +func (s sqlStore) Get(ctx context.Context, user identity.Requester, uid string) (*shorturls.ShortUrl, error) { var shortURL shorturls.ShortUrl err := s.db.WithDbSession(ctx, func(dbSession *db.Session) error { - exists, err := dbSession.Where("org_id=? AND uid=?", user.OrgID, uid).Get(&shortURL) + exists, err := dbSession.Where("org_id=? AND uid=?", user.GetOrgID(), uid).Get(&shortURL) if err != nil { return err } diff --git a/pkg/tests/apis/shorturl/shorturl_test.go b/pkg/tests/apis/shorturl/shorturl_test.go index 86445846acf..1b6f44dd7e4 100644 --- a/pkg/tests/apis/shorturl/shorturl_test.go +++ b/pkg/tests/apis/shorturl/shorturl_test.go @@ -5,13 +5,14 @@ import ( "fmt" "net/http" "testing" + "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/apimachinery/pkg/runtime/schema" + shorturlV1 "github.com/grafana/grafana/apps/shorturl/pkg/apis/shorturl/v1alpha1" "github.com/grafana/grafana/pkg/api/dtos" grafanarest "github.com/grafana/grafana/pkg/apiserver/rest" "github.com/grafana/grafana/pkg/services/apiserver/options" @@ -28,11 +29,7 @@ func TestMain(m *testing.M) { testsuite.Run(m) } -var gvr = schema.GroupVersionResource{ - Group: "shorturl.grafana.app", - Version: "v1alpha1", - Resource: "shorturls", -} +var gvr = shorturlV1.ShortURLKind().GroupVersionResource() var RESOURCEGROUP = gvr.GroupResource().String() @@ -78,29 +75,31 @@ func TestIntegrationShortURL(t *testing.T) { doLegacyOnlyTests(t, helper) }) - for _, mode := range []grafanarest.DualWriterMode{ - grafanarest.Mode1, - grafanarest.Mode2, - // grafanarest.Mode3, TODO: the /goto function needs to use an UpdateStatus client - // grafanarest.Mode4, - } { - t.Run(fmt.Sprintf("with dual write (unified storage, mode %d)", mode), func(t *testing.T) { - helper := apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{ - AppModeProduction: false, - DisableAnonymous: true, - APIServerStorageType: options.StorageTypeUnified, - EnableFeatureToggles: []string{ - featuremgmt.FlagKubernetesShortURLs, - }, - UnifiedStorageConfig: map[string]setting.UnifiedStorageConfig{ - RESOURCEGROUP: { - DualWriterMode: mode, + t.Run("modes", func(t *testing.T) { + for _, mode := range []grafanarest.DualWriterMode{ + grafanarest.Mode1, + grafanarest.Mode2, + grafanarest.Mode3, + grafanarest.Mode4, + } { + t.Run(fmt.Sprintf("dual write (unified storage, mode %d)", mode), func(t *testing.T) { + helper := apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{ + AppModeProduction: false, + DisableAnonymous: true, + APIServerStorageType: options.StorageTypeUnified, + EnableFeatureToggles: []string{ + featuremgmt.FlagKubernetesShortURLs, }, - }, + UnifiedStorageConfig: map[string]setting.UnifiedStorageConfig{ + RESOURCEGROUP: { + DualWriterMode: mode, + }, + }, + }) + doDualWriteTests(t, helper, mode) }) - doDualWriteTests(t, helper, mode) - }) - } + } + }) t.Run("with dual write (unified storage, mode 5)", func(t *testing.T) { helper := apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{ @@ -173,7 +172,7 @@ func doLegacyOnlyTests(t *testing.T, helper *apis.K8sTestHelper) { User: client.Args.User, Method: http.MethodGet, Path: "/goto/" + uid + "?orgId=default", - }, (*interface{})(nil)) + }, (*any)(nil)) assert.Equal(t, 302, redirectResponse.Response.StatusCode) }) } @@ -278,21 +277,23 @@ func doDualWriteTests(t *testing.T, helper *apis.K8sTestHelper, mode grafanarest User: client.Args.User, Method: http.MethodGet, Path: "/goto/" + uid + "?orgId=default", - }, (*interface{})(nil)) + }, (*any)(nil)) assert.Equal(t, 302, redirectResponse.Response.StatusCode) - // Verify lastSeenAt was updated (should be > 0 now) - found, err := client.Resource.Get(context.Background(), uid, metav1.GetOptions{}) - require.NoError(t, err) - status, exists := found.Object["status"].(map[string]interface{}) - assert.True(t, exists) - lastSeenAt, exists := status["lastSeenAt"].(int64) - assert.True(t, exists) + require.EventuallyWithT(t, func(t *assert.CollectT) { + // Verify lastSeenAt was updated (should be > 0 now) + found, err := client.Resource.Get(context.Background(), uid, metav1.GetOptions{}) + require.NoError(t, err) - assert.Greater(t, lastSeenAt, int64(0)) + lastSeenAt, exists, err := unstructured.NestedInt64(found.Object, "status", "lastSeenAt") + require.NoError(t, err) + require.True(t, exists) + + require.Greater(t, lastSeenAt, int64(1), "lastSeenAt should be greater than 1 after redirect") + }, time.Second*5, time.Millisecond*75, "lastSeenAt should be updated after redirect") // Clean up - err = client.Resource.Delete(context.Background(), uid, metav1.DeleteOptions{}) + err := client.Resource.Delete(context.Background(), uid, metav1.DeleteOptions{}) require.NoError(t, err) }) } @@ -458,7 +459,7 @@ func doUnifiedOnlyTests(t *testing.T, helper *apis.K8sTestHelper) { User: client.Args.User, Method: http.MethodGet, Path: "/goto/" + uid + "?orgId=default", - }, (*interface{})(nil)) + }, (*any)(nil)) assert.Equal(t, 302, redirectResponse.Response.StatusCode) // Clean up @@ -505,9 +506,9 @@ func getFromBothAPIs(t *testing.T, if legacyShortURL != nil { // If legacy API returns data, verify consistency - spec, ok := k8sResource.Object["spec"].(map[string]interface{}) + spec, ok := k8sResource.Object["spec"].(map[string]any) require.True(t, ok) - status, ok := k8sResource.Object["status"].(map[string]interface{}) + status, ok := k8sResource.Object["status"].(map[string]any) require.True(t, ok) assert.Equal(t, legacyShortURL.Uid, k8sResource.GetName()) assert.Equal(t, legacyShortURL.Path, spec["path"].(string)) From 05dc9b2be1cf5a9dfd06564403175b6417f18d50 Mon Sep 17 00:00:00 2001 From: Tom Ratcliffe Date: Thu, 30 Oct 2025 13:08:14 +0000 Subject: [PATCH 127/378] API Clients: Add lazy hooks to clients (#113226) --- .../rtkq/advisor/v0alpha1/endpoints.gen.ts | 7 + .../correlations/v0alpha1/endpoints.gen.ts | 3 + .../rtkq/dashboard/v0alpha1/endpoints.gen.ts | 8 + .../rtkq/folder/v1beta1/endpoints.gen.ts | 7 + .../rtkq/iam/v0alpha1/endpoints.gen.ts | 15 ++ .../src/clients/rtkq/legacy/endpoints.gen.ts | 143 ++++++++++++++++++ .../rtkq/migrate-to-cloud/endpoints.gen.ts | 8 + .../rtkq/playlist/v0alpha1/endpoints.gen.ts | 4 + .../rtkq/preferences/user/endpoints.gen.ts | 8 +- .../preferences/v1alpha1/endpoints.gen.ts | 6 + .../provisioning/v0alpha1/endpoints.gen.ts | 18 +++ .../rtkq/shorturl/v1alpha1/endpoints.gen.ts | 5 + .../src/scripts/generate-rtk-apis.ts | 16 +- 13 files changed, 241 insertions(+), 7 deletions(-) diff --git a/packages/grafana-api-clients/src/clients/rtkq/advisor/v0alpha1/endpoints.gen.ts b/packages/grafana-api-clients/src/clients/rtkq/advisor/v0alpha1/endpoints.gen.ts index 8cf2fec2b60..4b4de61be87 100644 --- a/packages/grafana-api-clients/src/clients/rtkq/advisor/v0alpha1/endpoints.gen.ts +++ b/packages/grafana-api-clients/src/clients/rtkq/advisor/v0alpha1/endpoints.gen.ts @@ -1008,24 +1008,31 @@ export type CheckTypeList = { }; export const { useGetApiResourcesQuery, + useLazyGetApiResourcesQuery, useListCheckQuery, + useLazyListCheckQuery, useCreateCheckMutation, useDeletecollectionCheckMutation, useGetCheckQuery, + useLazyGetCheckQuery, useReplaceCheckMutation, useDeleteCheckMutation, useUpdateCheckMutation, useGetCheckStatusQuery, + useLazyGetCheckStatusQuery, useReplaceCheckStatusMutation, useUpdateCheckStatusMutation, useListCheckTypeQuery, + useLazyListCheckTypeQuery, useCreateCheckTypeMutation, useDeletecollectionCheckTypeMutation, useGetCheckTypeQuery, + useLazyGetCheckTypeQuery, useReplaceCheckTypeMutation, useDeleteCheckTypeMutation, useUpdateCheckTypeMutation, useGetCheckTypeStatusQuery, + useLazyGetCheckTypeStatusQuery, useReplaceCheckTypeStatusMutation, useUpdateCheckTypeStatusMutation, } = injectedRtkApi; diff --git a/packages/grafana-api-clients/src/clients/rtkq/correlations/v0alpha1/endpoints.gen.ts b/packages/grafana-api-clients/src/clients/rtkq/correlations/v0alpha1/endpoints.gen.ts index 9f40ec322a5..6cfab61cdba 100644 --- a/packages/grafana-api-clients/src/clients/rtkq/correlations/v0alpha1/endpoints.gen.ts +++ b/packages/grafana-api-clients/src/clients/rtkq/correlations/v0alpha1/endpoints.gen.ts @@ -511,10 +511,13 @@ export type Status = { export type Patch = object; export const { useGetApiResourcesQuery, + useLazyGetApiResourcesQuery, useListCorrelationQuery, + useLazyListCorrelationQuery, useCreateCorrelationMutation, useDeletecollectionCorrelationMutation, useGetCorrelationQuery, + useLazyGetCorrelationQuery, useReplaceCorrelationMutation, useDeleteCorrelationMutation, useUpdateCorrelationMutation, diff --git a/packages/grafana-api-clients/src/clients/rtkq/dashboard/v0alpha1/endpoints.gen.ts b/packages/grafana-api-clients/src/clients/rtkq/dashboard/v0alpha1/endpoints.gen.ts index 9e4aee6b516..6ca3505d067 100644 --- a/packages/grafana-api-clients/src/clients/rtkq/dashboard/v0alpha1/endpoints.gen.ts +++ b/packages/grafana-api-clients/src/clients/rtkq/dashboard/v0alpha1/endpoints.gen.ts @@ -1061,21 +1061,29 @@ export type SearchResults = { }; export const { useGetApiResourcesQuery, + useLazyGetApiResourcesQuery, useListDashboardQuery, + useLazyListDashboardQuery, useCreateDashboardMutation, useDeletecollectionDashboardMutation, useGetDashboardQuery, + useLazyGetDashboardQuery, useReplaceDashboardMutation, useDeleteDashboardMutation, useUpdateDashboardMutation, useGetDashboardDtoQuery, + useLazyGetDashboardDtoQuery, useListLibraryPanelQuery, + useLazyListLibraryPanelQuery, useCreateLibraryPanelMutation, useDeletecollectionLibraryPanelMutation, useGetLibraryPanelQuery, + useLazyGetLibraryPanelQuery, useReplaceLibraryPanelMutation, useDeleteLibraryPanelMutation, useUpdateLibraryPanelMutation, useGetSearchQuery, + useLazyGetSearchQuery, useGetSearchSortableQuery, + useLazyGetSearchSortableQuery, } = injectedRtkApi; diff --git a/packages/grafana-api-clients/src/clients/rtkq/folder/v1beta1/endpoints.gen.ts b/packages/grafana-api-clients/src/clients/rtkq/folder/v1beta1/endpoints.gen.ts index b618f8b335a..9ef9e4ebfab 100644 --- a/packages/grafana-api-clients/src/clients/rtkq/folder/v1beta1/endpoints.gen.ts +++ b/packages/grafana-api-clients/src/clients/rtkq/folder/v1beta1/endpoints.gen.ts @@ -562,15 +562,22 @@ export type FolderInfoList = { }; export const { useGetApiResourcesQuery, + useLazyGetApiResourcesQuery, useListFolderQuery, + useLazyListFolderQuery, useCreateFolderMutation, useDeletecollectionFolderMutation, useGetFolderQuery, + useLazyGetFolderQuery, useReplaceFolderMutation, useDeleteFolderMutation, useUpdateFolderMutation, useGetFolderAccessQuery, + useLazyGetFolderAccessQuery, useGetFolderChildrenQuery, + useLazyGetFolderChildrenQuery, useGetFolderCountsQuery, + useLazyGetFolderCountsQuery, useGetFolderParentsQuery, + useLazyGetFolderParentsQuery, } = injectedRtkApi; diff --git a/packages/grafana-api-clients/src/clients/rtkq/iam/v0alpha1/endpoints.gen.ts b/packages/grafana-api-clients/src/clients/rtkq/iam/v0alpha1/endpoints.gen.ts index bd1585fc928..3645b4b3373 100644 --- a/packages/grafana-api-clients/src/clients/rtkq/iam/v0alpha1/endpoints.gen.ts +++ b/packages/grafana-api-clients/src/clients/rtkq/iam/v0alpha1/endpoints.gen.ts @@ -1733,41 +1733,56 @@ export type UserTeamList = { }; export const { useGetApiResourcesQuery, + useLazyGetApiResourcesQuery, useGetDisplayMappingQuery, + useLazyGetDisplayMappingQuery, useListServiceAccountQuery, + useLazyListServiceAccountQuery, useCreateServiceAccountMutation, useDeletecollectionServiceAccountMutation, useGetServiceAccountQuery, + useLazyGetServiceAccountQuery, useReplaceServiceAccountMutation, useDeleteServiceAccountMutation, useUpdateServiceAccountMutation, useGetServiceAccountTokensQuery, + useLazyGetServiceAccountTokensQuery, useListSsoSettingQuery, + useLazyListSsoSettingQuery, useGetSsoSettingQuery, + useLazyGetSsoSettingQuery, useReplaceSsoSettingMutation, useDeleteSsoSettingMutation, useUpdateSsoSettingMutation, useListTeamBindingQuery, + useLazyListTeamBindingQuery, useCreateTeamBindingMutation, useDeletecollectionTeamBindingMutation, useGetTeamBindingQuery, + useLazyGetTeamBindingQuery, useReplaceTeamBindingMutation, useDeleteTeamBindingMutation, useUpdateTeamBindingMutation, useListTeamQuery, + useLazyListTeamQuery, useCreateTeamMutation, useDeletecollectionTeamMutation, useGetTeamQuery, + useLazyGetTeamQuery, useReplaceTeamMutation, useDeleteTeamMutation, useUpdateTeamMutation, useGetTeamMembersQuery, + useLazyGetTeamMembersQuery, useListUserQuery, + useLazyListUserQuery, useCreateUserMutation, useDeletecollectionUserMutation, useGetUserQuery, + useLazyGetUserQuery, useReplaceUserMutation, useDeleteUserMutation, useUpdateUserMutation, useGetUserTeamsQuery, + useLazyGetUserTeamsQuery, } = injectedRtkApi; diff --git a/packages/grafana-api-clients/src/clients/rtkq/legacy/endpoints.gen.ts b/packages/grafana-api-clients/src/clients/rtkq/legacy/endpoints.gen.ts index eb201201379..bd6ff32f5bf 100644 --- a/packages/grafana-api-clients/src/clients/rtkq/legacy/endpoints.gen.ts +++ b/packages/grafana-api-clients/src/clients/rtkq/legacy/endpoints.gen.ts @@ -6502,319 +6502,462 @@ export type NotificationTemplateContent = { export const { useSearchResultMutation, useListRolesQuery, + useLazyListRolesQuery, useCreateRoleMutation, useDeleteRoleMutation, useGetRoleQuery, + useLazyGetRoleQuery, useUpdateRoleMutation, useGetRoleAssignmentsQuery, + useLazyGetRoleAssignmentsQuery, useSetRoleAssignmentsMutation, useGetAccessControlStatusQuery, + useLazyGetAccessControlStatusQuery, useListTeamsRolesMutation, useListTeamRolesQuery, + useLazyListTeamRolesQuery, useAddTeamRoleMutation, useSetTeamRolesMutation, useRemoveTeamRoleMutation, useListUsersRolesMutation, useListUserRolesQuery, + useLazyListUserRolesQuery, useAddUserRoleMutation, useSetUserRolesMutation, useRemoveUserRoleMutation, useGetResourceDescriptionQuery, + useLazyGetResourceDescriptionQuery, useGetResourcePermissionsQuery, + useLazyGetResourcePermissionsQuery, useSetResourcePermissionsMutation, useSetResourcePermissionsForBuiltInRoleMutation, useSetResourcePermissionsForTeamMutation, useSetResourcePermissionsForUserMutation, useGetSyncStatusQuery, + useLazyGetSyncStatusQuery, useReloadLdapCfgMutation, useGetLdapStatusQuery, + useLazyGetLdapStatusQuery, usePostSyncUserWithLdapMutation, useGetUserFromLdapQuery, + useLazyGetUserFromLdapQuery, useAdminProvisioningReloadAccessControlMutation, useAdminProvisioningReloadDashboardsMutation, useAdminProvisioningReloadDatasourcesMutation, useAdminProvisioningReloadPluginsMutation, useAdminGetSettingsQuery, + useLazyAdminGetSettingsQuery, useAdminGetStatsQuery, + useLazyAdminGetStatsQuery, useAdminCreateUserMutation, useAdminDeleteUserMutation, useAdminGetUserAuthTokensQuery, + useLazyAdminGetUserAuthTokensQuery, useAdminDisableUserMutation, useAdminEnableUserMutation, useAdminLogoutUserMutation, useAdminUpdateUserPasswordMutation, useAdminUpdateUserPermissionsMutation, useGetUserQuotaQuery, + useLazyGetUserQuotaQuery, useUpdateUserQuotaMutation, useAdminRevokeUserAuthTokenMutation, useGetAnnotationsQuery, + useLazyGetAnnotationsQuery, usePostAnnotationMutation, usePostGraphiteAnnotationMutation, useMassDeleteAnnotationsMutation, useGetAnnotationTagsQuery, + useLazyGetAnnotationTagsQuery, useDeleteAnnotationByIdMutation, useGetAnnotationByIdQuery, + useLazyGetAnnotationByIdQuery, usePatchAnnotationMutation, useUpdateAnnotationMutation, useListDevicesQuery, + useLazyListDevicesQuery, useSearchDevicesQuery, + useLazySearchDevicesQuery, useGetSessionListQuery, + useLazyGetSessionListQuery, useCreateSessionMutation, useDeleteSessionMutation, useGetSessionQuery, + useLazyGetSessionQuery, useCreateSnapshotMutation, useGetSnapshotQuery, + useLazyGetSnapshotQuery, useCancelSnapshotMutation, useUploadSnapshotMutation, useGetShapshotListQuery, + useLazyGetShapshotListQuery, useGetResourceDependenciesQuery, + useLazyGetResourceDependenciesQuery, useGetCloudMigrationTokenQuery, + useLazyGetCloudMigrationTokenQuery, useCreateCloudMigrationTokenMutation, useDeleteCloudMigrationTokenMutation, useRouteConvertPrometheusCortexGetRulesQuery, + useLazyRouteConvertPrometheusCortexGetRulesQuery, useRouteConvertPrometheusCortexPostRuleGroupsMutation, useRouteConvertPrometheusCortexDeleteNamespaceMutation, useRouteConvertPrometheusCortexGetNamespaceQuery, + useLazyRouteConvertPrometheusCortexGetNamespaceQuery, useRouteConvertPrometheusCortexPostRuleGroupMutation, useRouteConvertPrometheusCortexDeleteRuleGroupMutation, useRouteConvertPrometheusCortexGetRuleGroupQuery, + useLazyRouteConvertPrometheusCortexGetRuleGroupQuery, useRouteConvertPrometheusGetRulesQuery, + useLazyRouteConvertPrometheusGetRulesQuery, useRouteConvertPrometheusPostRuleGroupsMutation, useRouteConvertPrometheusDeleteNamespaceMutation, useRouteConvertPrometheusGetNamespaceQuery, + useLazyRouteConvertPrometheusGetNamespaceQuery, useRouteConvertPrometheusPostRuleGroupMutation, useRouteConvertPrometheusDeleteRuleGroupMutation, useRouteConvertPrometheusGetRuleGroupQuery, + useLazyRouteConvertPrometheusGetRuleGroupQuery, useSearchDashboardSnapshotsQuery, + useLazySearchDashboardSnapshotsQuery, useCalculateDashboardDiffMutation, usePostDashboardMutation, useGetHomeDashboardQuery, + useLazyGetHomeDashboardQuery, useImportDashboardMutation, useInterpolateDashboardMutation, useListPublicDashboardsQuery, + useLazyListPublicDashboardsQuery, useGetDashboardTagsQuery, + useLazyGetDashboardTagsQuery, useGetPublicDashboardQuery, + useLazyGetPublicDashboardQuery, useCreatePublicDashboardMutation, useDeletePublicDashboardMutation, useUpdatePublicDashboardMutation, useDeleteDashboardByUidMutation, useGetDashboardByUidQuery, + useLazyGetDashboardByUidQuery, useGetDashboardPermissionsListByUidQuery, + useLazyGetDashboardPermissionsListByUidQuery, useUpdateDashboardPermissionsByUidMutation, useRestoreDashboardVersionByUidMutation, useGetDashboardVersionsByUidQuery, + useLazyGetDashboardVersionsByUidQuery, useGetDashboardVersionByUidQuery, + useLazyGetDashboardVersionByUidQuery, useGetDataSourcesQuery, + useLazyGetDataSourcesQuery, useAddDataSourceMutation, useGetCorrelationsQuery, + useLazyGetCorrelationsQuery, useGetDataSourceIdByNameQuery, + useLazyGetDataSourceIdByNameQuery, useDeleteDataSourceByNameMutation, useGetDataSourceByNameQuery, + useLazyGetDataSourceByNameQuery, useDatasourceProxyDeleteByUiDcallsMutation, useDatasourceProxyGetByUiDcallsQuery, + useLazyDatasourceProxyGetByUiDcallsQuery, useDatasourceProxyPostByUiDcallsMutation, useGetCorrelationsBySourceUidQuery, + useLazyGetCorrelationsBySourceUidQuery, useCreateCorrelationMutation, useGetCorrelationQuery, + useLazyGetCorrelationQuery, useUpdateCorrelationMutation, useDeleteDataSourceByUidMutation, useGetDataSourceByUidQuery, + useLazyGetDataSourceByUidQuery, useUpdateDataSourceByUidMutation, useDeleteCorrelationMutation, useCheckDatasourceHealthWithUidQuery, + useLazyCheckDatasourceHealthWithUidQuery, useGetTeamLbacRulesApiQuery, + useLazyGetTeamLbacRulesApiQuery, useUpdateTeamLbacRulesApiMutation, useCallDatasourceResourceWithUidQuery, + useLazyCallDatasourceResourceWithUidQuery, useGetDataSourceCacheConfigQuery, + useLazyGetDataSourceCacheConfigQuery, useSetDataSourceCacheConfigMutation, useCleanDataSourceCacheMutation, useDisableDataSourceCacheMutation, useEnableDataSourceCacheMutation, useQueryMetricsWithExpressionsMutation, useGetFoldersQuery, + useLazyGetFoldersQuery, useCreateFolderMutation, useDeleteFolderMutation, useGetFolderByUidQuery, + useLazyGetFolderByUidQuery, useUpdateFolderMutation, useGetFolderDescendantCountsQuery, + useLazyGetFolderDescendantCountsQuery, useMoveFolderMutation, useGetFolderPermissionListQuery, + useLazyGetFolderPermissionListQuery, useUpdateFolderPermissionsMutation, useGetMappedGroupsQuery, + useLazyGetMappedGroupsQuery, useDeleteGroupMappingsMutation, useCreateGroupMappingsMutation, useUpdateGroupMappingsMutation, useGetGroupRolesQuery, + useLazyGetGroupRolesQuery, useGetHealthQuery, + useLazyGetHealthQuery, useGetLibraryElementsQuery, + useLazyGetLibraryElementsQuery, useCreateLibraryElementMutation, useGetLibraryElementByNameQuery, + useLazyGetLibraryElementByNameQuery, useDeleteLibraryElementByUidMutation, useGetLibraryElementByUidQuery, + useLazyGetLibraryElementByUidQuery, useUpdateLibraryElementMutation, useGetLibraryElementConnectionsQuery, + useLazyGetLibraryElementConnectionsQuery, useGetStatusQuery, + useLazyGetStatusQuery, useRefreshLicenseStatsQuery, + useLazyRefreshLicenseStatsQuery, useDeleteLicenseTokenMutation, useGetLicenseTokenQuery, + useLazyGetLicenseTokenQuery, usePostLicenseTokenMutation, usePostRenewLicenseTokenMutation, useGetSamlLogoutQuery, + useLazyGetSamlLogoutQuery, useGetCurrentOrgQuery, + useLazyGetCurrentOrgQuery, useUpdateCurrentOrgMutation, useUpdateCurrentOrgAddressMutation, useGetPendingOrgInvitesQuery, + useLazyGetPendingOrgInvitesQuery, useAddOrgInviteMutation, useRevokeInviteMutation, useGetOrgPreferencesQuery, + useLazyGetOrgPreferencesQuery, usePatchOrgPreferencesMutation, useUpdateOrgPreferencesMutation, useGetCurrentOrgQuotaQuery, + useLazyGetCurrentOrgQuotaQuery, useGetOrgUsersForCurrentOrgQuery, + useLazyGetOrgUsersForCurrentOrgQuery, useAddOrgUserToCurrentOrgMutation, useGetOrgUsersForCurrentOrgLookupQuery, + useLazyGetOrgUsersForCurrentOrgLookupQuery, useRemoveOrgUserForCurrentOrgMutation, useUpdateOrgUserForCurrentOrgMutation, useSearchOrgsQuery, + useLazySearchOrgsQuery, useCreateOrgMutation, useGetOrgByNameQuery, + useLazyGetOrgByNameQuery, useDeleteOrgByIdMutation, useGetOrgByIdQuery, + useLazyGetOrgByIdQuery, useUpdateOrgMutation, useUpdateOrgAddressMutation, useGetOrgQuotaQuery, + useLazyGetOrgQuotaQuery, useUpdateOrgQuotaMutation, useGetOrgUsersQuery, + useLazyGetOrgUsersQuery, useAddOrgUserMutation, useSearchOrgUsersQuery, + useLazySearchOrgUsersQuery, useRemoveOrgUserMutation, useUpdateOrgUserMutation, useSearchPlaylistsQuery, + useLazySearchPlaylistsQuery, useCreatePlaylistMutation, useDeletePlaylistMutation, useGetPlaylistQuery, + useLazyGetPlaylistQuery, useUpdatePlaylistMutation, useGetPlaylistItemsQuery, + useLazyGetPlaylistItemsQuery, useViewPublicDashboardQuery, + useLazyViewPublicDashboardQuery, useGetPublicAnnotationsQuery, + useLazyGetPublicAnnotationsQuery, useQueryPublicDashboardMutation, useSearchQueriesQuery, + useLazySearchQueriesQuery, useCreateQueryMutation, useUnstarQueryMutation, useStarQueryMutation, useDeleteQueryMutation, usePatchQueryCommentMutation, useListRecordingRulesQuery, + useLazyListRecordingRulesQuery, useCreateRecordingRuleMutation, useUpdateRecordingRuleMutation, useTestCreateRecordingRuleMutation, useDeleteRecordingRuleWriteTargetMutation, useGetRecordingRuleWriteTargetQuery, + useLazyGetRecordingRuleWriteTargetQuery, useCreateRecordingRuleWriteTargetMutation, useDeleteRecordingRuleMutation, useGetReportsQuery, + useLazyGetReportsQuery, useCreateReportMutation, useGetReportsByDashboardUidQuery, + useLazyGetReportsByDashboardUidQuery, useSendReportMutation, useGetSettingsImageQuery, + useLazyGetSettingsImageQuery, useRenderReportCsVsQuery, + useLazyRenderReportCsVsQuery, useRenderReportPdFsQuery, + useLazyRenderReportPdFsQuery, useGetReportSettingsQuery, + useLazyGetReportSettingsQuery, useSaveReportSettingsMutation, useSendTestEmailMutation, usePostAcsMutation, useGetMetadataQuery, + useLazyGetMetadataQuery, useGetSloQuery, + useLazyGetSloQuery, usePostSloMutation, useSearchQuery, + useLazySearchQuery, useListSortOptionsQuery, + useLazyListSortOptionsQuery, useCreateServiceAccountMutation, useSearchOrgServiceAccountsWithPagingQuery, + useLazySearchOrgServiceAccountsWithPagingQuery, useDeleteServiceAccountMutation, useRetrieveServiceAccountQuery, + useLazyRetrieveServiceAccountQuery, useUpdateServiceAccountMutation, useListTokensQuery, + useLazyListTokensQuery, useCreateTokenMutation, useDeleteTokenMutation, useRetrieveJwksQuery, + useLazyRetrieveJwksQuery, useGetSharingOptionsQuery, + useLazyGetSharingOptionsQuery, useCreateDashboardSnapshotMutation, useDeleteDashboardSnapshotByDeleteKeyQuery, + useLazyDeleteDashboardSnapshotByDeleteKeyQuery, useDeleteDashboardSnapshotMutation, useGetDashboardSnapshotQuery, + useLazyGetDashboardSnapshotQuery, useCreateTeamMutation, useSearchTeamsQuery, + useLazySearchTeamsQuery, useRemoveTeamGroupApiQueryMutation, useGetTeamGroupsApiQuery, + useLazyGetTeamGroupsApiQuery, useAddTeamGroupApiMutation, useSearchTeamGroupsQuery, + useLazySearchTeamGroupsQuery, useDeleteTeamByIdMutation, useGetTeamByIdQuery, + useLazyGetTeamByIdQuery, useUpdateTeamMutation, useGetTeamMembersQuery, + useLazyGetTeamMembersQuery, useAddTeamMemberMutation, useSetTeamMembershipsMutation, useRemoveTeamMemberMutation, useUpdateTeamMemberMutation, useGetTeamPreferencesQuery, + useLazyGetTeamPreferencesQuery, useUpdateTeamPreferencesMutation, useGetSignedInUserQuery, + useLazyGetSignedInUserQuery, useUpdateSignedInUserMutation, useGetUserAuthTokensQuery, + useLazyGetUserAuthTokensQuery, useUpdateUserEmailQuery, + useLazyUpdateUserEmailQuery, useClearHelpFlagsQuery, + useLazyClearHelpFlagsQuery, useSetHelpFlagMutation, useGetSignedInUserOrgListQuery, + useLazyGetSignedInUserOrgListQuery, useChangeUserPasswordMutation, useGetUserPreferencesQuery, + useLazyGetUserPreferencesQuery, usePatchUserPreferencesMutation, useUpdateUserPreferencesMutation, useGetUserQuotasQuery, + useLazyGetUserQuotasQuery, useRevokeUserAuthTokenMutation, useUnstarDashboardByUidMutation, useStarDashboardByUidMutation, useGetSignedInUserTeamListQuery, + useLazyGetSignedInUserTeamListQuery, useUserSetUsingOrgMutation, useSearchUsersQuery, + useLazySearchUsersQuery, useGetUserByLoginOrEmailQuery, + useLazyGetUserByLoginOrEmailQuery, useSearchUsersWithPagingQuery, + useLazySearchUsersWithPagingQuery, useGetUserByIdQuery, + useLazyGetUserByIdQuery, useUpdateUserMutation, useGetUserOrgListQuery, + useLazyGetUserOrgListQuery, useGetUserTeamsQuery, + useLazyGetUserTeamsQuery, useRouteGetAlertRulesQuery, + useLazyRouteGetAlertRulesQuery, useRoutePostAlertRuleMutation, useRouteGetAlertRulesExportQuery, + useLazyRouteGetAlertRulesExportQuery, useRouteDeleteAlertRuleMutation, useRouteGetAlertRuleQuery, + useLazyRouteGetAlertRuleQuery, useRoutePutAlertRuleMutation, useRouteGetAlertRuleExportQuery, + useLazyRouteGetAlertRuleExportQuery, useRouteGetContactpointsQuery, + useLazyRouteGetContactpointsQuery, useRoutePostContactpointsMutation, useRouteGetContactpointsExportQuery, + useLazyRouteGetContactpointsExportQuery, useRouteDeleteContactpointsMutation, useRoutePutContactpointMutation, useRouteDeleteAlertRuleGroupMutation, useRouteGetAlertRuleGroupQuery, + useLazyRouteGetAlertRuleGroupQuery, useRoutePutAlertRuleGroupMutation, useRouteGetAlertRuleGroupExportQuery, + useLazyRouteGetAlertRuleGroupExportQuery, useRouteGetMuteTimingsQuery, + useLazyRouteGetMuteTimingsQuery, useRoutePostMuteTimingMutation, useRouteExportMuteTimingsQuery, + useLazyRouteExportMuteTimingsQuery, useRouteDeleteMuteTimingMutation, useRouteGetMuteTimingQuery, + useLazyRouteGetMuteTimingQuery, useRoutePutMuteTimingMutation, useRouteExportMuteTimingQuery, + useLazyRouteExportMuteTimingQuery, useRouteResetPolicyTreeMutation, useRouteGetPolicyTreeQuery, + useLazyRouteGetPolicyTreeQuery, useRoutePutPolicyTreeMutation, useRouteGetPolicyTreeExportQuery, + useLazyRouteGetPolicyTreeExportQuery, useRouteGetTemplatesQuery, + useLazyRouteGetTemplatesQuery, useRouteDeleteTemplateMutation, useRouteGetTemplateQuery, + useLazyRouteGetTemplateQuery, useRoutePutTemplateMutation, useListAllProvidersSettingsQuery, + useLazyListAllProvidersSettingsQuery, useRemoveProviderSettingsMutation, useGetProviderSettingsQuery, + useLazyGetProviderSettingsQuery, useUpdateProviderSettingsMutation, } = injectedRtkApi; diff --git a/packages/grafana-api-clients/src/clients/rtkq/migrate-to-cloud/endpoints.gen.ts b/packages/grafana-api-clients/src/clients/rtkq/migrate-to-cloud/endpoints.gen.ts index 87bcb349ecd..d1aff7226ee 100644 --- a/packages/grafana-api-clients/src/clients/rtkq/migrate-to-cloud/endpoints.gen.ts +++ b/packages/grafana-api-clients/src/clients/rtkq/migrate-to-cloud/endpoints.gen.ts @@ -405,18 +405,26 @@ export type LibraryElementResponseIsAResponseStructForLibraryElementDto = { }; export const { useGetSessionListQuery, + useLazyGetSessionListQuery, useCreateSessionMutation, useDeleteSessionMutation, useGetSessionQuery, + useLazyGetSessionQuery, useCreateSnapshotMutation, useGetSnapshotQuery, + useLazyGetSnapshotQuery, useCancelSnapshotMutation, useUploadSnapshotMutation, useGetShapshotListQuery, + useLazyGetShapshotListQuery, useGetResourceDependenciesQuery, + useLazyGetResourceDependenciesQuery, useGetCloudMigrationTokenQuery, + useLazyGetCloudMigrationTokenQuery, useCreateCloudMigrationTokenMutation, useDeleteCloudMigrationTokenMutation, useGetDashboardByUidQuery, + useLazyGetDashboardByUidQuery, useGetLibraryElementByUidQuery, + useLazyGetLibraryElementByUidQuery, } = injectedRtkApi; diff --git a/packages/grafana-api-clients/src/clients/rtkq/playlist/v0alpha1/endpoints.gen.ts b/packages/grafana-api-clients/src/clients/rtkq/playlist/v0alpha1/endpoints.gen.ts index 51bf82c23c6..8e1bdfc1c4c 100644 --- a/packages/grafana-api-clients/src/clients/rtkq/playlist/v0alpha1/endpoints.gen.ts +++ b/packages/grafana-api-clients/src/clients/rtkq/playlist/v0alpha1/endpoints.gen.ts @@ -598,14 +598,18 @@ export type Status = { export type Patch = object; export const { useGetApiResourcesQuery, + useLazyGetApiResourcesQuery, useListPlaylistQuery, + useLazyListPlaylistQuery, useCreatePlaylistMutation, useDeletecollectionPlaylistMutation, useGetPlaylistQuery, + useLazyGetPlaylistQuery, useReplacePlaylistMutation, useDeletePlaylistMutation, useUpdatePlaylistMutation, useGetPlaylistStatusQuery, + useLazyGetPlaylistStatusQuery, useReplacePlaylistStatusMutation, useUpdatePlaylistStatusMutation, } = injectedRtkApi; diff --git a/packages/grafana-api-clients/src/clients/rtkq/preferences/user/endpoints.gen.ts b/packages/grafana-api-clients/src/clients/rtkq/preferences/user/endpoints.gen.ts index 60162b33858..71107ce1072 100644 --- a/packages/grafana-api-clients/src/clients/rtkq/preferences/user/endpoints.gen.ts +++ b/packages/grafana-api-clients/src/clients/rtkq/preferences/user/endpoints.gen.ts @@ -102,5 +102,9 @@ export type UpdatePrefsCmd = { timezone?: 'utc' | 'browser'; weekStart?: string; }; -export const { useGetUserPreferencesQuery, usePatchUserPreferencesMutation, useUpdateUserPreferencesMutation } = - injectedRtkApi; +export const { + useGetUserPreferencesQuery, + useLazyGetUserPreferencesQuery, + usePatchUserPreferencesMutation, + useUpdateUserPreferencesMutation, +} = injectedRtkApi; diff --git a/packages/grafana-api-clients/src/clients/rtkq/preferences/v1alpha1/endpoints.gen.ts b/packages/grafana-api-clients/src/clients/rtkq/preferences/v1alpha1/endpoints.gen.ts index 2ea0fd00730..0edda5148ea 100644 --- a/packages/grafana-api-clients/src/clients/rtkq/preferences/v1alpha1/endpoints.gen.ts +++ b/packages/grafana-api-clients/src/clients/rtkq/preferences/v1alpha1/endpoints.gen.ts @@ -778,17 +778,23 @@ export type StarsList = { }; export const { useGetApiResourcesQuery, + useLazyGetApiResourcesQuery, useListPreferencesQuery, + useLazyListPreferencesQuery, useCreatePreferencesMutation, useMergedPreferencesQuery, + useLazyMergedPreferencesQuery, useGetPreferencesQuery, + useLazyGetPreferencesQuery, useReplacePreferencesMutation, useDeletePreferencesMutation, useUpdatePreferencesMutation, useListStarsQuery, + useLazyListStarsQuery, useCreateStarsMutation, useDeletecollectionStarsMutation, useGetStarsQuery, + useLazyGetStarsQuery, useReplaceStarsMutation, useDeleteStarsMutation, useUpdateStarsMutation, diff --git a/packages/grafana-api-clients/src/clients/rtkq/provisioning/v0alpha1/endpoints.gen.ts b/packages/grafana-api-clients/src/clients/rtkq/provisioning/v0alpha1/endpoints.gen.ts index 7d566227d1a..a3c5d30952a 100644 --- a/packages/grafana-api-clients/src/clients/rtkq/provisioning/v0alpha1/endpoints.gen.ts +++ b/packages/grafana-api-clients/src/clients/rtkq/provisioning/v0alpha1/endpoints.gen.ts @@ -1639,39 +1639,57 @@ export type ResourceStats = { }; export const { useGetApiResourcesQuery, + useLazyGetApiResourcesQuery, useListJobQuery, + useLazyListJobQuery, useCreateJobMutation, useDeletecollectionJobMutation, useGetJobQuery, + useLazyGetJobQuery, useReplaceJobMutation, useDeleteJobMutation, useUpdateJobMutation, useListRepositoryQuery, + useLazyListRepositoryQuery, useCreateRepositoryMutation, useDeletecollectionRepositoryMutation, useGetRepositoryQuery, + useLazyGetRepositoryQuery, useReplaceRepositoryMutation, useDeleteRepositoryMutation, useUpdateRepositoryMutation, useGetRepositoryFilesQuery, + useLazyGetRepositoryFilesQuery, useGetRepositoryFilesWithPathQuery, + useLazyGetRepositoryFilesWithPathQuery, useReplaceRepositoryFilesWithPathMutation, useCreateRepositoryFilesWithPathMutation, useDeleteRepositoryFilesWithPathMutation, useGetRepositoryHistoryQuery, + useLazyGetRepositoryHistoryQuery, useGetRepositoryHistoryWithPathQuery, + useLazyGetRepositoryHistoryWithPathQuery, useGetRepositoryJobsQuery, + useLazyGetRepositoryJobsQuery, useCreateRepositoryJobsMutation, useGetRepositoryJobsWithPathQuery, + useLazyGetRepositoryJobsWithPathQuery, useGetRepositoryRefsQuery, + useLazyGetRepositoryRefsQuery, useGetRepositoryRenderWithPathQuery, + useLazyGetRepositoryRenderWithPathQuery, useGetRepositoryResourcesQuery, + useLazyGetRepositoryResourcesQuery, useGetRepositoryStatusQuery, + useLazyGetRepositoryStatusQuery, useReplaceRepositoryStatusMutation, useUpdateRepositoryStatusMutation, useCreateRepositoryTestMutation, useGetRepositoryWebhookQuery, + useLazyGetRepositoryWebhookQuery, useCreateRepositoryWebhookMutation, useGetFrontendSettingsQuery, + useLazyGetFrontendSettingsQuery, useGetResourceStatsQuery, + useLazyGetResourceStatsQuery, } = injectedRtkApi; diff --git a/packages/grafana-api-clients/src/clients/rtkq/shorturl/v1alpha1/endpoints.gen.ts b/packages/grafana-api-clients/src/clients/rtkq/shorturl/v1alpha1/endpoints.gen.ts index 374c96482a4..a4bfc1df1ba 100644 --- a/packages/grafana-api-clients/src/clients/rtkq/shorturl/v1alpha1/endpoints.gen.ts +++ b/packages/grafana-api-clients/src/clients/rtkq/shorturl/v1alpha1/endpoints.gen.ts @@ -599,15 +599,20 @@ export type GetGoto = { }; export const { useGetApiResourcesQuery, + useLazyGetApiResourcesQuery, useListShortUrlQuery, + useLazyListShortUrlQuery, useCreateShortUrlMutation, useDeletecollectionShortUrlMutation, useGetShortUrlQuery, + useLazyGetShortUrlQuery, useReplaceShortUrlMutation, useDeleteShortUrlMutation, useUpdateShortUrlMutation, useGetShortUrlGotoQuery, + useLazyGetShortUrlGotoQuery, useGetShortUrlStatusQuery, + useLazyGetShortUrlStatusQuery, useReplaceShortUrlStatusMutation, useUpdateShortUrlStatusMutation, } = injectedRtkApi; diff --git a/packages/grafana-api-clients/src/scripts/generate-rtk-apis.ts b/packages/grafana-api-clients/src/scripts/generate-rtk-apis.ts index 18fd3cbee59..a9422a02815 100644 --- a/packages/grafana-api-clients/src/scripts/generate-rtk-apis.ts +++ b/packages/grafana-api-clients/src/scripts/generate-rtk-apis.ts @@ -17,6 +17,12 @@ type OperationDefinition = { }; type EndpointMatcher = string[] | ((operationName: string, operationDefinition: OperationDefinition) => boolean); +const defaultHooksOptions = { + queries: true, + lazyQueries: true, + mutations: true, +}; + /** * Helper to return consistent base API generation config */ @@ -28,7 +34,7 @@ const createAPIConfig = (app: string, version: string, filterEndpoints?: Endpoin apiFile: `../clients/rtkq/${app}/${version}/baseAPI.ts`, filterEndpoints, tag: true, - hooks: true, + hooks: defaultHooksOptions, ...additional, }, }; @@ -43,7 +49,7 @@ const config: ConfigFile = { // OpenAPI3 client with all endpoints '../clients/rtkq/legacy/endpoints.gen.ts': { schemaFile: path.join(basePath, 'public/openapi3.json'), - hooks: true, + hooks: defaultHooksOptions, tag: true, apiFile: '../clients/rtkq/legacy/baseAPI.ts', filterEndpoints: (_name, operation) => !operation.operation.deprecated, @@ -51,7 +57,7 @@ const config: ConfigFile = { '../clients/rtkq/migrate-to-cloud/endpoints.gen.ts': { schemaFile: path.join(basePath, 'public/openapi3.json'), apiFile: '../clients/rtkq/migrate-to-cloud/baseAPI.ts', - hooks: true, + hooks: defaultHooksOptions, filterEndpoints: [ 'getSessionList', 'getSession', @@ -76,13 +82,13 @@ const config: ConfigFile = { }, '../clients/rtkq/preferences/user/endpoints.gen.ts': { schemaFile: path.join(basePath, 'public/openapi3.json'), - hooks: true, + hooks: defaultHooksOptions, apiFile: '../clients/rtkq/preferences/user/baseAPI.ts', filterEndpoints: ['getUserPreferences', 'updateUserPreferences', 'patchUserPreferences'], }, '../clients/rtkq/user/endpoints.gen.ts': { schemaFile: path.join(basePath, 'public/openapi3.json'), - hooks: true, + hooks: defaultHooksOptions, apiFile: '../clients/rtkq/user/baseAPI.ts', filterEndpoints: ['starDashboardByUid', 'unstarDashboardByUid'], }, From c4879522795b77d141386c6faecb91df4e1d11b5 Mon Sep 17 00:00:00 2001 From: Paul Marbach Date: Thu, 30 Oct 2025 10:04:08 -0400 Subject: [PATCH 128/378] Table: Support DataLinks and Actions in SparklineCell (#112244) * Table: Support DataLinks in SparklineCell * add data links to sparkline gdev * fix migrator test * Clean up single action use case --- .../panel-table/table_sparkline_cell.v42.json | 24 +++++++++++++++++-- .../panel-table/table_sparkline_cell.json | 22 ++++++++++++++++- .../Table/TableNG/Cells/SparklineCell.tsx | 23 ++++++++++++------ .../src/components/Table/TableNG/TableNG.tsx | 8 +------ .../TableNG/components/MaybeWrapWithLink.tsx | 1 + .../src/components/Table/TableNG/types.ts | 1 - .../src/components/Table/TableNG/utils.ts | 9 ------- 7 files changed, 61 insertions(+), 27 deletions(-) diff --git a/apps/dashboard/pkg/migration/testdata/dev-dashboards-output/panel-table/table_sparkline_cell.v42.json b/apps/dashboard/pkg/migration/testdata/dev-dashboards-output/panel-table/table_sparkline_cell.v42.json index 3c8310630d7..dae0d524c23 100644 --- a/apps/dashboard/pkg/migration/testdata/dev-dashboards-output/panel-table/table_sparkline_cell.v42.json +++ b/apps/dashboard/pkg/migration/testdata/dev-dashboards-output/panel-table/table_sparkline_cell.v42.json @@ -208,7 +208,27 @@ "value": 80 } ] - } + }, + "actions": [ + { + "fetch": { + "body": "{}", + "headers": [["Content-Type", "application/json"]], + "method": "GET", + "queryParams": [], + "url": "/api/health" + }, + "title": "Get instance health", + "type": "fetch" + } + ], + "links": [ + { + "targetBlank": true, + "title": "Google Grafana", + "url": "https://google.com/search?q=grafana" + } + ] }, "overrides": [] }, @@ -592,4 +612,4 @@ "title": "Panel Tests - Table - Sparklines", "uid": "d6373b49-1957-4f00-9218-ee2120d3ecd9", "weekStart": "" -} \ No newline at end of file +} diff --git a/devenv/dev-dashboards/panel-table/table_sparkline_cell.json b/devenv/dev-dashboards/panel-table/table_sparkline_cell.json index 3337c794279..4725580cf0e 100644 --- a/devenv/dev-dashboards/panel-table/table_sparkline_cell.json +++ b/devenv/dev-dashboards/panel-table/table_sparkline_cell.json @@ -204,7 +204,27 @@ "value": 80 } ] - } + }, + "actions": [ + { + "fetch": { + "body": "{}", + "headers": [["Content-Type", "application/json"]], + "method": "GET", + "queryParams": [], + "url": "/api/health" + }, + "title": "Get instance health", + "type": "fetch" + } + ], + "links": [ + { + "targetBlank": true, + "title": "Google Grafana", + "url": "https://google.com/search?q=grafana" + } + ] }, "overrides": [] }, diff --git a/packages/grafana-ui/src/components/Table/TableNG/Cells/SparklineCell.tsx b/packages/grafana-ui/src/components/Table/TableNG/Cells/SparklineCell.tsx index acedb2091a7..453fdb237b0 100644 --- a/packages/grafana-ui/src/components/Table/TableNG/Cells/SparklineCell.tsx +++ b/packages/grafana-ui/src/components/Table/TableNG/Cells/SparklineCell.tsx @@ -17,6 +17,7 @@ import { import { measureText } from '../../../../utils/measureText'; import { FormattedValueDisplay } from '../../../FormattedValueDisplay/FormattedValueDisplay'; import { Sparkline } from '../../../Sparkline/Sparkline'; +import { MaybeWrapWithLink } from '../components/MaybeWrapWithLink'; import { SparklineCellProps, TableCellStyles } from '../types'; import { getAlignmentFactor, getCellOptions, prepareSparklineValue } from '../utils'; @@ -38,7 +39,11 @@ export const SparklineCell = (props: SparklineCellProps) => { const sparkline = prepareSparklineValue(value, field); if (!sparkline) { - return <>{field.config.noValue || t('grafana-ui.table.sparkline.no-data', 'no data')}; + return ( + + {field.config.noValue || t('grafana-ui.table.sparkline.no-data', 'no data')} + + ); } // Get the step from the first two values to null-fill the x-axis based on timerange @@ -87,10 +92,10 @@ export const SparklineCell = (props: SparklineCellProps) => { } return ( - <> + {valueElement} - + ); }; @@ -107,8 +112,12 @@ function getTableSparklineCellOptions(field: Field): TableSparklineCellOptions { export const getStyles: TableCellStyles = (theme, { textAlign }) => css({ - width: '100%', - gap: theme.spacing(1), - justifyContent: 'space-between', - ...(textAlign === 'right' && { flexDirection: 'row-reverse' }), + '&, & > a': { + width: '100%', + display: 'flex', + alignItems: 'center', + justifyContent: 'space-between', + gap: theme.spacing(1), + ...(textAlign === 'right' && { flexDirection: 'row-reverse' }), + }, }); diff --git a/packages/grafana-ui/src/components/Table/TableNG/TableNG.tsx b/packages/grafana-ui/src/components/Table/TableNG/TableNG.tsx index 5f64c58773a..a3772785d63 100644 --- a/packages/grafana-ui/src/components/Table/TableNG/TableNG.tsx +++ b/packages/grafana-ui/src/components/Table/TableNG/TableNG.tsx @@ -94,7 +94,6 @@ import { predicateByName, shouldTextOverflow, shouldTextWrap, - withDataLinksActionsTooltip, getSummaryCellTextAlign, parseStyleJson, IS_SAFARI_26, @@ -406,7 +405,6 @@ export function TableNG(props: TableNGProps) { const result: FromFieldsResult = { columns: [], cellRootRenderers: {}, - colsWithTooltip: {}, }; let lastRowIdx = -1; @@ -464,7 +462,6 @@ export function TableNG(props: TableNGProps) { const shouldOverflow = !IS_SAFARI_26 && rowHeight !== 'auto' && (shouldTextOverflow(field) || Boolean(maxRowHeight)); const textWrap = rowHeight === 'auto' || shouldTextWrap(field); - const withTooltip = withDataLinksActionsTooltip(field, cellType); const canBeColorized = canFieldBeColorized(cellType, applyToRowBgFn); const cellStyleOptions: TableCellStyleOptions = { textAlign, @@ -473,8 +470,6 @@ export function TableNG(props: TableNGProps) { maxHeight: maxRowHeight, }; - result.colsWithTooltip[displayName] = withTooltip; - const defaultCellStyles = getDefaultCellStyles(theme, cellStyleOptions); const cellSpecificStyles = getCellSpecificStyles(cellType, field, theme, cellStyleOptions); const linkStyles = getLinkStyles(theme, canBeColorized); @@ -737,7 +732,7 @@ export function TableNG(props: TableNGProps) { ); const [nestedFieldWidths] = useColWidths(firstRowNestedData?.fields ?? [], availableWidth); - const { columns, cellRootRenderers, colsWithTooltip } = useMemo(() => { + const { columns, cellRootRenderers } = useMemo(() => { const result = fromFields(visibleFields, widths); // if nested frames are present, augment the columns to include the nested table expander column. @@ -805,7 +800,6 @@ export function TableNG(props: TableNGProps) { const field = columns[column.idx].field; if ( - colsWithTooltip[getDisplayName(field)] && target instanceof HTMLElement && // this walks up the tree to find either a faux link wrapper or the cell root // it then only proceeds if we matched the faux link wrapper diff --git a/packages/grafana-ui/src/components/Table/TableNG/components/MaybeWrapWithLink.tsx b/packages/grafana-ui/src/components/Table/TableNG/components/MaybeWrapWithLink.tsx index b43728dd1e8..7758bf8fd20 100644 --- a/packages/grafana-ui/src/components/Table/TableNG/components/MaybeWrapWithLink.tsx +++ b/packages/grafana-ui/src/components/Table/TableNG/components/MaybeWrapWithLink.tsx @@ -34,4 +34,5 @@ export const MaybeWrapWithLink = memo(({ field, rowIdx, children }: MaybeWrapWit // raw value return children; }); + MaybeWrapWithLink.displayName = 'MaybeWrapWithLink'; diff --git a/packages/grafana-ui/src/components/Table/TableNG/types.ts b/packages/grafana-ui/src/components/Table/TableNG/types.ts index c4d63b2826b..b828dfddbb6 100644 --- a/packages/grafana-ui/src/components/Table/TableNG/types.ts +++ b/packages/grafana-ui/src/components/Table/TableNG/types.ts @@ -308,7 +308,6 @@ export type CellRootRenderer = (key: React.Key, props: CellRendererProps; - colsWithTooltip: Record; } export interface FooterFieldState extends FieldState { diff --git a/packages/grafana-ui/src/components/Table/TableNG/utils.ts b/packages/grafana-ui/src/components/Table/TableNG/utils.ts index e3ab23b3e0e..867ee96b983 100644 --- a/packages/grafana-ui/src/components/Table/TableNG/utils.ts +++ b/packages/grafana-ui/src/components/Table/TableNG/utils.ts @@ -955,15 +955,6 @@ export function getApplyToRowBgFn( } } -/** @internal */ -export function withDataLinksActionsTooltip(field: Field, cellType: TableCellDisplayMode) { - return ( - cellType !== TableCellDisplayMode.DataLinks && - cellType !== TableCellDisplayMode.Actions && - (field.config.links?.length ?? 0) + (field.config.actions?.length ?? 0) > 1 - ); -} - /** @internal */ export function canFieldBeColorized( cellType: TableCellDisplayMode, From c3d7dbc2585f84a65dba3b8c54490e10fff63102 Mon Sep 17 00:00:00 2001 From: Kyle Brandt Date: Thu, 30 Oct 2025 10:05:12 -0400 Subject: [PATCH 129/378] SQL Expressions: Add endpoint to get Schemas (#108864) Return the SQL schema for all DS queries in request (to provide information to AI / Autocomplete for SQL expressions). All DS queries are treated as if they were inputs to SQL expressions in terms of conversion, regardless if they are selected in a query or not. Requires feature toggle queryService = true Endpoint is apis/query.grafana.app/v0alpha1/namespaces/default/sqlschemas --------- Co-authored-by: Todd Treece <360020+toddtreece@users.noreply.github.com> --- pkg/apis/query/v0alpha1/query.go | 9 + .../query/v0alpha1/zz_generated.deepcopy.go | 26 ++ .../query/v0alpha1/zz_generated.openapi.go | 27 ++ pkg/expr/sql/frame_table.go | 4 +- pkg/expr/sql_schema.go | 231 ++++++++++++++++++ pkg/registry/apis/query/query.go | 79 ++++-- pkg/registry/apis/query/register.go | 3 + pkg/registry/apis/query/sql_schema.go | 170 +++++++++++++ pkg/services/apiserver/builder/helper.go | 6 + .../public_dashboard_service_mock.go | 7 + .../publicdashboards/publicdashboard.go | 4 + .../publicdashboards/service/service.go | 5 + pkg/services/query/expr_sql_schema.go | 75 ++++++ pkg/services/query/query.go | 2 + pkg/services/query/query_service_mock.go | 6 + 15 files changed, 630 insertions(+), 24 deletions(-) create mode 100644 pkg/expr/sql_schema.go create mode 100644 pkg/registry/apis/query/sql_schema.go create mode 100644 pkg/services/query/expr_sql_schema.go diff --git a/pkg/apis/query/v0alpha1/query.go b/pkg/apis/query/v0alpha1/query.go index ef40c17ff45..f6ad172c348 100644 --- a/pkg/apis/query/v0alpha1/query.go +++ b/pkg/apis/query/v0alpha1/query.go @@ -7,6 +7,7 @@ import ( "github.com/grafana/grafana-plugin-sdk-go/backend" data "github.com/grafana/grafana-plugin-sdk-go/experimental/apis/data/v0alpha1" + "github.com/grafana/grafana/pkg/expr" ) // Generic query request with shared time across all values @@ -28,6 +29,14 @@ type QueryDataResponse struct { backend.QueryDataResponse `json:",inline"` } +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +type SQLSchemas struct { + metav1.TypeMeta `json:",inline"` + + // Backend wrapper (external dependency) + expr.SQLSchemas `json:"sqlSchemas,inline"` +} + // GetResponseCode return the right status code for the response by checking the responses. func GetResponseCode(rsp *backend.QueryDataResponse) int { if rsp == nil { diff --git a/pkg/apis/query/v0alpha1/zz_generated.deepcopy.go b/pkg/apis/query/v0alpha1/zz_generated.deepcopy.go index 38a7bd0b115..ad159a4a6cb 100644 --- a/pkg/apis/query/v0alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/query/v0alpha1/zz_generated.deepcopy.go @@ -262,3 +262,29 @@ func (in *QueryTypeDefinitionList) DeepCopyObject() runtime.Object { } return nil } + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SQLSchemas) DeepCopyInto(out *SQLSchemas) { + *out = *in + out.TypeMeta = in.TypeMeta + out.SQLSchemas = in.SQLSchemas.DeepCopy() + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SQLSchemas. +func (in *SQLSchemas) DeepCopy() *SQLSchemas { + if in == nil { + return nil + } + out := new(SQLSchemas) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *SQLSchemas) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} diff --git a/pkg/apis/query/v0alpha1/zz_generated.openapi.go b/pkg/apis/query/v0alpha1/zz_generated.openapi.go index 2ee9ed95395..68f42312ce9 100644 --- a/pkg/apis/query/v0alpha1/zz_generated.openapi.go +++ b/pkg/apis/query/v0alpha1/zz_generated.openapi.go @@ -23,6 +23,7 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "github.com/grafana/grafana/pkg/apis/query/v0alpha1.QueryDataResponse": schema_pkg_apis_query_v0alpha1_QueryDataResponse(ref), "github.com/grafana/grafana/pkg/apis/query/v0alpha1.QueryTypeDefinition": schema_pkg_apis_query_v0alpha1_QueryTypeDefinition(ref), "github.com/grafana/grafana/pkg/apis/query/v0alpha1.QueryTypeDefinitionList": schema_pkg_apis_query_v0alpha1_QueryTypeDefinitionList(ref), + "github.com/grafana/grafana/pkg/apis/query/v0alpha1.SQLSchemas": schema_pkg_apis_query_v0alpha1_SQLSchemas(ref), } } @@ -482,3 +483,29 @@ func schema_pkg_apis_query_v0alpha1_QueryTypeDefinitionList(ref common.Reference "github.com/grafana/grafana/pkg/apis/query/v0alpha1.QueryTypeDefinition", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"}, } } + +func schema_pkg_apis_query_v0alpha1_SQLSchemas(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + } +} diff --git a/pkg/expr/sql/frame_table.go b/pkg/expr/sql/frame_table.go index 2ac897b5007..245efc6e655 100644 --- a/pkg/expr/sql/frame_table.go +++ b/pkg/expr/sql/frame_table.go @@ -30,7 +30,7 @@ func (ft *FrameTable) String() string { return ft.Name() } -func schemaFromFrame(frame *data.Frame) mysql.Schema { +func SchemaFromFrame(frame *data.Frame) mysql.Schema { schema := make(mysql.Schema, len(frame.Fields)) for i, field := range frame.Fields { @@ -48,7 +48,7 @@ func schemaFromFrame(frame *data.Frame) mysql.Schema { // Schema implements the mysql.Table interface func (ft *FrameTable) Schema() mysql.Schema { if ft.schema == nil { - ft.schema = schemaFromFrame(ft.Frame) + ft.schema = SchemaFromFrame(ft.Frame) } return ft.schema } diff --git a/pkg/expr/sql_schema.go b/pkg/expr/sql_schema.go new file mode 100644 index 00000000000..c3851eed8bd --- /dev/null +++ b/pkg/expr/sql_schema.go @@ -0,0 +1,231 @@ +package expr + +import ( + "context" + "reflect" + "time" + + "github.com/grafana/grafana-plugin-sdk-go/data" + "github.com/grafana/grafana/pkg/expr/mathexp" + "github.com/grafana/grafana/pkg/expr/sql" +) + +// BasicColumn represents the column type for data that is input to a SQL expression. +type BasicColumn struct { + Name string `json:"name"` + MySQLType string `json:"mysqlType"` + Nullable bool `json:"nullable"` + DataFrameFieldType data.FieldType `json:"dataFrameFieldType"` +} + +// SchemaInfo provides information and some sample data for data that could be an input +// to a SQL expression. +type SchemaInfo struct { + Columns []BasicColumn `json:"columns"` + SampleRows [][]any `json:"sampleRows"` + Error string `json:"error,omitempty"` +} + +// SQLSchemas returns info about what the Schema for a DS query will be like if the +// query were to be used an input to SQL expressions. So effectively post SQL expressions input +// conversion. +// There is a a manual DeepCopy at the end of this file that will need to be updated when this our the +// underlying structs are change. The hack script will also need to be run to update the Query service API +// generated types. +type SQLSchemas map[string]SchemaInfo + +// GetSQLSchemas returns what the schemas are for SQL expressions for all DS queries +// in the request. It executes the queries to get the schemas. +// Intended use is for autocomplete and AI, so used during the authoring/editing experience only. +func (s *Service) GetSQLSchemas(ctx context.Context, req Request) (SQLSchemas, error) { + // Extract DS Nodes and Execute Them + // Building the pipeline is maybe not best, as it can have more errors. + filtered := make([]Query, 0, len(req.Queries)) + for _, q := range req.Queries { + if NodeTypeFromDatasourceUID(q.DataSource.UID) == TypeDatasourceNode { + filtered = append(filtered, q) + } + } + req.Queries = filtered + pipeline, err := s.buildPipeline(ctx, &req) + if err != nil { + return nil, err + } + + var schemas = make(SQLSchemas) + + for _, node := range pipeline { + // For now, execute calls convert at the end, so we are being lazy and running the full conversion. Longer run we want to run without + // full conversion and just get the schema. Maybe conversion should be + dsNode := node.(*DSNode) + // Make all input to SQL + dsNode.isInputToSQLExpr = true + + // TODO: check where time is coming from, don't recall + res, err := dsNode.Execute(ctx, time.Now(), mathexp.Vars{}, s) + if err != nil { + schemas[dsNode.RefID()] = SchemaInfo{Error: err.Error()} + continue + // we want to continue and get the schemas we can + } + if res.Error != nil { + schemas[dsNode.RefID()] = SchemaInfo{Error: res.Error.Error()} + continue + // we want to continue and get the schemas we can + } + + frames := res.Values.AsDataFrames(dsNode.RefID()) + if len(frames) == 0 { + schemas[dsNode.RefID()] = SchemaInfo{Error: "no data"} + } + frame := frames[0] + + schema := sql.SchemaFromFrame(frame) + columns := make([]BasicColumn, 0, len(schema)) + for _, col := range schema { + fT, _ := sql.MySQLColToFieldType(col) + columns = append(columns, BasicColumn{ + Name: col.Name, + MySQLType: col.Type.String(), + Nullable: col.Nullable, + DataFrameFieldType: fT, + }) + } + + // Cap at 3 rows. + const maxRows = 3 + n := frame.Rows() + if n > maxRows { + n = maxRows + } + sampleRows := make([][]any, 0, n) + for i := 0; i < n; i++ { + sampleRows = append(sampleRows, frame.RowCopy(i)) + } + + schemas[dsNode.RefID()] = SchemaInfo{Columns: columns, SampleRows: sampleRows} + } + + return schemas, nil +} + +// DeepCopy returns a deep copy of the schema. +// Used AI to make it, the kubernetes one doesn't like any or interface{} +func (s SQLSchemas) DeepCopy() SQLSchemas { + if s == nil { + return nil + } + out := make(SQLSchemas, len(s)) + for k, v := range s { + out[k] = SchemaInfo{ + Columns: copyColumns(v.Columns), + SampleRows: deepCopySampleRows2D(v.SampleRows), + Error: v.Error, + } + } + return out +} + +func copyColumns(in []BasicColumn) []BasicColumn { + if in == nil { + return nil + } + out := make([]BasicColumn, len(in)) + copy(out, in) // BasicColumn is value-only, so this suffices + return out +} + +// Deep-copy [][]any preserving nil vs empty slices and cloning elements. +func deepCopySampleRows2D(in [][]any) [][]any { + if in == nil { + return nil + } + out := make([][]any, len(in)) + for i, row := range in { + if row == nil { + // preserve nil inner slice + continue + } + newRow := make([]any, len(row)) + for j, v := range row { + newRow[j] = deepCopyAny(v) + } + out[i] = newRow + } + return out +} + +// Recursively clone pointers, maps, slices, arrays, and interfaces. +// Structs are copied by value (shallow for their internals). +func deepCopyAny(v any) any { + if v == nil { + return nil + } + return deepCopyRV(reflect.ValueOf(v)).Interface() +} + +func deepCopyRV(rv reflect.Value) reflect.Value { + if !rv.IsValid() { + return rv + } + + switch rv.Kind() { + case reflect.Ptr: + if rv.IsNil() { + return rv + } + elemCopy := deepCopyRV(rv.Elem()) + newPtr := reflect.New(rv.Type().Elem()) + if elemCopy.Type().AssignableTo(newPtr.Elem().Type()) { + newPtr.Elem().Set(elemCopy) + } else if elemCopy.Type().ConvertibleTo(newPtr.Elem().Type()) { + newPtr.Elem().Set(elemCopy.Convert(newPtr.Elem().Type())) + } else { + newPtr.Elem().Set(rv.Elem()) // fallback: shallow + } + return newPtr + + case reflect.Interface: + if rv.IsNil() { + return rv + } + return deepCopyRV(rv.Elem()) + + case reflect.Map: + if rv.IsNil() { + return reflect.Zero(rv.Type()) + } + newMap := reflect.MakeMapWithSize(rv.Type(), rv.Len()) + for _, k := range rv.MapKeys() { + newMap.SetMapIndex(deepCopyRV(k), deepCopyRV(rv.MapIndex(k))) + } + return newMap + + case reflect.Slice: + if rv.IsNil() { + return reflect.Zero(rv.Type()) + } + n := rv.Len() + newSlice := reflect.MakeSlice(rv.Type(), n, n) + for i := 0; i < n; i++ { + newSlice.Index(i).Set(deepCopyRV(rv.Index(i))) + } + return newSlice + + case reflect.Array: + n := rv.Len() + newArr := reflect.New(rv.Type()).Elem() + for i := 0; i < n; i++ { + newArr.Index(i).Set(deepCopyRV(rv.Index(i))) + } + return newArr + + case reflect.Struct: + // Value copy (OK unless the struct contains references you also want deep-copied). + return rv + + default: + // Scalars (string, bool, numbers), etc. + return rv + } +} diff --git a/pkg/registry/apis/query/query.go b/pkg/registry/apis/query/query.go index f63cb850bc7..30a1ae6b567 100644 --- a/pkg/registry/apis/query/query.go +++ b/pkg/registry/apis/query/query.go @@ -241,25 +241,40 @@ func (r *queryREST) Connect(connectCtx context.Context, name string, _ runtime.O }), nil } -func handleQuery(ctx context.Context, raw query.QueryDataRequest, b QueryAPIBuilder, httpreq *http.Request, responder responderWrapper, connectLogger log.Logger) (*backend.QueryDataResponse, error) { - var jsonQueries = make([]*simplejson.Json, 0, len(raw.Queries)) - for _, query := range raw.Queries { - dsRef, err := getValidDataSourceRef(ctx, query.Datasource, query.DatasourceID, b.legacyDatasourceLookup) - if err != nil { - connectLogger.Error("error getting valid datasource ref", err) - } - if dsRef != nil { - query.Datasource = dsRef +type preparedQuery struct { + mReq dtos.MetricRequest + cache datasources.CacheService + headers map[string]string + logger log.Logger + builder dsquerierclient.QSDatasourceClientBuilder + exprSvc *expr.Service + reportMetrics func() +} + +func prepareQuery( + ctx context.Context, + raw query.QueryDataRequest, + b QueryAPIBuilder, + httpreq *http.Request, + connectLogger log.Logger, +) (*preparedQuery, error) { + // Normalize DS refs and build []*simplejson.Json + jsonQueries := make([]*simplejson.Json, 0, len(raw.Queries)) + for _, q := range raw.Queries { + if dsRef, derr := getValidDataSourceRef(ctx, q.Datasource, q.DatasourceID, b.legacyDatasourceLookup); derr != nil { + connectLogger.Error("error getting valid datasource ref", "err", derr) + } else if dsRef != nil { + q.Datasource = dsRef } - jsonBytes, err := json.Marshal(query) + jsonBytes, err := json.Marshal(q) if err != nil { - connectLogger.Error("error marshalling", err) + connectLogger.Error("error marshalling query", "err", err) } - sjQuery, _ := simplejson.NewJson(jsonBytes) + sjQuery, err := simplejson.NewJson(jsonBytes) if err != nil { - connectLogger.Error("error unmarshalling", err) + connectLogger.Error("error creating simplejson for query", "err", err) } jsonQueries = append(jsonQueries, sjQuery) @@ -274,13 +289,11 @@ func handleQuery(ctx context.Context, raw query.QueryDataRequest, b QueryAPIBuil cache := &MyCacheService{ legacy: b.legacyDatasourceLookup, } - headers := ExtractKnownHeaders(httpreq.Header) instance, err := b.instanceProvider.GetInstance(ctx, connectLogger, headers) if err != nil { connectLogger.Error("failed to get instance configuration settings", "err", err) - responder.Error(err) return nil, err } @@ -288,12 +301,14 @@ func handleQuery(ctx context.Context, raw query.QueryDataRequest, b QueryAPIBuil dsQuerierLoggerWithSlug := instance.GetLogger() + // Datasource client qsDsClientBuilder qsDsClientBuilder := dsquerierclient.NewQsDatasourceClientBuilderWithInstance( instance, ctx, dsQuerierLoggerWithSlug, ) + // Expressions service exprService := expr.ProvideService( &setting.Cfg{ ExpressionsEnabled: instanceConfig.ExpressionsEnabled, @@ -310,17 +325,37 @@ func handleQuery(ctx context.Context, raw query.QueryDataRequest, b QueryAPIBuil qsDsClientBuilder, ) - qdr, err := service.QueryData(ctx, dsQuerierLoggerWithSlug, cache, exprService, mReq, qsDsClientBuilder, headers) + return &preparedQuery{ + mReq: mReq, + cache: cache, + headers: headers, + logger: dsQuerierLoggerWithSlug, + builder: qsDsClientBuilder, + exprSvc: exprService, + reportMetrics: func() { instance.ReportMetrics() }, + }, nil +} - // tell the `instance` structure that it can now report - // metrics that are only reported once during a request - instance.ReportMetrics() +func handlePreparedQuery(ctx context.Context, pq *preparedQuery) (*backend.QueryDataResponse, error) { + resp, err := service.QueryData(ctx, pq.logger, pq.cache, pq.exprSvc, pq.mReq, pq.builder, pq.headers) + pq.reportMetrics() + return resp, err +} +func handleQuery( + ctx context.Context, + raw query.QueryDataRequest, + b QueryAPIBuilder, + httpreq *http.Request, + responder responderWrapper, + connectLogger log.Logger, +) (*backend.QueryDataResponse, error) { + pq, err := prepareQuery(ctx, raw, b, httpreq, connectLogger) if err != nil { - return qdr, err + responder.Error(err) + return nil, err } - - return qdr, nil + return handlePreparedQuery(ctx, pq) } type responderWrapper struct { diff --git a/pkg/registry/apis/query/register.go b/pkg/registry/apis/query/register.go index 109de13276c..221b589b511 100644 --- a/pkg/registry/apis/query/register.go +++ b/pkg/registry/apis/query/register.go @@ -161,6 +161,7 @@ func addKnownTypes(scheme *runtime.Scheme, gv schema.GroupVersion) { &query.QueryDataResponse{}, &query.QueryTypeDefinition{}, &query.QueryTypeDefinitionList{}, + &query.SQLSchemas{}, ) } @@ -201,6 +202,8 @@ func (b *QueryAPIBuilder) UpdateAPIGroupInfo(apiGroupInfo *genericapiserver.APIG // The query endpoint -- NOTE, this uses a rewrite hack to allow requests without a name parameter storage["query"] = newQueryREST(b) + storage["sqlschemas"] = newSQLSchemasREST(b) + // Register the expressions query schemas err := queryschema.RegisterQueryTypes(b.queryTypes, storage) diff --git a/pkg/registry/apis/query/sql_schema.go b/pkg/registry/apis/query/sql_schema.go new file mode 100644 index 00000000000..10ec3dc2526 --- /dev/null +++ b/pkg/registry/apis/query/sql_schema.go @@ -0,0 +1,170 @@ +package query + +import ( + "context" + "net/http" + "strconv" + + "github.com/grafana/grafana-plugin-sdk-go/backend" + "github.com/grafana/grafana/pkg/expr" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/codes" + errorsK8s "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apiserver/pkg/endpoints/request" + "k8s.io/apiserver/pkg/registry/rest" + + query "github.com/grafana/grafana/pkg/apis/query/v0alpha1" + "github.com/grafana/grafana/pkg/infra/log" + service "github.com/grafana/grafana/pkg/services/query" + "github.com/grafana/grafana/pkg/web" +) + +type sqlSchemaREST struct { + logger log.Logger + builder *QueryAPIBuilder +} + +var ( + _ rest.Storage = (*sqlSchemaREST)(nil) + _ rest.SingularNameProvider = (*sqlSchemaREST)(nil) + _ rest.Connecter = (*sqlSchemaREST)(nil) + _ rest.Scoper = (*sqlSchemaREST)(nil) + _ rest.StorageMetadata = (*sqlSchemaREST)(nil) +) + +func newSQLSchemasREST(builder *QueryAPIBuilder) *sqlSchemaREST { + return &sqlSchemaREST{ + logger: log.New("query.sqlschemas"), + builder: builder, + } +} + +func (r *sqlSchemaREST) New() runtime.Object { + // This is added as the "ResponseType" regardless what ProducesObject() says :) + return &query.SQLSchemas{} +} + +func (r *sqlSchemaREST) Destroy() {} + +func (r *sqlSchemaREST) NamespaceScoped() bool { + return true +} + +func (r *sqlSchemaREST) GetSingularName() string { + return "SQLSchema" // Used for the +} + +func (r *sqlSchemaREST) ProducesMIMETypes(verb string) []string { + return []string{"application/json"} // and parquet! +} + +func (r *sqlSchemaREST) ProducesObject(verb string) interface{} { + return &query.SQLSchemas{} +} + +func (r *sqlSchemaREST) ConnectMethods() []string { + return []string{"POST"} +} + +func (r *sqlSchemaREST) NewConnectOptions() (runtime.Object, bool, string) { + return nil, false, "" // true means you can use the trailing path as a variable +} + +// called by mt query service and also when queryServiceFromUI is enabled, can be both mt and st +func (r *sqlSchemaREST) Connect(connectCtx context.Context, name string, _ runtime.Object, incomingResponder rest.Responder) (http.Handler, error) { + // See: /pkg/services/apiserver/builder/helper.go#L34 + // The name is set with a rewriter hack + if name != "name" { + r.logger.Debug("Connect name is not name") + return nil, errorsK8s.NewNotFound(schema.GroupResource{}, name) + } + b := r.builder + + return http.HandlerFunc(func(w http.ResponseWriter, httpreq *http.Request) { + ctx, span := b.tracer.Start(httpreq.Context(), "QueryService.GetSQLSchemas") + defer span.End() + ctx = request.WithNamespace(ctx, request.NamespaceValue(connectCtx)) + traceId := span.SpanContext().TraceID() + connectLogger := b.log.New("traceId", traceId.String(), "rule_uid", httpreq.Header.Get("X-Rule-Uid")) + responder := newResponderWrapper(incomingResponder, + func(statusCode *int, obj runtime.Object) { + if *statusCode/100 == 4 { + span.SetStatus(codes.Error, strconv.Itoa(*statusCode)) + } + + if *statusCode >= 500 { + o, ok := obj.(*query.QueryDataResponse) + if ok && o.Responses != nil { + for refId, response := range o.Responses { + if response.ErrorSource == backend.ErrorSourceDownstream { + *statusCode = http.StatusBadRequest //force this to be a 400 since it's downstream + span.SetStatus(codes.Error, strconv.Itoa(*statusCode)) + span.SetAttributes(attribute.String("error.source", "downstream")) + break + } else if response.Error != nil { + connectLogger.Debug("500 error without downstream error source", "error", response.Error, "errorSource", response.ErrorSource, "refId", refId) + span.SetStatus(codes.Error, "500 error without downstream error source") + } else { + span.SetStatus(codes.Error, "500 error without downstream error source and no Error message") + span.SetAttributes(attribute.String("error.ref_id", refId)) + } + } + } + } + }, + + func(err error) { + connectLogger.Error("error caught in handler", "err", err) + span.SetStatus(codes.Error, "query error") + + if err == nil { + return + } + + span.RecordError(err) + }) + + raw := &query.QueryDataRequest{} + err := web.Bind(httpreq, raw) + if err != nil { + connectLogger.Error("Hit unexpected error when reading query", "err", err) + err = errorsK8s.NewBadRequest("error reading query") + responder.Error(err) + return + } + + qdr, err := handleSQLSchemaQuery(ctx, *raw, *b, httpreq, *responder, connectLogger) + if err != nil { + responder.Error(err) + return + } + + responder.Object(200, &query.SQLSchemas{ + SQLSchemas: qdr, + }) + }), nil +} + +func handlePreparedSQLSchema(ctx context.Context, pq *preparedQuery) (expr.SQLSchemas, error) { + resp, err := service.GetSQLSchemas(ctx, pq.logger, pq.cache, pq.exprSvc, pq.mReq, pq.builder, pq.headers) + pq.reportMetrics() + return resp, err +} + +func handleSQLSchemaQuery( + ctx context.Context, + raw query.QueryDataRequest, + b QueryAPIBuilder, + httpreq *http.Request, + responder responderWrapper, + connectLogger log.Logger, +) (expr.SQLSchemas, error) { + pq, err := prepareQuery(ctx, raw, b, httpreq, connectLogger) + if err != nil { + responder.Error(err) + return nil, err + } + return handlePreparedSQLSchema(ctx, pq) +} diff --git a/pkg/services/apiserver/builder/helper.go b/pkg/services/apiserver/builder/helper.go index 222637401ee..cfcf3540b43 100644 --- a/pkg/services/apiserver/builder/helper.go +++ b/pkg/services/apiserver/builder/helper.go @@ -58,6 +58,12 @@ var PathRewriters = []filters.PathRewriter{ return matches[1] + "/name" // connector requires a name }, }, + { + Pattern: regexp.MustCompile(`(/apis/query.grafana.app/v0alpha1/namespaces/.*/sqlschemas$)`), + ReplaceFunc: func(matches []string) string { + return matches[1] + "/name" // connector requires a name + }, + }, { Pattern: regexp.MustCompile(`(/apis/.*/v0alpha1/namespaces/.*/queryconvert$)`), ReplaceFunc: func(matches []string) string { diff --git a/pkg/services/publicdashboards/public_dashboard_service_mock.go b/pkg/services/publicdashboards/public_dashboard_service_mock.go index b54ef3ec6db..c2b39355737 100644 --- a/pkg/services/publicdashboards/public_dashboard_service_mock.go +++ b/pkg/services/publicdashboards/public_dashboard_service_mock.go @@ -4,9 +4,12 @@ package publicdashboards import ( context "context" + "fmt" backend "github.com/grafana/grafana-plugin-sdk-go/backend" + "github.com/grafana/grafana/pkg/apimachinery/identity" + "github.com/grafana/grafana/pkg/expr" dashboards "github.com/grafana/grafana/pkg/services/dashboards" dtos "github.com/grafana/grafana/pkg/api/dtos" @@ -587,6 +590,10 @@ func (_m *FakePublicDashboardService) Update(ctx context.Context, u *user.Signed return r0, r1 } +func (_m *FakePublicDashboardService) GetSQLSchemas(ctx context.Context, user identity.Requester, reqDTO dtos.MetricRequest) (expr.SQLSchemas, error) { + return nil, fmt.Errorf("not implemented in public dashboards") +} + // NewFakePublicDashboardService creates a new instance of FakePublicDashboardService. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. func NewFakePublicDashboardService(t interface { diff --git a/pkg/services/publicdashboards/publicdashboard.go b/pkg/services/publicdashboards/publicdashboard.go index c3c2eb83496..b31657ef267 100644 --- a/pkg/services/publicdashboards/publicdashboard.go +++ b/pkg/services/publicdashboards/publicdashboard.go @@ -5,6 +5,8 @@ import ( "github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/grafana/grafana/pkg/api/dtos" + "github.com/grafana/grafana/pkg/apimachinery/identity" + "github.com/grafana/grafana/pkg/expr" contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model" "github.com/grafana/grafana/pkg/services/dashboards" . "github.com/grafana/grafana/pkg/services/publicdashboards/models" @@ -37,6 +39,8 @@ type Service interface { ExistsEnabledByAccessToken(ctx context.Context, accessToken string) (bool, error) ExistsEnabledByDashboardUid(ctx context.Context, dashboardUid string) (bool, error) + + GetSQLSchemas(ctx context.Context, user identity.Requester, reqDTO dtos.MetricRequest) (expr.SQLSchemas, error) } // ServiceWrapper these methods have different behavior between OSS and Enterprise. The latter would call the OSS service first diff --git a/pkg/services/publicdashboards/service/service.go b/pkg/services/publicdashboards/service/service.go index 239ce31829c..bb3c70dcef4 100644 --- a/pkg/services/publicdashboards/service/service.go +++ b/pkg/services/publicdashboards/service/service.go @@ -14,6 +14,7 @@ import ( "github.com/grafana/grafana/pkg/api/dtos" "github.com/grafana/grafana/pkg/apimachinery/identity" + "github.com/grafana/grafana/pkg/expr" "github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/infra/metrics" "github.com/grafana/grafana/pkg/services/accesscontrol" @@ -512,6 +513,10 @@ func (pd *PublicDashboardServiceImpl) logIsEnabledChanged(existingPubdash *Publi } } +func (pd *PublicDashboardServiceImpl) GetSQLSchemas(ctx context.Context, user identity.Requester, reqDTO dtos.MetricRequest) (expr.SQLSchemas, error) { + return nil, fmt.Errorf("sql schema endpoint not supported with public dashboards") +} + // Checks to see if PublicDashboard.ExistsEnabledByDashboardUid is true on create or changed on update func publicDashboardIsEnabledChanged(existingPubdash *PublicDashboard, newPubdash *PublicDashboard) bool { // creating dashboard, enabled true diff --git a/pkg/services/query/expr_sql_schema.go b/pkg/services/query/expr_sql_schema.go new file mode 100644 index 00000000000..db29da98625 --- /dev/null +++ b/pkg/services/query/expr_sql_schema.go @@ -0,0 +1,75 @@ +package query + +import ( + "context" + + "github.com/grafana/grafana/pkg/api/dtos" + "github.com/grafana/grafana/pkg/apimachinery/errutil" + "github.com/grafana/grafana/pkg/apimachinery/identity" + "github.com/grafana/grafana/pkg/expr" + "github.com/grafana/grafana/pkg/infra/log" + "github.com/grafana/grafana/pkg/services/datasources" + "github.com/grafana/grafana/pkg/services/dsquerierclient" + "github.com/grafana/grafana/pkg/services/validations" +) + +func (s *ServiceImpl) GetSQLSchemas(ctx context.Context, user identity.Requester, reqDTO dtos.MetricRequest) (expr.SQLSchemas, error) { + //TODO DEdupe code + + parsedReq, err := s.parseMetricRequest(ctx, user, false, reqDTO, false) + if err != nil { + return expr.SQLSchemas{}, err + } + exprReq := expr.Request{ + Queries: []expr.Query{}, + } + + if user != nil { // for passthrough authentication, SSE does not authenticate + exprReq.User = user + exprReq.OrgId = user.GetOrgID() + } + + for _, pq := range parsedReq.getFlattenedQueries() { + if pq.datasource == nil { + return nil, ErrMissingDataSourceInfo.Build(errutil.TemplateData{ + Public: map[string]any{ + "RefId": pq.query.RefID, + }, + }) + } + + exprReq.Queries = append(exprReq.Queries, expr.Query{ + JSON: pq.query.JSON, + Interval: pq.query.Interval, + RefID: pq.query.RefID, + MaxDataPoints: pq.query.MaxDataPoints, + QueryType: pq.query.QueryType, + DataSource: pq.datasource, + TimeRange: expr.AbsoluteTimeRange{ + From: pq.query.TimeRange.From, + To: pq.query.TimeRange.To, + }, + }) + } + + return s.expressionService.GetSQLSchemas(ctx, exprReq) +} + +func GetSQLSchemas(ctx context.Context, log log.Logger, dscache datasources.CacheService, exprService *expr.Service, reqDTO dtos.MetricRequest, qsDatasourceClientBuilder dsquerierclient.QSDatasourceClientBuilder, headers map[string]string) (expr.SQLSchemas, error) { + s := &ServiceImpl{ + log: log, + dataSourceCache: dscache, + expressionService: exprService, + dataSourceRequestValidator: validations.ProvideValidator(), + qsDatasourceClientBuilder: qsDatasourceClientBuilder, + headers: headers, + concurrentQueryLimit: 16, // TODO: make it configurable + } + + user, err := identity.GetRequester(ctx) + if err != nil { + return nil, err + } + + return s.GetSQLSchemas(ctx, user, reqDTO) +} diff --git a/pkg/services/query/query.go b/pkg/services/query/query.go index d69c69af134..138812ebd03 100644 --- a/pkg/services/query/query.go +++ b/pkg/services/query/query.go @@ -73,6 +73,8 @@ type Service interface { // this is more "forward compatible", for example supports per-query time ranges QueryDataNew(ctx context.Context, user identity.Requester, skipDSCache bool, reqDTO dtos.MetricRequest) (*backend.QueryDataResponse, error) + + GetSQLSchemas(ctx context.Context, user identity.Requester, reqDTO dtos.MetricRequest) (expr.SQLSchemas, error) } // Gives us compile time error if the service does not adhere to the contract of the interface diff --git a/pkg/services/query/query_service_mock.go b/pkg/services/query/query_service_mock.go index 22c08118941..c391b86061f 100644 --- a/pkg/services/query/query_service_mock.go +++ b/pkg/services/query/query_service_mock.go @@ -4,10 +4,12 @@ package query import ( context "context" + "fmt" backend "github.com/grafana/grafana-plugin-sdk-go/backend" dtos "github.com/grafana/grafana/pkg/api/dtos" + "github.com/grafana/grafana/pkg/expr" identity "github.com/grafana/grafana/pkg/apimachinery/identity" @@ -97,6 +99,10 @@ func (_m *FakeQueryService) Run(ctx context.Context) error { return r0 } +func (_m *FakeQueryService) GetSQLSchemas(ctx context.Context, user identity.Requester, reqDTO dtos.MetricRequest) (expr.SQLSchemas, error) { + return nil, fmt.Errorf("sql schema endpoint not supported with public dashboards") +} + // NewFakeQueryService creates a new instance of FakeQueryService. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. func NewFakeQueryService(t interface { From 92375279f70485dd56e3fb75e25d43a8937b11cc Mon Sep 17 00:00:00 2001 From: Ashley Harrison Date: Thu, 30 Oct 2025 14:22:44 +0000 Subject: [PATCH 130/378] Slider: Expose prop to control visibility of input (#113084) expose prop to control visibility of slider input --- .../src/components/Slider/Slider.test.tsx | 12 +++++++++ .../src/components/Slider/Slider.tsx | 25 +++++++++++-------- .../grafana-ui/src/components/Slider/types.ts | 2 ++ 3 files changed, 28 insertions(+), 11 deletions(-) diff --git a/packages/grafana-ui/src/components/Slider/Slider.test.tsx b/packages/grafana-ui/src/components/Slider/Slider.test.tsx index e24ccd7e751..1fb4ab1c03a 100644 --- a/packages/grafana-ui/src/components/Slider/Slider.test.tsx +++ b/packages/grafana-ui/src/components/Slider/Slider.test.tsx @@ -33,6 +33,18 @@ describe('Slider', () => { expect(sliderInput).toHaveValue('10'); }); + it('hides the slider input if showInput is false', () => { + render(); + + const slider = screen.getByRole('slider'); + const sliderInput = screen.queryByRole('textbox'); + + expect(slider).toHaveAttribute('aria-valuemin', '10'); + expect(slider).toHaveAttribute('aria-valuemax', '20'); + expect(slider).toHaveAttribute('aria-valuenow', '10'); + expect(sliderInput).not.toBeInTheDocument(); + }); + it('renders correct contents with a value', () => { render(); diff --git a/packages/grafana-ui/src/components/Slider/Slider.tsx b/packages/grafana-ui/src/components/Slider/Slider.tsx index b41f41d0af7..d8d310fa92b 100644 --- a/packages/grafana-ui/src/components/Slider/Slider.tsx +++ b/packages/grafana-ui/src/components/Slider/Slider.tsx @@ -29,6 +29,7 @@ export const Slider = ({ marks, included, inputId, + showInput = true, }: SliderProps) => { const isHorizontal = orientation === 'horizontal'; const styles = useStyles2(getStyles, isHorizontal, Boolean(marks)); @@ -114,17 +115,19 @@ export const Slider = ({ included={included} /> - + {showInput && ( + + )}
); diff --git a/packages/grafana-ui/src/components/Slider/types.ts b/packages/grafana-ui/src/components/Slider/types.ts index 812a8bed7d7..880bfd2f712 100644 --- a/packages/grafana-ui/src/components/Slider/types.ts +++ b/packages/grafana-ui/src/components/Slider/types.ts @@ -14,6 +14,8 @@ interface CommonSliderProps { marks?: SliderMarks; /** If the value is true, it means a continuous value interval, otherwise, it is a independent value. */ included?: boolean; + /** Controls visibility of the input field. Defaults to true. */ + showInput?: boolean; } export interface SliderProps extends CommonSliderProps { value?: number; From 63c5d8cb8f1c5432c7ed35569785f669d5b3bda8 Mon Sep 17 00:00:00 2001 From: Ashley Harrison Date: Thu, 30 Oct 2025 14:23:03 +0000 Subject: [PATCH 131/378] Collapse: Improve layout and deprecate `collapsible` prop (#113164) * deprecate collapsible prop, improve Collapse to allow for buttons in the header * add ariaLabel * Revert "add ariaLabel" This reverts commit a903a0da5da70065db31f4a98fb6caf0f6f93727. * add aria-labelledby --- .../src/querybuilder/QueryPatternsModal.tsx | 1 - .../querybuilder/shared/QueryOptionGroup.tsx | 1 - .../components/Collapse/Collapse.story.tsx | 39 ++++++++++- .../src/components/Collapse/Collapse.test.tsx | 2 +- .../src/components/Collapse/Collapse.tsx | 65 +++++++++---------- .../src/components/IconButton/IconButton.tsx | 7 +- .../import-to-gma/ConfirmConvertModal.tsx | 1 - .../import-to-gma/ImportToGMARules.tsx | 1 - .../EditDefaultPolicyForm.tsx | 1 - .../features/explore/CorrelationHelper.tsx | 2 - .../features/explore/Logs/LogsContainer.tsx | 6 +- .../features/explore/Logs/LogsSamplePanel.tsx | 1 - .../SpanFilters/SpanFilters.tsx | 2 +- .../logs/components/panel/LogLineContext.tsx | 1 - .../panel/LogLineDetailsComponent.tsx | 7 -- .../data-hover/DataHoverRows.tsx | 1 - .../LogsQueryEditor/AzureCheatSheet.tsx | 1 - .../ResourcePicker/AdvancedMulti.tsx | 1 - .../components/CheatSheet/LogsCheatSheet.tsx | 2 +- .../configuration/ConfigurationEditor.tsx | 2 +- .../QueryEditor/QueryOptionGroup.tsx | 1 - .../loki/components/LokiContextUi.tsx | 1 - .../components/QueryPatternsModal.tsx | 1 - .../configuration/ConfigurationEditor.tsx | 2 +- .../prometheus/QueryOptionGroup.tsx | 1 - 25 files changed, 83 insertions(+), 67 deletions(-) diff --git a/packages/grafana-prometheus/src/querybuilder/QueryPatternsModal.tsx b/packages/grafana-prometheus/src/querybuilder/QueryPatternsModal.tsx index a4f17087b21..2364bc80a86 100644 --- a/packages/grafana-prometheus/src/querybuilder/QueryPatternsModal.tsx +++ b/packages/grafana-prometheus/src/querybuilder/QueryPatternsModal.tsx @@ -111,7 +111,6 @@ export const QueryPatternsModal = (props: Props) => { } )} isOpen={isOpen} - collapsible={true} onToggle={() => { const action = isOpen ? 'close' : 'open'; reportInteraction(`grafana_prom_kickstart_toggle_pattern_card`, { diff --git a/packages/grafana-prometheus/src/querybuilder/shared/QueryOptionGroup.tsx b/packages/grafana-prometheus/src/querybuilder/shared/QueryOptionGroup.tsx index 554201a820d..8253d195ea0 100644 --- a/packages/grafana-prometheus/src/querybuilder/shared/QueryOptionGroup.tsx +++ b/packages/grafana-prometheus/src/querybuilder/shared/QueryOptionGroup.tsx @@ -20,7 +20,6 @@ export function QueryOptionGroup({ title, children, collapsedInfo }: Props) {
= { children: 'Panel data', isOpen: false, label: 'Collapse panel', - collapsible: true, }, argTypes: { onToggle: { action: 'toggled' }, @@ -57,4 +59,39 @@ Controlled.parameters = { }, }; +export const WithCustomLabel: StoryFn = (args) => { + const [, updateArgs] = useArgs(); + return ( + { + action('onToggle')({ isOpen: !args.isOpen }); + updateArgs({ isOpen: !args.isOpen }); + }} + label={ + + Collapse panel + + { + event.stopPropagation(); + action('onDeleteClick')(); + }} + aria-label="Delete" + name="trash-alt" + /> + + + } + > +

{args.children}

+
+ ); +}; +WithCustomLabel.parameters = { + controls: { + exclude: [...EXCLUDED_PROPS, 'label'], + }, +}; + export default meta; diff --git a/packages/grafana-ui/src/components/Collapse/Collapse.test.tsx b/packages/grafana-ui/src/components/Collapse/Collapse.test.tsx index 432ff8ef56e..817df10153d 100644 --- a/packages/grafana-ui/src/components/Collapse/Collapse.test.tsx +++ b/packages/grafana-ui/src/components/Collapse/Collapse.test.tsx @@ -42,7 +42,7 @@ describe('Collapse', () => { const onToggle = jest.fn(); const { user } = setup( - +
{contentText}
); diff --git a/packages/grafana-ui/src/components/Collapse/Collapse.tsx b/packages/grafana-ui/src/components/Collapse/Collapse.tsx index d0f8757e1ca..195ea24b4d1 100644 --- a/packages/grafana-ui/src/components/Collapse/Collapse.tsx +++ b/packages/grafana-ui/src/components/Collapse/Collapse.tsx @@ -1,12 +1,11 @@ import { css, cx } from '@emotion/css'; -import { useState } from 'react'; +import { useId, useState } from 'react'; import * as React from 'react'; import { GrafanaTheme2 } from '@grafana/data'; import { useStyles2 } from '../../themes/ThemeContext'; -import { clearButtonStyles } from '../Button/Button'; -import { Icon } from '../Icon/Icon'; +import { IconButton } from '../IconButton/IconButton'; const getStyles = (theme: GrafanaTheme2) => ({ collapse: css({ @@ -74,25 +73,21 @@ const getStyles = (theme: GrafanaTheme2) => ({ }, }), header: css({ + cursor: 'pointer', label: 'collapse__header', - padding: theme.spacing(1, 2, 1, 2), + padding: theme.spacing(1), display: 'flex', + gap: theme.spacing(1), }), - headerCollapsed: css({ - label: 'collapse__header--collapsed', - padding: theme.spacing(1, 2, 1, 2), + button: css({ + marginRight: 0, }), headerLabel: css({ label: 'collapse__header-label', fontWeight: theme.typography.fontWeightMedium, - marginRight: theme.spacing(1), fontSize: theme.typography.size.md, display: 'flex', - flex: '0 0 100%', - }), - icon: css({ - label: 'collapse__icon', - margin: theme.spacing(0.25, 1, 0, -1), + flex: 1, }), }); @@ -103,12 +98,12 @@ export interface Props { label: React.ReactNode; /** Indicates loading state of the content */ loading?: boolean; - /** Toggle collapsed header icon */ - collapsible?: boolean; /** Callback for the toggle functionality */ onToggle?: (isOpen: boolean) => void; /** Additional class name for the root element */ className?: string; + /** @deprecated this prop is no longer used and will be removed in Grafana 13 */ + collapsible?: boolean; } export const ControlledCollapse = ({ isOpen, onToggle, ...otherProps }: React.PropsWithChildren) => { @@ -116,7 +111,6 @@ export const ControlledCollapse = ({ isOpen, onToggle, ...otherProps }: React.Pr return ( { setOpen(!open); @@ -133,35 +127,38 @@ export const ControlledCollapse = ({ isOpen, onToggle, ...otherProps }: React.Pr * * https://developers.grafana.com/ui/latest/index.html?path=/docs/layout-collapse--docs */ -export const Collapse = ({ - isOpen, - label, - loading, - collapsible, - onToggle, - className, - children, -}: React.PropsWithChildren) => { - const buttonStyles = useStyles2(clearButtonStyles); +export const Collapse = ({ isOpen, label, loading, onToggle, className, children }: React.PropsWithChildren) => { const style = useStyles2(getStyles); + const labelId = useId(); + const contentId = useId(); + const onClickToggle = () => { if (onToggle) { onToggle(!isOpen); } }; - const panelClass = cx([style.collapse, className]); - const loaderClass = loading ? cx([style.loader, style.loaderActive]) : cx([style.loader]); - const headerClass = collapsible ? cx([style.header]) : cx([style.headerCollapsed]); + const loaderClass = loading ? cx([style.loader, style.loaderActive]) : style.loader; return (
- + {/* the inner button handles keyboard a11y. this is a convenience for mouse users */} + {/* eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions */} +
+ +
+ {label} +
+
{isOpen && ( -
+
{children}
diff --git a/packages/grafana-ui/src/components/IconButton/IconButton.tsx b/packages/grafana-ui/src/components/IconButton/IconButton.tsx index d4d77c33fab..f2d44eb2fa1 100644 --- a/packages/grafana-ui/src/components/IconButton/IconButton.tsx +++ b/packages/grafana-ui/src/components/IconButton/IconButton.tsx @@ -41,7 +41,12 @@ interface BasePropsWithAriaLabel extends BaseProps { ['aria-label']: string; } -export type Props = BasePropsWithTooltip | BasePropsWithAriaLabel; +interface BasePropsWithAriaLabelledBy extends BaseProps { + /** Reference to an element id that labels the button. No tooltip will be set in this case. */ + ['aria-labelledby']: string; +} + +export type Props = BasePropsWithTooltip | BasePropsWithAriaLabel | BasePropsWithAriaLabelledBy; /** * This component looks just like an icon but behaves like a button. diff --git a/public/app/features/alerting/unified/components/import-to-gma/ConfirmConvertModal.tsx b/public/app/features/alerting/unified/components/import-to-gma/ConfirmConvertModal.tsx index 4f2c364859a..bf2a253d7e8 100644 --- a/public/app/features/alerting/unified/components/import-to-gma/ConfirmConvertModal.tsx +++ b/public/app/features/alerting/unified/components/import-to-gma/ConfirmConvertModal.tsx @@ -385,7 +385,6 @@ function TargetFolderNotEmptyWarning({ targetFolderRules }: { targetFolderRules: )} isOpen={showTargetRules} onToggle={toggleShowTargetRules} - collapsible={true} > diff --git a/public/app/features/alerting/unified/components/import-to-gma/ImportToGMARules.tsx b/public/app/features/alerting/unified/components/import-to-gma/ImportToGMARules.tsx index bfdb5b3303c..d88d446642d 100644 --- a/public/app/features/alerting/unified/components/import-to-gma/ImportToGMARules.tsx +++ b/public/app/features/alerting/unified/components/import-to-gma/ImportToGMARules.tsx @@ -150,7 +150,6 @@ const ImportToGMARules = () => { label={t('alerting.import-to-gma.additional-settings', 'Additional settings')} isOpen={optionsShowing} onToggle={toggleOptions} - collapsible={true} > diff --git a/public/app/features/alerting/unified/components/notification-policies/EditDefaultPolicyForm.tsx b/public/app/features/alerting/unified/components/notification-policies/EditDefaultPolicyForm.tsx index dc87060c03d..61ce391d779 100644 --- a/public/app/features/alerting/unified/components/notification-policies/EditDefaultPolicyForm.tsx +++ b/public/app/features/alerting/unified/components/notification-policies/EditDefaultPolicyForm.tsx @@ -130,7 +130,6 @@ export const AmRootRouteForm = ({ actionButtons, alertManagerSourceName, onSubmi /> { })} { setIsLabelDescOpen(!isLabelDescOpen); @@ -201,7 +200,6 @@ export const CorrelationHelper = ({ exploreId, correlations }: Props) => { { setIsTransformOpen(!isTransformOpen); diff --git a/public/app/features/explore/Logs/LogsContainer.tsx b/public/app/features/explore/Logs/LogsContainer.tsx index 6ff6c9a248c..13bc78b5849 100644 --- a/public/app/features/explore/Logs/LogsContainer.tsx +++ b/public/app/features/explore/Logs/LogsContainer.tsx @@ -24,7 +24,7 @@ import { import { t } from '@grafana/i18n'; import { getDataSourceSrv } from '@grafana/runtime'; import { DataQuery } from '@grafana/schema'; -import { Collapse } from '@grafana/ui'; +import { PanelChrome } from '@grafana/ui'; import { MIXED_DATASOURCE_NAME } from 'app/plugins/datasource/mixed/MixedDataSource'; import { GetFieldLinksFn } from 'app/plugins/panel/logs/types'; import { ExploreItemState } from 'app/types/explore'; @@ -309,7 +309,7 @@ class LogsContainer extends PureComponent - + {(controls) => ( )} - + } isOpen={enabled} - collapsible={true} onToggle={onToggleLogsSampleCollapse} > 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 d9909845984..d48dabdf1fa 100644 --- a/public/app/features/explore/TraceView/components/TracePageHeader/SpanFilters/SpanFilters.tsx +++ b/public/app/features/explore/TraceView/components/TracePageHeader/SpanFilters/SpanFilters.tsx @@ -151,7 +151,7 @@ export const SpanFilters = memo((props: SpanFilterProps) => { return (
- + diff --git a/public/app/features/logs/components/panel/LogLineContext.tsx b/public/app/features/logs/components/panel/LogLineContext.tsx index 59a34bb9cae..1fab2336c3d 100644 --- a/public/app/features/logs/components/panel/LogLineContext.tsx +++ b/public/app/features/logs/components/panel/LogLineContext.tsx @@ -329,7 +329,6 @@ export const LogLineContext = memo(
{getLogRowContextUi(log, updateResults)}
)} setShowLog(!showLog)} className={styles.referenceLogLine} diff --git a/public/app/features/logs/components/panel/LogLineDetailsComponent.tsx b/public/app/features/logs/components/panel/LogLineDetailsComponent.tsx index 240bc546313..36bdbf2bdde 100644 --- a/public/app/features/logs/components/panel/LogLineDetailsComponent.tsx +++ b/public/app/features/logs/components/panel/LogLineDetailsComponent.tsx @@ -131,7 +131,6 @@ export const LogLineDetailsComponent = memo( handleToggle('logLineOpen', isOpen)} > @@ -140,7 +139,6 @@ export const LogLineDetailsComponent = memo( {displayedFields.length > 0 && setDisplayedFields && ( handleToggle('displayedFieldsOpen', isOpen)} > @@ -151,7 +149,6 @@ export const LogLineDetailsComponent = memo( handleToggle('linksOpen', isOpen)} > @@ -161,7 +158,6 @@ export const LogLineDetailsComponent = memo( {trace && ( handleToggle('traceOpen', isOpen)} > @@ -174,7 +170,6 @@ export const LogLineDetailsComponent = memo( className={styles.collapsable} key={'fields'} label={t('logs.log-line-details.fields-section', 'Fields')} - collapsible isOpen={fieldsOpen} onToggle={(isOpen: boolean) => handleToggle('fieldsOpen', isOpen)} > @@ -186,7 +181,6 @@ export const LogLineDetailsComponent = memo( className={styles.collapsable} key={group} label={group} - collapsible isOpen={store.getBool(`${logOptionsStorageKey}.log-details.${groupOptionName(group)}`, true)} onToggle={(isOpen: boolean) => handleToggle(groupOptionName(group), isOpen)} > @@ -199,7 +193,6 @@ export const LogLineDetailsComponent = memo( className={styles.collapsable} key={'fields'} label={t('logs.log-line-details.fields-section', 'Fields')} - collapsible isOpen={fieldsOpen} onToggle={(isOpen: boolean) => handleToggle('fieldsOpen', isOpen)} > diff --git a/public/app/features/visualization/data-hover/DataHoverRows.tsx b/public/app/features/visualization/data-hover/DataHoverRows.tsx index d99fcfd04f9..0c9ca3759d7 100644 --- a/public/app/features/visualization/data-hover/DataHoverRows.tsx +++ b/public/app/features/visualization/data-hover/DataHoverRows.tsx @@ -38,7 +38,6 @@ export const DataHoverRows = ({ layers, activeTabIndex }: Props) => { return shouldDisplayCollapse ? ( { diff --git a/public/app/plugins/datasource/azuremonitor/components/LogsQueryEditor/AzureCheatSheet.tsx b/public/app/plugins/datasource/azuremonitor/components/LogsQueryEditor/AzureCheatSheet.tsx index 5116a7b86fb..7ed4304b881 100644 --- a/public/app/plugins/datasource/azuremonitor/components/LogsQueryEditor/AzureCheatSheet.tsx +++ b/public/app/plugins/datasource/azuremonitor/components/LogsQueryEditor/AzureCheatSheet.tsx @@ -186,7 +186,6 @@ const AzureCheatSheet = (props: AzureCheatSheetProps) => { return ( setAreDropdownsOpen({ ...areDropdownsOpen, [category]: isOpen })} key={category} diff --git a/public/app/plugins/datasource/azuremonitor/components/ResourcePicker/AdvancedMulti.tsx b/public/app/plugins/datasource/azuremonitor/components/ResourcePicker/AdvancedMulti.tsx index d16cfff82e9..f9d5cee1d55 100644 --- a/public/app/plugins/datasource/azuremonitor/components/ResourcePicker/AdvancedMulti.tsx +++ b/public/app/plugins/datasource/azuremonitor/components/ResourcePicker/AdvancedMulti.tsx @@ -19,7 +19,6 @@ const AdvancedMulti = ({ resources, onChange, renderAdvanced }: ResourcePickerPr return (
setIsAdvancedOpen(!isAdvancedOpen)} diff --git a/public/app/plugins/datasource/cloudwatch/components/CheatSheet/LogsCheatSheet.tsx b/public/app/plugins/datasource/cloudwatch/components/CheatSheet/LogsCheatSheet.tsx index 86fcbd00857..082a8eaf44a 100644 --- a/public/app/plugins/datasource/cloudwatch/components/CheatSheet/LogsCheatSheet.tsx +++ b/public/app/plugins/datasource/cloudwatch/components/CheatSheet/LogsCheatSheet.tsx @@ -80,7 +80,7 @@ interface CollapseProps { const CheatSheetCollapse = (props: CollapseProps) => { const [isOpen, setIsOpen] = useState(false); return ( - + {props.children} ); diff --git a/public/app/plugins/datasource/grafana-postgresql-datasource/configuration/ConfigurationEditor.tsx b/public/app/plugins/datasource/grafana-postgresql-datasource/configuration/ConfigurationEditor.tsx index 8a76ff319f4..3a7ffccdbb7 100644 --- a/public/app/plugins/datasource/grafana-postgresql-datasource/configuration/ConfigurationEditor.tsx +++ b/public/app/plugins/datasource/grafana-postgresql-datasource/configuration/ConfigurationEditor.tsx @@ -113,7 +113,7 @@ export const PostgresConfigEditor = (props: DataSourcePluginOptionsEditorProps

- setIsOpen((x) => !x)}> + setIsOpen((x) => !x)}> The database user should only be granted SELECT permissions on the specified database & tables you want to query.
Grafana does not validate that queries are safe so queries can contain any SQL statement. For example, diff --git a/public/app/plugins/datasource/grafana-pyroscope-datasource/QueryEditor/QueryOptionGroup.tsx b/public/app/plugins/datasource/grafana-pyroscope-datasource/QueryEditor/QueryOptionGroup.tsx index c6c3dad3719..df27a4b83d8 100644 --- a/public/app/plugins/datasource/grafana-pyroscope-datasource/QueryEditor/QueryOptionGroup.tsx +++ b/public/app/plugins/datasource/grafana-pyroscope-datasource/QueryEditor/QueryOptionGroup.tsx @@ -19,7 +19,6 @@ export function QueryOptionGroup({ title, children, collapsedInfo }: Props) {

{ window.localStorage.setItem(IS_LOKI_LOG_CONTEXT_UI_OPEN, (!isOpen).toString()); diff --git a/public/app/plugins/datasource/loki/querybuilder/components/QueryPatternsModal.tsx b/public/app/plugins/datasource/loki/querybuilder/components/QueryPatternsModal.tsx index 9be0cc98ec7..7841d9f1edc 100644 --- a/public/app/plugins/datasource/loki/querybuilder/components/QueryPatternsModal.tsx +++ b/public/app/plugins/datasource/loki/querybuilder/components/QueryPatternsModal.tsx @@ -99,7 +99,6 @@ export const QueryPatternsModal = (props: Props) => { key={patternType} label={`${capitalize(patternType)} query starters`} isOpen={openTabs.includes(patternType)} - collapsible={true} onToggle={() => setOpenTabs((tabs) => // close tab if it's already open, otherwise open it diff --git a/public/app/plugins/datasource/mysql/configuration/ConfigurationEditor.tsx b/public/app/plugins/datasource/mysql/configuration/ConfigurationEditor.tsx index bf0acc0731d..46cd7d8b3e3 100644 --- a/public/app/plugins/datasource/mysql/configuration/ConfigurationEditor.tsx +++ b/public/app/plugins/datasource/mysql/configuration/ConfigurationEditor.tsx @@ -60,7 +60,7 @@ export const ConfigurationEditor = (props: DataSourcePluginOptionsEditorProps - setIsOpen((x) => !x)}> + setIsOpen((x) => !x)}> The database user should only be granted SELECT permissions on the specified database & tables you want to query.
Grafana does not validate that queries are safe so queries can contain any SQL statement. For example, diff --git a/public/app/plugins/datasource/tempo/_importedDependencies/datasources/prometheus/QueryOptionGroup.tsx b/public/app/plugins/datasource/tempo/_importedDependencies/datasources/prometheus/QueryOptionGroup.tsx index 4541016132b..dd68fa412ab 100644 --- a/public/app/plugins/datasource/tempo/_importedDependencies/datasources/prometheus/QueryOptionGroup.tsx +++ b/public/app/plugins/datasource/tempo/_importedDependencies/datasources/prometheus/QueryOptionGroup.tsx @@ -25,7 +25,6 @@ export function QueryOptionGroup({ title, children, collapsedInfo, queryStats, o
Date: Thu, 30 Oct 2025 15:31:57 +0100 Subject: [PATCH 132/378] Codegen/CI: Update makefile to also verify gen-cue (#113211) * update makefile to also verify gen-cue * update for jsonnet --- Makefile | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 5bf0150e047..ab2a0ae2c55 100644 --- a/Makefile +++ b/Makefile @@ -150,7 +150,19 @@ i18n-extract: i18n-extract-enterprise ##@ Building .PHONY: gen-cue -gen-cue: ## Do all CUE/Thema code generation +gen-cue: do-gen-cue + @if [ -n "$$CODEGEN_VERIFY" ]; then \ + echo "Verifying generated code is up to date..."; \ + if ! git diff --quiet; then \ + echo "Error: Generated cue files are not up to date. Please run 'make gen-cue' to regenerate."; \ + git diff --name-only; \ + exit 1; \ + fi; \ + echo "Generated cue files are up to date."; \ + fi + +.PHONY: do-gen-cue +do-gen-cue: ## Do all CUE/Thema code generation @echo "generate code from .cue files" go generate ./kinds/gen.go go generate ./public/app/plugins/gen.go @@ -223,10 +235,24 @@ fix-cue: $(cue) fix kinds/**/*.cue $(cue) fix public/app/plugins/**/**/*.cue + .PHONY: gen-jsonnet -gen-jsonnet: +gen-jsonnet: do-gen-jsonnet + @if [ -n "$$CODEGEN_VERIFY" ]; then \ + echo "Verifying generated code is up to date..."; \ + if ! git diff --quiet; then \ + echo "Error: Generated jsonnet files are not up to date. Please run 'make gen-jsonnet' to regenerate."; \ + git diff --name-only; \ + exit 1; \ + fi; \ + echo "Generated jsonnet files are up to date."; \ + fi + +.PHONY: do-gen-jsonnet +do-gen-jsonnet: go generate ./devenv/jsonnet + .PHONY: update-workspace update-workspace: gen-go @echo "updating workspace" From 20ec8ee61cec32d756d1faf2bfd3481342e3e655 Mon Sep 17 00:00:00 2001 From: Yunwen Zheng Date: Thu, 30 Oct 2025 10:37:13 -0400 Subject: [PATCH 133/378] useProvisionedRequestHandler: reset ref when a new request is loading (#113196) --- .../provisioning/hooks/useProvisionedRequestHandler.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/public/app/features/provisioning/hooks/useProvisionedRequestHandler.ts b/public/app/features/provisioning/hooks/useProvisionedRequestHandler.ts index 528e3ee49be..a5a09fb4ce3 100644 --- a/public/app/features/provisioning/hooks/useProvisionedRequestHandler.ts +++ b/public/app/features/provisioning/hooks/useProvisionedRequestHandler.ts @@ -90,6 +90,11 @@ export function useProvisionedRequestHandler({ workflow, }; + // Reset handler guard when a new request starts loading + if (request.isLoading) { + hasHandled.current = false; + } + if (request.isError) { hasHandled.current = true; handlers.onError?.(request.error, info); From d6bcca2f7e0c90222bc141dec4b101a25179e357 Mon Sep 17 00:00:00 2001 From: Lauren <61048546+laurenashleigh@users.noreply.github.com> Date: Thu, 30 Oct 2025 15:14:37 +0000 Subject: [PATCH 134/378] Alerting: Hide metadata if grouping by folder (#113216) * Alerting: Hide metadata if grouping by folder * resolve comments * resolve comments 2 --- .../alerting/unified/triage/Workbench.tsx | 30 +++++++++++++++---- .../unified/triage/rows/AlertRuleRow.tsx | 23 +++++++++----- .../unified/triage/scene/Workbench.tsx | 2 +- 3 files changed, 42 insertions(+), 13 deletions(-) diff --git a/public/app/features/alerting/unified/triage/Workbench.tsx b/public/app/features/alerting/unified/triage/Workbench.tsx index ceb4196ad7f..86ff6c03a1e 100644 --- a/public/app/features/alerting/unified/triage/Workbench.tsx +++ b/public/app/features/alerting/unified/triage/Workbench.tsx @@ -23,7 +23,7 @@ import { Domain, Filter, WorkbenchRow } from './types'; type WorkbenchProps = { domain: Domain; data: WorkbenchRow[]; - groupBy?: string[]; // @TODO proper type + groupBy?: string[]; filterBy?: Filter[]; queryRunner: SceneQueryRunner; }; @@ -36,13 +36,30 @@ function renderWorkbenchRow( leftColumnWidth: number, domain: Domain, key: React.Key, + enableFolderMeta: boolean, depth = 0 ): React.ReactElement { if (row.type === 'alertRule') { - return ; + return ( + + ); } else { const children = row.rows.map((childRow, childIndex) => - renderWorkbenchRow(childRow, leftColumnWidth, domain, `${key}-${generateRowKey(childRow, childIndex)}`, depth + 1) + renderWorkbenchRow( + childRow, + leftColumnWidth, + domain, + `${key}-${generateRowKey(childRow, childIndex)}`, + enableFolderMeta, + depth + 1 + ) ); // Check if this is a grafana_folder group and use FolderGroupRow @@ -99,11 +116,14 @@ function renderWorkbenchRow( │ │ │ │ └─────────────────────────┘ └───────────────────────────────────┘ */ -export function Workbench({ domain, data, queryRunner }: WorkbenchProps) { +export function Workbench({ domain, data, queryRunner, groupBy }: WorkbenchProps) { const styles = useStyles2(getStyles); const isLoading = !queryRunner.isDataReadyToDisplay(); const [pageIndex, setPageIndex] = useState(1); + + // Calculate once: show folder metadata only if not grouping by grafana_folder + const enableFolderMeta = !groupBy?.includes('grafana_folder'); // splitter for template and payload editor const splitter = useSplitter({ direction: 'row', @@ -151,7 +171,7 @@ export function Workbench({ domain, data, queryRunner }: WorkbenchProps) { ) : ( dataSlice.map((row, index) => { const rowKey = generateRowKey(row, index); - return renderWorkbenchRow(row, leftColumnWidth, domain, rowKey); + return renderWorkbenchRow(row, leftColumnWidth, domain, rowKey, enableFolderMeta); }) )} {hasMore && setPageIndex((prevIndex) => prevIndex + 1)} />} diff --git a/public/app/features/alerting/unified/triage/rows/AlertRuleRow.tsx b/public/app/features/alerting/unified/triage/rows/AlertRuleRow.tsx index 539dc2c4ed1..965e9b5ce31 100644 --- a/public/app/features/alerting/unified/triage/rows/AlertRuleRow.tsx +++ b/public/app/features/alerting/unified/triage/rows/AlertRuleRow.tsx @@ -16,9 +16,16 @@ interface AlertRuleRowProps { leftColumnWidth: number; rowKey: React.Key; depth?: number; + enableFolderMeta?: boolean; } -export const AlertRuleRow = ({ row, leftColumnWidth, rowKey, depth = 0 }: AlertRuleRowProps) => { +export const AlertRuleRow = ({ + row, + leftColumnWidth, + rowKey, + depth = 0, + enableFolderMeta = true, +}: AlertRuleRowProps) => { const { ruleUID, folder, title } = row.metadata; const [isDrawerOpen, setIsDrawerOpen] = useState(false); @@ -45,12 +52,14 @@ export const AlertRuleRow = ({ row, leftColumnWidth, rowKey, depth = 0 }: AlertR /> } metadata={ - - - - {folder} - - + enableFolderMeta ? ( + + + + {folder} + + + ) : undefined } content={} depth={depth} diff --git a/public/app/features/alerting/unified/triage/scene/Workbench.tsx b/public/app/features/alerting/unified/triage/scene/Workbench.tsx index f202a5cd0a0..d83908c2e91 100644 --- a/public/app/features/alerting/unified/triage/scene/Workbench.tsx +++ b/public/app/features/alerting/unified/triage/scene/Workbench.tsx @@ -34,7 +34,7 @@ export function WorkbenchRenderer() { const { data } = runner.useState(); const rows = data ? convertToWorkbenchRows(data, groupByKeys) : []; - return ; + return ; } type DataPoint = Record, string> & Record; From 44beedd09a50530a81c9afbea1eff190b6bfa6b9 Mon Sep 17 00:00:00 2001 From: Misi Date: Thu, 30 Oct 2025 16:50:40 +0100 Subject: [PATCH 135/378] IAM: Handle NULL external_uid, is_provisioned correctly for Teams (#113219) * Handle NULL external_uid correctly with MySQL * Add NULL handling to is_provisioned column --- pkg/registry/apis/iam/legacy/team.go | 21 ++++++++++---- pkg/tests/apis/iam/team_integration_test.go | 31 +++++++++++++++++++++ 2 files changed, 47 insertions(+), 5 deletions(-) diff --git a/pkg/registry/apis/iam/legacy/team.go b/pkg/registry/apis/iam/legacy/team.go index 51e68506fbd..874dea3dff9 100644 --- a/pkg/registry/apis/iam/legacy/team.go +++ b/pkg/registry/apis/iam/legacy/team.go @@ -2,6 +2,7 @@ package legacy import ( "context" + "database/sql" "errors" "fmt" "time" @@ -129,18 +130,18 @@ func (s *legacySQLStore) ListTeams(ctx context.Context, ns claims.NamespaceInfo, return nil, fmt.Errorf("expected non zero orgID") } - sql, err := s.sql(ctx) + sqlConn, err := s.sql(ctx) if err != nil { return nil, err } - req := newListTeams(sql, &query) + req := newListTeams(sqlConn, &query) q, err := sqltemplate.Execute(sqlQueryTeamsTemplate, req) if err != nil { return nil, fmt.Errorf("execute template %q: %w", sqlQueryTeamsTemplate.Name(), err) } - rows, err := sql.DB.GetSqlxSession().Query(ctx, q, req.GetArgs()...) + rows, err := sqlConn.DB.GetSqlxSession().Query(ctx, q, req.GetArgs()...) defer func() { if rows != nil { _ = rows.Close() @@ -155,11 +156,21 @@ func (s *legacySQLStore) ListTeams(ctx context.Context, ns claims.NamespaceInfo, var lastID int64 for rows.Next() { t := team.Team{} - err = rows.Scan(&t.ID, &t.UID, &t.Name, &t.Email, &t.ExternalUID, &t.IsProvisioned, &t.Created, &t.Updated) + var externalUID sql.NullString + var isProvisioned sql.NullBool + err = rows.Scan(&t.ID, &t.UID, &t.Name, &t.Email, &externalUID, &isProvisioned, &t.Created, &t.Updated) if err != nil { return res, err } + if externalUID.Valid { + t.ExternalUID = externalUID.String + } + + if isProvisioned.Valid { + t.IsProvisioned = isProvisioned.Bool + } + lastID = t.ID res.Teams = append(res.Teams, t) if len(res.Teams) > int(query.Pagination.Limit)-1 { @@ -170,7 +181,7 @@ func (s *legacySQLStore) ListTeams(ctx context.Context, ns claims.NamespaceInfo, } if query.UID == "" { - res.RV, err = sql.GetResourceVersion(ctx, "team", "updated") + res.RV, err = sqlConn.GetResourceVersion(ctx, "team", "updated") } return res, err diff --git a/pkg/tests/apis/iam/team_integration_test.go b/pkg/tests/apis/iam/team_integration_test.go index e8bb115dfb7..16d27456e03 100644 --- a/pkg/tests/apis/iam/team_integration_test.go +++ b/pkg/tests/apis/iam/team_integration_test.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "testing" + "time" "github.com/stretchr/testify/require" "k8s.io/apimachinery/pkg/api/errors" @@ -222,6 +223,36 @@ func doTeamCRUDTestsUsingTheNewAPIs(t *testing.T, helper *apis.K8sTestHelper) { require.Equal(t, createdUID, fetched.GetName()) require.Equal(t, "default", fetched.GetNamespace()) + + // Cleanup + err = teamClient.Resource.Delete(ctx, createdUID, metav1.DeleteOptions{}) + require.NoError(t, err) + }) + + t.Run("should list teams correctly", func(t *testing.T) { + ctx := context.Background() + + teamClient := helper.GetResourceClient(apis.ResourceClientArgs{ + User: helper.Org1.Admin, + Namespace: helper.Namespacer(helper.Org1.Admin.Identity.GetOrgID()), + GVR: gvrTeams, + }) + + // For ensuring that it is able to list a team which has external_uid = null and is_provisioned = null + // only matters when legacy storage is involved + env := helper.GetEnv() + res, err := env.SQLStore.GetSqlxSession().Exec(ctx, "INSERT INTO team (org_id, uid, name, email, is_provisioned, external_uid, created, updated) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", + helper.Org1.Admin.Identity.GetOrgID(), "t000000001", "List Team 1", "list-team-1@example.com", nil, nil, time.Now(), time.Now()) + require.NoError(t, err) + require.NotNil(t, res) + + list, err := teamClient.Resource.List(ctx, metav1.ListOptions{}) + require.NoError(t, err) + require.NotNil(t, list) + + // Cleanup + _, err = env.SQLStore.GetSqlxSession().Exec(ctx, "DELETE FROM team WHERE uid = ?", "t000000001") + require.NoError(t, err) }) } From 72e244c1e7117a03400429330ae1dac354a169c1 Mon Sep 17 00:00:00 2001 From: Jay Clifford <45856600+Jayclifford345@users.noreply.github.com> Date: Thu, 30 Oct 2025 15:57:16 +0000 Subject: [PATCH 136/378] fix(nav): Add tooltip to help button (#113225) Co-authored-by: Jack Baldry --- .../AppChrome/TopBar/HelpTopBarButton.tsx | 15 ++++++++++++++- public/locales/en-US/grafana.json | 7 ++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/public/app/core/components/AppChrome/TopBar/HelpTopBarButton.tsx b/public/app/core/components/AppChrome/TopBar/HelpTopBarButton.tsx index 62aed5080ef..02215cda4fd 100644 --- a/public/app/core/components/AppChrome/TopBar/HelpTopBarButton.tsx +++ b/public/app/core/components/AppChrome/TopBar/HelpTopBarButton.tsx @@ -34,7 +34,12 @@ export const HelpTopBarButton = memo(function HelpTopBarButton({ isSmallScreen } if (isSmallScreen || !enrichedHelpNode.hideFromTabs || interactiveLearningPluginId === undefined) { return ( } placement="bottom-end"> - + ); } @@ -48,6 +53,14 @@ export const HelpTopBarButton = memo(function HelpTopBarButton({ isSmallScreen } icon="question-circle" aria-label={t('navigation.help.aria-label', 'Help')} className={isOpen ? styles.helpButtonActive : undefined} + tooltip={ + isOpen + ? t( + 'navigation.help.interactive-learning.close-tooltip', + 'Close interactive learning, help, and documentation' + ) + : t('navigation.help.interactive-learning.open-tooltip', 'Open interactive learning, help, and documentation') + } onClick={() => { if (isOpen) { setDockedComponentId(undefined); diff --git a/public/locales/en-US/grafana.json b/public/locales/en-US/grafana.json index fb177e68314..c1736af9a50 100644 --- a/public/locales/en-US/grafana.json +++ b/public/locales/en-US/grafana.json @@ -10597,7 +10597,12 @@ } }, "help": { - "aria-label": "Help" + "aria-label": "Help", + "interactive-learning": { + "close-tooltip": "Close interactive learning, help, and documentation", + "open-tooltip": "Open interactive learning, help, and documentation" + }, + "tooltip": "Get help and useful links" }, "invite-user": { "invite-button": "Invite", From 7fbe2e5962c84246f95ecce23a6bb9b1a8223c2c Mon Sep 17 00:00:00 2001 From: Drew Slobodnjak <60050885+drew08t@users.noreply.github.com> Date: Thu, 30 Oct 2025 09:02:09 -0700 Subject: [PATCH 137/378] PanelTimeSettings: Update wording (#113176) * PanelTimeSettings: Update wording * Update wording --- .../panel-timerange/PanelTimeRangeDrawer.tsx | 18 ++++++++---------- public/locales/en-US/grafana.json | 16 ++++++++-------- 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/public/app/features/dashboard-scene/scene/panel-timerange/PanelTimeRangeDrawer.tsx b/public/app/features/dashboard-scene/scene/panel-timerange/PanelTimeRangeDrawer.tsx index 215a5fba5d4..234b2570707 100644 --- a/public/app/features/dashboard-scene/scene/panel-timerange/PanelTimeRangeDrawer.tsx +++ b/public/app/features/dashboard-scene/scene/panel-timerange/PanelTimeRangeDrawer.tsx @@ -100,17 +100,17 @@ export class PanelTimeRangeDrawer extends SceneObjectBase @@ -129,7 +129,7 @@ export class PanelTimeRangeDrawer extends SceneObjectBase - - Time window comparison - + Time comparison @@ -172,10 +170,10 @@ export class PanelTimeRangeDrawer extends SceneObjectBase Date: Thu, 30 Oct 2025 09:12:04 -0700 Subject: [PATCH 138/378] Geomap: Move beta layers to GA (#113186) --- .../visualizations/geomap/index.md | 30 +++++-------------- .../panel/geomap/layers/data/networkLayer.tsx | 2 -- .../panel/geomap/layers/data/photosLayer.tsx | 2 -- .../panel/geomap/layers/data/routeLayer.tsx | 2 -- 4 files changed, 7 insertions(+), 29 deletions(-) diff --git a/docs/sources/visualizations/panels-visualizations/visualizations/geomap/index.md b/docs/sources/visualizations/panels-visualizations/visualizations/geomap/index.md index 241622708db..fe941617bce 100644 --- a/docs/sources/visualizations/panels-visualizations/visualizations/geomap/index.md +++ b/docs/sources/visualizations/panels-visualizations/visualizations/geomap/index.md @@ -218,18 +218,14 @@ There are seven map layer types to choose from in a geomap. - [Heatmap](#heatmap-layer) visualizes a heatmap of the data. - [GeoJSON](#geojson-layer) renders static data from a GeoJSON file. - [Night / Day](#night--day-layer) renders a night / day region. -- [Route (Beta)](#route-layer-beta) render data points as a route. -- [Photos (Beta)](#photos-layer-beta) renders a photo at each data point. -- [Network (Beta)](#network-layer-beta) visualizes a network graph from the data. +- [Route](#route-layer) render data points as a route. +- [Photos](#photos-layer) renders a photo at each data point. +- [Network](#network-layer) visualizes a network graph from the data. - [Open Street Map](#open-street-map-layer) adds a map from a collaborative free geographic world database. - [CARTO basemap](#carto-basemap-layer) adds a layer from CARTO Raster basemaps. - [ArcGIS MapServer](#arcgis-mapserver-layer) adds a layer from an ESRI ArcGIS MapServer. - [XYZ Tile layer](#xyz-tile-layer) adds a map from a generic tile layer. -{{< admonition type="note" >}} -Beta is equivalent to the [public preview](/docs/release-life-cycle/) release stage. -{{< /admonition >}} - There are also two experimental (or alpha) layer types. - **Icon at last point (alpha)** renders an icon at the last data point. @@ -361,11 +357,7 @@ The Night / Day layer displays night and day regions based on the current time r [Extensions for OpenLayers - DayNight](https://viglino.github.io/ol-ext/examples/layer/map.daynight.html) -#### Route layer (Beta) - -{{< admonition type="caution" >}} -The Route layer is currently in [public preview](/docs/release-life-cycle/). Grafana Labs offers limited support, and breaking changes might occur prior to the feature being made generally available. -{{< /admonition >}} +#### Route layer The Route layer renders data points as a route. @@ -390,11 +382,7 @@ The layer can also render a route with arrows. [Extensions for OpenLayers - Flow Line Style](http://viglino.github.io/ol-ext/examples/style/map.style.gpxline.html) -#### Photos layer (Beta) - -{{< admonition type="caution" >}} -The Photos layer is currently in [public preview](/docs/release-life-cycle/). Grafana Labs offers limited support, and breaking changes might occur prior to the feature being made generally available. -{{< /admonition >}} +#### Photos layer The Photos layer renders a photo at each data point. @@ -417,11 +405,7 @@ The Photos layer renders a photo at each data point. [Extensions for OpenLayers - Image Photo Style](http://viglino.github.io/ol-ext/examples/style/map.style.photo.html) -#### Network layer (Beta) - -{{< admonition type="caution" >}} -The Network layer is currently in [public preview](/docs/release-life-cycle/). Grafana Labs offers limited support, and breaking changes might occur prior to the feature being made generally available. -{{< /admonition >}} +#### Network layer The Network layer renders a network graph. This layer supports the same [data format supported by the node graph visualization](ref:data-format) with the addition of [geospatial data](#location-mode) included in the nodes data. The geospatial data is used to locate and render the nodes on the map. @@ -709,7 +693,7 @@ Displays debug information in the upper right corner. This can be useful for deb #### Tooltip -Tooltips are supported for the **Markers**, **Heatmap**, **Photos** (beta) layers. +Tooltips are supported for the **Markers**, **Heatmap**, **Photos** layers. For these layer types, choose from the following tooltip options: - **None** displays tooltips only when a data point is clicked. diff --git a/public/app/plugins/panel/geomap/layers/data/networkLayer.tsx b/public/app/plugins/panel/geomap/layers/data/networkLayer.tsx index e6375e79159..b4b70f77724 100644 --- a/public/app/plugins/panel/geomap/layers/data/networkLayer.tsx +++ b/public/app/plugins/panel/geomap/layers/data/networkLayer.tsx @@ -18,7 +18,6 @@ import { EventBus, DataFrame, Field, - PluginState, } from '@grafana/data'; import { TextDimensionMode } from '@grafana/schema'; import { FrameVectorSource } from 'app/features/geo/utils/frameVectorSource'; @@ -69,7 +68,6 @@ export const networkLayer: MapLayerRegistryItem = { isBaseMap: false, showLocation: true, hideOpacity: true, - state: PluginState.beta, /** * Function that configures transformation and returns a transformer diff --git a/public/app/plugins/panel/geomap/layers/data/photosLayer.tsx b/public/app/plugins/panel/geomap/layers/data/photosLayer.tsx index 86932984cc2..c6e2ad7e402 100644 --- a/public/app/plugins/panel/geomap/layers/data/photosLayer.tsx +++ b/public/app/plugins/panel/geomap/layers/data/photosLayer.tsx @@ -9,7 +9,6 @@ import { PanelData, GrafanaTheme2, EventBus, - PluginState, FieldType, Field, MapLayerOptions, @@ -71,7 +70,6 @@ export const photosLayer: MapLayerRegistryItem = { isBaseMap: false, showLocation: true, hideOpacity: true, - state: PluginState.beta, /** * Function that configures transformation and returns a transformer diff --git a/public/app/plugins/panel/geomap/layers/data/routeLayer.tsx b/public/app/plugins/panel/geomap/layers/data/routeLayer.tsx index 16fd90076bd..ce220dd57f9 100644 --- a/public/app/plugins/panel/geomap/layers/data/routeLayer.tsx +++ b/public/app/plugins/panel/geomap/layers/data/routeLayer.tsx @@ -14,7 +14,6 @@ import { MapLayerRegistryItem, PanelData, GrafanaTheme2, - PluginState, EventBus, DataHoverEvent, DataHoverClearEvent, @@ -79,7 +78,6 @@ export const routeLayer: MapLayerRegistryItem = { description: 'Render data points as a route', isBaseMap: false, showLocation: true, - state: PluginState.beta, /** * Function that configures transformation and returns a transformer From 8d5e5e2eadb2365308f8c17f5804735b29146132 Mon Sep 17 00:00:00 2001 From: Yunwen Zheng Date: Thu, 30 Oct 2025 12:17:06 -0400 Subject: [PATCH 139/378] SaveDashboardAsForm: Adjust form field spacing (#113243) --- .../saving/SaveDashboardAsForm.tsx | 116 +++++++++--------- 1 file changed, 59 insertions(+), 57 deletions(-) diff --git a/public/app/features/dashboard-scene/saving/SaveDashboardAsForm.tsx b/public/app/features/dashboard-scene/saving/SaveDashboardAsForm.tsx index 896c2fa3474..4d90a871440 100644 --- a/public/app/features/dashboard-scene/saving/SaveDashboardAsForm.tsx +++ b/public/app/features/dashboard-scene/saving/SaveDashboardAsForm.tsx @@ -147,64 +147,66 @@ export function SaveDashboardAsForm({ dashboard, changeInfo }: Props) { return ( onSave(false))}> - } - invalid={!!errors.title} - error={errors.title?.message} - > - - - } - invalid={!!errors.description} - error={errors.description?.message} - > -