diff --git a/.citools/src/cog/go.mod b/.citools/src/cog/go.mod index 83bc319bb5e..6a2eab53809 100644 --- a/.citools/src/cog/go.mod +++ b/.citools/src/cog/go.mod @@ -10,7 +10,7 @@ require ( github.com/cockroachdb/apd/v3 v3.2.1 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/emicklei/proto v1.13.2 // indirect - github.com/expr-lang/expr v1.17.0 // indirect + github.com/expr-lang/expr v1.17.7 // indirect github.com/getkin/kin-openapi v0.132.0 // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect github.com/go-openapi/swag v0.23.0 // indirect diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 7ef6be6644c..7843dca6c87 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -24,7 +24,6 @@ /NOTICE.md @torkelo /README.md @grafana/docs-grafana /ROADMAP.md @torkelo -/SECURITY.md @grafana/security-team /SUPPORT.md @torkelo /WORKFLOW.md @torkelo /contribute/ @grafana/grafana-community-support @@ -426,6 +425,7 @@ 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/alerting-suite/ @grafana/alerting-frontend /e2e-playwright/cloud-plugins-suite/ @grafana/partner-datasources /e2e-playwright/dashboard-new-layouts/ @grafana/dashboards-squad /e2e-playwright/dashboard-cujs/ @grafana/dashboards-squad diff --git a/.github/actions/build-package/action.yml b/.github/actions/build-package/action.yml index dd5aaa13650..978c6645240 100644 --- a/.github/actions/build-package/action.yml +++ b/.github/actions/build-package/action.yml @@ -82,14 +82,6 @@ inputs: description: Docker registry of produced images default: docker.io required: false - ubuntu-base: - type: string - default: 'ubuntu:22.04' - required: false - alpine-base: - type: string - default: 'alpine:3.22' - required: false outputs: dist-dir: description: Directory where artifacts are placed @@ -134,13 +126,11 @@ runs: UBUNTU_TAG_FORMAT: ${{ inputs.docker-tag-format-ubuntu }} CHECKSUM: ${{ inputs.checksum }} VERIFY: ${{ inputs.verify }} - ALPINE_BASE: ${{ inputs.alpine-base }} - UBUNTU_BASE: ${{ inputs.ubuntu-base }} with: verb: run dagger-flags: --verbose=0 version: 0.18.8 - args: go run -C ${GRAFANA_PATH} ./pkg/build/cmd artifacts --artifacts ${ARTIFACTS} --grafana-dir=${GRAFANA_PATH} --alpine-base=${ALPINE_BASE} --ubuntu-base=${UBUNTU_BASE} --enterprise-dir=${ENTERPRISE_PATH} --version=${VERSION} --patches-repo=${PATCHES_REPO} --patches-ref=${PATCHES_REF} --patches-path=${PATCHES_PATH} --build-id=${BUILD_ID} --tag-format="${TAG_FORMAT}" --ubuntu-tag-format="${UBUNTU_TAG_FORMAT}" --org=${DOCKER_ORG} --registry=${DOCKER_REGISTRY} --checksum=${CHECKSUM} --verify=${VERIFY} > $OUTFILE + args: go run -C ${GRAFANA_PATH} ./pkg/build/cmd artifacts --artifacts ${ARTIFACTS} --grafana-dir=${GRAFANA_PATH} --enterprise-dir=${ENTERPRISE_PATH} --version=${VERSION} --patches-repo=${PATCHES_REPO} --patches-ref=${PATCHES_REF} --patches-path=${PATCHES_PATH} --build-id=${BUILD_ID} --tag-format="${TAG_FORMAT}" --ubuntu-tag-format="${UBUNTU_TAG_FORMAT}" --org=${DOCKER_ORG} --registry=${DOCKER_REGISTRY} --checksum=${CHECKSUM} --verify=${VERIFY} > $OUTFILE - id: output shell: bash env: diff --git a/.github/actions/change-detection/action.yml b/.github/actions/change-detection/action.yml index 2c6b46606f4..2b8484d7cf6 100644 --- a/.github/actions/change-detection/action.yml +++ b/.github/actions/change-detection/action.yml @@ -95,9 +95,11 @@ runs: - 'nx.json' - 'tsconfig.json' - '.yarn/**' + - 'apps/dashboard/pkg/migration/**' - '${{ inputs.self }}' e2e: - 'e2e/**' + - 'e2e-playwright/**' - '.github/actions/setup-enterprise/**' - '.github/actions/checkout/**' - 'emails/**' diff --git a/.github/pr-commands.json b/.github/pr-commands.json index ab42e204fce..bfff4753773 100644 --- a/.github/pr-commands.json +++ b/.github/pr-commands.json @@ -365,7 +365,9 @@ "type": "changedfiles", "matches": [ "public/app/plugins/panel/gauge/**/*", - "/packages/grafana-ui/src/components/Gauge/**/*" + "public/app/plugins/panel/radialbar/**/*", + "/packages/grafana-ui/src/components/Gauge/**/*", + "/packages/grafana-ui/src/components/RadialGauge/**/*" ], "action": "updateLabel", "addLabel": "area/panel/gauge" diff --git a/.github/workflows/cleanup-branches.yml b/.github/workflows/cleanup-branches.yml index 7f4a6909e6e..7f359309cca 100644 --- a/.github/workflows/cleanup-branches.yml +++ b/.github/workflows/cleanup-branches.yml @@ -14,5 +14,5 @@ jobs: - uses: actions/checkout@v5 - uses: grafana/shared-workflows/actions/cleanup-branches@cleanup-branches/v0.2.1 with: - dry-run: true + dry-run: false max-date: "1 month ago" diff --git a/.github/workflows/release-npm.yml b/.github/workflows/release-npm.yml index 999ccbc5e4a..9c332d0675a 100644 --- a/.github/workflows/release-npm.yml +++ b/.github/workflows/release-npm.yml @@ -90,6 +90,7 @@ jobs: with: persist-credentials: false ref: ${{ inputs.grafana_commit }} + fetch-depth: 2 # Need HEAD~1 for e2e-selectors change detection - name: Setup Node uses: ./.github/actions/setup-node @@ -127,3 +128,43 @@ jobs: env: NPM_TAG: ${{ steps.npm-tag.outputs.NPM_TAG }} run: ./scripts/publish-npm-packages.sh --dist-tag "$NPM_TAG" --registry 'https://registry.npmjs.org/' + + # Notify plugin-tools when e2e-selectors changes so it can update its bundled version + - name: Check for e2e-selectors changes + id: check-e2e-changes + run: | + CHANGES=$(git diff --name-only HEAD~1 HEAD -- packages/grafana-e2e-selectors | wc -l) + echo "changes=$CHANGES" >> "$GITHUB_OUTPUT" + if [ "$CHANGES" -gt 0 ]; then + echo "Detected $CHANGES file(s) changed in packages/grafana-e2e-selectors" + fi + + - name: Get Vault secrets + if: steps.check-e2e-changes.outputs.changes > 0 + id: vault-secrets + uses: grafana/shared-workflows/actions/get-vault-secrets@main + with: + repo_secrets: | + GRAFANA_DELIVERY_BOT_APP_PEM=delivery-bot-app:PRIVATE_KEY + + - name: Generate token for plugin-tools + if: steps.check-e2e-changes.outputs.changes > 0 + id: generate_token + uses: tibdex/github-app-token@3beb63f4bd073e61482598c45c71c1019b59b73a + with: + app_id: ${{ vars.DELIVERY_BOT_APP_ID }} + private_key: ${{ env.GRAFANA_DELIVERY_BOT_APP_PEM }} + repositories: '["plugin-tools"]' + permissions: '{"actions": "write"}' + + - name: Dispatch to plugin-tools + if: steps.check-e2e-changes.outputs.changes > 0 + env: + VERSION: ${{ inputs.version }} + GH_TOKEN: ${{ steps.generate_token.outputs.token }} + run: | + echo "Dispatching bump-e2e-selectors workflow to grafana/plugin-tools with version $VERSION" + gh workflow run bump-e2e-selectors.yml \ + --repo grafana/plugin-tools \ + --ref main \ + --field version="$VERSION" diff --git a/.yarn/patches/@storybook-core-npm-8.6.2-8c752112c0.patch b/.yarn/patches/@storybook-core-npm-8.6.2-8c752112c0.patch new file mode 100644 index 00000000000..730ecce8fb2 --- /dev/null +++ b/.yarn/patches/@storybook-core-npm-8.6.2-8c752112c0.patch @@ -0,0 +1,13 @@ +diff --git a/dist/builder-manager/index.js b/dist/builder-manager/index.js +index 3d7f9b213dae1801bda62b31db31b9113e382ccd..212501c63d20146c29db63fb0f6300c6779eecb5 100644 +--- a/dist/builder-manager/index.js ++++ b/dist/builder-manager/index.js +@@ -1970,7 +1970,7 @@ var pa = /^\/($|\?)/, G, C, xt = /* @__PURE__ */ o(async (e) => { + bundle: !0, + minify: !0, + sourcemap: !1, +- conditions: ["browser", "module", "default"], ++ conditions: ["@grafana-app/source", "browser", "module", "default"], + jsxFactory: "React.createElement", + jsxFragment: "React.Fragment", + jsx: "transform", diff --git a/CHANGELOG.md b/CHANGELOG.md index a4dfcb3171a..6bacfafdfd0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,101 @@ + + +# 12.3.1 (2025-12-16) + +### Features and enhancements + +- **Alerting:** Update alerting dependency [#114259](https://github.com/grafana/grafana/pull/114259), [@moustafab](https://github.com/moustafab) +- **Azure:** Improved column handling in logs query builder [#114841](https://github.com/grafana/grafana/pull/114841), [@aangelisc](https://github.com/aangelisc) +- **Azure:** Include aggregate columns in logs builder [#114835](https://github.com/grafana/grafana/pull/114835), [@aangelisc](https://github.com/aangelisc) +- **Dependencies:** Bump Go to v1.25.5 [#114751](https://github.com/grafana/grafana/pull/114751), [@macabu](https://github.com/macabu) +- **Docs:** Clarify section title for repeating rows and tabs [#115346](https://github.com/grafana/grafana/pull/115346), [@imatwawana](https://github.com/imatwawana) +- **Plugins:** Add PluginContext to plugins when scenes is disabled [#115064](https://github.com/grafana/grafana/pull/115064), [@hugohaggmark](https://github.com/hugohaggmark) +- **QueryEditorRows:** Clear hideSeriesFrom override on query edit [#114628](https://github.com/grafana/grafana/pull/114628), [@Sergej-Vlasov](https://github.com/Sergej-Vlasov) + +### Bug fixes + +- **Azure:** Fix `dcount` aggregation [#114907](https://github.com/grafana/grafana/pull/114907), [@aangelisc](https://github.com/aangelisc) +- **Azure:** Fix `percentile` syntax [#114707](https://github.com/grafana/grafana/pull/114707), [@aangelisc](https://github.com/aangelisc) +- **Dashboards:** Fix empty space under time controls when a dashboard has a lot of variables [#114730](https://github.com/grafana/grafana/pull/114730), [@oscarkilhed](https://github.com/oscarkilhed) +- **Plugins:** Datasource breadcrumb link should link to settings tab [#113910](https://github.com/grafana/grafana/pull/113910), [@wbrowne](https://github.com/wbrowne) +- **Postgresql:** Fix variable interpolation logic when the variable has multiple values [#114876](https://github.com/grafana/grafana/pull/114876), [@itsmylife](https://github.com/itsmylife) + + + + +# 12.2.3 (2025-12-16) + +### Features and enhancements + +- **Alerting:** Update alerting dependency [#114256](https://github.com/grafana/grafana/pull/114256), [@moustafab](https://github.com/moustafab) +- **Azure:** Improved column handling in logs query builder [#114840](https://github.com/grafana/grafana/pull/114840), [@aangelisc](https://github.com/aangelisc) +- **Azure:** Include aggregate columns in logs builder [#114834](https://github.com/grafana/grafana/pull/114834), [@aangelisc](https://github.com/aangelisc) +- **Dependencies:** Bump Go to v1.25.5 [#114753](https://github.com/grafana/grafana/pull/114753), [@macabu](https://github.com/macabu) +- **Plugins:** Add PluginContext to plugins when scenes is disabled [#115063](https://github.com/grafana/grafana/pull/115063), [@hugohaggmark](https://github.com/hugohaggmark) +- **QueryEditorRows:** Clear hideSeriesFrom override on query edit [#114629](https://github.com/grafana/grafana/pull/114629), [@Sergej-Vlasov](https://github.com/Sergej-Vlasov) + +### Bug fixes + +- **Alerting:** Fix contact points issue [#115412](https://github.com/grafana/grafana/pull/115412), [@yuri-tceretian](https://github.com/yuri-tceretian) +- **Azure:** Fix `dcount` aggregation [#114906](https://github.com/grafana/grafana/pull/114906), [@aangelisc](https://github.com/aangelisc) +- **Azure:** Fix `percentile` syntax [#114706](https://github.com/grafana/grafana/pull/114706), [@aangelisc](https://github.com/aangelisc) +- **Postgresql:** Fix variable interpolation logic when the variable has multiple values [#114875](https://github.com/grafana/grafana/pull/114875), [@itsmylife](https://github.com/itsmylife) + + + + +# 12.1.5 (2025-12-16) + +### Features and enhancements + +- **Alerting:** Update alerting dependency [#114254](https://github.com/grafana/grafana/pull/114254), [@moustafab](https://github.com/moustafab) +- **Dependencies:** Bump Go to v1.25.5 [#114755](https://github.com/grafana/grafana/pull/114755), [@macabu](https://github.com/macabu) +- **Docs:** Clarify section title for repeating rows and tabs [#115344](https://github.com/grafana/grafana/pull/115344), [@imatwawana](https://github.com/imatwawana) +- **Plugins:** Add PluginContext to plugins when scenes is disabled [#115062](https://github.com/grafana/grafana/pull/115062), [@hugohaggmark](https://github.com/hugohaggmark) + +### Bug fixes + +- **Alerting:** Fix contact points issue [#115411](https://github.com/grafana/grafana/pull/115411), [@yuri-tceretian](https://github.com/yuri-tceretian) +- **Azure:** Fix `dcount` aggregation [#114905](https://github.com/grafana/grafana/pull/114905), [@aangelisc](https://github.com/aangelisc) +- **Azure:** Fix `percentile` syntax [#114705](https://github.com/grafana/grafana/pull/114705), [@aangelisc](https://github.com/aangelisc) +- **Postgresql:** Fix variable interpolation logic when the variable has multiple values [#114874](https://github.com/grafana/grafana/pull/114874), [@itsmylife](https://github.com/itsmylife) + + + + +# 12.0.8 (2025-12-16) + +### Features and enhancements + +- **Alerting:** Update alerting dependency [#114252](https://github.com/grafana/grafana/pull/114252), [@moustafab](https://github.com/moustafab) +- **Dependencies:** Bump Go to v1.25.5 [#114756](https://github.com/grafana/grafana/pull/114756), [@macabu](https://github.com/macabu) +- **Docs:** Clarify section title for repeating rows and tabs [#115343](https://github.com/grafana/grafana/pull/115343), [@imatwawana](https://github.com/imatwawana) +- **Plugins:** Add PluginContext to plugins when scenes is disabled [#115061](https://github.com/grafana/grafana/pull/115061), [@hugohaggmark](https://github.com/hugohaggmark) + +### Bug fixes + +- **Alerting:** Fix contact points issue [#115410](https://github.com/grafana/grafana/pull/115410), [@yuri-tceretian](https://github.com/yuri-tceretian) +- **Azure:** Fix `dcount` aggregation [#114904](https://github.com/grafana/grafana/pull/114904), [@aangelisc](https://github.com/aangelisc) +- **Azure:** Fix `percentile` syntax [#114704](https://github.com/grafana/grafana/pull/114704), [@aangelisc](https://github.com/aangelisc) +- **Postgresql:** Fix variable interpolation logic when the variable has multiple values [#114873](https://github.com/grafana/grafana/pull/114873), [@itsmylife](https://github.com/itsmylife) + + + + +# 11.6.9 (2025-12-16) + +### Features and enhancements + +- **Alerting:** Update alerting dependency [#114249](https://github.com/grafana/grafana/pull/114249), [@moustafab](https://github.com/moustafab) +- **Dependencies:** Bump Go to v1.25.5 [#114757](https://github.com/grafana/grafana/pull/114757), [@macabu](https://github.com/macabu) +- **PDFTables:** Dynamically shrink font to try and fit whole table in pdf page width (Enterprise) +- **Plugins:** Add PluginContext to plugins when scenes is disabled [#115060](https://github.com/grafana/grafana/pull/115060), [@hugohaggmark](https://github.com/hugohaggmark) + +### Bug fixes + +- **Alerting:** Fix contacts point issues [#115409](https://github.com/grafana/grafana/pull/115409), [@yuri-tceretian](https://github.com/yuri-tceretian) + + # 12.3.0 (2025-11-19) diff --git a/SECURITY.md b/SECURITY.md deleted file mode 100644 index 42c58f9cd67..00000000000 --- a/SECURITY.md +++ /dev/null @@ -1,29 +0,0 @@ -# Reporting security issues - -If you think you have found a security vulnerability, we have two routes for reporting security issues. - -Important: Whichever route you choose, we ask you to not disclose the vulnerability before it has been fixed and announced, unless you received a response from the Grafana Labs security team that you can do so. - -[Full guidance on reporting a security issue can be found here](https://grafana.com/legal/report-a-security-issue/). - -This product is in scope for our Bug Bounty Program. To submit a vulnerability report, please visit [Grafana Labs Bug Bounty page](https://app.intigriti.com/programs/grafanalabs/grafanaossbbp/detail) and follow the instructions provided. Our security team will review your submission and get back to you as soon as possible. - ---- - -For products and services outside the scope of our bug bounty program, or if you do not wish to receive a bounty, you can report issues directly to us via email at security@grafana.com. This address can be used for all of Grafana Labs’ open source and commercial products (including but not limited to Grafana, Grafana Cloud, Grafana Enterprise, and grafana.com). - -Please encrypt your message to us; please use our PGP key. The key fingerprint is: - -225E 6A9B BB15 A37E 95EB 6312 C66A 51CC B44C 27E0 - -The key is available from [keyserver.ubuntu.com](https://keyserver.ubuntu.com/pks/lookup?search=0x225E6A9BBB15A37E95EB6312C66A51CCB44C27E0&fingerprint=on&op=index). - -Grafana Labs will send you a response indicating the next steps in handling your report. After the initial reply to your report, the security team will keep you informed of the progress towards a fix and full announcement, and may ask for additional information or guidance. - -**Important:** We ask you to not disclose the vulnerability before it have been fixed and announced, unless you received a response from the Grafana Labs security team that you can do so. - -## Security announcements - -We will post a summary, remediation, and mitigation details for any patch containing security fixes on the Grafana blog. The security announcement blog posts will be tagged with the [security tag](https://grafana.com/tags/security/). - -You can also track security announcements via the [RSS feed](https://grafana.com/tags/security/index.xml). diff --git a/apps/advisor/go.mod b/apps/advisor/go.mod index 1dc4d93b4f5..c1b2c7acd25 100644 --- a/apps/advisor/go.mod +++ b/apps/advisor/go.mod @@ -8,15 +8,15 @@ require ( github.com/google/go-github/v70 v70.0.0 github.com/grafana/authlib/types v0.0.0-20251119142549-be091cf2f4d4 github.com/grafana/grafana v0.0.0-00010101000000-000000000000 - github.com/grafana/grafana-app-sdk v0.48.5 - github.com/grafana/grafana-app-sdk/logging v0.48.3 + github.com/grafana/grafana-app-sdk v0.48.7 + github.com/grafana/grafana-app-sdk/logging v0.48.7 github.com/grafana/grafana-plugin-sdk-go v0.284.0 github.com/grafana/grafana/pkg/apimachinery v0.0.0 github.com/stretchr/testify v1.11.1 - k8s.io/apimachinery v0.34.2 - k8s.io/apiserver v0.34.2 - k8s.io/client-go v0.34.2 - k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 + k8s.io/apimachinery v0.34.3 + k8s.io/apiserver v0.34.3 + k8s.io/client-go v0.34.3 + k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e ) // transitive dependencies that need replaced @@ -44,7 +44,7 @@ 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 ( - cel.dev/expr v0.24.0 // indirect + cel.dev/expr v0.25.1 // indirect cloud.google.com/go/compute/metadata v0.9.0 // indirect dario.cat/mergo v1.0.2 // indirect filippo.io/edwards25519 v1.1.0 // indirect @@ -81,7 +81,7 @@ require ( github.com/blang/semver v3.5.1+incompatible // indirect github.com/blang/semver/v4 v4.0.0 // indirect github.com/bluele/gcache v0.0.2 // indirect - github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874 // indirect + github.com/bradfitz/gomemcache v0.0.0-20250403215159-8d39553ac7cf // 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.3 // indirect @@ -89,7 +89,7 @@ require ( github.com/cheekybits/genny v1.0.0 // indirect github.com/cloudflare/circl v1.6.1 // indirect github.com/coreos/go-semver v0.3.1 // indirect - github.com/coreos/go-systemd/v22 v22.5.0 // indirect + github.com/coreos/go-systemd/v22 v22.6.0 // 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 @@ -118,22 +118,24 @@ require ( github.com/go-logr/stdr v1.2.2 // 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/jsonpointer v0.22.4 // indirect + github.com/go-openapi/jsonreference v0.21.4 // 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.22.0 // indirect github.com/go-openapi/strfmt v0.24.0 // indirect - github.com/go-openapi/swag v0.23.1 // 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/swag v0.25.4 // indirect + github.com/go-openapi/swag/cmdutils v0.25.4 // indirect + github.com/go-openapi/swag/conv v0.25.4 // indirect + github.com/go-openapi/swag/fileutils v0.25.4 // indirect + github.com/go-openapi/swag/jsonname v0.25.4 // indirect + github.com/go-openapi/swag/jsonutils v0.25.4 // indirect + github.com/go-openapi/swag/loading v0.25.4 // indirect + github.com/go-openapi/swag/mangling v0.25.4 // indirect + github.com/go-openapi/swag/netutils v0.25.4 // indirect + github.com/go-openapi/swag/stringutils v0.25.4 // indirect + github.com/go-openapi/swag/typeutils v0.25.4 // indirect + github.com/go-openapi/swag/yamlutils v0.25.4 // 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 @@ -151,7 +153,7 @@ require ( github.com/google/btree v1.1.3 // indirect github.com/google/cel-go v0.26.1 // indirect github.com/google/flatbuffers v25.2.10+incompatible // indirect - github.com/google/gnostic-models v0.7.0 // indirect + github.com/google/gnostic-models v0.7.1 // indirect github.com/google/go-querystring v1.1.0 // indirect github.com/google/uuid v1.6.0 // indirect github.com/google/wire v0.7.0 // indirect @@ -163,6 +165,7 @@ require ( github.com/grafana/grafana-azure-sdk-go/v2 v2.3.1 // indirect github.com/grafana/grafana/apps/provisioning v0.0.0 // indirect github.com/grafana/grafana/pkg/apiserver v0.0.0 // indirect + github.com/grafana/grafana/pkg/semconv v0.0.0-20250804150913-990f1c69ecc2 // indirect github.com/grafana/otel-profiling-go v0.5.1 // indirect github.com/grafana/pyroscope-go/godeltaprof v0.1.9 // indirect github.com/grafana/sqlds/v4 v4.2.7 // indirect @@ -198,7 +201,7 @@ require ( 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 - github.com/mailru/easyjson v0.9.0 // indirect + github.com/mailru/easyjson v0.9.1 // indirect github.com/mattetti/filebuffer v1.0.1 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect @@ -241,10 +244,10 @@ require ( github.com/prometheus/alertmanager v0.28.2 // 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.3 // indirect + github.com/prometheus/common v0.67.4 // 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/prometheus/procfs v0.19.2 // 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 @@ -256,34 +259,34 @@ require ( github.com/shurcooL/vfsgen v0.0.0-20230704071429-0000e147ea92 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/spf13/cast v1.10.0 // indirect - github.com/spf13/cobra v1.10.1 // indirect + github.com/spf13/cobra v1.10.2 // indirect github.com/spf13/pflag v1.0.10 // indirect github.com/stoewer/go-strcase v1.3.1 // 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 github.com/tjhop/slog-gokit v0.1.5 // indirect - github.com/woodsbury/decimal128 v1.3.0 // indirect + github.com/woodsbury/decimal128 v1.4.0 // indirect github.com/x448/float16 v0.8.4 // indirect github.com/zeebo/xxh3 v1.0.2 // indirect - go.etcd.io/etcd/api/v3 v3.6.4 // indirect - go.etcd.io/etcd/client/pkg/v3 v3.6.4 // indirect - go.etcd.io/etcd/client/v3 v3.6.4 // indirect + go.etcd.io/etcd/api/v3 v3.6.6 // indirect + go.etcd.io/etcd/client/pkg/v3 v3.6.6 // indirect + go.etcd.io/etcd/client/v3 v3.6.6 // indirect go.mongodb.org/mongo-driver v1.17.4 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.64.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/instrumentation/net/http/otelhttp v0.64.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 v1.39.0 // indirect go.opentelemetry.io/otel/exporters/jaeger v1.17.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/otel/exporters/otlp/otlptrace v1.39.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0 // indirect + go.opentelemetry.io/otel/metric v1.39.0 // indirect + go.opentelemetry.io/otel/sdk v1.39.0 // indirect + go.opentelemetry.io/otel/trace v1.39.0 // indirect go.opentelemetry.io/proto/otlp v1.9.0 // indirect go.uber.org/atomic v1.11.0 // indirect go.uber.org/mock v0.6.0 // indirect @@ -291,28 +294,28 @@ require ( go.uber.org/zap v1.27.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.45.0 // indirect - golang.org/x/exp v0.0.0-20251002181428-27f1f14c8bb9 // indirect - golang.org/x/mod v0.30.0 // indirect - golang.org/x/net v0.47.0 // indirect - golang.org/x/oauth2 v0.33.0 // indirect - golang.org/x/sync v0.18.0 // indirect - golang.org/x/sys v0.38.0 // indirect - golang.org/x/telemetry v0.0.0-20251111182119-bc8e575c7b54 // indirect - golang.org/x/term v0.37.0 // indirect - golang.org/x/text v0.31.0 // indirect + golang.org/x/crypto v0.46.0 // indirect + golang.org/x/exp v0.0.0-20251209150349-8475f28825e9 // indirect + golang.org/x/mod v0.31.0 // indirect + golang.org/x/net v0.48.0 // indirect + golang.org/x/oauth2 v0.34.0 // indirect + golang.org/x/sync v0.19.0 // indirect + golang.org/x/sys v0.39.0 // indirect + golang.org/x/telemetry v0.0.0-20251203150158-8fff8a5912fc // indirect + golang.org/x/term v0.38.0 // indirect + golang.org/x/text v0.32.0 // indirect golang.org/x/time v0.14.0 // indirect - golang.org/x/tools v0.39.0 // indirect + golang.org/x/tools v0.40.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 gonum.org/v1/gonum v0.16.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20251111163417-95abcf5c77ba // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2 // indirect google.golang.org/grpc v1.77.0 // indirect - google.golang.org/protobuf v1.36.10 // indirect + google.golang.org/protobuf v1.36.11 // indirect gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect - gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect + gopkg.in/evanphx/json-patch.v4 v4.13.0 // 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 @@ -321,18 +324,18 @@ require ( 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.34.2 // indirect - k8s.io/apiextensions-apiserver v0.34.2 // indirect - k8s.io/component-base v0.34.2 // indirect + k8s.io/api v0.34.3 // indirect + k8s.io/apiextensions-apiserver v0.34.3 // indirect + k8s.io/component-base v0.34.3 // indirect k8s.io/klog/v2 v2.130.1 // indirect - k8s.io/kms v0.34.2 // indirect - k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 // indirect + k8s.io/kms v0.34.3 // indirect + k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 // indirect modernc.org/libc v1.66.10 // indirect modernc.org/mathutil v1.7.1 // indirect modernc.org/memory v1.11.0 // indirect modernc.org/sqlite v1.40.1 // indirect - sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2 // indirect - sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect + sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.34.0 // indirect + sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect sigs.k8s.io/randfill v1.0.0 // indirect sigs.k8s.io/structured-merge-diff/v6 v6.3.1 // indirect sigs.k8s.io/yaml v1.6.0 // indirect diff --git a/apps/advisor/go.sum b/apps/advisor/go.sum index 4c5843a2ee2..760641a8857 100644 --- a/apps/advisor/go.sum +++ b/apps/advisor/go.sum @@ -1,5 +1,5 @@ -cel.dev/expr v0.24.0 h1:56OvJKSH3hDGL0ml5uSxZmz3/3Pq4tJ+fb1unVLAFcY= -cel.dev/expr v0.24.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw= +cel.dev/expr v0.25.1 h1:1KrZg61W6TWSxuNZ37Xy49ps13NUovb66QLprthtwi4= +cel.dev/expr v0.25.1/go.mod h1:hrXvqGP6G6gyx8UAHSHJ5RGk//1Oj5nXQ2NI02Nrsg4= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7hw= @@ -228,8 +228,8 @@ github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2y github.com/bluele/gcache v0.0.2 h1:WcbfdXICg7G/DGBh1PFfcirkWOQV+v077yF1pSy3DGw= github.com/bluele/gcache v0.0.2/go.mod h1:m15KV+ECjptwSPxKhOhQoAFQVtUFjTVkc3H8o0t/fp0= 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/bradfitz/gomemcache v0.0.0-20250403215159-8d39553ac7cf h1:TqhNAT4zKbTdLa62d2HDBFdvgSbIGB3eJE8HqhgiL9I= +github.com/bradfitz/gomemcache v0.0.0-20250403215159-8d39553ac7cf/go.mod h1:r5xuitiExdLAJ09PR7vBVENGvp4ZuTBeWTGtxuX3K+c= 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= @@ -280,8 +280,8 @@ github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3Ee github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4= github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= -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/coreos/go-systemd/v22 v22.6.0 h1:aGVa/v8B7hpb0TKl0MWoAavPDmHvobFe5R5zn0bCJWo= +github.com/coreos/go-systemd/v22 v22.6.0/go.mod h1:iG+pp635Fo7ZmV/j14KUcmEyWF+0X7Lua8rrTWzYgWU= github.com/cpuguy83/go-md2man/v2 v2.0.6/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= @@ -413,10 +413,10 @@ github.com/go-openapi/analysis v0.24.0 h1:vE/VFFkICKyYuTWYnplQ+aVr45vlG6NcZKC7Bd 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/jsonpointer v0.22.4 h1:dZtK82WlNpVLDW2jlA1YCiVJFVqkED1MegOUy9kR5T4= +github.com/go-openapi/jsonpointer v0.22.4/go.mod h1:elX9+UgznpFhgBuaMQ7iu4lvvX1nvNsesQ3oxmYTw80= +github.com/go-openapi/jsonreference v0.21.4 h1:24qaE2y9bx/q3uRK/qN+TDwbok1NhbSmGjjySRCHtC8= +github.com/go-openapi/jsonreference v0.21.4/go.mod h1:rIENPTjDbLpzQmQWCj5kKj3ZlmEh+EFVbz3RTUh30/4= 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= @@ -425,28 +425,36 @@ github.com/go-openapi/spec v0.22.0 h1:xT/EsX4frL3U09QviRIZXvkh80yibxQmtoEvyqug0T 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.1 h1:lpsStH0n2ittzTnbaSloVZLuB5+fvSY/+hnagBjSNZU= -github.com/go-openapi/swag v0.23.1/go.mod h1:STZs8TbRvEQQKUA+JZNAm3EWlgaOBGpyFDqQnDHMef0= -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/swag v0.25.4 h1:OyUPUFYDPDBMkqyxOTkqDYFnrhuhi9NR6QVUvIochMU= +github.com/go-openapi/swag v0.25.4/go.mod h1:zNfJ9WZABGHCFg2RnY0S4IOkAcVTzJ6z2Bi+Q4i6qFQ= +github.com/go-openapi/swag/cmdutils v0.25.4 h1:8rYhB5n6WawR192/BfUu2iVlxqVR9aRgGJP6WaBoW+4= +github.com/go-openapi/swag/cmdutils v0.25.4/go.mod h1:pdae/AFo6WxLl5L0rq87eRzVPm/XRHM3MoYgRMvG4A0= +github.com/go-openapi/swag/conv v0.25.4 h1:/Dd7p0LZXczgUcC/Ikm1+YqVzkEeCc9LnOWjfkpkfe4= +github.com/go-openapi/swag/conv v0.25.4/go.mod h1:3LXfie/lwoAv0NHoEuY1hjoFAYkvlqI/Bn5EQDD3PPU= +github.com/go-openapi/swag/fileutils v0.25.4 h1:2oI0XNW5y6UWZTC7vAxC8hmsK/tOkWXHJQH4lKjqw+Y= +github.com/go-openapi/swag/fileutils v0.25.4/go.mod h1:cdOT/PKbwcysVQ9Tpr0q20lQKH7MGhOEb6EwmHOirUk= +github.com/go-openapi/swag/jsonname v0.25.4 h1:bZH0+MsS03MbnwBXYhuTttMOqk+5KcQ9869Vye1bNHI= +github.com/go-openapi/swag/jsonname v0.25.4/go.mod h1:GPVEk9CWVhNvWhZgrnvRA6utbAltopbKwDu8mXNUMag= +github.com/go-openapi/swag/jsonutils v0.25.4 h1:VSchfbGhD4UTf4vCdR2F4TLBdLwHyUDTd1/q4i+jGZA= +github.com/go-openapi/swag/jsonutils v0.25.4/go.mod h1:7OYGXpvVFPn4PpaSdPHJBtF0iGnbEaTk8AvBkoWnaAY= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4 h1:IACsSvBhiNJwlDix7wq39SS2Fh7lUOCJRmx/4SN4sVo= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4/go.mod h1:Mt0Ost9l3cUzVv4OEZG+WSeoHwjWLnarzMePNDAOBiM= +github.com/go-openapi/swag/loading v0.25.4 h1:jN4MvLj0X6yhCDduRsxDDw1aHe+ZWoLjW+9ZQWIKn2s= +github.com/go-openapi/swag/loading v0.25.4/go.mod h1:rpUM1ZiyEP9+mNLIQUdMiD7dCETXvkkC30z53i+ftTE= +github.com/go-openapi/swag/mangling v0.25.4 h1:2b9kBJk9JvPgxr36V23FxJLdwBrpijI26Bx5JH4Hp48= +github.com/go-openapi/swag/mangling v0.25.4/go.mod h1:6dxwu6QyORHpIIApsdZgb6wBk/DPU15MdyYj/ikn0Hg= +github.com/go-openapi/swag/netutils v0.25.4 h1:Gqe6K71bGRb3ZQLusdI8p/y1KLgV4M/k+/HzVSqT8H0= +github.com/go-openapi/swag/netutils v0.25.4/go.mod h1:m2W8dtdaoX7oj9rEttLyTeEFFEBvnAx9qHd5nJEBzYg= +github.com/go-openapi/swag/stringutils v0.25.4 h1:O6dU1Rd8bej4HPA3/CLPciNBBDwZj9HiEpdVsb8B5A8= +github.com/go-openapi/swag/stringutils v0.25.4/go.mod h1:GTsRvhJW5xM5gkgiFe0fV3PUlFm0dr8vki6/VSRaZK0= +github.com/go-openapi/swag/typeutils v0.25.4 h1:1/fbZOUN472NTc39zpa+YGHn3jzHWhv42wAJSN91wRw= +github.com/go-openapi/swag/typeutils v0.25.4/go.mod h1:Ou7g//Wx8tTLS9vG0UmzfCsjZjKhpjxayRKTHXf2pTE= +github.com/go-openapi/swag/yamlutils v0.25.4 h1:6jdaeSItEUb7ioS9lFoCZ65Cne1/RZtPBZ9A56h92Sw= +github.com/go-openapi/swag/yamlutils v0.25.4/go.mod h1:MNzq1ulQu+yd8Kl7wPOut/YHAAU/H6hL91fF+E2RFwc= +github.com/go-openapi/testify/enable/yaml/v2 v2.0.2 h1:0+Y41Pz1NkbTHz8NngxTuAXxEodtNSI1WG1c/m5Akw4= +github.com/go-openapi/testify/enable/yaml/v2 v2.0.2/go.mod h1:kme83333GCtJQHXQ8UKX3IBZu6z8T5Dvy5+CW3NLUUg= +github.com/go-openapi/testify/v2 v2.0.2 h1:X999g3jeLcoY8qctY/c/Z8iBHTbwLz7R2WXd6Ub6wls= +github.com/go-openapi/testify/v2 v2.0.2/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= 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= @@ -537,8 +545,8 @@ 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.7.0 h1:qwTtogB15McXDaNqTZdzPJRHvaVJlAl+HVQnLmJEJxo= -github.com/google/gnostic-models v0.7.0/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ= +github.com/google/gnostic-models v0.7.1 h1:SisTfuFKJSKM5CPZkffwi6coztzzeYUhc3v4yxLWH8c= +github.com/google/gnostic-models v0.7.1/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= @@ -623,10 +631,10 @@ github.com/grafana/dataplane/sdata v0.0.9 h1:AGL1LZnCUG4MnQtnWpBPbQ8ZpptaZs14w6k github.com/grafana/dataplane/sdata v0.0.9/go.mod h1:Jvs5ddpGmn6vcxT7tCTWAZ1mgi4sbcdFt9utQx5uMAU= 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.5 h1:MS8l9fTZz+VbTfgApn09jw27GxhQ6fNOWGhC4ydvZmM= -github.com/grafana/grafana-app-sdk v0.48.5/go.mod h1:HJsMOSBmt/D/Ihs1SvagOwmXKi0coBMVHlfvdd+qe9Y= -github.com/grafana/grafana-app-sdk/logging v0.48.3 h1:72NUpGNiJXCNQz/on++YSsl38xuVYYBKv5kKQaOClX4= -github.com/grafana/grafana-app-sdk/logging v0.48.3/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA= +github.com/grafana/grafana-app-sdk v0.48.7 h1:9mF7nqkqP0QUYYDlznoOt+GIyjzj45wGfUHB32u2ZMo= +github.com/grafana/grafana-app-sdk v0.48.7/go.mod h1:DWsaaH39ZMHwSOSoUBaeW8paMrRaYsjRYlLwCJYd78k= +github.com/grafana/grafana-app-sdk/logging v0.48.7 h1:Oa5qg473gka5+W/WQk61Xbw4YdAv+wV2Z4bJtzeCaQw= +github.com/grafana/grafana-app-sdk/logging v0.48.7/go.mod h1:5u3KalezoBAAo2Y3ytDYDAIIPvEqFLLDSxeiK99QxDU= github.com/grafana/grafana-aws-sdk v1.3.0 h1:/bfJzP93rCel1GbWoRSq0oUo424MZXt8jAp2BK9w8tM= github.com/grafana/grafana-aws-sdk v1.3.0/go.mod h1:VGycF0JkCGKND2O5je1ucOqPJ0ZNhZYzV3c2bNBAaGk= github.com/grafana/grafana-azure-sdk-go/v2 v2.3.1 h1:FFcEA01tW+SmuJIuDbHOdgUBL+d7DPrZ2N4zwzPhfGk= @@ -818,8 +826,8 @@ 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/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= -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/mailru/easyjson v0.9.1 h1:LbtsOm5WAswyWbvTEOqhypdPeZzHavpZx96/n553mR8= +github.com/mailru/easyjson v0.9.1/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= github.com/mattbaird/jsonpatch v0.0.0-20240118010651-0ba75a80ca38 h1:hQWBtNqRYrI7CWIaUSXXtNKR90KzcUA5uiuxFVWw7sU= github.com/mattbaird/jsonpatch v0.0.0-20240118010651-0ba75a80ca38/go.mod h1:M1qoD/MqPgTZIk0EWKB38wE28ACRfVcn+cU08jyArI0= github.com/mattetti/filebuffer v1.0.1 h1:gG7pyfnSIZCxdoKq+cPa8T0hhYtD9NxCdI4D7PTjRLM= @@ -1012,8 +1020,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.67.3 h1:shd26MlnwTw5jksTDhC7rTQIteBxy+ZZDr3t7F2xN2Q= -github.com/prometheus/common v0.67.3/go.mod h1:gP0fq6YjjNCLssJCQp0yk4M8W6ikLURwkdd/YKtTbyI= +github.com/prometheus/common v0.67.4 h1:yR3NqWO1/UyO1w2PhUvXlGQs/PtFmoveVO0KZ4+Lvsc= +github.com/prometheus/common v0.67.4/go.mod h1:gP0fq6YjjNCLssJCQp0yk4M8W6ikLURwkdd/YKtTbyI= 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= @@ -1025,8 +1033,8 @@ github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsT github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= -github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= +github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws= +github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw= github.com/prometheus/prometheus v0.303.1 h1:He/2jRE6sB23Ew38AIoR1WRR3fCMgPlJA2E0obD2WSY= github.com/prometheus/prometheus v0.303.1/go.mod h1:WEq2ogBPZoLjj9x5K67VEk7ECR0nRD9XCjaOt1lsYck= github.com/puzpuzpuz/xsync/v2 v2.5.1 h1:mVGYAvzDSu52+zaGyNjC+24Xw2bQi3kTr4QJ6N9pIIU= @@ -1080,8 +1088,8 @@ github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8 github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= 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/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU= +github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4= 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.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= @@ -1139,8 +1147,8 @@ github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZ 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/woodsbury/decimal128 v1.4.0 h1:xJATj7lLu4f2oObouMt2tgGiElE5gO6mSWUjQsBgUlc= +github.com/woodsbury/decimal128 v1.4.0/go.mod h1:BP46FUrVjVhdTbKT+XuQh2xfQaGki9LMIRJSFuh6THU= 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= @@ -1161,15 +1169,15 @@ gitlab.com/nyarla/go-crypt v0.0.0-20160106005555-d9a5dc2b789b/go.mod h1:T3BPAOm2 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.6.4 h1:7F6N7toCKcV72QmoUKa23yYLiiljMrT4xCeBL9BmXdo= -go.etcd.io/etcd/api/v3 v3.6.4/go.mod h1:eFhhvfR8Px1P6SEuLT600v+vrhdDTdcfMzmnxVXXSbk= +go.etcd.io/etcd/api/v3 v3.6.6 h1:mcaMp3+7JawWv69p6QShYWS8cIWUOl32bFLb6qf8pOQ= +go.etcd.io/etcd/api/v3 v3.6.6/go.mod h1:f/om26iXl2wSkcTA1zGQv8reJRSLVdoEBsi4JdfMrx4= go.etcd.io/etcd/client/pkg/v3 v3.5.4/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= -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/pkg/v3 v3.6.6 h1:uoqgzSOv2H9KlIF5O1Lsd8sW+eMLuV6wzE3q5GJGQNs= +go.etcd.io/etcd/client/pkg/v3 v3.6.6/go.mod h1:YngfUVmvsvOJ2rRgStIyHsKtOt9SZI2aBJrZiWJhCbI= 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.6.4 h1:YOMrCfMhRzY8NgtzUsHl8hC2EBSnuqbR3dh84Uryl7A= -go.etcd.io/etcd/client/v3 v3.6.4/go.mod h1:jaNNHCyg2FdALyKWnd7hxZXZxZANb0+KGY+YQaEMISo= +go.etcd.io/etcd/client/v3 v3.6.6 h1:G5z1wMf5B9SNexoxOHUGBaULurOZPIgGPsW6CN492ec= +go.etcd.io/etcd/client/v3 v3.6.6/go.mod h1:36Qv6baQ07znPR3+n7t+Rk5VHEzVYPvFfGmfF4wBHV8= go.etcd.io/etcd/pkg/v3 v3.6.4 h1:fy8bmXIec1Q35/jRZ0KOes8vuFxbvdN0aAFqmEfJZWA= go.etcd.io/etcd/pkg/v3 v3.6.4/go.mod h1:kKcYWP8gHuBRcteyv6MXWSN0+bVMnfgqiHueIZnKMtE= go.etcd.io/etcd/server/v3 v3.6.4 h1:LsCA7CzjVt+8WGrdsnh6RhC0XqCsLkBly3ve5rTxMAU= @@ -1195,19 +1203,19 @@ go.opentelemetry.io/contrib/detectors/gcp v1.38.0 h1:ZoYbqX7OaA/TAikspPl3ozPI6iY go.opentelemetry.io/contrib/detectors/gcp v1.38.0/go.mod h1:SU+iU7nu5ud4oCb3LQOhIZ3nRLj6FNVrKgtflbaf2ts= 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= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0/go.mod h1:fvPi2qXDqFs8M4B4fmJhE92TyQs9Ydjlg3RvfUp+NbQ= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.64.0 h1:RN3ifU8y4prNWeEnQp2kRRHz8UwonAEYZl8tUzHEXAk= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.64.0/go.mod h1:habDz3tEWiFANTo6oUE99EmaFUrCNYAAg3wiVmusm70= 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/instrumentation/net/http/otelhttp v0.64.0 h1:ssfIgGNANqpVFCndZvcuyKbl0g+UAVcbBcqGkG28H0Y= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.64.0/go.mod h1:GQ/474YrbE4Jx8gZ4q5I4hrhUzM6UPzyrqJYV2AqPoQ= 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.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= -go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= +go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48= +go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8= 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= @@ -1218,12 +1226,12 @@ go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0 h1:vl9 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/otlp/otlptrace v1.39.0 h1:f0cb2XPmrqn4XMy9PNliTgRKJgS5WcL/u0/WRYGz4t0= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0/go.mod h1:vnakAaFckOMiMtOIhFI2MNH4FYrZzXCYxmb1LlhoGz8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0 h1:in9O8ESIOlwJAEGTkkf34DesGRAc/Pn8qJ7k3r/42LM= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0/go.mod h1:Rp0EXBm5tfnv0WL+ARyO/PHBEaEAT8UUHQ6AGJcSq6c= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0 h1:Ckwye2FpXkYgiHX7fyVrN1uA/UYd9ounqqTuSNAv0k4= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0/go.mod h1:teIFJh5pW2y+AN7riv6IBPX2DuesS3HgP39mwOspKwU= 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= @@ -1235,18 +1243,18 @@ go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0/go.mod h1:mgIOzS7i 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.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= -go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= +go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0= +go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs= go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E= -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 v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18= +go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE= 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.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= -go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= +go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8= +go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew= go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ= -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/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI= +go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.opentelemetry.io/proto/otlp v1.9.0 h1:l706jCMITVouPOqEnii2fIAuO3IVGBRPV5ICjceRb/A= go.opentelemetry.io/proto/otlp v1.9.0/go.mod h1:xE+Cx5E/eEHw+ISFkwPLwCZefwVjY+pqKg1qcK03+/4= @@ -1282,8 +1290,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.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q= -golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4= +golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU= +golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0= 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= @@ -1294,8 +1302,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-20251002181428-27f1f14c8bb9 h1:TQwNpfvNkxAVlItJf6Cr5JTsVZoC/Sj7K3OZv2Pc14A= -golang.org/x/exp v0.0.0-20251002181428-27f1f14c8bb9/go.mod h1:TwQYMMnGpvZyc+JpB/UAuTNIsVJifOlSkrZkhcvpVUk= +golang.org/x/exp v0.0.0-20251209150349-8475f28825e9 h1:MDfG8Cvcqlt9XXrmEiD4epKn7VJHZO84hejP9Jmp0MM= +golang.org/x/exp v0.0.0-20251209150349-8475f28825e9/go.mod h1:EPRbTFwzwjXj9NpYyyrvenVh9Y+GFeEvMNh7Xuz7xgU= 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= @@ -1321,8 +1329,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.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk= -golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc= +golang.org/x/mod v0.31.0 h1:HaW9xtz0+kOcWKwli0ZXy79Ix+UW/vOfmWI5QVd2tgI= +golang.org/x/mod v0.31.0/go.mod h1:43JraMp9cGx1Rx3AqioxrbrhNsLl2l/iNAvuBkrezpg= 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= @@ -1377,8 +1385,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.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= -golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= +golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= +golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= 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= @@ -1401,8 +1409,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.33.0 h1:4Q+qn+E5z8gPRJfmRy7C2gGG3T4jIprK6aSYgTXGRpo= -golang.org/x/oauth2 v0.33.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= +golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw= +golang.org/x/oauth2 v0.34.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= @@ -1415,8 +1423,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.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= -golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.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= @@ -1505,14 +1513,14 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 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.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= -golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/telemetry v0.0.0-20251111182119-bc8e575c7b54 h1:E2/AqCUMZGgd73TQkxUMcMla25GB9i/5HOdLr+uH7Vo= -golang.org/x/telemetry v0.0.0-20251111182119-bc8e575c7b54/go.mod h1:hKdjCMrbv9skySur+Nek8Hd0uJ0GuxJIoIX2payrIdQ= +golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= +golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/telemetry v0.0.0-20251203150158-8fff8a5912fc h1:bH6xUXay0AIFMElXG2rQ4uiE+7ncwtiOdPfYK1NK2XA= +golang.org/x/telemetry v0.0.0-20251203150158-8fff8a5912fc/go.mod h1:hKdjCMrbv9skySur+Nek8Hd0uJ0GuxJIoIX2payrIdQ= 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.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU= -golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254= +golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q= +golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg= 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= @@ -1522,8 +1530,8 @@ 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.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= -golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= +golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= +golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= 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= @@ -1587,8 +1595,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.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ= -golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ= +golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA= +golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc= 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= @@ -1735,10 +1743,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-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-20251111163417-95abcf5c77ba h1:B14OtaXuMaCQsl2deSvNkyPKIzq3BjfxQp8d00QyWx4= -google.golang.org/genproto/googleapis/api v0.0.0-20251111163417-95abcf5c77ba/go.mod h1:G5IanEx8/PgI9w6CFcYQf7jMtHQhZruvfM1i3qOqk5U= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba h1:UKgtfRM7Yh93Sya0Fo8ZzhDP4qBckrrxEr2oF5UIVb8= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= +google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2 h1:7LRqPCEdE4TP4/9psdaB7F2nhZFfBiGJomA5sojLWdU= +google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2/go.mod h1:+rXWjjaukWZun3mLfjmVnQi18E1AsFbDN9QdJ5YXLto= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2 h1:2I6GHUeJ/4shcDpoUlLs/2WPnhg7yJwvXtqcMJt9liA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.18.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= @@ -1788,8 +1796,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.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= -google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/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= @@ -1799,8 +1807,8 @@ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8 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/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -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/evanphx/json-patch.v4 v4.13.0 h1:czT3CmqEaQ1aanPc5SdlgQrrEIb8w/wwCvWWnfEbYzo= +gopkg.in/evanphx/json-patch.v4 v4.13.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= @@ -1837,26 +1845,26 @@ 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.34.2 h1:fsSUNZhV+bnL6Aqrp6O7lMTy6o5x2C4XLjnh//8SLYY= -k8s.io/api v0.34.2/go.mod h1:MMBPaWlED2a8w4RSeanD76f7opUoypY8TFYkSM+3XHw= -k8s.io/apiextensions-apiserver v0.34.2 h1:WStKftnGeoKP4AZRz/BaAAEJvYp4mlZGN0UCv+uvsqo= -k8s.io/apiextensions-apiserver v0.34.2/go.mod h1:398CJrsgXF1wytdaanynDpJ67zG4Xq7yj91GrmYN2SE= -k8s.io/apimachinery v0.34.2 h1:zQ12Uk3eMHPxrsbUJgNF8bTauTVR2WgqJsTmwTE/NW4= -k8s.io/apimachinery v0.34.2/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= -k8s.io/apiserver v0.34.2 h1:2/yu8suwkmES7IzwlehAovo8dDE07cFRC7KMDb1+MAE= -k8s.io/apiserver v0.34.2/go.mod h1:gqJQy2yDOB50R3JUReHSFr+cwJnL8G1dzTA0YLEqAPI= -k8s.io/client-go v0.34.2 h1:Co6XiknN+uUZqiddlfAjT68184/37PS4QAzYvQvDR8M= -k8s.io/client-go v0.34.2/go.mod h1:2VYDl1XXJsdcAxw7BenFslRQX28Dxz91U9MWKjX97fE= -k8s.io/component-base v0.34.2 h1:HQRqK9x2sSAsd8+R4xxRirlTjowsg6fWCPwWYeSvogQ= -k8s.io/component-base v0.34.2/go.mod h1:9xw2FHJavUHBFpiGkZoKuYZ5pdtLKe97DEByaA+hHbM= +k8s.io/api v0.34.3 h1:D12sTP257/jSH2vHV2EDYrb16bS7ULlHpdNdNhEw2S4= +k8s.io/api v0.34.3/go.mod h1:PyVQBF886Q5RSQZOim7DybQjAbVs8g7gwJNhGtY5MBk= +k8s.io/apiextensions-apiserver v0.34.3 h1:p10fGlkDY09eWKOTeUSioxwLukJnm+KuDZdrW71y40g= +k8s.io/apiextensions-apiserver v0.34.3/go.mod h1:aujxvqGFRdb/cmXYfcRTeppN7S2XV/t7WMEc64zB5A0= +k8s.io/apimachinery v0.34.3 h1:/TB+SFEiQvN9HPldtlWOTp0hWbJ+fjU+wkxysf/aQnE= +k8s.io/apimachinery v0.34.3/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= +k8s.io/apiserver v0.34.3 h1:uGH1qpDvSiYG4HVFqc6A3L4CKiX+aBWDrrsxHYK0Bdo= +k8s.io/apiserver v0.34.3/go.mod h1:QPnnahMO5C2m3lm6fPW3+JmyQbvHZQ8uudAu/493P2w= +k8s.io/client-go v0.34.3 h1:wtYtpzy/OPNYf7WyNBTj3iUA0XaBHVqhv4Iv3tbrF5A= +k8s.io/client-go v0.34.3/go.mod h1:OxxeYagaP9Kdf78UrKLa3YZixMCfP6bgPwPwNBQBzpM= +k8s.io/component-base v0.34.3 h1:zsEgw6ELqK0XncCQomgO9DpUIzlrYuZYA0Cgo+JWpVk= +k8s.io/component-base v0.34.3/go.mod h1:5iIlD8wPfWE/xSHTRfbjuvUul2WZbI2nOUK65XL0E/c= 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.34.2 h1:91rj4MDZLyIT9KxG8J5/CcMH666Z88CF/xJQeuPfJc8= -k8s.io/kms v0.34.2/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= +k8s.io/kms v0.34.3 h1:QzBOD0sk1bGQVMcZQAHGjtbP1iKZJUyhC6D0I+BTxIE= +k8s.io/kms v0.34.3/go.mod h1:s1CFkLG7w9eaTYvctOxosx88fl4spqmixnNpys0JAtM= +k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e h1:iW9ChlU0cU16w8MpVYjXk12dqQ4BPFBEgif+ap7/hqQ= +k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e/go.mod h1:kdmbQkyfwUagLfXIad1y2TdrjPFWp2Q89B3qkRwf/pQ= +k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 h1:SjGebBtkBqHFOli+05xYbK8YF1Dzkbzn+gDM4X9T4Ck= +k8s.io/utils v0.0.0-20251002143259-bc988d571ff4/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= @@ -1886,10 +1894,10 @@ modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= -sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2 h1:jpcvIRr3GLoUoEKRkHKSmGjxb6lWwrBlJsXc+eUYQHM= -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/apiserver-network-proxy/konnectivity-client v0.34.0 h1:hSfpvjjTQXQY2Fol2CS0QHMNs/WI1MOSGzCm1KhM5ec= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.34.0/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw= +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg= +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/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.1 h1:JrhdFMqOd/+3ByqlP2I45kTOZmTRLBUm5pvRjeheg7E= diff --git a/apps/alerting/alertenrichment/go.mod b/apps/alerting/alertenrichment/go.mod index bb020e52bff..792ad18eeac 100644 --- a/apps/alerting/alertenrichment/go.mod +++ b/apps/alerting/alertenrichment/go.mod @@ -3,38 +3,48 @@ module github.com/grafana/grafana/apps/alerting/alertenrichment go 1.25.5 require ( - github.com/grafana/grafana-app-sdk v0.48.5 + github.com/grafana/grafana-app-sdk v0.48.7 github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250901080157-a0280d701b28 - k8s.io/apimachinery v0.34.2 - k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 + k8s.io/apimachinery v0.34.3 + k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e ) require ( github.com/emicklei/go-restful/v3 v3.13.0 // indirect github.com/fxamacker/cbor/v2 v2.9.0 // indirect github.com/go-logr/logr v1.4.3 // 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.1 // indirect - github.com/go-openapi/swag/jsonname v0.25.1 // indirect + github.com/go-openapi/jsonpointer v0.22.4 // indirect + github.com/go-openapi/jsonreference v0.21.4 // indirect + github.com/go-openapi/swag v0.25.4 // indirect + github.com/go-openapi/swag/cmdutils v0.25.4 // indirect + github.com/go-openapi/swag/conv v0.25.4 // indirect + github.com/go-openapi/swag/fileutils v0.25.4 // indirect + github.com/go-openapi/swag/jsonname v0.25.4 // indirect + github.com/go-openapi/swag/jsonutils v0.25.4 // indirect + github.com/go-openapi/swag/loading v0.25.4 // indirect + github.com/go-openapi/swag/mangling v0.25.4 // indirect + github.com/go-openapi/swag/netutils v0.25.4 // indirect + github.com/go-openapi/swag/stringutils v0.25.4 // indirect + github.com/go-openapi/swag/typeutils v0.25.4 // indirect + github.com/go-openapi/swag/yamlutils v0.25.4 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/google/gnostic-models v0.7.0 // indirect - github.com/josharian/intern v1.0.0 // indirect + github.com/google/gnostic-models v0.7.1 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/mailru/easyjson v0.9.0 // indirect + github.com/kr/pretty v0.3.1 // 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/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.47.0 // indirect - golang.org/x/text v0.31.0 // indirect - google.golang.org/protobuf v1.36.10 // indirect + golang.org/x/net v0.48.0 // indirect + golang.org/x/text v0.32.0 // indirect + google.golang.org/protobuf v1.36.11 // indirect + gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v3 v3.0.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 + k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 // indirect + sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect sigs.k8s.io/randfill v1.0.0 // indirect sigs.k8s.io/structured-merge-diff/v6 v6.3.1 // indirect ) diff --git a/apps/alerting/alertenrichment/go.sum b/apps/alerting/alertenrichment/go.sum index ef36568611c..9b83516bea0 100644 --- a/apps/alerting/alertenrichment/go.sum +++ b/apps/alerting/alertenrichment/go.sum @@ -1,3 +1,4 @@ +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= @@ -8,46 +9,73 @@ github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sa github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= 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-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.1 h1:lpsStH0n2ittzTnbaSloVZLuB5+fvSY/+hnagBjSNZU= -github.com/go-openapi/swag v0.23.1/go.mod h1:STZs8TbRvEQQKUA+JZNAm3EWlgaOBGpyFDqQnDHMef0= -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/jsonpointer v0.22.4 h1:dZtK82WlNpVLDW2jlA1YCiVJFVqkED1MegOUy9kR5T4= +github.com/go-openapi/jsonpointer v0.22.4/go.mod h1:elX9+UgznpFhgBuaMQ7iu4lvvX1nvNsesQ3oxmYTw80= +github.com/go-openapi/jsonreference v0.21.4 h1:24qaE2y9bx/q3uRK/qN+TDwbok1NhbSmGjjySRCHtC8= +github.com/go-openapi/jsonreference v0.21.4/go.mod h1:rIENPTjDbLpzQmQWCj5kKj3ZlmEh+EFVbz3RTUh30/4= +github.com/go-openapi/swag v0.25.4 h1:OyUPUFYDPDBMkqyxOTkqDYFnrhuhi9NR6QVUvIochMU= +github.com/go-openapi/swag v0.25.4/go.mod h1:zNfJ9WZABGHCFg2RnY0S4IOkAcVTzJ6z2Bi+Q4i6qFQ= +github.com/go-openapi/swag/cmdutils v0.25.4 h1:8rYhB5n6WawR192/BfUu2iVlxqVR9aRgGJP6WaBoW+4= +github.com/go-openapi/swag/cmdutils v0.25.4/go.mod h1:pdae/AFo6WxLl5L0rq87eRzVPm/XRHM3MoYgRMvG4A0= +github.com/go-openapi/swag/conv v0.25.4 h1:/Dd7p0LZXczgUcC/Ikm1+YqVzkEeCc9LnOWjfkpkfe4= +github.com/go-openapi/swag/conv v0.25.4/go.mod h1:3LXfie/lwoAv0NHoEuY1hjoFAYkvlqI/Bn5EQDD3PPU= +github.com/go-openapi/swag/fileutils v0.25.4 h1:2oI0XNW5y6UWZTC7vAxC8hmsK/tOkWXHJQH4lKjqw+Y= +github.com/go-openapi/swag/fileutils v0.25.4/go.mod h1:cdOT/PKbwcysVQ9Tpr0q20lQKH7MGhOEb6EwmHOirUk= +github.com/go-openapi/swag/jsonname v0.25.4 h1:bZH0+MsS03MbnwBXYhuTttMOqk+5KcQ9869Vye1bNHI= +github.com/go-openapi/swag/jsonname v0.25.4/go.mod h1:GPVEk9CWVhNvWhZgrnvRA6utbAltopbKwDu8mXNUMag= +github.com/go-openapi/swag/jsonutils v0.25.4 h1:VSchfbGhD4UTf4vCdR2F4TLBdLwHyUDTd1/q4i+jGZA= +github.com/go-openapi/swag/jsonutils v0.25.4/go.mod h1:7OYGXpvVFPn4PpaSdPHJBtF0iGnbEaTk8AvBkoWnaAY= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4 h1:IACsSvBhiNJwlDix7wq39SS2Fh7lUOCJRmx/4SN4sVo= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4/go.mod h1:Mt0Ost9l3cUzVv4OEZG+WSeoHwjWLnarzMePNDAOBiM= +github.com/go-openapi/swag/loading v0.25.4 h1:jN4MvLj0X6yhCDduRsxDDw1aHe+ZWoLjW+9ZQWIKn2s= +github.com/go-openapi/swag/loading v0.25.4/go.mod h1:rpUM1ZiyEP9+mNLIQUdMiD7dCETXvkkC30z53i+ftTE= +github.com/go-openapi/swag/mangling v0.25.4 h1:2b9kBJk9JvPgxr36V23FxJLdwBrpijI26Bx5JH4Hp48= +github.com/go-openapi/swag/mangling v0.25.4/go.mod h1:6dxwu6QyORHpIIApsdZgb6wBk/DPU15MdyYj/ikn0Hg= +github.com/go-openapi/swag/netutils v0.25.4 h1:Gqe6K71bGRb3ZQLusdI8p/y1KLgV4M/k+/HzVSqT8H0= +github.com/go-openapi/swag/netutils v0.25.4/go.mod h1:m2W8dtdaoX7oj9rEttLyTeEFFEBvnAx9qHd5nJEBzYg= +github.com/go-openapi/swag/stringutils v0.25.4 h1:O6dU1Rd8bej4HPA3/CLPciNBBDwZj9HiEpdVsb8B5A8= +github.com/go-openapi/swag/stringutils v0.25.4/go.mod h1:GTsRvhJW5xM5gkgiFe0fV3PUlFm0dr8vki6/VSRaZK0= +github.com/go-openapi/swag/typeutils v0.25.4 h1:1/fbZOUN472NTc39zpa+YGHn3jzHWhv42wAJSN91wRw= +github.com/go-openapi/swag/typeutils v0.25.4/go.mod h1:Ou7g//Wx8tTLS9vG0UmzfCsjZjKhpjxayRKTHXf2pTE= +github.com/go-openapi/swag/yamlutils v0.25.4 h1:6jdaeSItEUb7ioS9lFoCZ65Cne1/RZtPBZ9A56h92Sw= +github.com/go-openapi/swag/yamlutils v0.25.4/go.mod h1:MNzq1ulQu+yd8Kl7wPOut/YHAAU/H6hL91fF+E2RFwc= +github.com/go-openapi/testify/enable/yaml/v2 v2.0.2 h1:0+Y41Pz1NkbTHz8NngxTuAXxEodtNSI1WG1c/m5Akw4= +github.com/go-openapi/testify/enable/yaml/v2 v2.0.2/go.mod h1:kme83333GCtJQHXQ8UKX3IBZu6z8T5Dvy5+CW3NLUUg= +github.com/go-openapi/testify/v2 v2.0.2 h1:X999g3jeLcoY8qctY/c/Z8iBHTbwLz7R2WXd6Ub6wls= +github.com/go-openapi/testify/v2 v2.0.2/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -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/gnostic-models v0.7.1 h1:SisTfuFKJSKM5CPZkffwi6coztzzeYUhc3v4yxLWH8c= +github.com/google/gnostic-models v0.7.1/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/grafana/grafana-app-sdk v0.48.5 h1:MS8l9fTZz+VbTfgApn09jw27GxhQ6fNOWGhC4ydvZmM= -github.com/grafana/grafana-app-sdk v0.48.5/go.mod h1:HJsMOSBmt/D/Ihs1SvagOwmXKi0coBMVHlfvdd+qe9Y= +github.com/grafana/grafana-app-sdk v0.48.7 h1:9mF7nqkqP0QUYYDlznoOt+GIyjzj45wGfUHB32u2ZMo= +github.com/grafana/grafana-app-sdk v0.48.7/go.mod h1:DWsaaH39ZMHwSOSoUBaeW8paMrRaYsjRYlLwCJYd78k= 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= -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/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -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/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= 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/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= 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= @@ -73,8 +101,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.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= -golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= +golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= +golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= 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= @@ -83,8 +111,8 @@ 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/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.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= -golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= +golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= +golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= 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= @@ -93,8 +121,8 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= -google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/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= @@ -102,16 +130,16 @@ 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/apimachinery v0.34.2 h1:zQ12Uk3eMHPxrsbUJgNF8bTauTVR2WgqJsTmwTE/NW4= -k8s.io/apimachinery v0.34.2/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= +k8s.io/apimachinery v0.34.3 h1:/TB+SFEiQvN9HPldtlWOTp0hWbJ+fjU+wkxysf/aQnE= +k8s.io/apimachinery v0.34.3/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= 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= +k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e h1:iW9ChlU0cU16w8MpVYjXk12dqQ4BPFBEgif+ap7/hqQ= +k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e/go.mod h1:kdmbQkyfwUagLfXIad1y2TdrjPFWp2Q89B3qkRwf/pQ= +k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 h1:SjGebBtkBqHFOli+05xYbK8YF1Dzkbzn+gDM4X9T4Ck= +k8s.io/utils v0.0.0-20251002143259-bc988d571ff4/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg= +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/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.1 h1:JrhdFMqOd/+3ByqlP2I45kTOZmTRLBUm5pvRjeheg7E= diff --git a/apps/alerting/historian/go.mod b/apps/alerting/historian/go.mod index dc8b8ef80a9..0524e1a3852 100644 --- a/apps/alerting/historian/go.mod +++ b/apps/alerting/historian/go.mod @@ -6,15 +6,15 @@ require ( github.com/go-kit/log v0.2.1 github.com/grafana/alerting v0.0.0-20251212143239-491433b332b7 github.com/grafana/dskit v0.0.0-20250908063411-6b6da59b5cc4 - github.com/grafana/grafana-app-sdk v0.48.5 - github.com/grafana/grafana-app-sdk/logging v0.48.3 + github.com/grafana/grafana-app-sdk v0.48.7 + github.com/grafana/grafana-app-sdk/logging v0.48.7 github.com/prometheus/client_golang v1.23.2 github.com/spf13/pflag v1.0.10 github.com/stretchr/testify v1.11.1 - go.opentelemetry.io/otel v1.38.0 - go.opentelemetry.io/otel/trace v1.38.0 - k8s.io/apimachinery v0.34.2 - k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 + go.opentelemetry.io/otel v1.39.0 + go.opentelemetry.io/otel/trace v1.39.0 + k8s.io/apimachinery v0.34.3 + k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e ) require ( @@ -28,11 +28,11 @@ require ( github.com/aws/aws-sdk-go v1.55.7 // indirect github.com/benbjohnson/clock v1.3.5 // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874 // indirect + github.com/bradfitz/gomemcache v0.0.0-20250403215159-8d39553ac7cf // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cenkalti/backoff/v5 v5.0.3 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect - github.com/coreos/go-systemd/v22 v22.5.0 // indirect + github.com/coreos/go-systemd/v22 v22.6.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 @@ -42,11 +42,21 @@ require ( github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // 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/jsonpointer v0.22.4 // indirect + github.com/go-openapi/jsonreference v0.21.4 // indirect github.com/go-openapi/strfmt v0.24.0 // indirect - github.com/go-openapi/swag v0.23.1 // indirect - github.com/go-openapi/swag/jsonname v0.25.1 // indirect + github.com/go-openapi/swag v0.25.4 // indirect + github.com/go-openapi/swag/cmdutils v0.25.4 // indirect + github.com/go-openapi/swag/conv v0.25.4 // indirect + github.com/go-openapi/swag/fileutils v0.25.4 // indirect + github.com/go-openapi/swag/jsonname v0.25.4 // indirect + github.com/go-openapi/swag/jsonutils v0.25.4 // indirect + github.com/go-openapi/swag/loading v0.25.4 // indirect + github.com/go-openapi/swag/mangling v0.25.4 // indirect + github.com/go-openapi/swag/netutils v0.25.4 // indirect + github.com/go-openapi/swag/stringutils v0.25.4 // indirect + github.com/go-openapi/swag/typeutils v0.25.4 // indirect + github.com/go-openapi/swag/yamlutils v0.25.4 // indirect github.com/go-test/deep v1.1.1 // indirect github.com/go-viper/mapstructure/v2 v2.4.0 // indirect github.com/gofrs/uuid v4.4.0+incompatible // indirect @@ -57,7 +67,7 @@ require ( github.com/golang/protobuf v1.5.4 // indirect github.com/golang/snappy v1.0.0 // indirect github.com/google/btree v1.1.3 // indirect - github.com/google/gnostic-models v0.7.0 // indirect + github.com/google/gnostic-models v0.7.1 // 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 @@ -80,7 +90,7 @@ require ( 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 - github.com/mailru/easyjson v0.9.0 // indirect + github.com/mailru/easyjson v0.9.1 // 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 @@ -104,10 +114,10 @@ require ( github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/alertmanager v0.28.2 // indirect github.com/prometheus/client_model v0.6.2 // indirect - github.com/prometheus/common v0.67.3 // indirect + github.com/prometheus/common v0.67.4 // 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/prometheus/procfs v0.19.2 // indirect github.com/puzpuzpuz/xsync/v2 v2.5.1 // indirect github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 // indirect github.com/shopspring/decimal v1.4.0 // indirect @@ -117,7 +127,7 @@ require ( github.com/stretchr/objx v0.5.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/woodsbury/decimal128 v1.3.0 // indirect + github.com/woodsbury/decimal128 v1.4.0 // indirect github.com/x448/float16 v0.8.4 // indirect go.mongodb.org/mongo-driver v1.17.4 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect @@ -130,49 +140,49 @@ require ( go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.12.2 // indirect go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp 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/exporters/otlp/otlptrace v1.39.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.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.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 - go.opentelemetry.io/otel/sdk v1.38.0 // indirect + go.opentelemetry.io/otel/metric v1.39.0 // indirect + go.opentelemetry.io/otel/sdk v1.39.0 // indirect go.opentelemetry.io/otel/sdk/log v0.12.2 // indirect - go.opentelemetry.io/otel/sdk/metric v1.38.0 // indirect + go.opentelemetry.io/otel/sdk/metric v1.39.0 // indirect go.opentelemetry.io/proto/otlp v1.9.0 // indirect go.uber.org/atomic v1.11.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.45.0 // indirect - golang.org/x/mod v0.30.0 // indirect - golang.org/x/net v0.47.0 // indirect - golang.org/x/oauth2 v0.33.0 // indirect - golang.org/x/sync v0.18.0 // indirect - golang.org/x/sys v0.38.0 // indirect - golang.org/x/term v0.37.0 // indirect - golang.org/x/text v0.31.0 // indirect + golang.org/x/crypto v0.46.0 // indirect + golang.org/x/mod v0.31.0 // indirect + golang.org/x/net v0.48.0 // indirect + golang.org/x/oauth2 v0.34.0 // indirect + golang.org/x/sync v0.19.0 // indirect + golang.org/x/sys v0.39.0 // indirect + golang.org/x/term v0.38.0 // indirect + golang.org/x/text v0.32.0 // indirect golang.org/x/time v0.14.0 // indirect - golang.org/x/tools v0.39.0 // indirect + golang.org/x/tools v0.40.0 // indirect golang.org/x/tools/godoc v0.1.0-deprecated // indirect gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20251111163417-95abcf5c77ba // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2 // indirect google.golang.org/grpc v1.77.0 // indirect - google.golang.org/protobuf v1.36.10 // indirect + google.golang.org/protobuf v1.36.11 // indirect gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/mail.v2 v2.3.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/api v0.34.2 // indirect - k8s.io/apiextensions-apiserver v0.34.2 // indirect - k8s.io/client-go v0.34.2 // indirect + k8s.io/api v0.34.3 // indirect + k8s.io/apiextensions-apiserver v0.34.3 // indirect + k8s.io/client-go v0.34.3 // 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 + k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 // indirect + sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect sigs.k8s.io/randfill v1.0.0 // indirect sigs.k8s.io/structured-merge-diff/v6 v6.3.1 // indirect sigs.k8s.io/yaml v1.6.0 // indirect diff --git a/apps/alerting/historian/go.sum b/apps/alerting/historian/go.sum index e4440ed687f..6e82a1dea7b 100644 --- a/apps/alerting/historian/go.sum +++ b/apps/alerting/historian/go.sum @@ -63,8 +63,8 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24 github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= 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/bradfitz/gomemcache v0.0.0-20250403215159-8d39553ac7cf h1:TqhNAT4zKbTdLa62d2HDBFdvgSbIGB3eJE8HqhgiL9I= +github.com/bradfitz/gomemcache v0.0.0-20250403215159-8d39553ac7cf/go.mod h1:r5xuitiExdLAJ09PR7vBVENGvp4ZuTBeWTGtxuX3K+c= 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.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= @@ -80,8 +80,8 @@ github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6D github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= -github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/coreos/go-systemd/v22 v22.6.0 h1:aGVa/v8B7hpb0TKl0MWoAavPDmHvobFe5R5zn0bCJWo= +github.com/coreos/go-systemd/v22 v22.6.0/go.mod h1:iG+pp635Fo7ZmV/j14KUcmEyWF+0X7Lua8rrTWzYgWU= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -123,16 +123,42 @@ 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/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/jsonpointer v0.22.4 h1:dZtK82WlNpVLDW2jlA1YCiVJFVqkED1MegOUy9kR5T4= +github.com/go-openapi/jsonpointer v0.22.4/go.mod h1:elX9+UgznpFhgBuaMQ7iu4lvvX1nvNsesQ3oxmYTw80= +github.com/go-openapi/jsonreference v0.21.4 h1:24qaE2y9bx/q3uRK/qN+TDwbok1NhbSmGjjySRCHtC8= +github.com/go-openapi/jsonreference v0.21.4/go.mod h1:rIENPTjDbLpzQmQWCj5kKj3ZlmEh+EFVbz3RTUh30/4= 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.1 h1:lpsStH0n2ittzTnbaSloVZLuB5+fvSY/+hnagBjSNZU= -github.com/go-openapi/swag v0.23.1/go.mod h1:STZs8TbRvEQQKUA+JZNAm3EWlgaOBGpyFDqQnDHMef0= -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 v0.25.4 h1:OyUPUFYDPDBMkqyxOTkqDYFnrhuhi9NR6QVUvIochMU= +github.com/go-openapi/swag v0.25.4/go.mod h1:zNfJ9WZABGHCFg2RnY0S4IOkAcVTzJ6z2Bi+Q4i6qFQ= +github.com/go-openapi/swag/cmdutils v0.25.4 h1:8rYhB5n6WawR192/BfUu2iVlxqVR9aRgGJP6WaBoW+4= +github.com/go-openapi/swag/cmdutils v0.25.4/go.mod h1:pdae/AFo6WxLl5L0rq87eRzVPm/XRHM3MoYgRMvG4A0= +github.com/go-openapi/swag/conv v0.25.4 h1:/Dd7p0LZXczgUcC/Ikm1+YqVzkEeCc9LnOWjfkpkfe4= +github.com/go-openapi/swag/conv v0.25.4/go.mod h1:3LXfie/lwoAv0NHoEuY1hjoFAYkvlqI/Bn5EQDD3PPU= +github.com/go-openapi/swag/fileutils v0.25.4 h1:2oI0XNW5y6UWZTC7vAxC8hmsK/tOkWXHJQH4lKjqw+Y= +github.com/go-openapi/swag/fileutils v0.25.4/go.mod h1:cdOT/PKbwcysVQ9Tpr0q20lQKH7MGhOEb6EwmHOirUk= +github.com/go-openapi/swag/jsonname v0.25.4 h1:bZH0+MsS03MbnwBXYhuTttMOqk+5KcQ9869Vye1bNHI= +github.com/go-openapi/swag/jsonname v0.25.4/go.mod h1:GPVEk9CWVhNvWhZgrnvRA6utbAltopbKwDu8mXNUMag= +github.com/go-openapi/swag/jsonutils v0.25.4 h1:VSchfbGhD4UTf4vCdR2F4TLBdLwHyUDTd1/q4i+jGZA= +github.com/go-openapi/swag/jsonutils v0.25.4/go.mod h1:7OYGXpvVFPn4PpaSdPHJBtF0iGnbEaTk8AvBkoWnaAY= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4 h1:IACsSvBhiNJwlDix7wq39SS2Fh7lUOCJRmx/4SN4sVo= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4/go.mod h1:Mt0Ost9l3cUzVv4OEZG+WSeoHwjWLnarzMePNDAOBiM= +github.com/go-openapi/swag/loading v0.25.4 h1:jN4MvLj0X6yhCDduRsxDDw1aHe+ZWoLjW+9ZQWIKn2s= +github.com/go-openapi/swag/loading v0.25.4/go.mod h1:rpUM1ZiyEP9+mNLIQUdMiD7dCETXvkkC30z53i+ftTE= +github.com/go-openapi/swag/mangling v0.25.4 h1:2b9kBJk9JvPgxr36V23FxJLdwBrpijI26Bx5JH4Hp48= +github.com/go-openapi/swag/mangling v0.25.4/go.mod h1:6dxwu6QyORHpIIApsdZgb6wBk/DPU15MdyYj/ikn0Hg= +github.com/go-openapi/swag/netutils v0.25.4 h1:Gqe6K71bGRb3ZQLusdI8p/y1KLgV4M/k+/HzVSqT8H0= +github.com/go-openapi/swag/netutils v0.25.4/go.mod h1:m2W8dtdaoX7oj9rEttLyTeEFFEBvnAx9qHd5nJEBzYg= +github.com/go-openapi/swag/stringutils v0.25.4 h1:O6dU1Rd8bej4HPA3/CLPciNBBDwZj9HiEpdVsb8B5A8= +github.com/go-openapi/swag/stringutils v0.25.4/go.mod h1:GTsRvhJW5xM5gkgiFe0fV3PUlFm0dr8vki6/VSRaZK0= +github.com/go-openapi/swag/typeutils v0.25.4 h1:1/fbZOUN472NTc39zpa+YGHn3jzHWhv42wAJSN91wRw= +github.com/go-openapi/swag/typeutils v0.25.4/go.mod h1:Ou7g//Wx8tTLS9vG0UmzfCsjZjKhpjxayRKTHXf2pTE= +github.com/go-openapi/swag/yamlutils v0.25.4 h1:6jdaeSItEUb7ioS9lFoCZ65Cne1/RZtPBZ9A56h92Sw= +github.com/go-openapi/swag/yamlutils v0.25.4/go.mod h1:MNzq1ulQu+yd8Kl7wPOut/YHAAU/H6hL91fF+E2RFwc= +github.com/go-openapi/testify/enable/yaml/v2 v2.0.2 h1:0+Y41Pz1NkbTHz8NngxTuAXxEodtNSI1WG1c/m5Akw4= +github.com/go-openapi/testify/enable/yaml/v2 v2.0.2/go.mod h1:kme83333GCtJQHXQ8UKX3IBZu6z8T5Dvy5+CW3NLUUg= +github.com/go-openapi/testify/v2 v2.0.2 h1:X999g3jeLcoY8qctY/c/Z8iBHTbwLz7R2WXd6Ub6wls= +github.com/go-openapi/testify/v2 v2.0.2/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= 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= @@ -140,7 +166,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/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA= github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/googleapis v0.0.0-20180223154316-0cd9801be74a/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= @@ -187,8 +212,8 @@ 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/gnostic-models v0.7.0 h1:qwTtogB15McXDaNqTZdzPJRHvaVJlAl+HVQnLmJEJxo= -github.com/google/gnostic-models v0.7.0/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ= +github.com/google/gnostic-models v0.7.1 h1:SisTfuFKJSKM5CPZkffwi6coztzzeYUhc3v4yxLWH8c= +github.com/google/gnostic-models v0.7.1/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= @@ -222,10 +247,10 @@ github.com/grafana/alerting v0.0.0-20251212143239-491433b332b7 h1:ZzG/gCclEit9w0 github.com/grafana/alerting v0.0.0-20251212143239-491433b332b7/go.mod h1:l7v67cgP7x72ajB9UPZlumdrHqNztpKoqQ52cU8T3LU= 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.5 h1:MS8l9fTZz+VbTfgApn09jw27GxhQ6fNOWGhC4ydvZmM= -github.com/grafana/grafana-app-sdk v0.48.5/go.mod h1:HJsMOSBmt/D/Ihs1SvagOwmXKi0coBMVHlfvdd+qe9Y= -github.com/grafana/grafana-app-sdk/logging v0.48.3 h1:72NUpGNiJXCNQz/on++YSsl38xuVYYBKv5kKQaOClX4= -github.com/grafana/grafana-app-sdk/logging v0.48.3/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA= +github.com/grafana/grafana-app-sdk v0.48.7 h1:9mF7nqkqP0QUYYDlznoOt+GIyjzj45wGfUHB32u2ZMo= +github.com/grafana/grafana-app-sdk v0.48.7/go.mod h1:DWsaaH39ZMHwSOSoUBaeW8paMrRaYsjRYlLwCJYd78k= +github.com/grafana/grafana-app-sdk/logging v0.48.7 h1:Oa5qg473gka5+W/WQk61Xbw4YdAv+wV2Z4bJtzeCaQw= +github.com/grafana/grafana-app-sdk/logging v0.48.7/go.mod h1:5u3KalezoBAAo2Y3ytDYDAIIPvEqFLLDSxeiK99QxDU= github.com/grafana/loki/pkg/push v0.0.0-20250823105456-332df2b20000 h1:/5LKSYgLmAhwA4m6iGUD4w1YkydEWWjazn9qxCFT8W0= github.com/grafana/loki/pkg/push v0.0.0-20250823105456-332df2b20000/go.mod h1:/ZklAgE1i4f3Z8uriXwESmCr1VLF8lBGaJspuaGuf78= github.com/grafana/otel-profiling-go v0.5.1 h1:stVPKAFZSa7eGiqbYuG25VcqYksR6iWvF3YH66t4qL8= @@ -301,8 +326,8 @@ 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/mailru/easyjson v0.9.1 h1:LbtsOm5WAswyWbvTEOqhypdPeZzHavpZx96/n553mR8= +github.com/mailru/easyjson v0.9.1/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= 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= @@ -376,8 +401,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.67.3 h1:shd26MlnwTw5jksTDhC7rTQIteBxy+ZZDr3t7F2xN2Q= -github.com/prometheus/common v0.67.3/go.mod h1:gP0fq6YjjNCLssJCQp0yk4M8W6ikLURwkdd/YKtTbyI= +github.com/prometheus/common v0.67.4 h1:yR3NqWO1/UyO1w2PhUvXlGQs/PtFmoveVO0KZ4+Lvsc= +github.com/prometheus/common v0.67.4/go.mod h1:gP0fq6YjjNCLssJCQp0yk4M8W6ikLURwkdd/YKtTbyI= 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= @@ -387,8 +412,8 @@ github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsT github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= -github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= +github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws= +github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw= 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.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= @@ -431,8 +456,8 @@ github.com/uber/jaeger-lib v2.4.1+incompatible h1:td4jdvLcExb4cBISKIpHuGoVXh+dVK github.com/uber/jaeger-lib v2.4.1+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U= 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/woodsbury/decimal128 v1.4.0 h1:xJATj7lLu4f2oObouMt2tgGiElE5gO6mSWUjQsBgUlc= +github.com/woodsbury/decimal128 v1.4.0/go.mod h1:BP46FUrVjVhdTbKT+XuQh2xfQaGki9LMIRJSFuh6THU= 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.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -457,8 +482,8 @@ go.opentelemetry.io/contrib/propagators/jaeger v1.38.0/go.mod h1:oMvOXk78ZR3KEuP 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.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= -go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= +go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48= +go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8= 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= @@ -469,12 +494,12 @@ go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0 h1:vl9 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/otlp/otlptrace v1.39.0 h1:f0cb2XPmrqn4XMy9PNliTgRKJgS5WcL/u0/WRYGz4t0= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0/go.mod h1:vnakAaFckOMiMtOIhFI2MNH4FYrZzXCYxmb1LlhoGz8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0 h1:in9O8ESIOlwJAEGTkkf34DesGRAc/Pn8qJ7k3r/42LM= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0/go.mod h1:Rp0EXBm5tfnv0WL+ARyO/PHBEaEAT8UUHQ6AGJcSq6c= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0 h1:Ckwye2FpXkYgiHX7fyVrN1uA/UYd9ounqqTuSNAv0k4= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0/go.mod h1:teIFJh5pW2y+AN7riv6IBPX2DuesS3HgP39mwOspKwU= 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= @@ -486,20 +511,20 @@ go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0/go.mod h1:mgIOzS7i 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.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= -go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= +go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0= +go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs= go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E= -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 v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18= +go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE= 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/log/logtest v0.0.0-20250521073539-a85ae98dcedc h1:uqxdywfHqqCl6LmZzI3pUnXT1RGFYyUgxj0AkWPFxi0= go.opentelemetry.io/otel/sdk/log/logtest v0.0.0-20250521073539-a85ae98dcedc/go.mod h1:TY/N/FT7dmFrP/r5ym3g0yysP1DefqGpAZr4f82P0dE= -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/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8= +go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew= go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ= -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/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI= +go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA= go.opentelemetry.io/proto/otlp v1.9.0 h1:l706jCMITVouPOqEnii2fIAuO3IVGBRPV5ICjceRb/A= go.opentelemetry.io/proto/otlp v1.9.0/go.mod h1:xE+Cx5E/eEHw+ISFkwPLwCZefwVjY+pqKg1qcK03+/4= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= @@ -516,8 +541,8 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 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.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q= -golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4= +golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU= +golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0= 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= @@ -552,8 +577,8 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 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.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk= -golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc= +golang.org/x/mod v0.31.0 h1:HaW9xtz0+kOcWKwli0ZXy79Ix+UW/vOfmWI5QVd2tgI= +golang.org/x/mod v0.31.0/go.mod h1:43JraMp9cGx1Rx3AqioxrbrhNsLl2l/iNAvuBkrezpg= 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-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -585,16 +610,16 @@ golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= -golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= +golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= +golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.33.0 h1:4Q+qn+E5z8gPRJfmRy7C2gGG3T4jIprK6aSYgTXGRpo= -golang.org/x/oauth2 v0.33.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= +golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw= +golang.org/x/oauth2 v0.34.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= @@ -605,8 +630,8 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/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.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= -golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= 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= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -644,19 +669,19 @@ golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= -golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= +golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU= -golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254= +golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q= +golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg= 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= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= -golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= +golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= +golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= 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= @@ -706,8 +731,8 @@ golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ= -golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ= +golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA= +golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc= 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= @@ -774,10 +799,10 @@ google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7Fc google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto/googleapis/api v0.0.0-20251111163417-95abcf5c77ba h1:B14OtaXuMaCQsl2deSvNkyPKIzq3BjfxQp8d00QyWx4= -google.golang.org/genproto/googleapis/api v0.0.0-20251111163417-95abcf5c77ba/go.mod h1:G5IanEx8/PgI9w6CFcYQf7jMtHQhZruvfM1i3qOqk5U= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba h1:UKgtfRM7Yh93Sya0Fo8ZzhDP4qBckrrxEr2oF5UIVb8= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= +google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2 h1:7LRqPCEdE4TP4/9psdaB7F2nhZFfBiGJomA5sojLWdU= +google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2/go.mod h1:+rXWjjaukWZun3mLfjmVnQi18E1AsFbDN9QdJ5YXLto= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2 h1:2I6GHUeJ/4shcDpoUlLs/2WPnhg7yJwvXtqcMJt9liA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= @@ -804,8 +829,8 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= -google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/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= @@ -816,8 +841,8 @@ gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8 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/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -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/evanphx/json-patch.v4 v4.13.0 h1:czT3CmqEaQ1aanPc5SdlgQrrEIb8w/wwCvWWnfEbYzo= +gopkg.in/evanphx/json-patch.v4 v4.13.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/mail.v2 v2.3.1 h1:WYFn/oANrAGP2C0dcV6/pbkPzv8yGzqTjPmTeO7qoXk= @@ -840,26 +865,26 @@ 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.34.2 h1:fsSUNZhV+bnL6Aqrp6O7lMTy6o5x2C4XLjnh//8SLYY= -k8s.io/api v0.34.2/go.mod h1:MMBPaWlED2a8w4RSeanD76f7opUoypY8TFYkSM+3XHw= -k8s.io/apiextensions-apiserver v0.34.2 h1:WStKftnGeoKP4AZRz/BaAAEJvYp4mlZGN0UCv+uvsqo= -k8s.io/apiextensions-apiserver v0.34.2/go.mod h1:398CJrsgXF1wytdaanynDpJ67zG4Xq7yj91GrmYN2SE= -k8s.io/apimachinery v0.34.2 h1:zQ12Uk3eMHPxrsbUJgNF8bTauTVR2WgqJsTmwTE/NW4= -k8s.io/apimachinery v0.34.2/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= -k8s.io/client-go v0.34.2 h1:Co6XiknN+uUZqiddlfAjT68184/37PS4QAzYvQvDR8M= -k8s.io/client-go v0.34.2/go.mod h1:2VYDl1XXJsdcAxw7BenFslRQX28Dxz91U9MWKjX97fE= +k8s.io/api v0.34.3 h1:D12sTP257/jSH2vHV2EDYrb16bS7ULlHpdNdNhEw2S4= +k8s.io/api v0.34.3/go.mod h1:PyVQBF886Q5RSQZOim7DybQjAbVs8g7gwJNhGtY5MBk= +k8s.io/apiextensions-apiserver v0.34.3 h1:p10fGlkDY09eWKOTeUSioxwLukJnm+KuDZdrW71y40g= +k8s.io/apiextensions-apiserver v0.34.3/go.mod h1:aujxvqGFRdb/cmXYfcRTeppN7S2XV/t7WMEc64zB5A0= +k8s.io/apimachinery v0.34.3 h1:/TB+SFEiQvN9HPldtlWOTp0hWbJ+fjU+wkxysf/aQnE= +k8s.io/apimachinery v0.34.3/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= +k8s.io/client-go v0.34.3 h1:wtYtpzy/OPNYf7WyNBTj3iUA0XaBHVqhv4Iv3tbrF5A= +k8s.io/client-go v0.34.3/go.mod h1:OxxeYagaP9Kdf78UrKLa3YZixMCfP6bgPwPwNBQBzpM= 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= +k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e h1:iW9ChlU0cU16w8MpVYjXk12dqQ4BPFBEgif+ap7/hqQ= +k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e/go.mod h1:kdmbQkyfwUagLfXIad1y2TdrjPFWp2Q89B3qkRwf/pQ= +k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 h1:SjGebBtkBqHFOli+05xYbK8YF1Dzkbzn+gDM4X9T4Ck= +k8s.io/utils v0.0.0-20251002143259-bc988d571ff4/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= -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/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg= +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/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.1 h1:JrhdFMqOd/+3ByqlP2I45kTOZmTRLBUm5pvRjeheg7E= diff --git a/apps/alerting/notifications/go.mod b/apps/alerting/notifications/go.mod index f72c4c9775b..b958cb377aa 100644 --- a/apps/alerting/notifications/go.mod +++ b/apps/alerting/notifications/go.mod @@ -3,21 +3,21 @@ module github.com/grafana/grafana/apps/alerting/notifications go 1.25.5 require ( - github.com/grafana/grafana-app-sdk v0.48.5 - github.com/grafana/grafana-app-sdk/logging v0.48.3 - k8s.io/apimachinery v0.34.2 - k8s.io/apiserver v0.34.2 - k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 + github.com/grafana/grafana-app-sdk v0.48.7 + github.com/grafana/grafana-app-sdk/logging v0.48.7 + k8s.io/apimachinery v0.34.3 + k8s.io/apiserver v0.34.3 + k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e ) 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/bradfitz/gomemcache v0.0.0-20250403215159-8d39553ac7cf // indirect github.com/cenkalti/backoff/v5 v5.0.3 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/coreos/go-semver v0.3.1 // indirect - github.com/coreos/go-systemd/v22 v22.5.0 // indirect + github.com/coreos/go-systemd/v22 v22.6.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 @@ -26,14 +26,24 @@ require ( github.com/getkin/kin-openapi v0.133.0 // 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.1 // indirect - github.com/go-openapi/swag/jsonname v0.25.1 // indirect + github.com/go-openapi/jsonpointer v0.22.4 // indirect + github.com/go-openapi/jsonreference v0.21.4 // indirect + github.com/go-openapi/swag v0.25.4 // indirect + github.com/go-openapi/swag/cmdutils v0.25.4 // indirect + github.com/go-openapi/swag/conv v0.25.4 // indirect + github.com/go-openapi/swag/fileutils v0.25.4 // indirect + github.com/go-openapi/swag/jsonname v0.25.4 // indirect + github.com/go-openapi/swag/jsonutils v0.25.4 // indirect + github.com/go-openapi/swag/loading v0.25.4 // indirect + github.com/go-openapi/swag/mangling v0.25.4 // indirect + github.com/go-openapi/swag/netutils v0.25.4 // indirect + github.com/go-openapi/swag/stringutils v0.25.4 // indirect + github.com/go-openapi/swag/typeutils v0.25.4 // indirect + github.com/go-openapi/swag/yamlutils v0.25.4 // indirect github.com/go-test/deep v1.1.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/protobuf v1.5.4 // indirect - github.com/google/gnostic-models v0.7.0 // indirect + github.com/google/gnostic-models v0.7.1 // 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 @@ -44,7 +54,7 @@ require ( github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/kylelemons/godebug v1.1.0 // indirect - github.com/mailru/easyjson v0.9.0 // indirect + github.com/mailru/easyjson v0.9.1 // 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 @@ -54,57 +64,56 @@ require ( github.com/onsi/ginkgo/v2 v2.22.2 // indirect github.com/onsi/gomega v1.36.2 // indirect github.com/perimeterx/marshmallow v1.1.5 // indirect - github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/client_golang v1.23.2 // indirect github.com/prometheus/client_model v0.6.2 // indirect - github.com/prometheus/common v0.67.3 // indirect - github.com/prometheus/procfs v0.16.1 // indirect + github.com/prometheus/common v0.67.4 // indirect + github.com/prometheus/procfs v0.19.2 // 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/woodsbury/decimal128 v1.4.0 // indirect github.com/x448/float16 v0.8.4 // indirect - go.etcd.io/etcd/api/v3 v3.6.4 // indirect - go.etcd.io/etcd/client/pkg/v3 v3.6.4 // indirect - go.etcd.io/etcd/client/v3 v3.6.4 // indirect + go.etcd.io/etcd/api/v3 v3.6.6 // indirect + go.etcd.io/etcd/client/pkg/v3 v3.6.6 // indirect + go.etcd.io/etcd/client/v3 v3.6.6 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.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/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.64.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.64.0 // indirect + go.opentelemetry.io/otel v1.39.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0 // indirect + go.opentelemetry.io/otel/metric v1.39.0 // indirect + go.opentelemetry.io/otel/sdk v1.39.0 // indirect + go.opentelemetry.io/otel/trace v1.39.0 // indirect go.opentelemetry.io/proto/otlp v1.9.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.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.47.0 // indirect - golang.org/x/oauth2 v0.33.0 // indirect - golang.org/x/sync v0.18.0 // indirect - golang.org/x/sys v0.38.0 // indirect - golang.org/x/term v0.37.0 // indirect - golang.org/x/text v0.31.0 // indirect + golang.org/x/net v0.48.0 // indirect + golang.org/x/oauth2 v0.34.0 // indirect + golang.org/x/sync v0.19.0 // indirect + golang.org/x/sys v0.39.0 // indirect + golang.org/x/term v0.38.0 // indirect + golang.org/x/text v0.32.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-20251111163417-95abcf5c77ba // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2 // indirect google.golang.org/grpc v1.77.0 // indirect - google.golang.org/protobuf v1.36.10 // indirect - gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect + google.golang.org/protobuf v1.36.11 // indirect + gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/api v0.34.2 // indirect - k8s.io/apiextensions-apiserver v0.34.2 // indirect - k8s.io/client-go v0.34.2 // indirect - k8s.io/component-base v0.34.2 // indirect + k8s.io/api v0.34.3 // indirect + k8s.io/apiextensions-apiserver v0.34.3 // indirect + k8s.io/client-go v0.34.3 // indirect + k8s.io/component-base v0.34.3 // indirect k8s.io/klog/v2 v2.130.1 // indirect - k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 // indirect - sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2 // indirect - sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect + k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 // indirect + sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.34.0 // indirect + sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect sigs.k8s.io/randfill v1.0.0 // indirect sigs.k8s.io/structured-merge-diff/v6 v6.3.1 // indirect sigs.k8s.io/yaml v1.6.0 // indirect diff --git a/apps/alerting/notifications/go.sum b/apps/alerting/notifications/go.sum index 57b099ab2f1..ea54639af1d 100644 --- a/apps/alerting/notifications/go.sum +++ b/apps/alerting/notifications/go.sum @@ -4,8 +4,8 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= -github.com/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/bradfitz/gomemcache v0.0.0-20250403215159-8d39553ac7cf h1:TqhNAT4zKbTdLa62d2HDBFdvgSbIGB3eJE8HqhgiL9I= +github.com/bradfitz/gomemcache v0.0.0-20250403215159-8d39553ac7cf/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= @@ -13,8 +13,8 @@ github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4= github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec= -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/coreos/go-systemd/v22 v22.6.0 h1:aGVa/v8B7hpb0TKl0MWoAavPDmHvobFe5R5zn0bCJWo= +github.com/coreos/go-systemd/v22 v22.6.0/go.mod h1:iG+pp635Fo7ZmV/j14KUcmEyWF+0X7Lua8rrTWzYgWU= 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= @@ -36,19 +36,44 @@ 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.1 h1:lpsStH0n2ittzTnbaSloVZLuB5+fvSY/+hnagBjSNZU= -github.com/go-openapi/swag v0.23.1/go.mod h1:STZs8TbRvEQQKUA+JZNAm3EWlgaOBGpyFDqQnDHMef0= -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/jsonpointer v0.22.4 h1:dZtK82WlNpVLDW2jlA1YCiVJFVqkED1MegOUy9kR5T4= +github.com/go-openapi/jsonpointer v0.22.4/go.mod h1:elX9+UgznpFhgBuaMQ7iu4lvvX1nvNsesQ3oxmYTw80= +github.com/go-openapi/jsonreference v0.21.4 h1:24qaE2y9bx/q3uRK/qN+TDwbok1NhbSmGjjySRCHtC8= +github.com/go-openapi/jsonreference v0.21.4/go.mod h1:rIENPTjDbLpzQmQWCj5kKj3ZlmEh+EFVbz3RTUh30/4= +github.com/go-openapi/swag v0.25.4 h1:OyUPUFYDPDBMkqyxOTkqDYFnrhuhi9NR6QVUvIochMU= +github.com/go-openapi/swag v0.25.4/go.mod h1:zNfJ9WZABGHCFg2RnY0S4IOkAcVTzJ6z2Bi+Q4i6qFQ= +github.com/go-openapi/swag/cmdutils v0.25.4 h1:8rYhB5n6WawR192/BfUu2iVlxqVR9aRgGJP6WaBoW+4= +github.com/go-openapi/swag/cmdutils v0.25.4/go.mod h1:pdae/AFo6WxLl5L0rq87eRzVPm/XRHM3MoYgRMvG4A0= +github.com/go-openapi/swag/conv v0.25.4 h1:/Dd7p0LZXczgUcC/Ikm1+YqVzkEeCc9LnOWjfkpkfe4= +github.com/go-openapi/swag/conv v0.25.4/go.mod h1:3LXfie/lwoAv0NHoEuY1hjoFAYkvlqI/Bn5EQDD3PPU= +github.com/go-openapi/swag/fileutils v0.25.4 h1:2oI0XNW5y6UWZTC7vAxC8hmsK/tOkWXHJQH4lKjqw+Y= +github.com/go-openapi/swag/fileutils v0.25.4/go.mod h1:cdOT/PKbwcysVQ9Tpr0q20lQKH7MGhOEb6EwmHOirUk= +github.com/go-openapi/swag/jsonname v0.25.4 h1:bZH0+MsS03MbnwBXYhuTttMOqk+5KcQ9869Vye1bNHI= +github.com/go-openapi/swag/jsonname v0.25.4/go.mod h1:GPVEk9CWVhNvWhZgrnvRA6utbAltopbKwDu8mXNUMag= +github.com/go-openapi/swag/jsonutils v0.25.4 h1:VSchfbGhD4UTf4vCdR2F4TLBdLwHyUDTd1/q4i+jGZA= +github.com/go-openapi/swag/jsonutils v0.25.4/go.mod h1:7OYGXpvVFPn4PpaSdPHJBtF0iGnbEaTk8AvBkoWnaAY= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4 h1:IACsSvBhiNJwlDix7wq39SS2Fh7lUOCJRmx/4SN4sVo= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4/go.mod h1:Mt0Ost9l3cUzVv4OEZG+WSeoHwjWLnarzMePNDAOBiM= +github.com/go-openapi/swag/loading v0.25.4 h1:jN4MvLj0X6yhCDduRsxDDw1aHe+ZWoLjW+9ZQWIKn2s= +github.com/go-openapi/swag/loading v0.25.4/go.mod h1:rpUM1ZiyEP9+mNLIQUdMiD7dCETXvkkC30z53i+ftTE= +github.com/go-openapi/swag/mangling v0.25.4 h1:2b9kBJk9JvPgxr36V23FxJLdwBrpijI26Bx5JH4Hp48= +github.com/go-openapi/swag/mangling v0.25.4/go.mod h1:6dxwu6QyORHpIIApsdZgb6wBk/DPU15MdyYj/ikn0Hg= +github.com/go-openapi/swag/netutils v0.25.4 h1:Gqe6K71bGRb3ZQLusdI8p/y1KLgV4M/k+/HzVSqT8H0= +github.com/go-openapi/swag/netutils v0.25.4/go.mod h1:m2W8dtdaoX7oj9rEttLyTeEFFEBvnAx9qHd5nJEBzYg= +github.com/go-openapi/swag/stringutils v0.25.4 h1:O6dU1Rd8bej4HPA3/CLPciNBBDwZj9HiEpdVsb8B5A8= +github.com/go-openapi/swag/stringutils v0.25.4/go.mod h1:GTsRvhJW5xM5gkgiFe0fV3PUlFm0dr8vki6/VSRaZK0= +github.com/go-openapi/swag/typeutils v0.25.4 h1:1/fbZOUN472NTc39zpa+YGHn3jzHWhv42wAJSN91wRw= +github.com/go-openapi/swag/typeutils v0.25.4/go.mod h1:Ou7g//Wx8tTLS9vG0UmzfCsjZjKhpjxayRKTHXf2pTE= +github.com/go-openapi/swag/yamlutils v0.25.4 h1:6jdaeSItEUb7ioS9lFoCZ65Cne1/RZtPBZ9A56h92Sw= +github.com/go-openapi/swag/yamlutils v0.25.4/go.mod h1:MNzq1ulQu+yd8Kl7wPOut/YHAAU/H6hL91fF+E2RFwc= +github.com/go-openapi/testify/enable/yaml/v2 v2.0.2 h1:0+Y41Pz1NkbTHz8NngxTuAXxEodtNSI1WG1c/m5Akw4= +github.com/go-openapi/testify/enable/yaml/v2 v2.0.2/go.mod h1:kme83333GCtJQHXQ8UKX3IBZu6z8T5Dvy5+CW3NLUUg= +github.com/go-openapi/testify/v2 v2.0.2 h1:X999g3jeLcoY8qctY/c/Z8iBHTbwLz7R2WXd6Ub6wls= +github.com/go-openapi/testify/v2 v2.0.2/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= 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/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo= @@ -60,8 +85,8 @@ github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= -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/gnostic-models v0.7.1 h1:SisTfuFKJSKM5CPZkffwi6coztzzeYUhc3v4yxLWH8c= +github.com/google/gnostic-models v0.7.1/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= @@ -71,10 +96,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.48.5 h1:MS8l9fTZz+VbTfgApn09jw27GxhQ6fNOWGhC4ydvZmM= -github.com/grafana/grafana-app-sdk v0.48.5/go.mod h1:HJsMOSBmt/D/Ihs1SvagOwmXKi0coBMVHlfvdd+qe9Y= -github.com/grafana/grafana-app-sdk/logging v0.48.3 h1:72NUpGNiJXCNQz/on++YSsl38xuVYYBKv5kKQaOClX4= -github.com/grafana/grafana-app-sdk/logging v0.48.3/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA= +github.com/grafana/grafana-app-sdk v0.48.7 h1:9mF7nqkqP0QUYYDlznoOt+GIyjzj45wGfUHB32u2ZMo= +github.com/grafana/grafana-app-sdk v0.48.7/go.mod h1:DWsaaH39ZMHwSOSoUBaeW8paMrRaYsjRYlLwCJYd78k= +github.com/grafana/grafana-app-sdk/logging v0.48.7 h1:Oa5qg473gka5+W/WQk61Xbw4YdAv+wV2Z4bJtzeCaQw= +github.com/grafana/grafana-app-sdk/logging v0.48.7/go.mod h1:5u3KalezoBAAo2Y3ytDYDAIIPvEqFLLDSxeiK99QxDU= 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.3 h1:B+8ClL/kCQkRiU82d9xajRPKYMrB7E0MbtzWVi1K4ns= @@ -104,8 +129,8 @@ 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/mailru/easyjson v0.9.1 h1:LbtsOm5WAswyWbvTEOqhypdPeZzHavpZx96/n553mR8= +github.com/mailru/easyjson v0.9.1/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= 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= @@ -127,8 +152,6 @@ 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/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= @@ -140,11 +163,11 @@ github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1: 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.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.67.3 h1:shd26MlnwTw5jksTDhC7rTQIteBxy+ZZDr3t7F2xN2Q= -github.com/prometheus/common v0.67.3/go.mod h1:gP0fq6YjjNCLssJCQp0yk4M8W6ikLURwkdd/YKtTbyI= +github.com/prometheus/common v0.67.4 h1:yR3NqWO1/UyO1w2PhUvXlGQs/PtFmoveVO0KZ4+Lvsc= +github.com/prometheus/common v0.67.4/go.mod h1:gP0fq6YjjNCLssJCQp0yk4M8W6ikLURwkdd/YKtTbyI= github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= -github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= +github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws= +github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw= 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= @@ -165,8 +188,8 @@ github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75 h1:6fotK7 github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75/go.mod h1:KO6IkyS8Y3j8OdNO85qEYBsRPuteD+YciPomcXdrMnk= 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/woodsbury/decimal128 v1.4.0 h1:xJATj7lLu4f2oObouMt2tgGiElE5gO6mSWUjQsBgUlc= +github.com/woodsbury/decimal128 v1.4.0/go.mod h1:BP46FUrVjVhdTbKT+XuQh2xfQaGki9LMIRJSFuh6THU= 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/xiang90/probing v0.0.0-20221125231312-a49e3df8f510 h1:S2dVYn90KE98chqDkyE9Z4N61UnQd+KOfgp5Iu53llk= @@ -175,12 +198,12 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= go.etcd.io/bbolt v1.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.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.6.4 h1:9HBYrjppeOfFjBjaMTRxT3R7xT0GLK8EJMVC4xg6ok0= -go.etcd.io/etcd/client/pkg/v3 v3.6.4/go.mod h1:sbdzr2cl3HzVmxNw//PH7aLGVtY4QySjQFuaCgcRFAI= -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.etcd.io/etcd/api/v3 v3.6.6 h1:mcaMp3+7JawWv69p6QShYWS8cIWUOl32bFLb6qf8pOQ= +go.etcd.io/etcd/api/v3 v3.6.6/go.mod h1:f/om26iXl2wSkcTA1zGQv8reJRSLVdoEBsi4JdfMrx4= +go.etcd.io/etcd/client/pkg/v3 v3.6.6 h1:uoqgzSOv2H9KlIF5O1Lsd8sW+eMLuV6wzE3q5GJGQNs= +go.etcd.io/etcd/client/pkg/v3 v3.6.6/go.mod h1:YngfUVmvsvOJ2rRgStIyHsKtOt9SZI2aBJrZiWJhCbI= +go.etcd.io/etcd/client/v3 v3.6.6 h1:G5z1wMf5B9SNexoxOHUGBaULurOZPIgGPsW6CN492ec= +go.etcd.io/etcd/client/v3 v3.6.6/go.mod h1:36Qv6baQ07znPR3+n7t+Rk5VHEzVYPvFfGmfF4wBHV8= go.etcd.io/etcd/pkg/v3 v3.6.4 h1:fy8bmXIec1Q35/jRZ0KOes8vuFxbvdN0aAFqmEfJZWA= go.etcd.io/etcd/pkg/v3 v3.6.4/go.mod h1:kKcYWP8gHuBRcteyv6MXWSN0+bVMnfgqiHueIZnKMtE= go.etcd.io/etcd/server/v3 v3.6.4 h1:LsCA7CzjVt+8WGrdsnh6RhC0XqCsLkBly3ve5rTxMAU= @@ -189,26 +212,26 @@ go.etcd.io/raft/v3 v3.6.0 h1:5NtvbDVYpnfZWcIHgGRk9DyzkBIXOi8j+DDp1IcnUWQ= go.etcd.io/raft/v3 v3.6.0/go.mod h1:nLvLevg6+xrVtHUmVaTcTz603gQPHfh7kUAwV6YpfGo= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= -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/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/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/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.64.0 h1:RN3ifU8y4prNWeEnQp2kRRHz8UwonAEYZl8tUzHEXAk= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.64.0/go.mod h1:habDz3tEWiFANTo6oUE99EmaFUrCNYAAg3wiVmusm70= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.64.0 h1:ssfIgGNANqpVFCndZvcuyKbl0g+UAVcbBcqGkG28H0Y= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.64.0/go.mod h1:GQ/474YrbE4Jx8gZ4q5I4hrhUzM6UPzyrqJYV2AqPoQ= +go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48= +go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0 h1:f0cb2XPmrqn4XMy9PNliTgRKJgS5WcL/u0/WRYGz4t0= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0/go.mod h1:vnakAaFckOMiMtOIhFI2MNH4FYrZzXCYxmb1LlhoGz8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0 h1:in9O8ESIOlwJAEGTkkf34DesGRAc/Pn8qJ7k3r/42LM= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0/go.mod h1:Rp0EXBm5tfnv0WL+ARyO/PHBEaEAT8UUHQ6AGJcSq6c= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0 h1:Ckwye2FpXkYgiHX7fyVrN1uA/UYd9ounqqTuSNAv0k4= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0/go.mod h1:teIFJh5pW2y+AN7riv6IBPX2DuesS3HgP39mwOspKwU= +go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0= +go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs= +go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18= +go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE= +go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8= +go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew= +go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI= +go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA= go.opentelemetry.io/proto/otlp v1.9.0 h1:l706jCMITVouPOqEnii2fIAuO3IVGBRPV5ICjceRb/A= go.opentelemetry.io/proto/otlp v1.9.0/go.mod h1:xE+Cx5E/eEHw+ISFkwPLwCZefwVjY+pqKg1qcK03+/4= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= @@ -224,8 +247,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.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q= -golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4= +golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU= +golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0= 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,30 +259,30 @@ 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.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= -golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= +golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= +golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.33.0 h1:4Q+qn+E5z8gPRJfmRy7C2gGG3T4jIprK6aSYgTXGRpo= -golang.org/x/oauth2 v0.33.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= +golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw= +golang.org/x/oauth2 v0.34.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-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.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= -golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 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.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= -golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU= -golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254= +golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= +golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q= +golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg= 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.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= -golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= +golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= +golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= 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= @@ -267,8 +290,8 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm 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.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ= -golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ= +golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA= +golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc= 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= @@ -279,20 +302,20 @@ 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/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto/googleapis/api v0.0.0-20251111163417-95abcf5c77ba h1:B14OtaXuMaCQsl2deSvNkyPKIzq3BjfxQp8d00QyWx4= -google.golang.org/genproto/googleapis/api v0.0.0-20251111163417-95abcf5c77ba/go.mod h1:G5IanEx8/PgI9w6CFcYQf7jMtHQhZruvfM1i3qOqk5U= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba h1:UKgtfRM7Yh93Sya0Fo8ZzhDP4qBckrrxEr2oF5UIVb8= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= +google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2 h1:7LRqPCEdE4TP4/9psdaB7F2nhZFfBiGJomA5sojLWdU= +google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2/go.mod h1:+rXWjjaukWZun3mLfjmVnQi18E1AsFbDN9QdJ5YXLto= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2 h1:2I6GHUeJ/4shcDpoUlLs/2WPnhg7yJwvXtqcMJt9liA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/grpc v1.18.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM= google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= -google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= -google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/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/evanphx/json-patch.v4 v4.13.0 h1:czT3CmqEaQ1aanPc5SdlgQrrEIb8w/wwCvWWnfEbYzo= +gopkg.in/evanphx/json-patch.v4 v4.13.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/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= @@ -300,28 +323,28 @@ gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYs gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -k8s.io/api v0.34.2 h1:fsSUNZhV+bnL6Aqrp6O7lMTy6o5x2C4XLjnh//8SLYY= -k8s.io/api v0.34.2/go.mod h1:MMBPaWlED2a8w4RSeanD76f7opUoypY8TFYkSM+3XHw= -k8s.io/apiextensions-apiserver v0.34.2 h1:WStKftnGeoKP4AZRz/BaAAEJvYp4mlZGN0UCv+uvsqo= -k8s.io/apiextensions-apiserver v0.34.2/go.mod h1:398CJrsgXF1wytdaanynDpJ67zG4Xq7yj91GrmYN2SE= -k8s.io/apimachinery v0.34.2 h1:zQ12Uk3eMHPxrsbUJgNF8bTauTVR2WgqJsTmwTE/NW4= -k8s.io/apimachinery v0.34.2/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= -k8s.io/apiserver v0.34.2 h1:2/yu8suwkmES7IzwlehAovo8dDE07cFRC7KMDb1+MAE= -k8s.io/apiserver v0.34.2/go.mod h1:gqJQy2yDOB50R3JUReHSFr+cwJnL8G1dzTA0YLEqAPI= -k8s.io/client-go v0.34.2 h1:Co6XiknN+uUZqiddlfAjT68184/37PS4QAzYvQvDR8M= -k8s.io/client-go v0.34.2/go.mod h1:2VYDl1XXJsdcAxw7BenFslRQX28Dxz91U9MWKjX97fE= -k8s.io/component-base v0.34.2 h1:HQRqK9x2sSAsd8+R4xxRirlTjowsg6fWCPwWYeSvogQ= -k8s.io/component-base v0.34.2/go.mod h1:9xw2FHJavUHBFpiGkZoKuYZ5pdtLKe97DEByaA+hHbM= +k8s.io/api v0.34.3 h1:D12sTP257/jSH2vHV2EDYrb16bS7ULlHpdNdNhEw2S4= +k8s.io/api v0.34.3/go.mod h1:PyVQBF886Q5RSQZOim7DybQjAbVs8g7gwJNhGtY5MBk= +k8s.io/apiextensions-apiserver v0.34.3 h1:p10fGlkDY09eWKOTeUSioxwLukJnm+KuDZdrW71y40g= +k8s.io/apiextensions-apiserver v0.34.3/go.mod h1:aujxvqGFRdb/cmXYfcRTeppN7S2XV/t7WMEc64zB5A0= +k8s.io/apimachinery v0.34.3 h1:/TB+SFEiQvN9HPldtlWOTp0hWbJ+fjU+wkxysf/aQnE= +k8s.io/apimachinery v0.34.3/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= +k8s.io/apiserver v0.34.3 h1:uGH1qpDvSiYG4HVFqc6A3L4CKiX+aBWDrrsxHYK0Bdo= +k8s.io/apiserver v0.34.3/go.mod h1:QPnnahMO5C2m3lm6fPW3+JmyQbvHZQ8uudAu/493P2w= +k8s.io/client-go v0.34.3 h1:wtYtpzy/OPNYf7WyNBTj3iUA0XaBHVqhv4Iv3tbrF5A= +k8s.io/client-go v0.34.3/go.mod h1:OxxeYagaP9Kdf78UrKLa3YZixMCfP6bgPwPwNBQBzpM= +k8s.io/component-base v0.34.3 h1:zsEgw6ELqK0XncCQomgO9DpUIzlrYuZYA0Cgo+JWpVk= +k8s.io/component-base v0.34.3/go.mod h1:5iIlD8wPfWE/xSHTRfbjuvUul2WZbI2nOUK65XL0E/c= 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/apiserver-network-proxy/konnectivity-client v0.31.2 h1:jpcvIRr3GLoUoEKRkHKSmGjxb6lWwrBlJsXc+eUYQHM= -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= +k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e h1:iW9ChlU0cU16w8MpVYjXk12dqQ4BPFBEgif+ap7/hqQ= +k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e/go.mod h1:kdmbQkyfwUagLfXIad1y2TdrjPFWp2Q89B3qkRwf/pQ= +k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 h1:SjGebBtkBqHFOli+05xYbK8YF1Dzkbzn+gDM4X9T4Ck= +k8s.io/utils v0.0.0-20251002143259-bc988d571ff4/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.34.0 h1:hSfpvjjTQXQY2Fol2CS0QHMNs/WI1MOSGzCm1KhM5ec= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.34.0/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw= +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg= +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/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.1 h1:JrhdFMqOd/+3ByqlP2I45kTOZmTRLBUm5pvRjeheg7E= diff --git a/apps/alerting/notifications/kinds/v0alpha1/template_spec.cue b/apps/alerting/notifications/kinds/v0alpha1/template_spec.cue index 4c3157f39a4..297d3331eeb 100644 --- a/apps/alerting/notifications/kinds/v0alpha1/template_spec.cue +++ b/apps/alerting/notifications/kinds/v0alpha1/template_spec.cue @@ -1,6 +1,9 @@ package v0alpha1 +TemplateKind: *"grafana" | "mimir" + TemplateGroupSpec: { title: string content: string + kind: TemplateKind } diff --git a/apps/alerting/notifications/pkg/apis/alertingnotifications/v0alpha1/templategroup_spec_gen.go b/apps/alerting/notifications/pkg/apis/alertingnotifications/v0alpha1/templategroup_spec_gen.go index ecba2959665..2f4fee39b9e 100644 --- a/apps/alerting/notifications/pkg/apis/alertingnotifications/v0alpha1/templategroup_spec_gen.go +++ b/apps/alerting/notifications/pkg/apis/alertingnotifications/v0alpha1/templategroup_spec_gen.go @@ -2,13 +2,24 @@ package v0alpha1 +// +k8s:openapi-gen=true +type TemplateGroupTemplateKind string + +const ( + TemplateGroupTemplateKindGrafana TemplateGroupTemplateKind = "grafana" + TemplateGroupTemplateKindMimir TemplateGroupTemplateKind = "mimir" +) + // +k8s:openapi-gen=true type TemplateGroupSpec struct { - Title string `json:"title"` - Content string `json:"content"` + Title string `json:"title"` + Content string `json:"content"` + Kind TemplateGroupTemplateKind `json:"kind"` } // NewTemplateGroupSpec creates a new TemplateGroupSpec object. func NewTemplateGroupSpec() *TemplateGroupSpec { - return &TemplateGroupSpec{} + return &TemplateGroupSpec{ + Kind: TemplateGroupTemplateKindGrafana, + } } diff --git a/apps/alerting/notifications/pkg/apis/alertingnotifications_manifest.go b/apps/alerting/notifications/pkg/apis/alertingnotifications_manifest.go index e16f443a4f6..18447f62760 100644 --- a/apps/alerting/notifications/pkg/apis/alertingnotifications_manifest.go +++ b/apps/alerting/notifications/pkg/apis/alertingnotifications_manifest.go @@ -26,7 +26,7 @@ var ( rawSchemaRoutingTreev0alpha1 = []byte(`{"Matcher":{"additionalProperties":false,"properties":{"label":{"type":"string"},"type":{"enum":["=","!=","=~","!~"],"type":"string"},"value":{"type":"string"}},"required":["type","label","value"],"type":"object"},"Route":{"additionalProperties":false,"properties":{"active_time_intervals":{"items":{"type":"string"},"type":"array"},"continue":{"type":"boolean"},"group_by":{"items":{"type":"string"},"type":"array"},"group_interval":{"type":"string"},"group_wait":{"type":"string"},"matchers":{"items":{"$ref":"#/components/schemas/Matcher"},"type":"array"},"mute_time_intervals":{"items":{"type":"string"},"type":"array"},"receiver":{"type":"string"},"repeat_interval":{"type":"string"},"routes":{"items":{"$ref":"#/components/schemas/Route"},"type":"array"}},"required":["continue"],"type":"object"},"RouteDefaults":{"additionalProperties":false,"properties":{"group_by":{"items":{"type":"string"},"type":"array"},"group_interval":{"type":"string"},"group_wait":{"type":"string"},"receiver":{"type":"string"},"repeat_interval":{"type":"string"}},"required":["receiver"],"type":"object"},"RoutingTree":{"properties":{"spec":{"$ref":"#/components/schemas/spec"}},"required":["spec"]},"spec":{"additionalProperties":false,"properties":{"defaults":{"$ref":"#/components/schemas/RouteDefaults"},"routes":{"items":{"$ref":"#/components/schemas/Route"},"type":"array"}},"required":["defaults","routes"],"type":"object"}}`) versionSchemaRoutingTreev0alpha1 app.VersionSchema _ = json.Unmarshal(rawSchemaRoutingTreev0alpha1, &versionSchemaRoutingTreev0alpha1) - rawSchemaTemplateGroupv0alpha1 = []byte(`{"TemplateGroup":{"properties":{"spec":{"$ref":"#/components/schemas/spec"}},"required":["spec"]},"spec":{"additionalProperties":false,"properties":{"content":{"type":"string"},"title":{"type":"string"}},"required":["title","content"],"type":"object"}}`) + rawSchemaTemplateGroupv0alpha1 = []byte(`{"TemplateGroup":{"properties":{"spec":{"$ref":"#/components/schemas/spec"}},"required":["spec"]},"TemplateKind":{"enum":["grafana","mimir"],"type":"string"},"spec":{"additionalProperties":false,"properties":{"content":{"type":"string"},"kind":{"$ref":"#/components/schemas/TemplateKind","default":"grafana"},"title":{"type":"string"}},"required":["title","content","kind"],"type":"object"}}`) versionSchemaTemplateGroupv0alpha1 app.VersionSchema _ = json.Unmarshal(rawSchemaTemplateGroupv0alpha1, &versionSchemaTemplateGroupv0alpha1) rawSchemaTimeIntervalv0alpha1 = []byte(`{"Interval":{"additionalProperties":false,"properties":{"days_of_month":{"items":{"type":"string"},"type":"array"},"location":{"type":"string"},"months":{"items":{"type":"string"},"type":"array"},"times":{"items":{"$ref":"#/components/schemas/TimeRange"},"type":"array"},"weekdays":{"items":{"type":"string"},"type":"array"},"years":{"items":{"type":"string"},"type":"array"}},"type":"object"},"TimeInterval":{"properties":{"spec":{"$ref":"#/components/schemas/spec"}},"required":["spec"]},"TimeRange":{"additionalProperties":false,"properties":{"end_time":{"type":"string"},"start_time":{"type":"string"}},"required":["start_time","end_time"],"type":"object"},"spec":{"additionalProperties":false,"properties":{"name":{"type":"string"},"time_intervals":{"items":{"$ref":"#/components/schemas/Interval"},"type":"array"}},"required":["name","time_intervals"],"type":"object"}}`) diff --git a/apps/alerting/rules/go.mod b/apps/alerting/rules/go.mod index 63da00536a6..45028a5bb0f 100644 --- a/apps/alerting/rules/go.mod +++ b/apps/alerting/rules/go.mod @@ -3,16 +3,16 @@ module github.com/grafana/grafana/apps/alerting/rules go 1.25.5 require ( - github.com/grafana/grafana-app-sdk v0.48.5 - github.com/grafana/grafana-app-sdk/logging v0.48.3 - github.com/prometheus/common v0.67.3 - k8s.io/apimachinery v0.34.2 - k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 + github.com/grafana/grafana-app-sdk v0.48.7 + github.com/grafana/grafana-app-sdk/logging v0.48.7 + github.com/prometheus/common v0.67.4 + k8s.io/apimachinery v0.34.3 + k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e ) require ( github.com/beorn7/perks v1.0.1 // indirect - github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874 // indirect + github.com/bradfitz/gomemcache v0.0.0-20250403215159-8d39553ac7cf // 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 @@ -22,13 +22,23 @@ require ( github.com/getkin/kin-openapi v0.133.0 // 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.1 // indirect - github.com/go-openapi/swag/jsonname v0.25.1 // indirect + github.com/go-openapi/jsonpointer v0.22.4 // indirect + github.com/go-openapi/jsonreference v0.21.4 // indirect + github.com/go-openapi/swag v0.25.4 // indirect + github.com/go-openapi/swag/cmdutils v0.25.4 // indirect + github.com/go-openapi/swag/conv v0.25.4 // indirect + github.com/go-openapi/swag/fileutils v0.25.4 // indirect + github.com/go-openapi/swag/jsonname v0.25.4 // indirect + github.com/go-openapi/swag/jsonutils v0.25.4 // indirect + github.com/go-openapi/swag/loading v0.25.4 // indirect + github.com/go-openapi/swag/mangling v0.25.4 // indirect + github.com/go-openapi/swag/netutils v0.25.4 // indirect + github.com/go-openapi/swag/stringutils v0.25.4 // indirect + github.com/go-openapi/swag/typeutils v0.25.4 // indirect + github.com/go-openapi/swag/yamlutils v0.25.4 // 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/gnostic-models v0.7.1 // 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 @@ -37,7 +47,7 @@ require ( 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/mailru/easyjson v0.9.1 // 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 @@ -50,42 +60,42 @@ require ( 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/procfs v0.16.1 // indirect + github.com/prometheus/procfs v0.19.2 // 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/woodsbury/decimal128 v1.4.0 // indirect github.com/x448/float16 v0.8.4 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // 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/otel v1.39.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0 // indirect + go.opentelemetry.io/otel/metric v1.39.0 // indirect + go.opentelemetry.io/otel/sdk v1.39.0 // indirect + go.opentelemetry.io/otel/trace v1.39.0 // indirect go.opentelemetry.io/proto/otlp v1.9.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.47.0 // indirect - golang.org/x/oauth2 v0.33.0 // indirect - golang.org/x/sync v0.18.0 // indirect - golang.org/x/sys v0.38.0 // indirect - golang.org/x/term v0.37.0 // indirect - golang.org/x/text v0.31.0 // indirect + golang.org/x/net v0.48.0 // indirect + golang.org/x/oauth2 v0.34.0 // indirect + golang.org/x/sync v0.19.0 // indirect + golang.org/x/sys v0.39.0 // indirect + golang.org/x/term v0.38.0 // indirect + golang.org/x/text v0.32.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-20251111163417-95abcf5c77ba // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2 // indirect google.golang.org/grpc v1.77.0 // indirect - google.golang.org/protobuf v1.36.10 // indirect + google.golang.org/protobuf v1.36.11 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/api v0.34.2 // indirect - k8s.io/apiextensions-apiserver v0.34.2 // indirect - k8s.io/client-go v0.34.2 // indirect + k8s.io/api v0.34.3 // indirect + k8s.io/apiextensions-apiserver v0.34.3 // indirect + k8s.io/client-go v0.34.3 // 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 + k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 // indirect + sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect sigs.k8s.io/randfill v1.0.0 // indirect sigs.k8s.io/structured-merge-diff/v6 v6.3.1 // indirect sigs.k8s.io/yaml v1.6.0 // indirect diff --git a/apps/alerting/rules/go.sum b/apps/alerting/rules/go.sum index 3df8e8b5ebe..e5233ba82c9 100644 --- a/apps/alerting/rules/go.sum +++ b/apps/alerting/rules/go.sum @@ -1,7 +1,7 @@ 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/bradfitz/gomemcache v0.0.0-20250403215159-8d39553ac7cf h1:TqhNAT4zKbTdLa62d2HDBFdvgSbIGB3eJE8HqhgiL9I= +github.com/bradfitz/gomemcache v0.0.0-20250403215159-8d39553ac7cf/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= @@ -23,14 +23,40 @@ 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.1 h1:lpsStH0n2ittzTnbaSloVZLuB5+fvSY/+hnagBjSNZU= -github.com/go-openapi/swag v0.23.1/go.mod h1:STZs8TbRvEQQKUA+JZNAm3EWlgaOBGpyFDqQnDHMef0= -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/jsonpointer v0.22.4 h1:dZtK82WlNpVLDW2jlA1YCiVJFVqkED1MegOUy9kR5T4= +github.com/go-openapi/jsonpointer v0.22.4/go.mod h1:elX9+UgznpFhgBuaMQ7iu4lvvX1nvNsesQ3oxmYTw80= +github.com/go-openapi/jsonreference v0.21.4 h1:24qaE2y9bx/q3uRK/qN+TDwbok1NhbSmGjjySRCHtC8= +github.com/go-openapi/jsonreference v0.21.4/go.mod h1:rIENPTjDbLpzQmQWCj5kKj3ZlmEh+EFVbz3RTUh30/4= +github.com/go-openapi/swag v0.25.4 h1:OyUPUFYDPDBMkqyxOTkqDYFnrhuhi9NR6QVUvIochMU= +github.com/go-openapi/swag v0.25.4/go.mod h1:zNfJ9WZABGHCFg2RnY0S4IOkAcVTzJ6z2Bi+Q4i6qFQ= +github.com/go-openapi/swag/cmdutils v0.25.4 h1:8rYhB5n6WawR192/BfUu2iVlxqVR9aRgGJP6WaBoW+4= +github.com/go-openapi/swag/cmdutils v0.25.4/go.mod h1:pdae/AFo6WxLl5L0rq87eRzVPm/XRHM3MoYgRMvG4A0= +github.com/go-openapi/swag/conv v0.25.4 h1:/Dd7p0LZXczgUcC/Ikm1+YqVzkEeCc9LnOWjfkpkfe4= +github.com/go-openapi/swag/conv v0.25.4/go.mod h1:3LXfie/lwoAv0NHoEuY1hjoFAYkvlqI/Bn5EQDD3PPU= +github.com/go-openapi/swag/fileutils v0.25.4 h1:2oI0XNW5y6UWZTC7vAxC8hmsK/tOkWXHJQH4lKjqw+Y= +github.com/go-openapi/swag/fileutils v0.25.4/go.mod h1:cdOT/PKbwcysVQ9Tpr0q20lQKH7MGhOEb6EwmHOirUk= +github.com/go-openapi/swag/jsonname v0.25.4 h1:bZH0+MsS03MbnwBXYhuTttMOqk+5KcQ9869Vye1bNHI= +github.com/go-openapi/swag/jsonname v0.25.4/go.mod h1:GPVEk9CWVhNvWhZgrnvRA6utbAltopbKwDu8mXNUMag= +github.com/go-openapi/swag/jsonutils v0.25.4 h1:VSchfbGhD4UTf4vCdR2F4TLBdLwHyUDTd1/q4i+jGZA= +github.com/go-openapi/swag/jsonutils v0.25.4/go.mod h1:7OYGXpvVFPn4PpaSdPHJBtF0iGnbEaTk8AvBkoWnaAY= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4 h1:IACsSvBhiNJwlDix7wq39SS2Fh7lUOCJRmx/4SN4sVo= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4/go.mod h1:Mt0Ost9l3cUzVv4OEZG+WSeoHwjWLnarzMePNDAOBiM= +github.com/go-openapi/swag/loading v0.25.4 h1:jN4MvLj0X6yhCDduRsxDDw1aHe+ZWoLjW+9ZQWIKn2s= +github.com/go-openapi/swag/loading v0.25.4/go.mod h1:rpUM1ZiyEP9+mNLIQUdMiD7dCETXvkkC30z53i+ftTE= +github.com/go-openapi/swag/mangling v0.25.4 h1:2b9kBJk9JvPgxr36V23FxJLdwBrpijI26Bx5JH4Hp48= +github.com/go-openapi/swag/mangling v0.25.4/go.mod h1:6dxwu6QyORHpIIApsdZgb6wBk/DPU15MdyYj/ikn0Hg= +github.com/go-openapi/swag/netutils v0.25.4 h1:Gqe6K71bGRb3ZQLusdI8p/y1KLgV4M/k+/HzVSqT8H0= +github.com/go-openapi/swag/netutils v0.25.4/go.mod h1:m2W8dtdaoX7oj9rEttLyTeEFFEBvnAx9qHd5nJEBzYg= +github.com/go-openapi/swag/stringutils v0.25.4 h1:O6dU1Rd8bej4HPA3/CLPciNBBDwZj9HiEpdVsb8B5A8= +github.com/go-openapi/swag/stringutils v0.25.4/go.mod h1:GTsRvhJW5xM5gkgiFe0fV3PUlFm0dr8vki6/VSRaZK0= +github.com/go-openapi/swag/typeutils v0.25.4 h1:1/fbZOUN472NTc39zpa+YGHn3jzHWhv42wAJSN91wRw= +github.com/go-openapi/swag/typeutils v0.25.4/go.mod h1:Ou7g//Wx8tTLS9vG0UmzfCsjZjKhpjxayRKTHXf2pTE= +github.com/go-openapi/swag/yamlutils v0.25.4 h1:6jdaeSItEUb7ioS9lFoCZ65Cne1/RZtPBZ9A56h92Sw= +github.com/go-openapi/swag/yamlutils v0.25.4/go.mod h1:MNzq1ulQu+yd8Kl7wPOut/YHAAU/H6hL91fF+E2RFwc= +github.com/go-openapi/testify/enable/yaml/v2 v2.0.2 h1:0+Y41Pz1NkbTHz8NngxTuAXxEodtNSI1WG1c/m5Akw4= +github.com/go-openapi/testify/enable/yaml/v2 v2.0.2/go.mod h1:kme83333GCtJQHXQ8UKX3IBZu6z8T5Dvy5+CW3NLUUg= +github.com/go-openapi/testify/v2 v2.0.2 h1:X999g3jeLcoY8qctY/c/Z8iBHTbwLz7R2WXd6Ub6wls= +github.com/go-openapi/testify/v2 v2.0.2/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= 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= @@ -39,8 +65,8 @@ 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/gnostic-models v0.7.1 h1:SisTfuFKJSKM5CPZkffwi6coztzzeYUhc3v4yxLWH8c= +github.com/google/gnostic-models v0.7.1/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= @@ -48,10 +74,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.48.5 h1:MS8l9fTZz+VbTfgApn09jw27GxhQ6fNOWGhC4ydvZmM= -github.com/grafana/grafana-app-sdk v0.48.5/go.mod h1:HJsMOSBmt/D/Ihs1SvagOwmXKi0coBMVHlfvdd+qe9Y= -github.com/grafana/grafana-app-sdk/logging v0.48.3 h1:72NUpGNiJXCNQz/on++YSsl38xuVYYBKv5kKQaOClX4= -github.com/grafana/grafana-app-sdk/logging v0.48.3/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA= +github.com/grafana/grafana-app-sdk v0.48.7 h1:9mF7nqkqP0QUYYDlznoOt+GIyjzj45wGfUHB32u2ZMo= +github.com/grafana/grafana-app-sdk v0.48.7/go.mod h1:DWsaaH39ZMHwSOSoUBaeW8paMrRaYsjRYlLwCJYd78k= +github.com/grafana/grafana-app-sdk/logging v0.48.7 h1:Oa5qg473gka5+W/WQk61Xbw4YdAv+wV2Z4bJtzeCaQw= +github.com/grafana/grafana-app-sdk/logging v0.48.7/go.mod h1:5u3KalezoBAAo2Y3ytDYDAIIPvEqFLLDSxeiK99QxDU= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3 h1:NmZ1PKzSTQbuGHw9DGPFomqkkLWMC+vZCkfs+FHv1Vg= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3/go.mod h1:zQrxl1YP88HQlA6i9c63DSVPFklWpGX4OWAc9bFuaH4= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -73,8 +99,8 @@ 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/mailru/easyjson v0.9.1 h1:LbtsOm5WAswyWbvTEOqhypdPeZzHavpZx96/n553mR8= +github.com/mailru/easyjson v0.9.1/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= @@ -95,8 +121,6 @@ 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/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= @@ -104,10 +128,10 @@ github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h 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.3 h1:shd26MlnwTw5jksTDhC7rTQIteBxy+ZZDr3t7F2xN2Q= -github.com/prometheus/common v0.67.3/go.mod h1:gP0fq6YjjNCLssJCQp0yk4M8W6ikLURwkdd/YKtTbyI= -github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= -github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= +github.com/prometheus/common v0.67.4 h1:yR3NqWO1/UyO1w2PhUvXlGQs/PtFmoveVO0KZ4+Lvsc= +github.com/prometheus/common v0.67.4/go.mod h1:gP0fq6YjjNCLssJCQp0yk4M8W6ikLURwkdd/YKtTbyI= +github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws= +github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw= 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= @@ -122,30 +146,30 @@ 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/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/woodsbury/decimal128 v1.4.0 h1:xJATj7lLu4f2oObouMt2tgGiElE5gO6mSWUjQsBgUlc= +github.com/woodsbury/decimal128 v1.4.0/go.mod h1:BP46FUrVjVhdTbKT+XuQh2xfQaGki9LMIRJSFuh6THU= 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.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= -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/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48= +go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0 h1:f0cb2XPmrqn4XMy9PNliTgRKJgS5WcL/u0/WRYGz4t0= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0/go.mod h1:vnakAaFckOMiMtOIhFI2MNH4FYrZzXCYxmb1LlhoGz8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0 h1:in9O8ESIOlwJAEGTkkf34DesGRAc/Pn8qJ7k3r/42LM= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0/go.mod h1:Rp0EXBm5tfnv0WL+ARyO/PHBEaEAT8UUHQ6AGJcSq6c= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0 h1:Ckwye2FpXkYgiHX7fyVrN1uA/UYd9ounqqTuSNAv0k4= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0/go.mod h1:teIFJh5pW2y+AN7riv6IBPX2DuesS3HgP39mwOspKwU= +go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0= +go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs= +go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18= +go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE= +go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8= +go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew= +go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI= +go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA= go.opentelemetry.io/proto/otlp v1.9.0 h1:l706jCMITVouPOqEnii2fIAuO3IVGBRPV5ICjceRb/A= go.opentelemetry.io/proto/otlp v1.9.0/go.mod h1:xE+Cx5E/eEHw+ISFkwPLwCZefwVjY+pqKg1qcK03+/4= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= @@ -163,34 +187,34 @@ 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.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= -golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= -golang.org/x/oauth2 v0.33.0 h1:4Q+qn+E5z8gPRJfmRy7C2gGG3T4jIprK6aSYgTXGRpo= -golang.org/x/oauth2 v0.33.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= +golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= +golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= +golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw= +golang.org/x/oauth2 v0.34.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.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= -golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.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.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= -golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU= -golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254= +golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= +golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q= +golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg= 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.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= -golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= +golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= +golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= 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.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ= -golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ= +golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA= +golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc= 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= @@ -199,39 +223,39 @@ 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-20251111163417-95abcf5c77ba h1:B14OtaXuMaCQsl2deSvNkyPKIzq3BjfxQp8d00QyWx4= -google.golang.org/genproto/googleapis/api v0.0.0-20251111163417-95abcf5c77ba/go.mod h1:G5IanEx8/PgI9w6CFcYQf7jMtHQhZruvfM1i3qOqk5U= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba h1:UKgtfRM7Yh93Sya0Fo8ZzhDP4qBckrrxEr2oF5UIVb8= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= +google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2 h1:7LRqPCEdE4TP4/9psdaB7F2nhZFfBiGJomA5sojLWdU= +google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2/go.mod h1:+rXWjjaukWZun3mLfjmVnQi18E1AsFbDN9QdJ5YXLto= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2 h1:2I6GHUeJ/4shcDpoUlLs/2WPnhg7yJwvXtqcMJt9liA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM= google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= -google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= -google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/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/evanphx/json-patch.v4 v4.13.0 h1:czT3CmqEaQ1aanPc5SdlgQrrEIb8w/wwCvWWnfEbYzo= +gopkg.in/evanphx/json-patch.v4 v4.13.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.2 h1:fsSUNZhV+bnL6Aqrp6O7lMTy6o5x2C4XLjnh//8SLYY= -k8s.io/api v0.34.2/go.mod h1:MMBPaWlED2a8w4RSeanD76f7opUoypY8TFYkSM+3XHw= -k8s.io/apiextensions-apiserver v0.34.2 h1:WStKftnGeoKP4AZRz/BaAAEJvYp4mlZGN0UCv+uvsqo= -k8s.io/apiextensions-apiserver v0.34.2/go.mod h1:398CJrsgXF1wytdaanynDpJ67zG4Xq7yj91GrmYN2SE= -k8s.io/apimachinery v0.34.2 h1:zQ12Uk3eMHPxrsbUJgNF8bTauTVR2WgqJsTmwTE/NW4= -k8s.io/apimachinery v0.34.2/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= -k8s.io/client-go v0.34.2 h1:Co6XiknN+uUZqiddlfAjT68184/37PS4QAzYvQvDR8M= -k8s.io/client-go v0.34.2/go.mod h1:2VYDl1XXJsdcAxw7BenFslRQX28Dxz91U9MWKjX97fE= +k8s.io/api v0.34.3 h1:D12sTP257/jSH2vHV2EDYrb16bS7ULlHpdNdNhEw2S4= +k8s.io/api v0.34.3/go.mod h1:PyVQBF886Q5RSQZOim7DybQjAbVs8g7gwJNhGtY5MBk= +k8s.io/apiextensions-apiserver v0.34.3 h1:p10fGlkDY09eWKOTeUSioxwLukJnm+KuDZdrW71y40g= +k8s.io/apiextensions-apiserver v0.34.3/go.mod h1:aujxvqGFRdb/cmXYfcRTeppN7S2XV/t7WMEc64zB5A0= +k8s.io/apimachinery v0.34.3 h1:/TB+SFEiQvN9HPldtlWOTp0hWbJ+fjU+wkxysf/aQnE= +k8s.io/apimachinery v0.34.3/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= +k8s.io/client-go v0.34.3 h1:wtYtpzy/OPNYf7WyNBTj3iUA0XaBHVqhv4Iv3tbrF5A= +k8s.io/client-go v0.34.3/go.mod h1:OxxeYagaP9Kdf78UrKLa3YZixMCfP6bgPwPwNBQBzpM= 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= +k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e h1:iW9ChlU0cU16w8MpVYjXk12dqQ4BPFBEgif+ap7/hqQ= +k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e/go.mod h1:kdmbQkyfwUagLfXIad1y2TdrjPFWp2Q89B3qkRwf/pQ= +k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 h1:SjGebBtkBqHFOli+05xYbK8YF1Dzkbzn+gDM4X9T4Ck= +k8s.io/utils v0.0.0-20251002143259-bc988d571ff4/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg= +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/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.1 h1:JrhdFMqOd/+3ByqlP2I45kTOZmTRLBUm5pvRjeheg7E= diff --git a/apps/annotation/go.mod b/apps/annotation/go.mod index 946c42fe38f..aa4942ccd60 100644 --- a/apps/annotation/go.mod +++ b/apps/annotation/go.mod @@ -3,15 +3,15 @@ module github.com/grafana/grafana/apps/annotation go 1.25.5 require ( - github.com/grafana/grafana-app-sdk v0.48.5 - github.com/grafana/grafana-app-sdk/logging v0.48.3 - k8s.io/apimachinery v0.34.2 - k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 + github.com/grafana/grafana-app-sdk v0.48.7 + github.com/grafana/grafana-app-sdk/logging v0.48.7 + k8s.io/apimachinery v0.34.3 + k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e ) require ( github.com/beorn7/perks v1.0.1 // indirect - github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874 // indirect + github.com/bradfitz/gomemcache v0.0.0-20250403215159-8d39553ac7cf // 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 @@ -21,13 +21,23 @@ require ( github.com/getkin/kin-openapi v0.133.0 // 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.1 // indirect - github.com/go-openapi/swag/jsonname v0.25.1 // indirect + github.com/go-openapi/jsonpointer v0.22.4 // indirect + github.com/go-openapi/jsonreference v0.21.4 // indirect + github.com/go-openapi/swag v0.25.4 // indirect + github.com/go-openapi/swag/cmdutils v0.25.4 // indirect + github.com/go-openapi/swag/conv v0.25.4 // indirect + github.com/go-openapi/swag/fileutils v0.25.4 // indirect + github.com/go-openapi/swag/jsonname v0.25.4 // indirect + github.com/go-openapi/swag/jsonutils v0.25.4 // indirect + github.com/go-openapi/swag/loading v0.25.4 // indirect + github.com/go-openapi/swag/mangling v0.25.4 // indirect + github.com/go-openapi/swag/netutils v0.25.4 // indirect + github.com/go-openapi/swag/stringutils v0.25.4 // indirect + github.com/go-openapi/swag/typeutils v0.25.4 // indirect + github.com/go-openapi/swag/yamlutils v0.25.4 // 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/gnostic-models v0.7.1 // 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 @@ -36,7 +46,7 @@ require ( 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/mailru/easyjson v0.9.1 // 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 @@ -49,43 +59,43 @@ require ( 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.3 // indirect - github.com/prometheus/procfs v0.16.1 // indirect + github.com/prometheus/common v0.67.4 // indirect + github.com/prometheus/procfs v0.19.2 // 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/woodsbury/decimal128 v1.4.0 // indirect github.com/x448/float16 v0.8.4 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // 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/otel v1.39.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0 // indirect + go.opentelemetry.io/otel/metric v1.39.0 // indirect + go.opentelemetry.io/otel/sdk v1.39.0 // indirect + go.opentelemetry.io/otel/trace v1.39.0 // indirect go.opentelemetry.io/proto/otlp v1.9.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.47.0 // indirect - golang.org/x/oauth2 v0.33.0 // indirect - golang.org/x/sync v0.18.0 // indirect - golang.org/x/sys v0.38.0 // indirect - golang.org/x/term v0.37.0 // indirect - golang.org/x/text v0.31.0 // indirect + golang.org/x/net v0.48.0 // indirect + golang.org/x/oauth2 v0.34.0 // indirect + golang.org/x/sync v0.19.0 // indirect + golang.org/x/sys v0.39.0 // indirect + golang.org/x/term v0.38.0 // indirect + golang.org/x/text v0.32.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-20251111163417-95abcf5c77ba // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2 // indirect google.golang.org/grpc v1.77.0 // indirect - google.golang.org/protobuf v1.36.10 // indirect + google.golang.org/protobuf v1.36.11 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/api v0.34.2 // indirect - k8s.io/apiextensions-apiserver v0.34.2 // indirect - k8s.io/client-go v0.34.2 // indirect + k8s.io/api v0.34.3 // indirect + k8s.io/apiextensions-apiserver v0.34.3 // indirect + k8s.io/client-go v0.34.3 // 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 + k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 // indirect + sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect sigs.k8s.io/randfill v1.0.0 // indirect sigs.k8s.io/structured-merge-diff/v6 v6.3.1 // indirect sigs.k8s.io/yaml v1.6.0 // indirect diff --git a/apps/annotation/go.sum b/apps/annotation/go.sum index 3df8e8b5ebe..e5233ba82c9 100644 --- a/apps/annotation/go.sum +++ b/apps/annotation/go.sum @@ -1,7 +1,7 @@ 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/bradfitz/gomemcache v0.0.0-20250403215159-8d39553ac7cf h1:TqhNAT4zKbTdLa62d2HDBFdvgSbIGB3eJE8HqhgiL9I= +github.com/bradfitz/gomemcache v0.0.0-20250403215159-8d39553ac7cf/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= @@ -23,14 +23,40 @@ 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.1 h1:lpsStH0n2ittzTnbaSloVZLuB5+fvSY/+hnagBjSNZU= -github.com/go-openapi/swag v0.23.1/go.mod h1:STZs8TbRvEQQKUA+JZNAm3EWlgaOBGpyFDqQnDHMef0= -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/jsonpointer v0.22.4 h1:dZtK82WlNpVLDW2jlA1YCiVJFVqkED1MegOUy9kR5T4= +github.com/go-openapi/jsonpointer v0.22.4/go.mod h1:elX9+UgznpFhgBuaMQ7iu4lvvX1nvNsesQ3oxmYTw80= +github.com/go-openapi/jsonreference v0.21.4 h1:24qaE2y9bx/q3uRK/qN+TDwbok1NhbSmGjjySRCHtC8= +github.com/go-openapi/jsonreference v0.21.4/go.mod h1:rIENPTjDbLpzQmQWCj5kKj3ZlmEh+EFVbz3RTUh30/4= +github.com/go-openapi/swag v0.25.4 h1:OyUPUFYDPDBMkqyxOTkqDYFnrhuhi9NR6QVUvIochMU= +github.com/go-openapi/swag v0.25.4/go.mod h1:zNfJ9WZABGHCFg2RnY0S4IOkAcVTzJ6z2Bi+Q4i6qFQ= +github.com/go-openapi/swag/cmdutils v0.25.4 h1:8rYhB5n6WawR192/BfUu2iVlxqVR9aRgGJP6WaBoW+4= +github.com/go-openapi/swag/cmdutils v0.25.4/go.mod h1:pdae/AFo6WxLl5L0rq87eRzVPm/XRHM3MoYgRMvG4A0= +github.com/go-openapi/swag/conv v0.25.4 h1:/Dd7p0LZXczgUcC/Ikm1+YqVzkEeCc9LnOWjfkpkfe4= +github.com/go-openapi/swag/conv v0.25.4/go.mod h1:3LXfie/lwoAv0NHoEuY1hjoFAYkvlqI/Bn5EQDD3PPU= +github.com/go-openapi/swag/fileutils v0.25.4 h1:2oI0XNW5y6UWZTC7vAxC8hmsK/tOkWXHJQH4lKjqw+Y= +github.com/go-openapi/swag/fileutils v0.25.4/go.mod h1:cdOT/PKbwcysVQ9Tpr0q20lQKH7MGhOEb6EwmHOirUk= +github.com/go-openapi/swag/jsonname v0.25.4 h1:bZH0+MsS03MbnwBXYhuTttMOqk+5KcQ9869Vye1bNHI= +github.com/go-openapi/swag/jsonname v0.25.4/go.mod h1:GPVEk9CWVhNvWhZgrnvRA6utbAltopbKwDu8mXNUMag= +github.com/go-openapi/swag/jsonutils v0.25.4 h1:VSchfbGhD4UTf4vCdR2F4TLBdLwHyUDTd1/q4i+jGZA= +github.com/go-openapi/swag/jsonutils v0.25.4/go.mod h1:7OYGXpvVFPn4PpaSdPHJBtF0iGnbEaTk8AvBkoWnaAY= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4 h1:IACsSvBhiNJwlDix7wq39SS2Fh7lUOCJRmx/4SN4sVo= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4/go.mod h1:Mt0Ost9l3cUzVv4OEZG+WSeoHwjWLnarzMePNDAOBiM= +github.com/go-openapi/swag/loading v0.25.4 h1:jN4MvLj0X6yhCDduRsxDDw1aHe+ZWoLjW+9ZQWIKn2s= +github.com/go-openapi/swag/loading v0.25.4/go.mod h1:rpUM1ZiyEP9+mNLIQUdMiD7dCETXvkkC30z53i+ftTE= +github.com/go-openapi/swag/mangling v0.25.4 h1:2b9kBJk9JvPgxr36V23FxJLdwBrpijI26Bx5JH4Hp48= +github.com/go-openapi/swag/mangling v0.25.4/go.mod h1:6dxwu6QyORHpIIApsdZgb6wBk/DPU15MdyYj/ikn0Hg= +github.com/go-openapi/swag/netutils v0.25.4 h1:Gqe6K71bGRb3ZQLusdI8p/y1KLgV4M/k+/HzVSqT8H0= +github.com/go-openapi/swag/netutils v0.25.4/go.mod h1:m2W8dtdaoX7oj9rEttLyTeEFFEBvnAx9qHd5nJEBzYg= +github.com/go-openapi/swag/stringutils v0.25.4 h1:O6dU1Rd8bej4HPA3/CLPciNBBDwZj9HiEpdVsb8B5A8= +github.com/go-openapi/swag/stringutils v0.25.4/go.mod h1:GTsRvhJW5xM5gkgiFe0fV3PUlFm0dr8vki6/VSRaZK0= +github.com/go-openapi/swag/typeutils v0.25.4 h1:1/fbZOUN472NTc39zpa+YGHn3jzHWhv42wAJSN91wRw= +github.com/go-openapi/swag/typeutils v0.25.4/go.mod h1:Ou7g//Wx8tTLS9vG0UmzfCsjZjKhpjxayRKTHXf2pTE= +github.com/go-openapi/swag/yamlutils v0.25.4 h1:6jdaeSItEUb7ioS9lFoCZ65Cne1/RZtPBZ9A56h92Sw= +github.com/go-openapi/swag/yamlutils v0.25.4/go.mod h1:MNzq1ulQu+yd8Kl7wPOut/YHAAU/H6hL91fF+E2RFwc= +github.com/go-openapi/testify/enable/yaml/v2 v2.0.2 h1:0+Y41Pz1NkbTHz8NngxTuAXxEodtNSI1WG1c/m5Akw4= +github.com/go-openapi/testify/enable/yaml/v2 v2.0.2/go.mod h1:kme83333GCtJQHXQ8UKX3IBZu6z8T5Dvy5+CW3NLUUg= +github.com/go-openapi/testify/v2 v2.0.2 h1:X999g3jeLcoY8qctY/c/Z8iBHTbwLz7R2WXd6Ub6wls= +github.com/go-openapi/testify/v2 v2.0.2/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= 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= @@ -39,8 +65,8 @@ 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/gnostic-models v0.7.1 h1:SisTfuFKJSKM5CPZkffwi6coztzzeYUhc3v4yxLWH8c= +github.com/google/gnostic-models v0.7.1/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= @@ -48,10 +74,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.48.5 h1:MS8l9fTZz+VbTfgApn09jw27GxhQ6fNOWGhC4ydvZmM= -github.com/grafana/grafana-app-sdk v0.48.5/go.mod h1:HJsMOSBmt/D/Ihs1SvagOwmXKi0coBMVHlfvdd+qe9Y= -github.com/grafana/grafana-app-sdk/logging v0.48.3 h1:72NUpGNiJXCNQz/on++YSsl38xuVYYBKv5kKQaOClX4= -github.com/grafana/grafana-app-sdk/logging v0.48.3/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA= +github.com/grafana/grafana-app-sdk v0.48.7 h1:9mF7nqkqP0QUYYDlznoOt+GIyjzj45wGfUHB32u2ZMo= +github.com/grafana/grafana-app-sdk v0.48.7/go.mod h1:DWsaaH39ZMHwSOSoUBaeW8paMrRaYsjRYlLwCJYd78k= +github.com/grafana/grafana-app-sdk/logging v0.48.7 h1:Oa5qg473gka5+W/WQk61Xbw4YdAv+wV2Z4bJtzeCaQw= +github.com/grafana/grafana-app-sdk/logging v0.48.7/go.mod h1:5u3KalezoBAAo2Y3ytDYDAIIPvEqFLLDSxeiK99QxDU= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3 h1:NmZ1PKzSTQbuGHw9DGPFomqkkLWMC+vZCkfs+FHv1Vg= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3/go.mod h1:zQrxl1YP88HQlA6i9c63DSVPFklWpGX4OWAc9bFuaH4= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -73,8 +99,8 @@ 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/mailru/easyjson v0.9.1 h1:LbtsOm5WAswyWbvTEOqhypdPeZzHavpZx96/n553mR8= +github.com/mailru/easyjson v0.9.1/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= @@ -95,8 +121,6 @@ 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/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= @@ -104,10 +128,10 @@ github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h 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.3 h1:shd26MlnwTw5jksTDhC7rTQIteBxy+ZZDr3t7F2xN2Q= -github.com/prometheus/common v0.67.3/go.mod h1:gP0fq6YjjNCLssJCQp0yk4M8W6ikLURwkdd/YKtTbyI= -github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= -github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= +github.com/prometheus/common v0.67.4 h1:yR3NqWO1/UyO1w2PhUvXlGQs/PtFmoveVO0KZ4+Lvsc= +github.com/prometheus/common v0.67.4/go.mod h1:gP0fq6YjjNCLssJCQp0yk4M8W6ikLURwkdd/YKtTbyI= +github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws= +github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw= 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= @@ -122,30 +146,30 @@ 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/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/woodsbury/decimal128 v1.4.0 h1:xJATj7lLu4f2oObouMt2tgGiElE5gO6mSWUjQsBgUlc= +github.com/woodsbury/decimal128 v1.4.0/go.mod h1:BP46FUrVjVhdTbKT+XuQh2xfQaGki9LMIRJSFuh6THU= 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.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= -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/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48= +go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0 h1:f0cb2XPmrqn4XMy9PNliTgRKJgS5WcL/u0/WRYGz4t0= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0/go.mod h1:vnakAaFckOMiMtOIhFI2MNH4FYrZzXCYxmb1LlhoGz8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0 h1:in9O8ESIOlwJAEGTkkf34DesGRAc/Pn8qJ7k3r/42LM= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0/go.mod h1:Rp0EXBm5tfnv0WL+ARyO/PHBEaEAT8UUHQ6AGJcSq6c= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0 h1:Ckwye2FpXkYgiHX7fyVrN1uA/UYd9ounqqTuSNAv0k4= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0/go.mod h1:teIFJh5pW2y+AN7riv6IBPX2DuesS3HgP39mwOspKwU= +go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0= +go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs= +go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18= +go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE= +go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8= +go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew= +go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI= +go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA= go.opentelemetry.io/proto/otlp v1.9.0 h1:l706jCMITVouPOqEnii2fIAuO3IVGBRPV5ICjceRb/A= go.opentelemetry.io/proto/otlp v1.9.0/go.mod h1:xE+Cx5E/eEHw+ISFkwPLwCZefwVjY+pqKg1qcK03+/4= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= @@ -163,34 +187,34 @@ 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.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= -golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= -golang.org/x/oauth2 v0.33.0 h1:4Q+qn+E5z8gPRJfmRy7C2gGG3T4jIprK6aSYgTXGRpo= -golang.org/x/oauth2 v0.33.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= +golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= +golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= +golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw= +golang.org/x/oauth2 v0.34.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.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= -golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.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.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= -golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU= -golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254= +golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= +golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q= +golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg= 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.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= -golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= +golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= +golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= 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.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ= -golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ= +golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA= +golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc= 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= @@ -199,39 +223,39 @@ 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-20251111163417-95abcf5c77ba h1:B14OtaXuMaCQsl2deSvNkyPKIzq3BjfxQp8d00QyWx4= -google.golang.org/genproto/googleapis/api v0.0.0-20251111163417-95abcf5c77ba/go.mod h1:G5IanEx8/PgI9w6CFcYQf7jMtHQhZruvfM1i3qOqk5U= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba h1:UKgtfRM7Yh93Sya0Fo8ZzhDP4qBckrrxEr2oF5UIVb8= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= +google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2 h1:7LRqPCEdE4TP4/9psdaB7F2nhZFfBiGJomA5sojLWdU= +google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2/go.mod h1:+rXWjjaukWZun3mLfjmVnQi18E1AsFbDN9QdJ5YXLto= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2 h1:2I6GHUeJ/4shcDpoUlLs/2WPnhg7yJwvXtqcMJt9liA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM= google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= -google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= -google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/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/evanphx/json-patch.v4 v4.13.0 h1:czT3CmqEaQ1aanPc5SdlgQrrEIb8w/wwCvWWnfEbYzo= +gopkg.in/evanphx/json-patch.v4 v4.13.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.2 h1:fsSUNZhV+bnL6Aqrp6O7lMTy6o5x2C4XLjnh//8SLYY= -k8s.io/api v0.34.2/go.mod h1:MMBPaWlED2a8w4RSeanD76f7opUoypY8TFYkSM+3XHw= -k8s.io/apiextensions-apiserver v0.34.2 h1:WStKftnGeoKP4AZRz/BaAAEJvYp4mlZGN0UCv+uvsqo= -k8s.io/apiextensions-apiserver v0.34.2/go.mod h1:398CJrsgXF1wytdaanynDpJ67zG4Xq7yj91GrmYN2SE= -k8s.io/apimachinery v0.34.2 h1:zQ12Uk3eMHPxrsbUJgNF8bTauTVR2WgqJsTmwTE/NW4= -k8s.io/apimachinery v0.34.2/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= -k8s.io/client-go v0.34.2 h1:Co6XiknN+uUZqiddlfAjT68184/37PS4QAzYvQvDR8M= -k8s.io/client-go v0.34.2/go.mod h1:2VYDl1XXJsdcAxw7BenFslRQX28Dxz91U9MWKjX97fE= +k8s.io/api v0.34.3 h1:D12sTP257/jSH2vHV2EDYrb16bS7ULlHpdNdNhEw2S4= +k8s.io/api v0.34.3/go.mod h1:PyVQBF886Q5RSQZOim7DybQjAbVs8g7gwJNhGtY5MBk= +k8s.io/apiextensions-apiserver v0.34.3 h1:p10fGlkDY09eWKOTeUSioxwLukJnm+KuDZdrW71y40g= +k8s.io/apiextensions-apiserver v0.34.3/go.mod h1:aujxvqGFRdb/cmXYfcRTeppN7S2XV/t7WMEc64zB5A0= +k8s.io/apimachinery v0.34.3 h1:/TB+SFEiQvN9HPldtlWOTp0hWbJ+fjU+wkxysf/aQnE= +k8s.io/apimachinery v0.34.3/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= +k8s.io/client-go v0.34.3 h1:wtYtpzy/OPNYf7WyNBTj3iUA0XaBHVqhv4Iv3tbrF5A= +k8s.io/client-go v0.34.3/go.mod h1:OxxeYagaP9Kdf78UrKLa3YZixMCfP6bgPwPwNBQBzpM= 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= +k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e h1:iW9ChlU0cU16w8MpVYjXk12dqQ4BPFBEgif+ap7/hqQ= +k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e/go.mod h1:kdmbQkyfwUagLfXIad1y2TdrjPFWp2Q89B3qkRwf/pQ= +k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 h1:SjGebBtkBqHFOli+05xYbK8YF1Dzkbzn+gDM4X9T4Ck= +k8s.io/utils v0.0.0-20251002143259-bc988d571ff4/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg= +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/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.1 h1:JrhdFMqOd/+3ByqlP2I45kTOZmTRLBUm5pvRjeheg7E= diff --git a/apps/collections/go.mod b/apps/collections/go.mod index 00575d7e6d4..05b9e33db99 100644 --- a/apps/collections/go.mod +++ b/apps/collections/go.mod @@ -3,11 +3,11 @@ module github.com/grafana/grafana/apps/collections go 1.25.5 require ( - github.com/grafana/grafana-app-sdk v0.48.5 + github.com/grafana/grafana-app-sdk v0.48.7 github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250804150913-990f1c69ecc2 github.com/stretchr/testify v1.11.1 - k8s.io/apimachinery v0.34.2 - k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 + k8s.io/apimachinery v0.34.3 + k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e ) require ( @@ -18,19 +18,29 @@ require ( github.com/fxamacker/cbor/v2 v2.9.0 // indirect github.com/getkin/kin-openapi v0.133.0 // indirect github.com/go-logr/logr v1.4.3 // 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.1 // indirect - github.com/go-openapi/swag/jsonname v0.25.1 // indirect + github.com/go-openapi/jsonpointer v0.22.4 // indirect + github.com/go-openapi/jsonreference v0.21.4 // indirect + github.com/go-openapi/swag v0.25.4 // indirect + github.com/go-openapi/swag/cmdutils v0.25.4 // indirect + github.com/go-openapi/swag/conv v0.25.4 // indirect + github.com/go-openapi/swag/fileutils v0.25.4 // indirect + github.com/go-openapi/swag/jsonname v0.25.4 // indirect + github.com/go-openapi/swag/jsonutils v0.25.4 // indirect + github.com/go-openapi/swag/loading v0.25.4 // indirect + github.com/go-openapi/swag/mangling v0.25.4 // indirect + github.com/go-openapi/swag/netutils v0.25.4 // indirect + github.com/go-openapi/swag/stringutils v0.25.4 // indirect + github.com/go-openapi/swag/typeutils v0.25.4 // indirect + github.com/go-openapi/swag/yamlutils v0.25.4 // 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/grafana/grafana-app-sdk/logging v0.48.3 // indirect + github.com/google/gnostic-models v0.7.1 // indirect + github.com/grafana/grafana-app-sdk/logging v0.48.7 // 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/mailru/easyjson v0.9.1 // 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 @@ -41,28 +51,28 @@ require ( 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.3 // indirect - github.com/prometheus/procfs v0.16.1 // indirect + github.com/prometheus/common v0.67.4 // indirect + github.com/prometheus/procfs v0.19.2 // indirect github.com/stretchr/objx v0.5.2 // indirect - github.com/woodsbury/decimal128 v1.3.0 // indirect + github.com/woodsbury/decimal128 v1.4.0 // indirect github.com/x448/float16 v0.8.4 // indirect - go.opentelemetry.io/otel v1.38.0 // indirect - go.opentelemetry.io/otel/trace v1.38.0 // indirect + go.opentelemetry.io/otel v1.39.0 // indirect + go.opentelemetry.io/otel/trace v1.39.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.47.0 // indirect - golang.org/x/oauth2 v0.33.0 // indirect - golang.org/x/sys v0.38.0 // indirect - golang.org/x/term v0.37.0 // indirect - golang.org/x/text v0.31.0 // indirect + golang.org/x/net v0.48.0 // indirect + golang.org/x/oauth2 v0.34.0 // indirect + golang.org/x/sys v0.39.0 // indirect + golang.org/x/term v0.38.0 // indirect + golang.org/x/text v0.32.0 // indirect golang.org/x/time v0.14.0 // indirect - google.golang.org/protobuf v1.36.10 // indirect + google.golang.org/protobuf v1.36.11 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/client-go v0.34.2 // indirect + k8s.io/client-go v0.34.3 // 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 + k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 // indirect + sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect sigs.k8s.io/randfill v1.0.0 // indirect sigs.k8s.io/structured-merge-diff/v6 v6.3.1 // indirect sigs.k8s.io/yaml v1.6.0 // indirect diff --git a/apps/collections/go.sum b/apps/collections/go.sum index 75a19848d73..aa5de8cbe99 100644 --- a/apps/collections/go.sum +++ b/apps/collections/go.sum @@ -14,29 +14,55 @@ github.com/getkin/kin-openapi v0.133.0 h1:pJdmNohVIJ97r4AUFtEXRXwESr8b0bD721u/Tz github.com/getkin/kin-openapi v0.133.0/go.mod h1:boAciF6cXk5FhPqe/NQeBTeenbjqU4LhWBf09ILVvWE= 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-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.1 h1:lpsStH0n2ittzTnbaSloVZLuB5+fvSY/+hnagBjSNZU= -github.com/go-openapi/swag v0.23.1/go.mod h1:STZs8TbRvEQQKUA+JZNAm3EWlgaOBGpyFDqQnDHMef0= -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/jsonpointer v0.22.4 h1:dZtK82WlNpVLDW2jlA1YCiVJFVqkED1MegOUy9kR5T4= +github.com/go-openapi/jsonpointer v0.22.4/go.mod h1:elX9+UgznpFhgBuaMQ7iu4lvvX1nvNsesQ3oxmYTw80= +github.com/go-openapi/jsonreference v0.21.4 h1:24qaE2y9bx/q3uRK/qN+TDwbok1NhbSmGjjySRCHtC8= +github.com/go-openapi/jsonreference v0.21.4/go.mod h1:rIENPTjDbLpzQmQWCj5kKj3ZlmEh+EFVbz3RTUh30/4= +github.com/go-openapi/swag v0.25.4 h1:OyUPUFYDPDBMkqyxOTkqDYFnrhuhi9NR6QVUvIochMU= +github.com/go-openapi/swag v0.25.4/go.mod h1:zNfJ9WZABGHCFg2RnY0S4IOkAcVTzJ6z2Bi+Q4i6qFQ= +github.com/go-openapi/swag/cmdutils v0.25.4 h1:8rYhB5n6WawR192/BfUu2iVlxqVR9aRgGJP6WaBoW+4= +github.com/go-openapi/swag/cmdutils v0.25.4/go.mod h1:pdae/AFo6WxLl5L0rq87eRzVPm/XRHM3MoYgRMvG4A0= +github.com/go-openapi/swag/conv v0.25.4 h1:/Dd7p0LZXczgUcC/Ikm1+YqVzkEeCc9LnOWjfkpkfe4= +github.com/go-openapi/swag/conv v0.25.4/go.mod h1:3LXfie/lwoAv0NHoEuY1hjoFAYkvlqI/Bn5EQDD3PPU= +github.com/go-openapi/swag/fileutils v0.25.4 h1:2oI0XNW5y6UWZTC7vAxC8hmsK/tOkWXHJQH4lKjqw+Y= +github.com/go-openapi/swag/fileutils v0.25.4/go.mod h1:cdOT/PKbwcysVQ9Tpr0q20lQKH7MGhOEb6EwmHOirUk= +github.com/go-openapi/swag/jsonname v0.25.4 h1:bZH0+MsS03MbnwBXYhuTttMOqk+5KcQ9869Vye1bNHI= +github.com/go-openapi/swag/jsonname v0.25.4/go.mod h1:GPVEk9CWVhNvWhZgrnvRA6utbAltopbKwDu8mXNUMag= +github.com/go-openapi/swag/jsonutils v0.25.4 h1:VSchfbGhD4UTf4vCdR2F4TLBdLwHyUDTd1/q4i+jGZA= +github.com/go-openapi/swag/jsonutils v0.25.4/go.mod h1:7OYGXpvVFPn4PpaSdPHJBtF0iGnbEaTk8AvBkoWnaAY= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4 h1:IACsSvBhiNJwlDix7wq39SS2Fh7lUOCJRmx/4SN4sVo= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4/go.mod h1:Mt0Ost9l3cUzVv4OEZG+WSeoHwjWLnarzMePNDAOBiM= +github.com/go-openapi/swag/loading v0.25.4 h1:jN4MvLj0X6yhCDduRsxDDw1aHe+ZWoLjW+9ZQWIKn2s= +github.com/go-openapi/swag/loading v0.25.4/go.mod h1:rpUM1ZiyEP9+mNLIQUdMiD7dCETXvkkC30z53i+ftTE= +github.com/go-openapi/swag/mangling v0.25.4 h1:2b9kBJk9JvPgxr36V23FxJLdwBrpijI26Bx5JH4Hp48= +github.com/go-openapi/swag/mangling v0.25.4/go.mod h1:6dxwu6QyORHpIIApsdZgb6wBk/DPU15MdyYj/ikn0Hg= +github.com/go-openapi/swag/netutils v0.25.4 h1:Gqe6K71bGRb3ZQLusdI8p/y1KLgV4M/k+/HzVSqT8H0= +github.com/go-openapi/swag/netutils v0.25.4/go.mod h1:m2W8dtdaoX7oj9rEttLyTeEFFEBvnAx9qHd5nJEBzYg= +github.com/go-openapi/swag/stringutils v0.25.4 h1:O6dU1Rd8bej4HPA3/CLPciNBBDwZj9HiEpdVsb8B5A8= +github.com/go-openapi/swag/stringutils v0.25.4/go.mod h1:GTsRvhJW5xM5gkgiFe0fV3PUlFm0dr8vki6/VSRaZK0= +github.com/go-openapi/swag/typeutils v0.25.4 h1:1/fbZOUN472NTc39zpa+YGHn3jzHWhv42wAJSN91wRw= +github.com/go-openapi/swag/typeutils v0.25.4/go.mod h1:Ou7g//Wx8tTLS9vG0UmzfCsjZjKhpjxayRKTHXf2pTE= +github.com/go-openapi/swag/yamlutils v0.25.4 h1:6jdaeSItEUb7ioS9lFoCZ65Cne1/RZtPBZ9A56h92Sw= +github.com/go-openapi/swag/yamlutils v0.25.4/go.mod h1:MNzq1ulQu+yd8Kl7wPOut/YHAAU/H6hL91fF+E2RFwc= +github.com/go-openapi/testify/enable/yaml/v2 v2.0.2 h1:0+Y41Pz1NkbTHz8NngxTuAXxEodtNSI1WG1c/m5Akw4= +github.com/go-openapi/testify/enable/yaml/v2 v2.0.2/go.mod h1:kme83333GCtJQHXQ8UKX3IBZu6z8T5Dvy5+CW3NLUUg= +github.com/go-openapi/testify/v2 v2.0.2 h1:X999g3jeLcoY8qctY/c/Z8iBHTbwLz7R2WXd6Ub6wls= +github.com/go-openapi/testify/v2 v2.0.2/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= 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/google/gnostic-models v0.7.0 h1:qwTtogB15McXDaNqTZdzPJRHvaVJlAl+HVQnLmJEJxo= -github.com/google/gnostic-models v0.7.0/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ= +github.com/google/gnostic-models v0.7.1 h1:SisTfuFKJSKM5CPZkffwi6coztzzeYUhc3v4yxLWH8c= +github.com/google/gnostic-models v0.7.1/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/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.48.5 h1:MS8l9fTZz+VbTfgApn09jw27GxhQ6fNOWGhC4ydvZmM= -github.com/grafana/grafana-app-sdk v0.48.5/go.mod h1:HJsMOSBmt/D/Ihs1SvagOwmXKi0coBMVHlfvdd+qe9Y= -github.com/grafana/grafana-app-sdk/logging v0.48.3 h1:72NUpGNiJXCNQz/on++YSsl38xuVYYBKv5kKQaOClX4= -github.com/grafana/grafana-app-sdk/logging v0.48.3/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA= +github.com/grafana/grafana-app-sdk v0.48.7 h1:9mF7nqkqP0QUYYDlznoOt+GIyjzj45wGfUHB32u2ZMo= +github.com/grafana/grafana-app-sdk v0.48.7/go.mod h1:DWsaaH39ZMHwSOSoUBaeW8paMrRaYsjRYlLwCJYd78k= +github.com/grafana/grafana-app-sdk/logging v0.48.7 h1:Oa5qg473gka5+W/WQk61Xbw4YdAv+wV2Z4bJtzeCaQw= +github.com/grafana/grafana-app-sdk/logging v0.48.7/go.mod h1:5u3KalezoBAAo2Y3ytDYDAIIPvEqFLLDSxeiK99QxDU= 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= @@ -58,8 +84,8 @@ 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/mailru/easyjson v0.9.1 h1:LbtsOm5WAswyWbvTEOqhypdPeZzHavpZx96/n553mR8= +github.com/mailru/easyjson v0.9.1/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= @@ -76,8 +102,6 @@ github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 h1:bQx3WeLcUWy+RletI github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90/go.mod h1:y5+oSEHCPT/DGrS++Wc/479ERge0zTFxaF8PbGKcg2o= 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= @@ -85,10 +109,10 @@ github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h 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.3 h1:shd26MlnwTw5jksTDhC7rTQIteBxy+ZZDr3t7F2xN2Q= -github.com/prometheus/common v0.67.3/go.mod h1:gP0fq6YjjNCLssJCQp0yk4M8W6ikLURwkdd/YKtTbyI= -github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= -github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= +github.com/prometheus/common v0.67.4 h1:yR3NqWO1/UyO1w2PhUvXlGQs/PtFmoveVO0KZ4+Lvsc= +github.com/prometheus/common v0.67.4/go.mod h1:gP0fq6YjjNCLssJCQp0yk4M8W6ikLURwkdd/YKtTbyI= +github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws= +github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw= 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= @@ -101,16 +125,16 @@ 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/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/woodsbury/decimal128 v1.4.0 h1:xJATj7lLu4f2oObouMt2tgGiElE5gO6mSWUjQsBgUlc= +github.com/woodsbury/decimal128 v1.4.0/go.mod h1:BP46FUrVjVhdTbKT+XuQh2xfQaGki9LMIRJSFuh6THU= 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/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/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/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48= +go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8= +go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI= +go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA= 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= @@ -126,24 +150,24 @@ 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.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= -golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= -golang.org/x/oauth2 v0.33.0 h1:4Q+qn+E5z8gPRJfmRy7C2gGG3T4jIprK6aSYgTXGRpo= -golang.org/x/oauth2 v0.33.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= +golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= +golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= +golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw= +golang.org/x/oauth2 v0.34.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/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.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= -golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU= -golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254= +golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= +golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q= +golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg= 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.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= -golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= +golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= +golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= 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= @@ -154,31 +178,31 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= -google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/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/evanphx/json-patch.v4 v4.13.0 h1:czT3CmqEaQ1aanPc5SdlgQrrEIb8w/wwCvWWnfEbYzo= +gopkg.in/evanphx/json-patch.v4 v4.13.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.2 h1:fsSUNZhV+bnL6Aqrp6O7lMTy6o5x2C4XLjnh//8SLYY= -k8s.io/api v0.34.2/go.mod h1:MMBPaWlED2a8w4RSeanD76f7opUoypY8TFYkSM+3XHw= -k8s.io/apimachinery v0.34.2 h1:zQ12Uk3eMHPxrsbUJgNF8bTauTVR2WgqJsTmwTE/NW4= -k8s.io/apimachinery v0.34.2/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= -k8s.io/client-go v0.34.2 h1:Co6XiknN+uUZqiddlfAjT68184/37PS4QAzYvQvDR8M= -k8s.io/client-go v0.34.2/go.mod h1:2VYDl1XXJsdcAxw7BenFslRQX28Dxz91U9MWKjX97fE= +k8s.io/api v0.34.3 h1:D12sTP257/jSH2vHV2EDYrb16bS7ULlHpdNdNhEw2S4= +k8s.io/api v0.34.3/go.mod h1:PyVQBF886Q5RSQZOim7DybQjAbVs8g7gwJNhGtY5MBk= +k8s.io/apimachinery v0.34.3 h1:/TB+SFEiQvN9HPldtlWOTp0hWbJ+fjU+wkxysf/aQnE= +k8s.io/apimachinery v0.34.3/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= +k8s.io/client-go v0.34.3 h1:wtYtpzy/OPNYf7WyNBTj3iUA0XaBHVqhv4Iv3tbrF5A= +k8s.io/client-go v0.34.3/go.mod h1:OxxeYagaP9Kdf78UrKLa3YZixMCfP6bgPwPwNBQBzpM= 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= +k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e h1:iW9ChlU0cU16w8MpVYjXk12dqQ4BPFBEgif+ap7/hqQ= +k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e/go.mod h1:kdmbQkyfwUagLfXIad1y2TdrjPFWp2Q89B3qkRwf/pQ= +k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 h1:SjGebBtkBqHFOli+05xYbK8YF1Dzkbzn+gDM4X9T4Ck= +k8s.io/utils v0.0.0-20251002143259-bc988d571ff4/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg= +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/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.1 h1:JrhdFMqOd/+3ByqlP2I45kTOZmTRLBUm5pvRjeheg7E= diff --git a/apps/correlations/go.mod b/apps/correlations/go.mod index 29bc91e70a6..388afc2fd38 100644 --- a/apps/correlations/go.mod +++ b/apps/correlations/go.mod @@ -3,15 +3,15 @@ module github.com/grafana/grafana/apps/correlations go 1.25.5 require ( - github.com/grafana/grafana-app-sdk v0.48.5 - github.com/grafana/grafana-app-sdk/logging v0.48.3 - k8s.io/apimachinery v0.34.2 - k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 + github.com/grafana/grafana-app-sdk v0.48.7 + github.com/grafana/grafana-app-sdk/logging v0.48.7 + k8s.io/apimachinery v0.34.3 + k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e ) require ( github.com/beorn7/perks v1.0.1 // indirect - github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874 // indirect + github.com/bradfitz/gomemcache v0.0.0-20250403215159-8d39553ac7cf // 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 @@ -21,13 +21,23 @@ require ( github.com/getkin/kin-openapi v0.133.0 // 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.1 // indirect - github.com/go-openapi/swag/jsonname v0.25.1 // indirect + github.com/go-openapi/jsonpointer v0.22.4 // indirect + github.com/go-openapi/jsonreference v0.21.4 // indirect + github.com/go-openapi/swag v0.25.4 // indirect + github.com/go-openapi/swag/cmdutils v0.25.4 // indirect + github.com/go-openapi/swag/conv v0.25.4 // indirect + github.com/go-openapi/swag/fileutils v0.25.4 // indirect + github.com/go-openapi/swag/jsonname v0.25.4 // indirect + github.com/go-openapi/swag/jsonutils v0.25.4 // indirect + github.com/go-openapi/swag/loading v0.25.4 // indirect + github.com/go-openapi/swag/mangling v0.25.4 // indirect + github.com/go-openapi/swag/netutils v0.25.4 // indirect + github.com/go-openapi/swag/stringutils v0.25.4 // indirect + github.com/go-openapi/swag/typeutils v0.25.4 // indirect + github.com/go-openapi/swag/yamlutils v0.25.4 // 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/gnostic-models v0.7.1 // 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 @@ -36,7 +46,7 @@ require ( 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/mailru/easyjson v0.9.1 // 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 @@ -49,43 +59,43 @@ require ( 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.3 // indirect - github.com/prometheus/procfs v0.16.1 // indirect + github.com/prometheus/common v0.67.4 // indirect + github.com/prometheus/procfs v0.19.2 // 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/woodsbury/decimal128 v1.4.0 // indirect github.com/x448/float16 v0.8.4 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // 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/otel v1.39.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0 // indirect + go.opentelemetry.io/otel/metric v1.39.0 // indirect + go.opentelemetry.io/otel/sdk v1.39.0 // indirect + go.opentelemetry.io/otel/trace v1.39.0 // indirect go.opentelemetry.io/proto/otlp v1.9.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.47.0 // indirect - golang.org/x/oauth2 v0.33.0 // indirect - golang.org/x/sync v0.18.0 // indirect - golang.org/x/sys v0.38.0 // indirect - golang.org/x/term v0.37.0 // indirect - golang.org/x/text v0.31.0 // indirect + golang.org/x/net v0.48.0 // indirect + golang.org/x/oauth2 v0.34.0 // indirect + golang.org/x/sync v0.19.0 // indirect + golang.org/x/sys v0.39.0 // indirect + golang.org/x/term v0.38.0 // indirect + golang.org/x/text v0.32.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-20251111163417-95abcf5c77ba // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2 // indirect google.golang.org/grpc v1.77.0 // indirect - google.golang.org/protobuf v1.36.10 // indirect + google.golang.org/protobuf v1.36.11 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/api v0.34.2 // indirect - k8s.io/apiextensions-apiserver v0.34.2 // indirect - k8s.io/client-go v0.34.2 // indirect + k8s.io/api v0.34.3 // indirect + k8s.io/apiextensions-apiserver v0.34.3 // indirect + k8s.io/client-go v0.34.3 // 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 + k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 // indirect + sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect sigs.k8s.io/randfill v1.0.0 // indirect sigs.k8s.io/structured-merge-diff/v6 v6.3.1 // indirect sigs.k8s.io/yaml v1.6.0 // indirect diff --git a/apps/correlations/go.sum b/apps/correlations/go.sum index 3df8e8b5ebe..e5233ba82c9 100644 --- a/apps/correlations/go.sum +++ b/apps/correlations/go.sum @@ -1,7 +1,7 @@ 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/bradfitz/gomemcache v0.0.0-20250403215159-8d39553ac7cf h1:TqhNAT4zKbTdLa62d2HDBFdvgSbIGB3eJE8HqhgiL9I= +github.com/bradfitz/gomemcache v0.0.0-20250403215159-8d39553ac7cf/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= @@ -23,14 +23,40 @@ 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.1 h1:lpsStH0n2ittzTnbaSloVZLuB5+fvSY/+hnagBjSNZU= -github.com/go-openapi/swag v0.23.1/go.mod h1:STZs8TbRvEQQKUA+JZNAm3EWlgaOBGpyFDqQnDHMef0= -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/jsonpointer v0.22.4 h1:dZtK82WlNpVLDW2jlA1YCiVJFVqkED1MegOUy9kR5T4= +github.com/go-openapi/jsonpointer v0.22.4/go.mod h1:elX9+UgznpFhgBuaMQ7iu4lvvX1nvNsesQ3oxmYTw80= +github.com/go-openapi/jsonreference v0.21.4 h1:24qaE2y9bx/q3uRK/qN+TDwbok1NhbSmGjjySRCHtC8= +github.com/go-openapi/jsonreference v0.21.4/go.mod h1:rIENPTjDbLpzQmQWCj5kKj3ZlmEh+EFVbz3RTUh30/4= +github.com/go-openapi/swag v0.25.4 h1:OyUPUFYDPDBMkqyxOTkqDYFnrhuhi9NR6QVUvIochMU= +github.com/go-openapi/swag v0.25.4/go.mod h1:zNfJ9WZABGHCFg2RnY0S4IOkAcVTzJ6z2Bi+Q4i6qFQ= +github.com/go-openapi/swag/cmdutils v0.25.4 h1:8rYhB5n6WawR192/BfUu2iVlxqVR9aRgGJP6WaBoW+4= +github.com/go-openapi/swag/cmdutils v0.25.4/go.mod h1:pdae/AFo6WxLl5L0rq87eRzVPm/XRHM3MoYgRMvG4A0= +github.com/go-openapi/swag/conv v0.25.4 h1:/Dd7p0LZXczgUcC/Ikm1+YqVzkEeCc9LnOWjfkpkfe4= +github.com/go-openapi/swag/conv v0.25.4/go.mod h1:3LXfie/lwoAv0NHoEuY1hjoFAYkvlqI/Bn5EQDD3PPU= +github.com/go-openapi/swag/fileutils v0.25.4 h1:2oI0XNW5y6UWZTC7vAxC8hmsK/tOkWXHJQH4lKjqw+Y= +github.com/go-openapi/swag/fileutils v0.25.4/go.mod h1:cdOT/PKbwcysVQ9Tpr0q20lQKH7MGhOEb6EwmHOirUk= +github.com/go-openapi/swag/jsonname v0.25.4 h1:bZH0+MsS03MbnwBXYhuTttMOqk+5KcQ9869Vye1bNHI= +github.com/go-openapi/swag/jsonname v0.25.4/go.mod h1:GPVEk9CWVhNvWhZgrnvRA6utbAltopbKwDu8mXNUMag= +github.com/go-openapi/swag/jsonutils v0.25.4 h1:VSchfbGhD4UTf4vCdR2F4TLBdLwHyUDTd1/q4i+jGZA= +github.com/go-openapi/swag/jsonutils v0.25.4/go.mod h1:7OYGXpvVFPn4PpaSdPHJBtF0iGnbEaTk8AvBkoWnaAY= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4 h1:IACsSvBhiNJwlDix7wq39SS2Fh7lUOCJRmx/4SN4sVo= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4/go.mod h1:Mt0Ost9l3cUzVv4OEZG+WSeoHwjWLnarzMePNDAOBiM= +github.com/go-openapi/swag/loading v0.25.4 h1:jN4MvLj0X6yhCDduRsxDDw1aHe+ZWoLjW+9ZQWIKn2s= +github.com/go-openapi/swag/loading v0.25.4/go.mod h1:rpUM1ZiyEP9+mNLIQUdMiD7dCETXvkkC30z53i+ftTE= +github.com/go-openapi/swag/mangling v0.25.4 h1:2b9kBJk9JvPgxr36V23FxJLdwBrpijI26Bx5JH4Hp48= +github.com/go-openapi/swag/mangling v0.25.4/go.mod h1:6dxwu6QyORHpIIApsdZgb6wBk/DPU15MdyYj/ikn0Hg= +github.com/go-openapi/swag/netutils v0.25.4 h1:Gqe6K71bGRb3ZQLusdI8p/y1KLgV4M/k+/HzVSqT8H0= +github.com/go-openapi/swag/netutils v0.25.4/go.mod h1:m2W8dtdaoX7oj9rEttLyTeEFFEBvnAx9qHd5nJEBzYg= +github.com/go-openapi/swag/stringutils v0.25.4 h1:O6dU1Rd8bej4HPA3/CLPciNBBDwZj9HiEpdVsb8B5A8= +github.com/go-openapi/swag/stringutils v0.25.4/go.mod h1:GTsRvhJW5xM5gkgiFe0fV3PUlFm0dr8vki6/VSRaZK0= +github.com/go-openapi/swag/typeutils v0.25.4 h1:1/fbZOUN472NTc39zpa+YGHn3jzHWhv42wAJSN91wRw= +github.com/go-openapi/swag/typeutils v0.25.4/go.mod h1:Ou7g//Wx8tTLS9vG0UmzfCsjZjKhpjxayRKTHXf2pTE= +github.com/go-openapi/swag/yamlutils v0.25.4 h1:6jdaeSItEUb7ioS9lFoCZ65Cne1/RZtPBZ9A56h92Sw= +github.com/go-openapi/swag/yamlutils v0.25.4/go.mod h1:MNzq1ulQu+yd8Kl7wPOut/YHAAU/H6hL91fF+E2RFwc= +github.com/go-openapi/testify/enable/yaml/v2 v2.0.2 h1:0+Y41Pz1NkbTHz8NngxTuAXxEodtNSI1WG1c/m5Akw4= +github.com/go-openapi/testify/enable/yaml/v2 v2.0.2/go.mod h1:kme83333GCtJQHXQ8UKX3IBZu6z8T5Dvy5+CW3NLUUg= +github.com/go-openapi/testify/v2 v2.0.2 h1:X999g3jeLcoY8qctY/c/Z8iBHTbwLz7R2WXd6Ub6wls= +github.com/go-openapi/testify/v2 v2.0.2/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= 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= @@ -39,8 +65,8 @@ 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/gnostic-models v0.7.1 h1:SisTfuFKJSKM5CPZkffwi6coztzzeYUhc3v4yxLWH8c= +github.com/google/gnostic-models v0.7.1/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= @@ -48,10 +74,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.48.5 h1:MS8l9fTZz+VbTfgApn09jw27GxhQ6fNOWGhC4ydvZmM= -github.com/grafana/grafana-app-sdk v0.48.5/go.mod h1:HJsMOSBmt/D/Ihs1SvagOwmXKi0coBMVHlfvdd+qe9Y= -github.com/grafana/grafana-app-sdk/logging v0.48.3 h1:72NUpGNiJXCNQz/on++YSsl38xuVYYBKv5kKQaOClX4= -github.com/grafana/grafana-app-sdk/logging v0.48.3/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA= +github.com/grafana/grafana-app-sdk v0.48.7 h1:9mF7nqkqP0QUYYDlznoOt+GIyjzj45wGfUHB32u2ZMo= +github.com/grafana/grafana-app-sdk v0.48.7/go.mod h1:DWsaaH39ZMHwSOSoUBaeW8paMrRaYsjRYlLwCJYd78k= +github.com/grafana/grafana-app-sdk/logging v0.48.7 h1:Oa5qg473gka5+W/WQk61Xbw4YdAv+wV2Z4bJtzeCaQw= +github.com/grafana/grafana-app-sdk/logging v0.48.7/go.mod h1:5u3KalezoBAAo2Y3ytDYDAIIPvEqFLLDSxeiK99QxDU= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3 h1:NmZ1PKzSTQbuGHw9DGPFomqkkLWMC+vZCkfs+FHv1Vg= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3/go.mod h1:zQrxl1YP88HQlA6i9c63DSVPFklWpGX4OWAc9bFuaH4= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -73,8 +99,8 @@ 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/mailru/easyjson v0.9.1 h1:LbtsOm5WAswyWbvTEOqhypdPeZzHavpZx96/n553mR8= +github.com/mailru/easyjson v0.9.1/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= @@ -95,8 +121,6 @@ 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/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= @@ -104,10 +128,10 @@ github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h 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.3 h1:shd26MlnwTw5jksTDhC7rTQIteBxy+ZZDr3t7F2xN2Q= -github.com/prometheus/common v0.67.3/go.mod h1:gP0fq6YjjNCLssJCQp0yk4M8W6ikLURwkdd/YKtTbyI= -github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= -github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= +github.com/prometheus/common v0.67.4 h1:yR3NqWO1/UyO1w2PhUvXlGQs/PtFmoveVO0KZ4+Lvsc= +github.com/prometheus/common v0.67.4/go.mod h1:gP0fq6YjjNCLssJCQp0yk4M8W6ikLURwkdd/YKtTbyI= +github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws= +github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw= 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= @@ -122,30 +146,30 @@ 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/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/woodsbury/decimal128 v1.4.0 h1:xJATj7lLu4f2oObouMt2tgGiElE5gO6mSWUjQsBgUlc= +github.com/woodsbury/decimal128 v1.4.0/go.mod h1:BP46FUrVjVhdTbKT+XuQh2xfQaGki9LMIRJSFuh6THU= 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.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= -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/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48= +go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0 h1:f0cb2XPmrqn4XMy9PNliTgRKJgS5WcL/u0/WRYGz4t0= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0/go.mod h1:vnakAaFckOMiMtOIhFI2MNH4FYrZzXCYxmb1LlhoGz8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0 h1:in9O8ESIOlwJAEGTkkf34DesGRAc/Pn8qJ7k3r/42LM= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0/go.mod h1:Rp0EXBm5tfnv0WL+ARyO/PHBEaEAT8UUHQ6AGJcSq6c= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0 h1:Ckwye2FpXkYgiHX7fyVrN1uA/UYd9ounqqTuSNAv0k4= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0/go.mod h1:teIFJh5pW2y+AN7riv6IBPX2DuesS3HgP39mwOspKwU= +go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0= +go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs= +go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18= +go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE= +go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8= +go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew= +go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI= +go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA= go.opentelemetry.io/proto/otlp v1.9.0 h1:l706jCMITVouPOqEnii2fIAuO3IVGBRPV5ICjceRb/A= go.opentelemetry.io/proto/otlp v1.9.0/go.mod h1:xE+Cx5E/eEHw+ISFkwPLwCZefwVjY+pqKg1qcK03+/4= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= @@ -163,34 +187,34 @@ 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.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= -golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= -golang.org/x/oauth2 v0.33.0 h1:4Q+qn+E5z8gPRJfmRy7C2gGG3T4jIprK6aSYgTXGRpo= -golang.org/x/oauth2 v0.33.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= +golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= +golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= +golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw= +golang.org/x/oauth2 v0.34.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.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= -golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.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.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= -golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU= -golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254= +golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= +golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q= +golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg= 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.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= -golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= +golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= +golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= 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.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ= -golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ= +golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA= +golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc= 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= @@ -199,39 +223,39 @@ 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-20251111163417-95abcf5c77ba h1:B14OtaXuMaCQsl2deSvNkyPKIzq3BjfxQp8d00QyWx4= -google.golang.org/genproto/googleapis/api v0.0.0-20251111163417-95abcf5c77ba/go.mod h1:G5IanEx8/PgI9w6CFcYQf7jMtHQhZruvfM1i3qOqk5U= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba h1:UKgtfRM7Yh93Sya0Fo8ZzhDP4qBckrrxEr2oF5UIVb8= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= +google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2 h1:7LRqPCEdE4TP4/9psdaB7F2nhZFfBiGJomA5sojLWdU= +google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2/go.mod h1:+rXWjjaukWZun3mLfjmVnQi18E1AsFbDN9QdJ5YXLto= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2 h1:2I6GHUeJ/4shcDpoUlLs/2WPnhg7yJwvXtqcMJt9liA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM= google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= -google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= -google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/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/evanphx/json-patch.v4 v4.13.0 h1:czT3CmqEaQ1aanPc5SdlgQrrEIb8w/wwCvWWnfEbYzo= +gopkg.in/evanphx/json-patch.v4 v4.13.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.2 h1:fsSUNZhV+bnL6Aqrp6O7lMTy6o5x2C4XLjnh//8SLYY= -k8s.io/api v0.34.2/go.mod h1:MMBPaWlED2a8w4RSeanD76f7opUoypY8TFYkSM+3XHw= -k8s.io/apiextensions-apiserver v0.34.2 h1:WStKftnGeoKP4AZRz/BaAAEJvYp4mlZGN0UCv+uvsqo= -k8s.io/apiextensions-apiserver v0.34.2/go.mod h1:398CJrsgXF1wytdaanynDpJ67zG4Xq7yj91GrmYN2SE= -k8s.io/apimachinery v0.34.2 h1:zQ12Uk3eMHPxrsbUJgNF8bTauTVR2WgqJsTmwTE/NW4= -k8s.io/apimachinery v0.34.2/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= -k8s.io/client-go v0.34.2 h1:Co6XiknN+uUZqiddlfAjT68184/37PS4QAzYvQvDR8M= -k8s.io/client-go v0.34.2/go.mod h1:2VYDl1XXJsdcAxw7BenFslRQX28Dxz91U9MWKjX97fE= +k8s.io/api v0.34.3 h1:D12sTP257/jSH2vHV2EDYrb16bS7ULlHpdNdNhEw2S4= +k8s.io/api v0.34.3/go.mod h1:PyVQBF886Q5RSQZOim7DybQjAbVs8g7gwJNhGtY5MBk= +k8s.io/apiextensions-apiserver v0.34.3 h1:p10fGlkDY09eWKOTeUSioxwLukJnm+KuDZdrW71y40g= +k8s.io/apiextensions-apiserver v0.34.3/go.mod h1:aujxvqGFRdb/cmXYfcRTeppN7S2XV/t7WMEc64zB5A0= +k8s.io/apimachinery v0.34.3 h1:/TB+SFEiQvN9HPldtlWOTp0hWbJ+fjU+wkxysf/aQnE= +k8s.io/apimachinery v0.34.3/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= +k8s.io/client-go v0.34.3 h1:wtYtpzy/OPNYf7WyNBTj3iUA0XaBHVqhv4Iv3tbrF5A= +k8s.io/client-go v0.34.3/go.mod h1:OxxeYagaP9Kdf78UrKLa3YZixMCfP6bgPwPwNBQBzpM= 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= +k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e h1:iW9ChlU0cU16w8MpVYjXk12dqQ4BPFBEgif+ap7/hqQ= +k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e/go.mod h1:kdmbQkyfwUagLfXIad1y2TdrjPFWp2Q89B3qkRwf/pQ= +k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 h1:SjGebBtkBqHFOli+05xYbK8YF1Dzkbzn+gDM4X9T4Ck= +k8s.io/utils v0.0.0-20251002143259-bc988d571ff4/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg= +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/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.1 h1:JrhdFMqOd/+3ByqlP2I45kTOZmTRLBUm5pvRjeheg7E= diff --git a/apps/dashboard/go.mod b/apps/dashboard/go.mod index 00fe99f0c9c..86d5ec1ff09 100644 --- a/apps/dashboard/go.mod +++ b/apps/dashboard/go.mod @@ -5,17 +5,17 @@ go 1.25.5 require ( cuelang.org/go v0.11.1 github.com/grafana/authlib/types v0.0.0-20251119142549-be091cf2f4d4 - github.com/grafana/grafana-app-sdk v0.48.5 - github.com/grafana/grafana-app-sdk/logging v0.48.3 + github.com/grafana/grafana-app-sdk v0.48.7 + github.com/grafana/grafana-app-sdk/logging v0.48.7 github.com/grafana/grafana-plugin-sdk-go v0.284.0 github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250514132646-acbc7b54ed9e github.com/hashicorp/golang-lru/v2 v2.0.7 github.com/prometheus/client_golang v1.23.2 github.com/stretchr/testify v1.11.1 - k8s.io/apimachinery v0.34.2 - k8s.io/apiserver v0.34.2 - k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 - k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 + k8s.io/apimachinery v0.34.3 + k8s.io/apiserver v0.34.3 + k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e + k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 ) require ( @@ -34,17 +34,27 @@ require ( github.com/go-jose/go-jose/v4 v4.1.3 // 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.1 // indirect - github.com/go-openapi/swag/jsonname v0.25.1 // indirect + github.com/go-openapi/jsonpointer v0.22.4 // indirect + github.com/go-openapi/jsonreference v0.21.4 // indirect + github.com/go-openapi/swag v0.25.4 // indirect + github.com/go-openapi/swag/cmdutils v0.25.4 // indirect + github.com/go-openapi/swag/conv v0.25.4 // indirect + github.com/go-openapi/swag/fileutils v0.25.4 // indirect + github.com/go-openapi/swag/jsonname v0.25.4 // indirect + github.com/go-openapi/swag/jsonutils v0.25.4 // indirect + github.com/go-openapi/swag/loading v0.25.4 // indirect + github.com/go-openapi/swag/mangling v0.25.4 // indirect + github.com/go-openapi/swag/netutils v0.25.4 // indirect + github.com/go-openapi/swag/stringutils v0.25.4 // indirect + github.com/go-openapi/swag/typeutils v0.25.4 // indirect + github.com/go-openapi/swag/yamlutils v0.25.4 // indirect github.com/go-test/deep v1.1.1 // indirect github.com/goccy/go-json v0.10.5 // indirect github.com/gogo/googleapis v1.4.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/google/flatbuffers v25.2.10+incompatible // indirect - github.com/google/gnostic-models v0.7.0 // indirect + github.com/google/gnostic-models v0.7.1 // indirect github.com/google/go-cmp v0.7.0 // indirect github.com/google/uuid v1.6.0 // indirect github.com/grafana/authlib v0.0.0-20250930082137-a40e2c2b094f // indirect @@ -66,7 +76,7 @@ require ( github.com/klauspost/compress v1.18.0 // indirect github.com/klauspost/cpuid/v2 v2.3.0 // indirect github.com/lib/pq v1.10.9 // indirect - github.com/mailru/easyjson v0.9.0 // indirect + github.com/mailru/easyjson v0.9.1 // indirect github.com/mattetti/filebuffer v1.0.1 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect @@ -80,55 +90,55 @@ require ( github.com/oklog/run v1.1.0 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect github.com/patrickmn/go-cache v2.1.0+incompatible // indirect - github.com/pelletier/go-toml/v2 v2.2.3 // indirect + github.com/pelletier/go-toml/v2 v2.2.4 // indirect github.com/perimeterx/marshmallow v1.1.5 // indirect github.com/pierrec/lz4/v4 v4.1.22 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/client_model v0.6.2 // indirect - github.com/prometheus/common v0.67.3 // indirect - github.com/prometheus/procfs v0.16.1 // indirect + github.com/prometheus/common v0.67.4 // indirect + github.com/prometheus/procfs v0.19.2 // indirect github.com/rivo/uniseg v0.4.7 // indirect github.com/spf13/pflag v1.0.10 // indirect github.com/stretchr/objx v0.5.2 // indirect - github.com/woodsbury/decimal128 v1.3.0 // indirect + github.com/woodsbury/decimal128 v1.4.0 // indirect github.com/x448/float16 v0.8.4 // indirect github.com/zeebo/xxh3 v1.0.2 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.64.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace 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/otlp/otlptrace v1.38.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc 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/otel v1.39.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0 // indirect + go.opentelemetry.io/otel/metric v1.39.0 // indirect + go.opentelemetry.io/otel/sdk v1.39.0 // indirect + go.opentelemetry.io/otel/trace v1.39.0 // indirect go.opentelemetry.io/proto/otlp v1.9.0 // indirect 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.30.0 // indirect - golang.org/x/net v0.47.0 // indirect - golang.org/x/oauth2 v0.33.0 // indirect - golang.org/x/sync v0.18.0 // indirect - golang.org/x/sys v0.38.0 // indirect - golang.org/x/telemetry v0.0.0-20251111182119-bc8e575c7b54 // indirect - golang.org/x/term v0.37.0 // indirect - golang.org/x/text v0.31.0 // indirect + golang.org/x/exp v0.0.0-20251209150349-8475f28825e9 // indirect + golang.org/x/mod v0.31.0 // indirect + golang.org/x/net v0.48.0 // indirect + golang.org/x/oauth2 v0.34.0 // indirect + golang.org/x/sync v0.19.0 // indirect + golang.org/x/sys v0.39.0 // indirect + golang.org/x/telemetry v0.0.0-20251203150158-8fff8a5912fc // indirect + golang.org/x/term v0.38.0 // indirect + golang.org/x/text v0.32.0 // indirect golang.org/x/time v0.14.0 // indirect - golang.org/x/tools v0.39.0 // indirect + golang.org/x/tools v0.40.0 // indirect golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20251111163417-95abcf5c77ba // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2 // indirect google.golang.org/grpc v1.77.0 // indirect - google.golang.org/protobuf v1.36.10 // indirect + google.golang.org/protobuf v1.36.11 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/client-go v0.34.2 // indirect - k8s.io/component-base v0.34.2 // indirect + k8s.io/client-go v0.34.3 // indirect + k8s.io/component-base v0.34.3 // indirect k8s.io/klog/v2 v2.130.1 // indirect - sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect + sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect sigs.k8s.io/randfill v1.0.0 // indirect sigs.k8s.io/structured-merge-diff/v6 v6.3.1 // indirect sigs.k8s.io/yaml v1.6.0 // indirect diff --git a/apps/dashboard/go.sum b/apps/dashboard/go.sum index a93f97a1d0e..3bc70db5e6e 100644 --- a/apps/dashboard/go.sum +++ b/apps/dashboard/go.sum @@ -1,5 +1,5 @@ -cuelabs.dev/go/oci/ociregistry v0.0.0-20240906074133-82eb438dd565 h1:R5wwEcbEZSBmeyg91MJZTxfd7WpBo2jPof3AYjRbxwY= -cuelabs.dev/go/oci/ociregistry v0.0.0-20240906074133-82eb438dd565/go.mod h1:5A4xfTzHTXfeVJBU6RAUf+QrlfTCW+017q/QiW+sMLg= +cuelabs.dev/go/oci/ociregistry v0.0.0-20251212221603-3adeb8663819 h1:Zh+Ur3OsoWpvALHPLT45nOekHkgOt+IOfutBbPqM17I= +cuelabs.dev/go/oci/ociregistry v0.0.0-20251212221603-3adeb8663819/go.mod h1:WjmQxb+W6nVNCgj8nXrF24lIz95AHwnSl36tpjDZSU8= cuelang.org/go v0.11.1 h1:pV+49MX1mmvDm8Qh3Za3M786cty8VKPWzQ1Ho4gZRP0= cuelang.org/go v0.11.1/go.mod h1:PBY6XvPUswPPJ2inpvUozP9mebDVTXaeehQikhZPBz0= github.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwToPjQ= @@ -28,8 +28,8 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/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/emicklei/proto v1.13.2 h1:z/etSFO3uyXeuEsVPzfl56WNgzcvIr42aQazXaQmFZY= -github.com/emicklei/proto v1.13.2/go.mod h1:rn1FgRS/FANiZdD2djyH7TMA9jdRDcYQ9IEN9yvjX0A= +github.com/emicklei/proto v1.14.2 h1:wJPxPy2Xifja9cEMrcA/g08art5+7CGJNFNk35iXC1I= +github.com/emicklei/proto v1.14.2/go.mod h1:rn1FgRS/FANiZdD2djyH7TMA9jdRDcYQ9IEN9yvjX0A= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= @@ -47,14 +47,40 @@ 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.1 h1:lpsStH0n2ittzTnbaSloVZLuB5+fvSY/+hnagBjSNZU= -github.com/go-openapi/swag v0.23.1/go.mod h1:STZs8TbRvEQQKUA+JZNAm3EWlgaOBGpyFDqQnDHMef0= -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/jsonpointer v0.22.4 h1:dZtK82WlNpVLDW2jlA1YCiVJFVqkED1MegOUy9kR5T4= +github.com/go-openapi/jsonpointer v0.22.4/go.mod h1:elX9+UgznpFhgBuaMQ7iu4lvvX1nvNsesQ3oxmYTw80= +github.com/go-openapi/jsonreference v0.21.4 h1:24qaE2y9bx/q3uRK/qN+TDwbok1NhbSmGjjySRCHtC8= +github.com/go-openapi/jsonreference v0.21.4/go.mod h1:rIENPTjDbLpzQmQWCj5kKj3ZlmEh+EFVbz3RTUh30/4= +github.com/go-openapi/swag v0.25.4 h1:OyUPUFYDPDBMkqyxOTkqDYFnrhuhi9NR6QVUvIochMU= +github.com/go-openapi/swag v0.25.4/go.mod h1:zNfJ9WZABGHCFg2RnY0S4IOkAcVTzJ6z2Bi+Q4i6qFQ= +github.com/go-openapi/swag/cmdutils v0.25.4 h1:8rYhB5n6WawR192/BfUu2iVlxqVR9aRgGJP6WaBoW+4= +github.com/go-openapi/swag/cmdutils v0.25.4/go.mod h1:pdae/AFo6WxLl5L0rq87eRzVPm/XRHM3MoYgRMvG4A0= +github.com/go-openapi/swag/conv v0.25.4 h1:/Dd7p0LZXczgUcC/Ikm1+YqVzkEeCc9LnOWjfkpkfe4= +github.com/go-openapi/swag/conv v0.25.4/go.mod h1:3LXfie/lwoAv0NHoEuY1hjoFAYkvlqI/Bn5EQDD3PPU= +github.com/go-openapi/swag/fileutils v0.25.4 h1:2oI0XNW5y6UWZTC7vAxC8hmsK/tOkWXHJQH4lKjqw+Y= +github.com/go-openapi/swag/fileutils v0.25.4/go.mod h1:cdOT/PKbwcysVQ9Tpr0q20lQKH7MGhOEb6EwmHOirUk= +github.com/go-openapi/swag/jsonname v0.25.4 h1:bZH0+MsS03MbnwBXYhuTttMOqk+5KcQ9869Vye1bNHI= +github.com/go-openapi/swag/jsonname v0.25.4/go.mod h1:GPVEk9CWVhNvWhZgrnvRA6utbAltopbKwDu8mXNUMag= +github.com/go-openapi/swag/jsonutils v0.25.4 h1:VSchfbGhD4UTf4vCdR2F4TLBdLwHyUDTd1/q4i+jGZA= +github.com/go-openapi/swag/jsonutils v0.25.4/go.mod h1:7OYGXpvVFPn4PpaSdPHJBtF0iGnbEaTk8AvBkoWnaAY= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4 h1:IACsSvBhiNJwlDix7wq39SS2Fh7lUOCJRmx/4SN4sVo= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4/go.mod h1:Mt0Ost9l3cUzVv4OEZG+WSeoHwjWLnarzMePNDAOBiM= +github.com/go-openapi/swag/loading v0.25.4 h1:jN4MvLj0X6yhCDduRsxDDw1aHe+ZWoLjW+9ZQWIKn2s= +github.com/go-openapi/swag/loading v0.25.4/go.mod h1:rpUM1ZiyEP9+mNLIQUdMiD7dCETXvkkC30z53i+ftTE= +github.com/go-openapi/swag/mangling v0.25.4 h1:2b9kBJk9JvPgxr36V23FxJLdwBrpijI26Bx5JH4Hp48= +github.com/go-openapi/swag/mangling v0.25.4/go.mod h1:6dxwu6QyORHpIIApsdZgb6wBk/DPU15MdyYj/ikn0Hg= +github.com/go-openapi/swag/netutils v0.25.4 h1:Gqe6K71bGRb3ZQLusdI8p/y1KLgV4M/k+/HzVSqT8H0= +github.com/go-openapi/swag/netutils v0.25.4/go.mod h1:m2W8dtdaoX7oj9rEttLyTeEFFEBvnAx9qHd5nJEBzYg= +github.com/go-openapi/swag/stringutils v0.25.4 h1:O6dU1Rd8bej4HPA3/CLPciNBBDwZj9HiEpdVsb8B5A8= +github.com/go-openapi/swag/stringutils v0.25.4/go.mod h1:GTsRvhJW5xM5gkgiFe0fV3PUlFm0dr8vki6/VSRaZK0= +github.com/go-openapi/swag/typeutils v0.25.4 h1:1/fbZOUN472NTc39zpa+YGHn3jzHWhv42wAJSN91wRw= +github.com/go-openapi/swag/typeutils v0.25.4/go.mod h1:Ou7g//Wx8tTLS9vG0UmzfCsjZjKhpjxayRKTHXf2pTE= +github.com/go-openapi/swag/yamlutils v0.25.4 h1:6jdaeSItEUb7ioS9lFoCZ65Cne1/RZtPBZ9A56h92Sw= +github.com/go-openapi/swag/yamlutils v0.25.4/go.mod h1:MNzq1ulQu+yd8Kl7wPOut/YHAAU/H6hL91fF+E2RFwc= +github.com/go-openapi/testify/enable/yaml/v2 v2.0.2 h1:0+Y41Pz1NkbTHz8NngxTuAXxEodtNSI1WG1c/m5Akw4= +github.com/go-openapi/testify/enable/yaml/v2 v2.0.2/go.mod h1:kme83333GCtJQHXQ8UKX3IBZu6z8T5Dvy5+CW3NLUUg= +github.com/go-openapi/testify/v2 v2.0.2 h1:X999g3jeLcoY8qctY/c/Z8iBHTbwLz7R2WXd6Ub6wls= +github.com/go-openapi/testify/v2 v2.0.2/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= github.com/go-quicktest/qt v1.101.0 h1:O1K29Txy5P2OK0dGo59b7b0LR6wKfIhttaAhHUyn7eI= github.com/go-quicktest/qt v1.101.0/go.mod h1:14Bz/f7NwaXPtdYEgzsx46kqSxVwTbzVZsDC26tQJow= github.com/go-test/deep v1.1.1 h1:0r/53hagsehfO4bzD2Pgr/+RgHqhmf+k1Bpse2cTu1U= @@ -71,8 +97,8 @@ github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs= github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= 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.7.0 h1:qwTtogB15McXDaNqTZdzPJRHvaVJlAl+HVQnLmJEJxo= -github.com/google/gnostic-models v0.7.0/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ= +github.com/google/gnostic-models v0.7.1 h1:SisTfuFKJSKM5CPZkffwi6coztzzeYUhc3v4yxLWH8c= +github.com/google/gnostic-models v0.7.1/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ= 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= @@ -85,10 +111,10 @@ github.com/grafana/authlib/types v0.0.0-20251119142549-be091cf2f4d4 h1:Muoy+FMGr github.com/grafana/authlib/types v0.0.0-20251119142549-be091cf2f4d4/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.5 h1:MS8l9fTZz+VbTfgApn09jw27GxhQ6fNOWGhC4ydvZmM= -github.com/grafana/grafana-app-sdk v0.48.5/go.mod h1:HJsMOSBmt/D/Ihs1SvagOwmXKi0coBMVHlfvdd+qe9Y= -github.com/grafana/grafana-app-sdk/logging v0.48.3 h1:72NUpGNiJXCNQz/on++YSsl38xuVYYBKv5kKQaOClX4= -github.com/grafana/grafana-app-sdk/logging v0.48.3/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA= +github.com/grafana/grafana-app-sdk v0.48.7 h1:9mF7nqkqP0QUYYDlznoOt+GIyjzj45wGfUHB32u2ZMo= +github.com/grafana/grafana-app-sdk v0.48.7/go.mod h1:DWsaaH39ZMHwSOSoUBaeW8paMrRaYsjRYlLwCJYd78k= +github.com/grafana/grafana-app-sdk/logging v0.48.7 h1:Oa5qg473gka5+W/WQk61Xbw4YdAv+wV2Z4bJtzeCaQw= +github.com/grafana/grafana-app-sdk/logging v0.48.7/go.mod h1:5u3KalezoBAAo2Y3ytDYDAIIPvEqFLLDSxeiK99QxDU= github.com/grafana/grafana-plugin-sdk-go v0.284.0 h1:1bK7eWsnPBLUWDcWJWe218Ik5ad0a5JpEL4mH9ry7Ws= github.com/grafana/grafana-plugin-sdk-go v0.284.0/go.mod h1:lHPniaSxq3SL5MxDIPy04TYB1jnTp/ivkYO+xn5Rz3E= github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250514132646-acbc7b54ed9e h1:BTKk7LHuG1kmAkucwTA7DuMbKpKvJTKrGdBmUNO4dfQ= @@ -142,8 +168,8 @@ github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0 github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -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/mailru/easyjson v0.9.1 h1:LbtsOm5WAswyWbvTEOqhypdPeZzHavpZx96/n553mR8= +github.com/mailru/easyjson v0.9.1/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= github.com/mattetti/filebuffer v1.0.1 h1:gG7pyfnSIZCxdoKq+cPa8T0hhYtD9NxCdI4D7PTjRLM= github.com/mattetti/filebuffer v1.0.1/go.mod h1:YdMURNDOttIiruleeVr6f56OrMc+MydEnTcXwtkxNVs= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= @@ -185,12 +211,12 @@ github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= -github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= -github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= +github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040= +github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M= 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/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/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU= @@ -204,12 +230,12 @@ github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h 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.3 h1:shd26MlnwTw5jksTDhC7rTQIteBxy+ZZDr3t7F2xN2Q= -github.com/prometheus/common v0.67.3/go.mod h1:gP0fq6YjjNCLssJCQp0yk4M8W6ikLURwkdd/YKtTbyI= -github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= -github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= -github.com/protocolbuffers/txtpbfmt v0.0.0-20241112170944-20d2c9ebc01d h1:HWfigq7lB31IeJL8iy7jkUmU/PG1Sr8jVGhS749dbUA= -github.com/protocolbuffers/txtpbfmt v0.0.0-20241112170944-20d2c9ebc01d/go.mod h1:jgxiZysxFPM+iWKwQwPR+y+Jvo54ARd4EisXxKYpB5c= +github.com/prometheus/common v0.67.4 h1:yR3NqWO1/UyO1w2PhUvXlGQs/PtFmoveVO0KZ4+Lvsc= +github.com/prometheus/common v0.67.4/go.mod h1:gP0fq6YjjNCLssJCQp0yk4M8W6ikLURwkdd/YKtTbyI= +github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws= +github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw= +github.com/protocolbuffers/txtpbfmt v0.0.0-20251124094003-fcb97cc64c7b h1:fPVI9E6QNFYI0Ph3XpKUDrcAvbCifHvqYJcntFLPog8= +github.com/protocolbuffers/txtpbfmt v0.0.0-20251124094003-fcb97cc64c7b/go.mod h1:JSbkp0BviKovYYt9XunS95M3mLPibE9bGg+Y95DsEEY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= @@ -231,8 +257,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/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/woodsbury/decimal128 v1.4.0 h1:xJATj7lLu4f2oObouMt2tgGiElE5gO6mSWUjQsBgUlc= +github.com/woodsbury/decimal128 v1.4.0/go.mod h1:BP46FUrVjVhdTbKT+XuQh2xfQaGki9LMIRJSFuh6THU= 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= @@ -243,34 +269,34 @@ github.com/zeebo/xxh3 v1.0.2 h1:xZmwmqxHZA8AI603jOQ0tMqmBr9lPeFwGg6d+xy9DC0= github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= -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/google.golang.org/grpc/otelgrpc v0.64.0 h1:RN3ifU8y4prNWeEnQp2kRRHz8UwonAEYZl8tUzHEXAk= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.64.0/go.mod h1:habDz3tEWiFANTo6oUE99EmaFUrCNYAAg3wiVmusm70= 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/instrumentation/net/http/otelhttp v0.64.0 h1:ssfIgGNANqpVFCndZvcuyKbl0g+UAVcbBcqGkG28H0Y= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.64.0/go.mod h1:GQ/474YrbE4Jx8gZ4q5I4hrhUzM6UPzyrqJYV2AqPoQ= 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.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 v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48= +go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0 h1:f0cb2XPmrqn4XMy9PNliTgRKJgS5WcL/u0/WRYGz4t0= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0/go.mod h1:vnakAaFckOMiMtOIhFI2MNH4FYrZzXCYxmb1LlhoGz8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0 h1:in9O8ESIOlwJAEGTkkf34DesGRAc/Pn8qJ7k3r/42LM= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0/go.mod h1:Rp0EXBm5tfnv0WL+ARyO/PHBEaEAT8UUHQ6AGJcSq6c= go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM= -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/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0= +go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs= go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E= -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/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18= +go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE= +go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8= +go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew= go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ= -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/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI= +go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA= go.opentelemetry.io/proto/otlp v1.9.0 h1:l706jCMITVouPOqEnii2fIAuO3IVGBRPV5ICjceRb/A= go.opentelemetry.io/proto/otlp v1.9.0/go.mod h1:xE+Cx5E/eEHw+ISFkwPLwCZefwVjY+pqKg1qcK03+/4= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= @@ -282,25 +308,25 @@ 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/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/exp v0.0.0-20251209150349-8475f28825e9 h1:MDfG8Cvcqlt9XXrmEiD4epKn7VJHZO84hejP9Jmp0MM= +golang.org/x/exp v0.0.0-20251209150349-8475f28825e9/go.mod h1:EPRbTFwzwjXj9NpYyyrvenVh9Y+GFeEvMNh7Xuz7xgU= 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.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk= -golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc= +golang.org/x/mod v0.31.0 h1:HaW9xtz0+kOcWKwli0ZXy79Ix+UW/vOfmWI5QVd2tgI= +golang.org/x/mod v0.31.0/go.mod h1:43JraMp9cGx1Rx3AqioxrbrhNsLl2l/iNAvuBkrezpg= 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.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= -golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= -golang.org/x/oauth2 v0.33.0 h1:4Q+qn+E5z8gPRJfmRy7C2gGG3T4jIprK6aSYgTXGRpo= -golang.org/x/oauth2 v0.33.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= +golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= +golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= +golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw= +golang.org/x/oauth2 v0.34.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.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= -golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.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-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -311,24 +337,24 @@ golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 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.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= -golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/telemetry v0.0.0-20251111182119-bc8e575c7b54 h1:E2/AqCUMZGgd73TQkxUMcMla25GB9i/5HOdLr+uH7Vo= -golang.org/x/telemetry v0.0.0-20251111182119-bc8e575c7b54/go.mod h1:hKdjCMrbv9skySur+Nek8Hd0uJ0GuxJIoIX2payrIdQ= -golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU= -golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254= +golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= +golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/telemetry v0.0.0-20251203150158-8fff8a5912fc h1:bH6xUXay0AIFMElXG2rQ4uiE+7ncwtiOdPfYK1NK2XA= +golang.org/x/telemetry v0.0.0-20251203150158-8fff8a5912fc/go.mod h1:hKdjCMrbv9skySur+Nek8Hd0uJ0GuxJIoIX2payrIdQ= +golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q= +golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg= 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.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= -golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= +golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= +golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= 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.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ= -golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ= +golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA= +golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc= 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= @@ -337,42 +363,42 @@ 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/genproto/googleapis/api v0.0.0-20251111163417-95abcf5c77ba h1:B14OtaXuMaCQsl2deSvNkyPKIzq3BjfxQp8d00QyWx4= -google.golang.org/genproto/googleapis/api v0.0.0-20251111163417-95abcf5c77ba/go.mod h1:G5IanEx8/PgI9w6CFcYQf7jMtHQhZruvfM1i3qOqk5U= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba h1:UKgtfRM7Yh93Sya0Fo8ZzhDP4qBckrrxEr2oF5UIVb8= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= +google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2 h1:7LRqPCEdE4TP4/9psdaB7F2nhZFfBiGJomA5sojLWdU= +google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2/go.mod h1:+rXWjjaukWZun3mLfjmVnQi18E1AsFbDN9QdJ5YXLto= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2 h1:2I6GHUeJ/4shcDpoUlLs/2WPnhg7yJwvXtqcMJt9liA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM= google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= -google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= -google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/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/evanphx/json-patch.v4 v4.13.0 h1:czT3CmqEaQ1aanPc5SdlgQrrEIb8w/wwCvWWnfEbYzo= +gopkg.in/evanphx/json-patch.v4 v4.13.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.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 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.2 h1:fsSUNZhV+bnL6Aqrp6O7lMTy6o5x2C4XLjnh//8SLYY= -k8s.io/api v0.34.2/go.mod h1:MMBPaWlED2a8w4RSeanD76f7opUoypY8TFYkSM+3XHw= -k8s.io/apimachinery v0.34.2 h1:zQ12Uk3eMHPxrsbUJgNF8bTauTVR2WgqJsTmwTE/NW4= -k8s.io/apimachinery v0.34.2/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= -k8s.io/apiserver v0.34.2 h1:2/yu8suwkmES7IzwlehAovo8dDE07cFRC7KMDb1+MAE= -k8s.io/apiserver v0.34.2/go.mod h1:gqJQy2yDOB50R3JUReHSFr+cwJnL8G1dzTA0YLEqAPI= -k8s.io/client-go v0.34.2 h1:Co6XiknN+uUZqiddlfAjT68184/37PS4QAzYvQvDR8M= -k8s.io/client-go v0.34.2/go.mod h1:2VYDl1XXJsdcAxw7BenFslRQX28Dxz91U9MWKjX97fE= -k8s.io/component-base v0.34.2 h1:HQRqK9x2sSAsd8+R4xxRirlTjowsg6fWCPwWYeSvogQ= -k8s.io/component-base v0.34.2/go.mod h1:9xw2FHJavUHBFpiGkZoKuYZ5pdtLKe97DEByaA+hHbM= +k8s.io/api v0.34.3 h1:D12sTP257/jSH2vHV2EDYrb16bS7ULlHpdNdNhEw2S4= +k8s.io/api v0.34.3/go.mod h1:PyVQBF886Q5RSQZOim7DybQjAbVs8g7gwJNhGtY5MBk= +k8s.io/apimachinery v0.34.3 h1:/TB+SFEiQvN9HPldtlWOTp0hWbJ+fjU+wkxysf/aQnE= +k8s.io/apimachinery v0.34.3/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= +k8s.io/apiserver v0.34.3 h1:uGH1qpDvSiYG4HVFqc6A3L4CKiX+aBWDrrsxHYK0Bdo= +k8s.io/apiserver v0.34.3/go.mod h1:QPnnahMO5C2m3lm6fPW3+JmyQbvHZQ8uudAu/493P2w= +k8s.io/client-go v0.34.3 h1:wtYtpzy/OPNYf7WyNBTj3iUA0XaBHVqhv4Iv3tbrF5A= +k8s.io/client-go v0.34.3/go.mod h1:OxxeYagaP9Kdf78UrKLa3YZixMCfP6bgPwPwNBQBzpM= +k8s.io/component-base v0.34.3 h1:zsEgw6ELqK0XncCQomgO9DpUIzlrYuZYA0Cgo+JWpVk= +k8s.io/component-base v0.34.3/go.mod h1:5iIlD8wPfWE/xSHTRfbjuvUul2WZbI2nOUK65XL0E/c= 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= +k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e h1:iW9ChlU0cU16w8MpVYjXk12dqQ4BPFBEgif+ap7/hqQ= +k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e/go.mod h1:kdmbQkyfwUagLfXIad1y2TdrjPFWp2Q89B3qkRwf/pQ= +k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 h1:SjGebBtkBqHFOli+05xYbK8YF1Dzkbzn+gDM4X9T4Ck= +k8s.io/utils v0.0.0-20251002143259-bc988d571ff4/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg= +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/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.1 h1:JrhdFMqOd/+3ByqlP2I45kTOZmTRLBUm5pvRjeheg7E= diff --git a/apps/dashboard/pkg/apis/dashboard/v0alpha1/dashboard_kind.cue b/apps/dashboard/pkg/apis/dashboard/v0alpha1/dashboard_kind.cue index 4a255a57ba6..8338c9e13c5 100644 --- a/apps/dashboard/pkg/apis/dashboard/v0alpha1/dashboard_kind.cue +++ b/apps/dashboard/pkg/apis/dashboard/v0alpha1/dashboard_kind.cue @@ -706,6 +706,10 @@ lineage: schemas: [{ // Field options allow you to change how the data is displayed in your visualizations. fieldConfig?: #FieldConfigSource + + // When a panel is migrated from a previous version (Angular to React), this field is set to the original panel type. + // This is used to determine the original panel type when migrating to a new version so the plugin migration can be applied. + autoMigrateFrom?: string } @cuetsy(kind="interface") @grafana(TSVeneer="type") @grafanamaturity(NeedsExpertReview) // The data model used in Grafana, namely the data frame, is a columnar-oriented table structure that unifies both time series and table query results. diff --git a/apps/dashboard/pkg/apis/dashboard/v1beta1/dashboard_kind.cue b/apps/dashboard/pkg/apis/dashboard/v1beta1/dashboard_kind.cue index 4a255a57ba6..8338c9e13c5 100644 --- a/apps/dashboard/pkg/apis/dashboard/v1beta1/dashboard_kind.cue +++ b/apps/dashboard/pkg/apis/dashboard/v1beta1/dashboard_kind.cue @@ -706,6 +706,10 @@ lineage: schemas: [{ // Field options allow you to change how the data is displayed in your visualizations. fieldConfig?: #FieldConfigSource + + // When a panel is migrated from a previous version (Angular to React), this field is set to the original panel type. + // This is used to determine the original panel type when migrating to a new version so the plugin migration can be applied. + autoMigrateFrom?: string } @cuetsy(kind="interface") @grafana(TSVeneer="type") @grafanamaturity(NeedsExpertReview) // The data model used in Grafana, namely the data frame, is a columnar-oriented table structure that unifies both time series and table query results. diff --git a/apps/dashboard/pkg/migration/README.md b/apps/dashboard/pkg/migration/README.md index ab938e31f66..6fd2069cce9 100644 --- a/apps/dashboard/pkg/migration/README.md +++ b/apps/dashboard/pkg/migration/README.md @@ -53,6 +53,7 @@ v0alpha1 (Legacy JSON) → v1beta1 (Migrated JSON) → v2alpha1/v2beta1 (Structu - Transforms JSON dashboards to structured dashboard format - v2 schema is the stable, typed schema with proper type definitions - Handles modern dashboard features and Kubernetes-native storage +- Preserves Angular panel migration data for frontend processing (see [Angular Panel Migrations](#angular-panel-migrations)) - See [V2 to V1 Layout Conversion](./conversion/v2_to_v1_layout_conversion.md) for details on how V2 layouts are converted back to V1 panel arrays #### v2 to v0/v1 Conversion: @@ -61,6 +62,76 @@ v0alpha1 (Legacy JSON) → v1beta1 (Migrated JSON) → v2alpha1/v2beta1 (Structu - v0alpha1 and v1beta1 share the same spec structure (only API version differs) - Enables backward compatibility when storing v2 dashboards in legacy format +### Angular Panel Migrations + +When converting dashboards from v0/v1 to v2, panels with Angular types require special handling. The `autoMigrateFrom` field is used in v0 and v1 to indicate the panel was migrated from a deprecated plugin type, and the target plugin contains migration logic to transform the original panel's options and field configurations. + +Panel plugins define their own migration logic via `plugin.onPanelTypeChanged()`. This migration runs in the frontend when a panel type changes, transforming old options/fieldConfig to the new format. Examples: +- `singlestat.format: "short"` → `stat.fieldConfig.defaults.unit: "short"` +- `graph.legend.show: true` → `timeseries.options.legend.showLegend: true` + +The v2 schema doesn't include `autoMigrateFrom` as a typed field, so we need a mechanism to preserve the original panel data for the frontend to run these plugin migrations. + +#### `__angularMigration` Temporary Data + +The backend v1 → v2 conversion preserves the original panel data in a temporary field within `vizConfig.spec.options`. This works for **any** Angular panel, not just specific panel types: + +```json +{ + "vizConfig": { + "kind": "stat", + "spec": { + "options": { + "__angularMigration": { + "autoMigrateFrom": "singlestat", + "originalPanel": { + "type": "singlestat", + "format": "short", + "colorBackground": true, + "sparkline": { "show": true }, + "fieldConfig": { ... }, + "options": { ... } + } + } + } + } + } +} +``` + +#### How It Works + +1. **Backend (v1 → v2):** The conversion detects panels that need Angular migration in two ways: + - If `autoMigrateFrom` is already set on the panel (from v0 → v1 migration) - panel type already converted + - If the panel type is a known Angular panel type (fallback for dashboards stored directly as v1 without v0 → v1 migration) + + In the second case, the conversion also transforms the panel type (e.g., `singlestat` → `stat`) and sets `autoMigrateFrom`. This replicates the same logic as the v0 → v1 migration. + + The entire original panel is stored under `options.__angularMigration` for the frontend to run plugin-specific migrations. + +2. **Frontend (v2 load):** When building a `VizPanel` from v2 data: + - Extracts `__angularMigration` from options + - Removes it from the options object (not persisted) + - Attaches a custom migration handler via `_UNSAFE_customMigrationHandler` + +3. **Plugin load (VizPanel activation):** When the plugin loads, the migration handler calls `plugin.onPanelTypeChanged()` with the original panel data, allowing the plugin's own migration code to run + +#### Key Points + +- Works for **any** panel with `autoMigrateFrom`, not limited to specific panel types +- Each plugin defines its own migration logic - the backend just preserves the data +- The `originalPanel` contains the complete panel data to ensure no information is lost +- Migration data is removed from options after loaded in frontend +- The 0v → v1 and v1 → v2 conversions automatically detects these Angular panel types if `autoMigrateFrom` is not set. + +#### Implementation Files + +| File | Purpose | +|------|---------| +| `apps/dashboard/pkg/migration/conversion/v1beta1_to_v2alpha1.go` | Injects `__angularMigration` during v1 → v2 | +| `public/app/features/dashboard-scene/serialization/layoutSerializers/utils.ts` | Extracts and consumes `__angularMigration` | +| `public/app/features/dashboard-scene/serialization/angularMigration.ts` | Creates migration handler for v2 path | + ## Conversion Matrix The system supports conversions between all dashboard API versions: diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/migrations/v0alpha1.migrations.v42.json b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/migrations/v0alpha1.migrations.v42.json index 89ce80876d2..e4e6f8831da 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/migrations/v0alpha1.migrations.v42.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/input/migrated_dev_dashboards/migrations/v0alpha1.migrations.v42.json @@ -300,15 +300,9 @@ "y": 0 }, "id": 6, - "options": { - "code": { - "language": "plaintext", - "showLineNumbers": false, - "showMiniMap": false - }, - "content": "# Graph panel \u003e\u003e Timeseries panel\n\nKnown issues:\n* hiding null/empty series\n* time regions", - "mode": "markdown" - }, + "options": {}, + "content": "# Graph panel \u003e\u003e Timeseries panel\n\nKnown issues:\n* hiding null/empty series\n* time regions", + "mode": "markdown", "pluginVersion": "11.0.0-pre", "targets": [ { diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/v1beta1.angular-migrations.json b/apps/dashboard/pkg/migration/conversion/testdata/input/v1beta1.angular-migrations.json new file mode 100644 index 00000000000..3d496f51731 --- /dev/null +++ b/apps/dashboard/pkg/migration/conversion/testdata/input/v1beta1.angular-migrations.json @@ -0,0 +1,1310 @@ +{ + "kind": "Dashboard", + "apiVersion": "dashboard.grafana.app/v1beta1", + "metadata": { + "name": "angular-migrations-test" + }, + "spec": { + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations \u0026 Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "links": [ + { + "asDropdown": false, + "icon": "external link", + "includeVars": false, + "keepTime": false, + "tags": [], + "targetBlank": true, + "title": "Auto migrate graph panel (TRUE)", + "tooltip": "", + "type": "link", + "url": " /d/cdd412c4/?__feature.autoMigrateGraphPanel=true" + }, + { + "asDropdown": false, + "icon": "external link", + "includeVars": false, + "keepTime": false, + "tags": [], + "targetBlank": true, + "title": "Auto migrate graph panel (FALSE)", + "tooltip": "", + "type": "link", + "url": " /d/cdd412c4/?__feature.autoMigrateGraphPanel=false" + }, + { + "asDropdown": false, + "icon": "external link", + "includeVars": false, + "keepTime": false, + "tags": [], + "targetBlank": true, + "title": "Auto migrate table (old) panel (TRUE)", + "tooltip": "", + "type": "link", + "url": " /d/cdd412c4/?__feature.autoMigrateTablePanel=true" + }, + { + "asDropdown": false, + "icon": "external link", + "includeVars": false, + "keepTime": false, + "tags": [], + "targetBlank": true, + "title": "Auto migrate table (old) panel (FALSE)", + "tooltip": "", + "type": "link", + "url": " /d/cdd412c4/?__feature.autoMigrateTablePanel=false" + }, + { + "asDropdown": false, + "icon": "external link", + "includeVars": false, + "keepTime": false, + "tags": [], + "targetBlank": true, + "title": "Auto migrate piechart panel (TRUE)", + "tooltip": "", + "type": "link", + "url": " /d/cdd412c4/?__feature.autoMigratePiechartPanel=true" + }, + { + "asDropdown": false, + "icon": "external link", + "includeVars": false, + "keepTime": false, + "tags": [], + "targetBlank": true, + "title": "Auto migrate piechart panel (FALSE)", + "tooltip": "", + "type": "link", + "url": " /d/cdd412c4/?__feature.autoMigratePiechartPanel=false" + }, + { + "asDropdown": false, + "icon": "external link", + "includeVars": false, + "keepTime": false, + "tags": [], + "targetBlank": true, + "title": "Auto migrate worldmap panel (TRUE)", + "tooltip": "", + "type": "link", + "url": " /d/cdd412c4/?__feature.autoMigrateWorldmapPanel=true" + }, + { + "asDropdown": false, + "icon": "external link", + "includeVars": false, + "keepTime": false, + "tags": [], + "targetBlank": true, + "title": "Auto migrate worldmap panel (FALSE)", + "tooltip": "", + "type": "link", + "url": " /d/cdd412c4/?__feature.autoMigrateWorldmapPanel=false" + }, + { + "asDropdown": false, + "icon": "external link", + "includeVars": false, + "keepTime": false, + "tags": [], + "targetBlank": true, + "title": "Auto migrate stat panel (TRUE)", + "tooltip": "", + "type": "link", + "url": " /d/cdd412c4/?__feature.autoMigrateStatPanel=true" + }, + { + "asDropdown": false, + "icon": "external link", + "includeVars": false, + "keepTime": false, + "tags": [], + "targetBlank": true, + "title": "Auto migrate stat panel (FALSE)", + "tooltip": "", + "type": "link", + "url": " /d/cdd412c4/?__feature.autoMigrateStatPanel=false" + }, + { + "asDropdown": false, + "icon": "external link", + "includeVars": false, + "keepTime": false, + "tags": [], + "targetBlank": true, + "title": "Auto migrate (TRUE)", + "tooltip": "", + "type": "link", + "url": "/d/cdd412c4/?__feature.autoMigrateOldPanels=true" + }, + { + "asDropdown": false, + "icon": "external link", + "includeVars": false, + "keepTime": false, + "tags": [], + "targetBlank": true, + "title": "Auto migrate (FALSE)", + "tooltip": "", + "type": "link", + "url": "/d/cdd412c4/?__feature.autoMigrateOldPanels=false" + }, + { + "asDropdown": false, + "icon": "external link", + "includeVars": false, + "keepTime": false, + "tags": [], + "targetBlank": true, + "title": "Disable angular (TRUE)", + "tooltip": "", + "type": "link", + "url": "/d/cdd412c4/?__feature.disableAngular=true" + }, + { + "asDropdown": false, + "icon": "external link", + "includeVars": false, + "keepTime": false, + "tags": [], + "targetBlank": true, + "title": "Disable angular (FALSE)", + "tooltip": "", + "type": "link", + "url": "/d/cdd412c4/?__feature.disableAngular=false" + } + ], + "liveNow": false, + "panels": [ + { + "aliasColors": {}, + "type": "graph", + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "type": "grafana-testdata-datasource" + }, + "fieldConfig": { + "defaults": { + "unit": "short" + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 11, + "w": 16, + "x": 0, + "y": 0 + }, + "hiddenSeries": false, + "id": 4, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "percentage": false, + "pluginVersion": "11.0.0-pre", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "datasource": { + "type": "grafana-testdata-datasource" + }, + "refId": "A", + "scenarioId": "random_walk", + "seriesCount": 3 + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Flot graph", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + }, + { + "datasource": { + "type": "grafana-testdata-datasource" + }, + "gridPos": { + "h": 11, + "w": 8, + "x": 16, + "y": 0 + }, + "id": 6, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "# Graph panel \u003e\u003e Timeseries panel\n\nKnown issues:\n* hiding null/empty series\n* time regions", + "mode": "markdown" + }, + "pluginVersion": "11.0.0-pre", + "targets": [ + { + "datasource": { + "type": "grafana-testdata-datasource" + }, + "refId": "A" + } + ], + "title": "Status + Notes", + "type": "text" + }, + { + "aliasColors": {}, + "autoMigrateFrom": "graph", + "bars": true, + "dashLength": 10, + "dashes": false, + "datasource": { + "type": "grafana-testdata-datasource" + }, + "fieldConfig": { + "defaults": { + "unit": "short" + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 11, + "w": 16, + "x": 0, + "y": 11 + }, + "hiddenSeries": false, + "id": 28, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": false, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "percentage": false, + "pluginVersion": "11.0.0-pre", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "datasource": { + "type": "grafana-testdata-datasource" + }, + "rawFrameContent": "[\n {\n \"schema\": {\n \"refId\": \"A\",\n \"meta\": {\n \"typeVersion\": [\n 0,\n 0\n ],\n \"custom\": {\n \"customStat\": 10\n }\n },\n \"fields\": [\n {\n \"name\": \"time\",\n \"type\": \"time\",\n \"typeInfo\": {\n \"frame\": \"time.Time\",\n \"nullable\": true\n },\n \"config\": {\n \"interval\": 3600000\n }\n },\n {\n \"name\": \"Value\",\n \"type\": \"number\",\n \"typeInfo\": {\n \"frame\": \"float64\",\n \"nullable\": true\n },\n \"labels\": {\n \"pod\": \"A-pod\"\n },\n \"config\": {}\n }\n ]\n },\n \"data\": {\n \"values\": [\n [\n 1727107111901,\n 1727110711901,\n 1727114311901,\n 1727117911901,\n 1727121511901,\n 1727125111901\n ],\n [\n 1.907286825122581,\n 2.260951647569786,\n 1.887442338051216,\n 2.1526144400893514,\n 1.7287721375237766,\n 1.7262902137793208\n ]\n ]\n }\n },\n {\n \"schema\": {\n \"refId\": \"A\",\n \"meta\": {\n \"typeVersion\": [\n 0,\n 0\n ],\n \"custom\": {\n \"customStat\": 10\n }\n },\n \"fields\": [\n {\n \"name\": \"time\",\n \"type\": \"time\",\n \"typeInfo\": {\n \"frame\": \"time.Time\",\n \"nullable\": true\n },\n \"config\": {\n \"interval\": 3600000\n }\n },\n {\n \"name\": \"Value\",\n \"type\": \"number\",\n \"typeInfo\": {\n \"frame\": \"float64\",\n \"nullable\": true\n },\n \"labels\": {\n \"pod\": \"A-pod1\"\n },\n \"config\": {}\n }\n ]\n },\n \"data\": {\n \"values\": [\n [\n 1727107111901,\n 1727110711901,\n 1727114311901,\n 1727117911901,\n 1727121511901,\n 1727125111901\n ],\n [\n 1.907286825122581,\n 1.589539045095202,\n 1.5914283506847613,\n 1.8976990616650726,\n 1.758223085999124,\n 2.2294649594813816\n ]\n ]\n }\n },\n {\n \"schema\": {\n \"refId\": \"A\",\n \"meta\": {\n \"typeVersion\": [\n 0,\n 0\n ],\n \"custom\": {\n \"customStat\": 10\n }\n },\n \"fields\": [\n {\n \"name\": \"time\",\n \"type\": \"time\",\n \"typeInfo\": {\n \"frame\": \"time.Time\",\n \"nullable\": true\n },\n \"config\": {\n \"interval\": 3600000\n }\n },\n {\n \"name\": \"Value\",\n \"type\": \"number\",\n \"typeInfo\": {\n \"frame\": \"float64\",\n \"nullable\": true\n },\n \"labels\": {\n \"pod\": \"A-pod2\"\n },\n \"config\": {}\n }\n ]\n },\n \"data\": {\n \"values\": [\n [\n 1727107111901,\n 1727110711901,\n 1727114311901,\n 1727117911901,\n 1727121511901,\n 1727125111901\n ],\n [\n 1.907286825122581,\n 2.0914263380328766,\n 1.8164545521094575,\n 1.621111084665713,\n 1.3902653996444705,\n 1.482803315949775\n ]\n ]\n }\n }\n]", + "refId": "A", + "scenarioId": "raw_frame" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Flot graph - x axis series mode", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "barchart", + "xaxis": { + "mode": "series", + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "$$hashKey": "object:88", + "format": "short", + "logBase": 1, + "show": true + }, + { + "$$hashKey": "object:89", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + }, + { + "datasource": { + "type": "grafana-testdata-datasource" + }, + "gridPos": { + "h": 11, + "w": 8, + "x": 16, + "y": 11 + }, + "id": 29, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "# Graph panel \u003e\u003e Bar chart panel\n", + "mode": "markdown" + }, + "pluginVersion": "11.0.0-pre", + "targets": [ + { + "datasource": { + "type": "grafana-testdata-datasource" + }, + "refId": "A" + } + ], + "title": "Status + Notes", + "type": "text" + }, + { + "aliasColors": {}, + "autoMigrateFrom": "graph", + "bars": true, + "dashLength": 10, + "dashes": false, + "datasource": { + "default": false, + "type": "datasource", + "uid": "-- Dashboard --" + }, + "fieldConfig": { + "defaults": { + "unit": "short" + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 11, + "w": 16, + "x": 0, + "y": 22 + }, + "hiddenSeries": false, + "id": 32, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": false, + "show": true, + "total": false, + "values": true + }, + "lines": false, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "percentage": false, + "pluginVersion": "11.3.0-pre", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "panelId": 28, + "refId": "A" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Flot graph - x axis series mode (with legend calcs)", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "bargauge", + "xaxis": { + "mode": "series", + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "$$hashKey": "object:88", + "format": "short", + "logBase": 1, + "show": true + }, + { + "$$hashKey": "object:89", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + }, + { + "aliasColors": {}, + "autoMigrateFrom": "graph", + "bars": true, + "dashLength": 10, + "dashes": false, + "datasource": { + "type": "grafana-testdata-datasource" + }, + "fieldConfig": { + "defaults": { + "unit": "short" + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 11, + "w": 16, + "x": 0, + "y": 22 + }, + "hiddenSeries": false, + "id": 30, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": false, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "percentage": false, + "pluginVersion": "11.0.0-pre", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "datasource": { + "type": "grafana-testdata-datasource" + }, + "refId": "A", + "scenarioId": "random_walk", + "seriesCount": 3 + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Flot graph - x axis histogram mode", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "histogram", + "xaxis": { + "mode": "histogram", + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:193", + "format": "short", + "logBase": 1, + "show": true + }, + { + "$$hashKey": "object:194", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + }, + { + "datasource": { + "type": "grafana-testdata-datasource" + }, + "gridPos": { + "h": 11, + "w": 8, + "x": 16, + "y": 22 + }, + "id": 33, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "# Graph panel \u003e\u003e Bar gauge panel\n", + "mode": "markdown" + }, + "pluginVersion": "11.3.0-pre", + "targets": [ + { + "datasource": { + "type": "grafana-testdata-datasource" + }, + "refId": "A" + } + ], + "title": "Status + Notes", + "type": "text" + }, + { + "datasource": { + "type": "grafana-testdata-datasource" + }, + "gridPos": { + "h": 11, + "w": 8, + "x": 16, + "y": 22 + }, + "id": 31, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "# Graph panel \u003e\u003e Histogram panel\n", + "mode": "markdown" + }, + "pluginVersion": "11.0.0-pre", + "targets": [ + { + "datasource": { + "type": "grafana-testdata-datasource" + }, + "refId": "A" + } + ], + "title": "Status + Notes", + "type": "text" + }, + { + "autoMigrateFrom": "table-old", + "columns": [], + "datasource": { + "type": "grafana-testdata-datasource" + }, + "fontSize": "100%", + "gridPos": { + "h": 10, + "w": 16, + "x": 0, + "y": 33 + }, + "id": 2, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true, + "showRowNums": false + }, + "pluginVersion": "9.5.0-pre", + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "align": "auto", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "date" + }, + { + "alias": "", + "align": "right", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "number", + "unit": "short" + } + ], + "targets": [ + { + "datasource": { + "type": "grafana-testdata-datasource" + }, + "refId": "A", + "scenarioId": "random_walk_table" + } + ], + "title": "Table (old)", + "transform": "table", + "transformations": [ + { + "id": "merge", + "options": { + "reducers": [] + } + } + ], + "type": "table" + }, + { + "datasource": { + "type": "grafana-testdata-datasource" + }, + "gridPos": { + "h": 10, + "w": 8, + "x": 16, + "y": 33 + }, + "id": 7, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "# Table (old) \u003e\u003e Table\n\nKnown issues:\n* wrapping text\n* style changes", + "mode": "markdown" + }, + "pluginVersion": "11.0.0-pre", + "targets": [ + { + "datasource": { + "type": "grafana-testdata-datasource" + }, + "refId": "A" + } + ], + "title": "Status + Notes", + "type": "text" + }, + { + "autoMigrateFrom": "grafana-singlestat-panel", + "colorBackground": false, + "colorValue": true, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": { + "type": "grafana-testdata-datasource" + }, + "format": "areaF2", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 43 + }, + "id": 9, + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "postfix": "b", + "postfixFontSize": "50%", + "prefix": "a", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "datasource": { + "type": "grafana-testdata-datasource" + }, + "refId": "A" + } + ], + "thresholds": "", + "title": "grafana-singlestat-panel", + "type": "stat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "datasource": { + "type": "grafana-testdata-datasource" + }, + "fieldConfig": { + "defaults": { + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "ms" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 43 + }, + "id": 23, + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "mean" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "11.0.0-pre", + "targets": [ + { + "datasource": { + "type": "grafana-testdata-datasource" + }, + "refId": "A" + } + ], + "title": "singlestat (old, internal. Migrated if schema \u003c 28)", + "type": "stat" + }, + { + "datasource": { + "type": "grafana-testdata-datasource" + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 43 + }, + "id": 10, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "# Singlestat \u003e\u003e Stat\n\nKnown issues:\n* limited options", + "mode": "markdown" + }, + "pluginVersion": "11.0.0-pre", + "targets": [ + { + "datasource": { + "type": "grafana-testdata-datasource" + }, + "refId": "A" + } + ], + "title": "Status + Notes", + "type": "text" + }, + { + "autoMigrateFrom": "grafana-piechart-panel", + "datasource": { + "type": "grafana-testdata-datasource" + }, + "gridPos": { + "h": 10, + "w": 16, + "x": 0, + "y": 51 + }, + "id": 24, + "options": { + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "pieType": "pie", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "9.5.0-pre", + "targets": [ + { + "datasource": { + "type": "grafana-testdata-datasource" + }, + "refId": "A", + "scenarioId": "random_walk_table" + } + ], + "title": "grafana-piechart-panel", + "transformations": [ + { + "id": "merge", + "options": { + "reducers": [] + } + } + ], + "type": "piechart" + }, + { + "datasource": { + "type": "grafana-testdata-datasource" + }, + "gridPos": { + "h": 10, + "w": 8, + "x": 16, + "y": 51 + }, + "id": 25, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "# grafana-piechart-panel \u003e\u003e piechart\n\nKnown issues:\n* TBD", + "mode": "markdown" + }, + "pluginVersion": "11.0.0-pre", + "targets": [ + { + "datasource": { + "type": "grafana-testdata-datasource" + }, + "refId": "A" + } + ], + "title": "Status + Notes", + "type": "text" + }, + { + "autoMigrateFrom": "grafana-worldmap-panel", + "circleMaxSize": 30, + "circleMinSize": 2, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": { + "type": "grafana-testdata-datasource" + }, + "decimals": 0, + "esMetric": "Count", + "gridPos": { + "h": 10, + "w": 16, + "x": 0, + "y": 61 + }, + "hideEmpty": false, + "hideZero": false, + "id": 26, + "initialZoom": 1, + "locationData": "countries", + "mapCenter": "(0°, 0°)", + "mapCenterLatitude": 0, + "mapCenterLongitude": 0, + "maxDataPoints": 1, + "mouseWheelZoom": false, + "options": { + "basemap": { + "name": "Basemap", + "type": "default" + }, + "controls": { + "mouseWheelZoom": false, + "showAttribution": true, + "showDebug": false, + "showMeasure": false, + "showScale": false, + "showZoom": true + }, + "layers": [ + { + "config": { + "showLegend": true, + "style": { + "color": { + "fixed": "dark-green" + }, + "opacity": 0.4, + "rotation": { + "fixed": 0, + "max": 360, + "min": -360, + "mode": "mod" + }, + "size": { + "fixed": 5, + "max": 30, + "min": 2 + }, + "symbol": { + "fixed": "img/icons/marker/circle.svg", + "mode": "fixed" + }, + "symbolAlign": { + "horizontal": "center", + "vertical": "center" + }, + "textConfig": { + "fontSize": 12, + "offsetX": 0, + "offsetY": 0, + "textAlign": "center", + "textBaseline": "middle" + } + } + }, + "location": { + "gazetteer": "public/gazetteer/countries.json", + "mode": "lookup" + }, + "name": "Layer 0", + "tooltip": true, + "type": "markers" + } + ], + "tooltip": { + "mode": "details" + }, + "view": { + "allLayers": true, + "id": "zero", + "lat": 0, + "lon": 0, + "zoom": 1 + } + }, + "pluginVersion": "10.4.0-pre", + "showLegend": true, + "stickyLabels": false, + "tableQueryOptions": { + "geohashField": "geohash", + "latitudeField": "latitude", + "longitudeField": "longitude", + "metricField": "metric", + "queryType": "geohash" + }, + "targets": [ + { + "csvFileName": "flight_info_by_state.csv", + "datasource": { + "type": "grafana-testdata-datasource" + }, + "refId": "A", + "scenarioId": "csv_file" + } + ], + "thresholds": "0,10", + "title": "grafana-worldmap-panel", + "transformations": [ + { + "id": "merge", + "options": { + "reducers": [] + } + }, + { + "id": "reduce", + "options": { + "reducers": [ + "sum" + ] + } + } + ], + "type": "geomap", + "unitPlural": "", + "unitSingle": "", + "valueName": "total" + }, + { + "datasource": { + "type": "grafana-testdata-datasource" + }, + "gridPos": { + "h": 10, + "w": 8, + "x": 16, + "y": 61 + }, + "id": 27, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "# grafana-worldmap-panel \u003e\u003e geomap\n\nKnown issues:\n* TBD", + "mode": "markdown" + }, + "pluginVersion": "11.0.0-pre", + "targets": [ + { + "datasource": { + "type": "grafana-testdata-datasource" + }, + "refId": "A" + } + ], + "title": "Status + Notes", + "type": "text" + } + ], + "refresh": "", + "schemaVersion": 42, + "tags": [ + "gdev", + "migrations", + "angular" + ], + "templating": { + "list": [] + }, + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "Devenv - Panel migrations", + "uid": "cdd412c4", + "weekStart": "" + }, + "status": { + "conversion": { + "failed": false, + "storedVersion": "v0alpha1" + } + } +} \ No newline at end of file diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/v1beta1.panel-target-missing-refid.json b/apps/dashboard/pkg/migration/conversion/testdata/input/v1beta1.panel-target-missing-refid.json new file mode 100644 index 00000000000..65bf0b136a6 --- /dev/null +++ b/apps/dashboard/pkg/migration/conversion/testdata/input/v1beta1.panel-target-missing-refid.json @@ -0,0 +1,156 @@ +{ + "apiVersion": "dashboard.grafana.app/v1beta1", + "kind": "Dashboard", + "metadata": { + "name": "ad5vfcn", + "namespace": "default", + "uid": "dlMZZl6GndU8gJLUQSmgZxXBPCNXyXhNBeQJhHXl0r4X", + "resourceVersion": "2", + "generation": 2, + "creationTimestamp": "2025-11-28T10:14:21Z", + "labels": { + "grafana.app/deprecatedInternalID": "288" + }, + "annotations": { + "grafana.app/createdBy": "user:eex2ofwuj0agwd", + "grafana.app/updatedBy": "user:eex2ofwuj0agwd", + "grafana.app/updatedTimestamp": "2025-11-28T10:15:06Z" + } + }, + "spec": { + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": 288, + "links": [], + "panels": [ + { + "datasource": { + "type": "testdata", + "uid": "gdev-testdata" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 0 + }, + "id": 1, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0-pre", + "targets": [ + { + "datasource": {}, + "queryType": "randomWalk" + }, + { + "datasource": {}, + "queryType": "randomWalk" + } + ], + "title": "New panel", + "type": "timeseries" + } + ], + "preload": false, + "schemaVersion": 42, + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": {}, + "timezone": "browser", + "title": "Panel ds inheritance ", + "uid": "ad5vfcn", + "version": 2 + }, + "status": {} +} diff --git a/apps/dashboard/pkg/migration/conversion/testdata/input/v2beta1.value-mapping-and-overrides.json b/apps/dashboard/pkg/migration/conversion/testdata/input/v2beta1.value-mapping-and-overrides.json new file mode 100644 index 00000000000..54507dafbea --- /dev/null +++ b/apps/dashboard/pkg/migration/conversion/testdata/input/v2beta1.value-mapping-and-overrides.json @@ -0,0 +1,864 @@ +{ + "kind": "DashboardWithAccessInfo", + "apiVersion": "dashboard.grafana.app/v2beta1", + "metadata": { + "name": "value-mapping-test", + "namespace": "default", + "uid": "value-mapping-test", + "resourceVersion": "1765384157199094", + "generation": 2, + "creationTimestamp": "2025-11-19T20:09:28Z", + "labels": { + "grafana.app/deprecatedInternalID": "646372978987008" + } + }, + "spec": { + "annotations": [ + { + "kind": "AnnotationQuery", + "spec": { + "query": { + "kind": "DataQuery", + "group": "grafana", + "version": "v0", + "datasource": { + "name": "-- Grafana --" + }, + "spec": {} + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations \u0026 Alerts", + "builtIn": true, + "legacyOptions": { + "type": "dashboard" + } + } + } + ], + "cursorSync": "Off", + "description": "Test dashboard for all value mapping types and override matcher types", + "editable": true, + "elements": { + "panel-1": { + "kind": "Panel", + "spec": { + "id": 1, + "title": "ValueMap Example", + "description": "Panel with ValueMap mapping type - maps specific text values to colors and display text", + "links": [], + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "DataQuery", + "group": "prometheus", + "version": "v0", + "datasource": { + "name": "prometheus-uid" + }, + "spec": { + "expr": "up" + } + }, + "refId": "A", + "hidden": false + } + } + ], + "transformations": [], + "queryOptions": {} + } + }, + "vizConfig": { + "kind": "VizConfig", + "group": "stat", + "version": "", + "spec": { + "options": {}, + "fieldConfig": { + "defaults": { + "mappings": [ + { + "type": "value", + "options": { + "critical": { + "text": "Critical!", + "color": "red", + "index": 0 + }, + "ok": { + "text": "OK", + "color": "green", + "index": 2 + }, + "warning": { + "text": "Warning", + "color": "orange", + "index": 1 + } + } + } + ] + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "status" + }, + "properties": [ + { + "id": "custom.width", + "value": 100 + }, + { + "id": "custom.align", + "value": "center" + } + ] + } + ] + } + } + } + } + }, + "panel-2": { + "kind": "Panel", + "spec": { + "id": 2, + "title": "RangeMap Example", + "description": "Panel with RangeMap mapping type - maps numerical ranges to colors and display text", + "links": [], + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "DataQuery", + "group": "prometheus", + "version": "v0", + "datasource": { + "name": "prometheus-uid" + }, + "spec": { + "expr": "cpu_usage_percent" + } + }, + "refId": "A", + "hidden": false + } + } + ], + "transformations": [], + "queryOptions": {} + } + }, + "vizConfig": { + "kind": "VizConfig", + "group": "gauge", + "version": "", + "spec": { + "options": {}, + "fieldConfig": { + "defaults": { + "mappings": [ + { + "type": "range", + "options": { + "from": 0, + "to": 50, + "result": { + "text": "Low", + "color": "green", + "index": 0 + } + } + }, + { + "type": "range", + "options": { + "from": 50, + "to": 80, + "result": { + "text": "Medium", + "color": "orange", + "index": 1 + } + } + }, + { + "type": "range", + "options": { + "from": 80, + "to": 100, + "result": { + "text": "High", + "color": "red", + "index": 2 + } + } + } + ] + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^cpu_/" + }, + "properties": [ + { + "id": "unit", + "value": "percent" + }, + { + "id": "decimals", + "value": 2 + } + ] + } + ] + } + } + } + } + }, + "panel-3": { + "kind": "Panel", + "spec": { + "id": 3, + "title": "RegexMap Example", + "description": "Panel with RegexMap mapping type - maps values matching regex patterns to colors", + "links": [], + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "DataQuery", + "group": "prometheus", + "version": "v0", + "datasource": { + "name": "prometheus-uid" + }, + "spec": { + "expr": "log_level" + } + }, + "refId": "A", + "hidden": false + } + } + ], + "transformations": [], + "queryOptions": {} + } + }, + "vizConfig": { + "kind": "VizConfig", + "group": "stat", + "version": "", + "spec": { + "options": {}, + "fieldConfig": { + "defaults": { + "mappings": [ + { + "type": "regex", + "options": { + "pattern": "/^error.*/", + "result": { + "text": "Error", + "color": "red", + "index": 0 + } + } + }, + { + "type": "regex", + "options": { + "pattern": "/^warn.*/", + "result": { + "text": "Warning", + "color": "orange", + "index": 1 + } + } + }, + { + "type": "regex", + "options": { + "pattern": "/^info.*/", + "result": { + "text": "Info", + "color": "blue", + "index": 2 + } + } + } + ] + }, + "overrides": [ + { + "matcher": { + "id": "byType", + "options": "string" + }, + "properties": [ + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + } + ] + } + ] + } + } + } + } + }, + "panel-4": { + "kind": "Panel", + "spec": { + "id": 4, + "title": "SpecialValueMap Example", + "description": "Panel with SpecialValueMap mapping type - maps special values like null, NaN, true, false to display text", + "links": [], + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "DataQuery", + "group": "prometheus", + "version": "v0", + "datasource": { + "name": "prometheus-uid" + }, + "spec": { + "expr": "some_metric" + } + }, + "refId": "A", + "hidden": false + } + } + ], + "transformations": [], + "queryOptions": {} + } + }, + "vizConfig": { + "kind": "VizConfig", + "group": "stat", + "version": "", + "spec": { + "options": {}, + "fieldConfig": { + "defaults": { + "mappings": [ + { + "type": "special", + "options": { + "match": "null", + "result": { + "text": "No Data", + "color": "gray", + "index": 0 + } + } + }, + { + "type": "special", + "options": { + "match": "nan", + "result": { + "text": "Not a Number", + "color": "gray", + "index": 1 + } + } + }, + { + "type": "special", + "options": { + "match": "null+nan", + "result": { + "text": "N/A", + "color": "gray", + "index": 2 + } + } + }, + { + "type": "special", + "options": { + "match": "true", + "result": { + "text": "Yes", + "color": "green", + "index": 3 + } + } + }, + { + "type": "special", + "options": { + "match": "false", + "result": { + "text": "No", + "color": "red", + "index": 4 + } + } + }, + { + "type": "special", + "options": { + "match": "empty", + "result": { + "text": "Empty", + "color": "gray", + "index": 5 + } + } + } + ] + }, + "overrides": [ + { + "matcher": { + "id": "byFrameRefID", + "options": "A" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + } + ] + } + } + } + } + }, + "panel-6": { + "kind": "Panel", + "spec": { + "id": 6, + "title": "Empty Properties Override Example", + "description": "Panel with override that has empty properties array - tests conversion of overrides without any property modifications", + "links": [], + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "DataQuery", + "group": "prometheus", + "version": "v0", + "datasource": { + "name": "prometheus-uid" + }, + "spec": { + "expr": "empty_override_metric" + } + }, + "refId": "A", + "hidden": false + } + } + ], + "transformations": [], + "queryOptions": {} + } + }, + "vizConfig": { + "kind": "VizConfig", + "group": "stat", + "version": "", + "spec": { + "options": {}, + "fieldConfig": { + "defaults": {}, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "field_with_empty_override" + }, + "properties": [] + } + ] + } + } + } + } + }, + "panel-5": { + "kind": "Panel", + "spec": { + "id": 5, + "title": "Combined Mappings and Overrides Example", + "description": "Panel with all mapping types combined - demonstrates mixing different mapping types and multiple override matchers", + "links": [], + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "DataQuery", + "group": "prometheus", + "version": "v0", + "datasource": { + "name": "prometheus-uid" + }, + "spec": { + "expr": "combined_metric" + } + }, + "refId": "A", + "hidden": false + } + }, + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "DataQuery", + "group": "prometheus", + "version": "v0", + "datasource": { + "name": "prometheus-uid" + }, + "spec": { + "expr": "secondary_metric" + } + }, + "refId": "B", + "hidden": false + } + } + ], + "transformations": [], + "queryOptions": {} + } + }, + "vizConfig": { + "kind": "VizConfig", + "group": "table", + "version": "", + "spec": { + "options": {}, + "fieldConfig": { + "defaults": { + "mappings": [ + { + "type": "value", + "options": { + "failure": { + "text": "Failure", + "color": "red", + "index": 1 + }, + "success": { + "text": "Success", + "color": "green", + "index": 0 + } + } + }, + { + "type": "range", + "options": { + "from": 0, + "to": 100, + "result": { + "text": "In Range", + "color": "blue", + "index": 2 + } + } + }, + { + "type": "regex", + "options": { + "pattern": "/^[A-Z]{3}-\\d+$/", + "result": { + "text": "ID Format", + "color": "purple", + "index": 3 + } + } + }, + { + "type": "special", + "options": { + "match": "null", + "result": { + "text": "Missing", + "color": "gray", + "index": 4 + } + } + } + ] + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "status" + }, + "properties": [ + { + "id": "custom.width", + "value": 120 + }, + { + "id": "custom.cellOptions", + "value": { + "type": "color-background" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^value_/" + }, + "properties": [ + { + "id": "unit", + "value": "short" + }, + { + "id": "min", + "value": 0 + }, + { + "id": "max", + "value": 100 + } + ] + }, + { + "matcher": { + "id": "byType", + "options": "number" + }, + "properties": [ + { + "id": "decimals", + "value": 2 + }, + { + "id": "thresholds", + "value": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 50 + }, + { + "color": "red", + "value": 80 + } + ] + } + } + ] + }, + { + "matcher": { + "id": "byFrameRefID", + "options": "B" + }, + "properties": [ + { + "id": "displayName", + "value": "Secondary Query" + } + ] + }, + { + "matcher": { + "id": "byValue", + "options": { + "op": "gte", + "reducer": "allIsNull", + "value": 0 + } + }, + "properties": [ + { + "id": "custom.hidden", + "value": true + } + ] + } + ] + } + } + } + } + } + }, + "layout": { + "kind": "GridLayout", + "spec": { + "items": [ + { + "kind": "GridLayoutItem", + "spec": { + "x": 0, + "y": 0, + "width": 12, + "height": 8, + "element": { + "kind": "ElementReference", + "name": "panel-1" + } + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "x": 12, + "y": 0, + "width": 12, + "height": 8, + "element": { + "kind": "ElementReference", + "name": "panel-2" + } + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "x": 0, + "y": 8, + "width": 12, + "height": 8, + "element": { + "kind": "ElementReference", + "name": "panel-3" + } + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "x": 12, + "y": 8, + "width": 12, + "height": 8, + "element": { + "kind": "ElementReference", + "name": "panel-4" + } + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "x": 0, + "y": 16, + "width": 24, + "height": 8, + "element": { + "kind": "ElementReference", + "name": "panel-5" + } + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "x": 0, + "y": 24, + "width": 12, + "height": 8, + "element": { + "kind": "ElementReference", + "name": "panel-6" + } + } + } + ] + } + }, + "links": [], + "liveNow": false, + "preload": false, + "tags": [ + "value-mapping", + "overrides", + "test" + ], + "timeSettings": { + "timezone": "browser", + "from": "now-6h", + "to": "now", + "autoRefresh": "", + "autoRefreshIntervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "hideTimepicker": false, + "fiscalYearStartMonth": 0 + }, + "title": "Value Mapping and Overrides Test", + "variables": [] + }, + "status": { + "conversion": { + "failed": false, + "storedVersion": "v1beta1" + } + } + } \ No newline at end of file diff --git a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v10.table_thresholds.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v10.table_thresholds.v42.v2alpha1.json index 5fdde6e46be..669e2e742a6 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v10.table_thresholds.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v10.table_thresholds.v42.v2alpha1.json @@ -66,7 +66,29 @@ "kind": "table", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "styles": [ + { + "align": "auto", + "thresholds": [ + "20", + "30" + ] + }, + { + "align": "auto", + "thresholds": [ + "200", + "300" + ] + } + ] + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -110,7 +132,22 @@ "kind": "table", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "styles": [ + { + "align": "auto", + "thresholds": [ + "50", + "75" + ] + } + ] + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -154,7 +191,22 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "styles": [ + { + "thresholds": [ + "5", + "10", + "15" + ] + } + ] + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v10.table_thresholds.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v10.table_thresholds.v42.v2beta1.json index b2eb0336cf2..22a36b375a0 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v10.table_thresholds.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v10.table_thresholds.v42.v2beta1.json @@ -69,7 +69,29 @@ "group": "table", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "styles": [ + { + "align": "auto", + "thresholds": [ + "20", + "30" + ] + }, + { + "align": "auto", + "thresholds": [ + "200", + "300" + ] + } + ] + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -115,7 +137,22 @@ "group": "table", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "styles": [ + { + "align": "auto", + "thresholds": [ + "50", + "75" + ] + } + ] + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -161,7 +198,22 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "styles": [ + { + "thresholds": [ + "5", + "10", + "15" + ] + } + ] + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v11.no-op-migration.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v11.no-op-migration.v42.v2alpha1.json index 7185cc96f69..b9007aeab43 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v11.no-op-migration.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v11.no-op-migration.v42.v2alpha1.json @@ -66,7 +66,18 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "yAxes": [ + { + "show": true + } + ] + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -110,7 +121,20 @@ "kind": "stat", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "singlestat", + "originalOptions": { + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ] + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v11.no-op-migration.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v11.no-op-migration.v42.v2beta1.json index 2a0200eb4cb..75255794c5c 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v11.no-op-migration.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v11.no-op-migration.v42.v2beta1.json @@ -69,7 +69,18 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "yAxes": [ + { + "show": true + } + ] + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -115,7 +126,20 @@ "group": "stat", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "singlestat", + "originalOptions": { + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ] + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v13.graph_thresholds.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v13.graph_thresholds.v42.v2alpha1.json index 2d55803abbe..091b4103636 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v13.graph_thresholds.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v13.graph_thresholds.v42.v2alpha1.json @@ -66,7 +66,20 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "grid": { + "threshold1": 200, + "threshold1Color": "yellow", + "threshold2": 400, + "threshold2Color": "red", + "thresholdLine": true + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -110,7 +123,20 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "grid": { + "threshold1": 100, + "threshold1Color": "green", + "threshold2": 300, + "threshold2Color": "blue", + "thresholdLine": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -154,7 +180,18 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "grid": { + "threshold1": 150, + "threshold1Color": "orange", + "thresholdLine": true + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -198,7 +235,25 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "grid": { + "threshold1": 200, + "threshold1Color": "yellow", + "thresholdLine": false + }, + "thresholds": [ + { + "color": "purple", + "colorMode": "custom", + "value": 50 + } + ] + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -242,7 +297,12 @@ "kind": "stat", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "singlestat", + "originalOptions": {} + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v13.graph_thresholds.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v13.graph_thresholds.v42.v2beta1.json index 97fc1bfca44..0fdbbd1990b 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v13.graph_thresholds.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v13.graph_thresholds.v42.v2beta1.json @@ -69,7 +69,20 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "grid": { + "threshold1": 200, + "threshold1Color": "yellow", + "threshold2": 400, + "threshold2Color": "red", + "thresholdLine": true + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -115,7 +128,20 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "grid": { + "threshold1": 100, + "threshold1Color": "green", + "threshold2": 300, + "threshold2Color": "blue", + "thresholdLine": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -161,7 +187,18 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "grid": { + "threshold1": 150, + "threshold1Color": "orange", + "thresholdLine": true + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -207,7 +244,25 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "grid": { + "threshold1": 200, + "threshold1Color": "yellow", + "thresholdLine": false + }, + "thresholds": [ + { + "color": "purple", + "colorMode": "custom", + "value": 50 + } + ] + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -253,7 +308,12 @@ "group": "stat", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "singlestat", + "originalOptions": {} + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v13.minimal_graph_config.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v13.minimal_graph_config.v42.v2alpha1.json index 818011bba5b..b2673944cb7 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v13.minimal_graph_config.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v13.minimal_graph_config.v42.v2alpha1.json @@ -72,7 +72,12 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": {} + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v13.minimal_graph_config.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v13.minimal_graph_config.v42.v2beta1.json index 3c12cff0619..1b8e98bafc0 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v13.minimal_graph_config.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v13.minimal_graph_config.v42.v2beta1.json @@ -75,7 +75,12 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": {} + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v14.shared_crosshair_to_graph_tooltip.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v14.shared_crosshair_to_graph_tooltip.v42.v2alpha1.json index 4c9617a521e..5a00a12baa3 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v14.shared_crosshair_to_graph_tooltip.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v14.shared_crosshair_to_graph_tooltip.v42.v2alpha1.json @@ -68,7 +68,18 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "yAxes": [ + { + "show": true + } + ] + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -114,7 +125,20 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "yAxes": [ + { + "max": 100, + "min": 0, + "show": true + } + ] + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v14.shared_crosshair_to_graph_tooltip.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v14.shared_crosshair_to_graph_tooltip.v42.v2beta1.json index bf07de3de24..9251f743242 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v14.shared_crosshair_to_graph_tooltip.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v14.shared_crosshair_to_graph_tooltip.v42.v2beta1.json @@ -71,7 +71,18 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "yAxes": [ + { + "show": true + } + ] + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -119,7 +130,20 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "yAxes": [ + { + "max": 100, + "min": 0, + "show": true + } + ] + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v15.mimir_rollout_debugging.v42.v0alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v15.mimir_rollout_debugging.v42.v0alpha1.json index 6c259253e55..35cc948844c 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v15.mimir_rollout_debugging.v42.v0alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v15.mimir_rollout_debugging.v42.v0alpha1.json @@ -743,7 +743,9 @@ "text": "prod", "value": "prod" }, - "datasource": "$datasource", + "datasource": { + "uid": "$datasource" + }, "hide": 0, "includeAll": true, "label": "cluster", @@ -764,7 +766,9 @@ "text": "prod", "value": "prod" }, - "datasource": "$datasource", + "datasource": { + "uid": "$datasource" + }, "hide": 0, "includeAll": false, "label": "namespace", diff --git a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v15.mimir_rollout_debugging.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v15.mimir_rollout_debugging.v42.v2alpha1.json index 8d340c0f65e..26945033c4c 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v15.mimir_rollout_debugging.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v15.mimir_rollout_debugging.v42.v2alpha1.json @@ -961,8 +961,12 @@ "hide": "dontHide", "refresh": "onDashboardLoad", "skipUrlSync": false, + "datasource": { + "type": "", + "uid": "$datasource" + }, "query": { - "kind": "prometheus", + "kind": "", "spec": { "__legacyStringValue": "label_values(up, job)" } @@ -988,8 +992,12 @@ "hide": "dontHide", "refresh": "onDashboardLoad", "skipUrlSync": false, + "datasource": { + "type": "", + "uid": "$datasource" + }, "query": { - "kind": "prometheus", + "kind": "", "spec": { "__legacyStringValue": "label_values(up{job=~\"$cluster\"}, instance)" } diff --git a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v15.mimir_rollout_debugging.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v15.mimir_rollout_debugging.v42.v2beta1.json index 8070895766a..344b0ef564a 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v15.mimir_rollout_debugging.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v15.mimir_rollout_debugging.v42.v2beta1.json @@ -978,8 +978,11 @@ "skipUrlSync": false, "query": { "kind": "DataQuery", - "group": "prometheus", + "group": "", "version": "v0", + "datasource": { + "name": "$datasource" + }, "spec": { "__legacyStringValue": "label_values(up, job)" } @@ -1007,8 +1010,11 @@ "skipUrlSync": false, "query": { "kind": "DataQuery", - "group": "prometheus", + "group": "", "version": "v0", + "datasource": { + "name": "$datasource" + }, "spec": { "__legacyStringValue": "label_values(up{job=~\"$cluster\"}, instance)" } diff --git a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v15.no-op-migration.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v15.no-op-migration.v42.v2alpha1.json index cd1daaf4806..551348d7852 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v15.no-op-migration.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v15.no-op-migration.v42.v2alpha1.json @@ -83,7 +83,18 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "yAxes": [ + { + "show": true + } + ] + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -127,7 +138,20 @@ "kind": "stat", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "singlestat", + "originalOptions": { + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ] + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v15.no-op-migration.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v15.no-op-migration.v42.v2beta1.json index 63a51a69c96..c6ab962de2f 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v15.no-op-migration.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v15.no-op-migration.v42.v2beta1.json @@ -87,7 +87,18 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "yAxes": [ + { + "show": true + } + ] + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -133,7 +144,20 @@ "group": "stat", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "singlestat", + "originalOptions": { + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ] + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v16.grid_layout_upgrade.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v16.grid_layout_upgrade.v42.v2alpha1.json index 13e2bd96197..c4198fa24b9 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v16.grid_layout_upgrade.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v16.grid_layout_upgrade.v42.v2alpha1.json @@ -66,7 +66,12 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": {} + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -110,7 +115,14 @@ "kind": "logs", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "logs", + "originalOptions": { + "height": 100 + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -154,7 +166,12 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": {} + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -198,7 +215,12 @@ "kind": "stat", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "singlestat", + "originalOptions": {} + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -254,7 +276,14 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "height": 200 + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -282,7 +311,14 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "height": 200 + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v16.grid_layout_upgrade.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v16.grid_layout_upgrade.v42.v2beta1.json index bbd59bf1a07..578e9d707ad 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v16.grid_layout_upgrade.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v16.grid_layout_upgrade.v42.v2beta1.json @@ -69,7 +69,12 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": {} + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -115,7 +120,14 @@ "group": "logs", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "logs", + "originalOptions": { + "height": 100 + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -161,7 +173,12 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": {} + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -207,7 +224,12 @@ "group": "stat", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "singlestat", + "originalOptions": {} + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -265,7 +287,14 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "height": 200 + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -294,7 +323,14 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "height": 200 + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v17.minspan_to_maxperrow.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v17.minspan_to_maxperrow.v42.v2alpha1.json index 05de2de2aa4..ecc7830b8fa 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v17.minspan_to_maxperrow.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v17.minspan_to_maxperrow.v42.v2alpha1.json @@ -66,7 +66,12 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": {} + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -110,7 +115,12 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": {} + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -154,7 +164,12 @@ "kind": "stat", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "singlestat", + "originalOptions": {} + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -242,7 +257,12 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": {} + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -374,7 +394,12 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": {} + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -462,7 +487,12 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": {} + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v17.minspan_to_maxperrow.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v17.minspan_to_maxperrow.v42.v2beta1.json index 778a653435a..ce68572f0d2 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v17.minspan_to_maxperrow.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v17.minspan_to_maxperrow.v42.v2beta1.json @@ -69,7 +69,12 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": {} + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -115,7 +120,12 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": {} + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -161,7 +171,12 @@ "group": "stat", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "singlestat", + "originalOptions": {} + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -253,7 +268,12 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": {} + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -391,7 +411,12 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": {} + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -483,7 +508,12 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": {} + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v18.gauge_options.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v18.gauge_options.v42.v2alpha1.json index d524005a101..55f7729fc1a 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v18.gauge_options.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v18.gauge_options.v42.v2alpha1.json @@ -288,6 +288,10 @@ "spec": { "pluginVersion": "", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": {} + }, "legend": { "show": true, "showLegend": true diff --git a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v18.gauge_options.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v18.gauge_options.v42.v2beta1.json index b80c575053c..758bdfad09e 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v18.gauge_options.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v18.gauge_options.v42.v2beta1.json @@ -299,6 +299,10 @@ "version": "", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": {} + }, "legend": { "show": true, "showLegend": true diff --git a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v19.panel_links.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v19.panel_links.v42.v2alpha1.json index 3d78d0167b3..596bd229b79 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v19.panel_links.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v19.panel_links.v42.v2alpha1.json @@ -71,7 +71,12 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": {} + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -312,7 +317,12 @@ "kind": "stat", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "singlestat", + "originalOptions": {} + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v19.panel_links.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v19.panel_links.v42.v2beta1.json index 2842123f75e..1302e17c7f3 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v19.panel_links.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v19.panel_links.v42.v2beta1.json @@ -74,7 +74,12 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": {} + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -325,7 +330,12 @@ "group": "stat", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "singlestat", + "originalOptions": {} + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v2.panels-and-services.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v2.panels-and-services.v42.v2alpha1.json index b6b4f83cdf7..d30c3ce7923 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v2.panels-and-services.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v2.panels-and-services.v42.v2alpha1.json @@ -68,7 +68,20 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graphite", + "originalOptions": { + "grid": { + "max": 100, + "min": 0 + }, + "legend": true, + "y2_format": "short", + "y_format": "percent" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -114,7 +127,18 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "grid": { + "min": 0 + }, + "legend": false, + "y_format": "bytes" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -158,7 +182,20 @@ "kind": "table", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table", + "originalOptions": { + "grid": { + "max": 100, + "min": 0 + }, + "legend": true, + "y2_format": "bytes", + "y_format": "short" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -204,7 +241,15 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graphite", + "originalOptions": { + "legend": true, + "y2_format": "Bps" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v2.panels-and-services.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v2.panels-and-services.v42.v2beta1.json index 0b9d3bacd35..6a02d64f5b2 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v2.panels-and-services.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v2.panels-and-services.v42.v2beta1.json @@ -71,7 +71,20 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graphite", + "originalOptions": { + "grid": { + "max": 100, + "min": 0 + }, + "legend": true, + "y2_format": "short", + "y_format": "percent" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -119,7 +132,18 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "grid": { + "min": 0 + }, + "legend": false, + "y_format": "bytes" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -165,7 +189,20 @@ "group": "table", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table", + "originalOptions": { + "grid": { + "max": 100, + "min": 0 + }, + "legend": true, + "y2_format": "bytes", + "y_format": "short" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -213,7 +250,15 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graphite", + "originalOptions": { + "legend": true, + "y2_format": "Bps" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v21.data_links_series_to_field.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v21.data_links_series_to_field.v42.v2alpha1.json index 170e3c6ccad..a93d077fef3 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v21.data_links_series_to_field.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v21.data_links_series_to_field.v42.v2alpha1.json @@ -181,6 +181,10 @@ "spec": { "pluginVersion": "", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": {} + }, "dataLinks": [ { "title": "Graph Data Link", diff --git a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v21.data_links_series_to_field.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v21.data_links_series_to_field.v42.v2beta1.json index b87e2c2fb9e..6244177502b 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v21.data_links_series_to_field.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v21.data_links_series_to_field.v42.v2beta1.json @@ -188,6 +188,10 @@ "version": "", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": {} + }, "dataLinks": [ { "title": "Graph Data Link", diff --git a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v22.table_panel_align.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v22.table_panel_align.v42.v2alpha1.json index 28eefba141b..10c570651e5 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v22.table_panel_align.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v22.table_panel_align.v42.v2alpha1.json @@ -66,7 +66,25 @@ "kind": "table", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "styles": [ + { + "align": "auto", + "pattern": "Time", + "type": "number" + }, + { + "align": "auto", + "pattern": "Value", + "type": "string" + } + ] + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v22.table_panel_align.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v22.table_panel_align.v42.v2beta1.json index d9de4392f97..8c7d86f1d86 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v22.table_panel_align.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v22.table_panel_align.v42.v2beta1.json @@ -69,7 +69,25 @@ "group": "table", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "styles": [ + { + "align": "auto", + "pattern": "Time", + "type": "number" + }, + { + "align": "auto", + "pattern": "Value", + "type": "string" + } + ] + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v24.table-angular.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v24.table-angular.v42.v2alpha1.json index 206e53baee2..6fa76798215 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v24.table-angular.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v24.table-angular.v42.v2alpha1.json @@ -81,7 +81,29 @@ "kind": "table", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "legend": true, + "styles": [ + { + "colors": [ + "red", + "yellow", + "green" + ], + "pattern": "/.*/", + "thresholds": [ + "10", + "20", + "30" + ] + } + ] + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -125,7 +147,31 @@ "kind": "table", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "styles": [ + { + "align": "center", + "pattern": "/.*/" + }, + { + "align": "left", + "pattern": "LeftColumn" + }, + { + "align": "right", + "pattern": "RightColumn" + }, + { + "align": "auto", + "pattern": "AutoColumn" + } + ] + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -169,7 +215,35 @@ "kind": "table", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "styles": [ + { + "pattern": "/.*/", + "unit": "short" + }, + { + "alias": "Exact Match", + "pattern": "ExactColumnName" + }, + { + "alias": "Regex Match", + "pattern": "/Regex.*Pattern/" + }, + { + "alias": "Start Pattern", + "pattern": "/^Start/" + }, + { + "alias": "End Pattern", + "pattern": "/End$/" + } + ] + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -213,7 +287,37 @@ "kind": "table", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "styles": [ + { + "pattern": "/.*/", + "unit": "short" + }, + { + "link": true, + "linkTargetBlank": true, + "linkTooltip": "Click to view details", + "linkUrl": "http://example.com/with-tooltip", + "pattern": "LinkWithTooltip" + }, + { + "link": true, + "linkTargetBlank": false, + "linkUrl": "http://example.com/no-tooltip", + "pattern": "LinkWithoutTooltip" + }, + { + "link": true, + "linkUrl": "http://example.com/minimal", + "pattern": "LinkMinimal" + } + ] + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -257,7 +361,37 @@ "kind": "table", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "styles": [ + { + "pattern": "/.*/", + "unit": "short" + }, + { + "alias": "ISO Date", + "dateFormat": "YYYY-MM-DD", + "pattern": "DateISO", + "type": "date" + }, + { + "alias": "Full DateTime", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "DateTime", + "type": "date" + }, + { + "alias": "Time Only", + "dateFormat": "HH:mm:ss", + "pattern": "TimeOnly", + "type": "date" + } + ] + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -301,7 +435,29 @@ "kind": "table", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table", + "originalOptions": { + "styles": [ + { + "colors": [ + "red", + "yellow", + "green" + ], + "pattern": "/.*/", + "thresholds": [ + "10", + "20" + ], + "unit": "short" + } + ], + "table": "table2" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -389,7 +545,12 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": {} + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -433,7 +594,12 @@ "kind": "stat", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "singlestat", + "originalOptions": {} + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -477,7 +643,57 @@ "kind": "table", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "styles": [ + { + "align": "center", + "colorMode": "cell", + "colors": [ + "green", + "yellow", + "red" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [ + "100", + "500" + ], + "unit": "bytes" + }, + { + "alias": "Current Status", + "align": "left", + "colorMode": "value", + "decimals": 0, + "pattern": "Status", + "unit": "short" + }, + { + "colorMode": "row", + "link": true, + "linkTargetBlank": true, + "linkTooltip": "View error details", + "linkUrl": "http://example.com/errors", + "pattern": "/Error.*/" + }, + { + "alias": "Timestamp", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "date" + }, + { + "pattern": "Hidden", + "type": "hidden" + } + ] + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -521,7 +737,47 @@ "kind": "table", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "columns": [ + { + "text": "Average", + "value": "avg" + }, + { + "text": "Maximum", + "value": "max" + }, + { + "text": "Minimum", + "value": "min" + }, + { + "text": "Total", + "value": "total" + }, + { + "text": "Current", + "value": "current" + }, + { + "text": "Count", + "value": "count" + } + ], + "styles": [ + { + "decimals": 1, + "pattern": "/.*/", + "unit": "percent" + } + ], + "transform": "timeseries_aggregations" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -565,7 +821,20 @@ "kind": "table", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "styles": [ + { + "pattern": "/.*/", + "unit": "short" + } + ], + "transform": "timeseries_to_rows" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -609,7 +878,20 @@ "kind": "table", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "styles": [ + { + "pattern": "/.*/", + "unit": "bytes" + } + ], + "transform": "timeseries_to_columns" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -653,7 +935,20 @@ "kind": "table", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "styles": [ + { + "align": "auto", + "pattern": "/.*/" + } + ], + "transform": "table" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -712,7 +1007,20 @@ "kind": "table", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "styles": [ + { + "pattern": "/.*/", + "unit": "short" + } + ], + "transform": "timeseries_to_rows" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -756,7 +1064,29 @@ "kind": "table", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "styles": [ + { + "colors": [ + "green", + "yellow", + "orange", + "red" + ], + "pattern": "/.*/", + "thresholds": [ + 10, + "20", + 30.5 + ] + } + ] + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -800,7 +1130,31 @@ "kind": "table", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "styles": [ + { + "colorMode": "cell", + "pattern": "/.*/" + }, + { + "colorMode": "cell", + "pattern": "CellColumn" + }, + { + "colorMode": "row", + "pattern": "RowColumn" + }, + { + "colorMode": "value", + "pattern": "ValueColumn" + } + ] + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v24.table-angular.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v24.table-angular.v42.v2beta1.json index 9eeeb11b247..9ae87fe0f32 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v24.table-angular.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v24.table-angular.v42.v2beta1.json @@ -85,7 +85,29 @@ "group": "table", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "legend": true, + "styles": [ + { + "colors": [ + "red", + "yellow", + "green" + ], + "pattern": "/.*/", + "thresholds": [ + "10", + "20", + "30" + ] + } + ] + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -131,7 +153,31 @@ "group": "table", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "styles": [ + { + "align": "center", + "pattern": "/.*/" + }, + { + "align": "left", + "pattern": "LeftColumn" + }, + { + "align": "right", + "pattern": "RightColumn" + }, + { + "align": "auto", + "pattern": "AutoColumn" + } + ] + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -177,7 +223,35 @@ "group": "table", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "styles": [ + { + "pattern": "/.*/", + "unit": "short" + }, + { + "alias": "Exact Match", + "pattern": "ExactColumnName" + }, + { + "alias": "Regex Match", + "pattern": "/Regex.*Pattern/" + }, + { + "alias": "Start Pattern", + "pattern": "/^Start/" + }, + { + "alias": "End Pattern", + "pattern": "/End$/" + } + ] + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -223,7 +297,37 @@ "group": "table", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "styles": [ + { + "pattern": "/.*/", + "unit": "short" + }, + { + "link": true, + "linkTargetBlank": true, + "linkTooltip": "Click to view details", + "linkUrl": "http://example.com/with-tooltip", + "pattern": "LinkWithTooltip" + }, + { + "link": true, + "linkTargetBlank": false, + "linkUrl": "http://example.com/no-tooltip", + "pattern": "LinkWithoutTooltip" + }, + { + "link": true, + "linkUrl": "http://example.com/minimal", + "pattern": "LinkMinimal" + } + ] + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -269,7 +373,37 @@ "group": "table", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "styles": [ + { + "pattern": "/.*/", + "unit": "short" + }, + { + "alias": "ISO Date", + "dateFormat": "YYYY-MM-DD", + "pattern": "DateISO", + "type": "date" + }, + { + "alias": "Full DateTime", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "DateTime", + "type": "date" + }, + { + "alias": "Time Only", + "dateFormat": "HH:mm:ss", + "pattern": "TimeOnly", + "type": "date" + } + ] + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -315,7 +449,29 @@ "group": "table", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table", + "originalOptions": { + "styles": [ + { + "colors": [ + "red", + "yellow", + "green" + ], + "pattern": "/.*/", + "thresholds": [ + "10", + "20" + ], + "unit": "short" + } + ], + "table": "table2" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -407,7 +563,12 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": {} + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -453,7 +614,12 @@ "group": "stat", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "singlestat", + "originalOptions": {} + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -499,7 +665,57 @@ "group": "table", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "styles": [ + { + "align": "center", + "colorMode": "cell", + "colors": [ + "green", + "yellow", + "red" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [ + "100", + "500" + ], + "unit": "bytes" + }, + { + "alias": "Current Status", + "align": "left", + "colorMode": "value", + "decimals": 0, + "pattern": "Status", + "unit": "short" + }, + { + "colorMode": "row", + "link": true, + "linkTargetBlank": true, + "linkTooltip": "View error details", + "linkUrl": "http://example.com/errors", + "pattern": "/Error.*/" + }, + { + "alias": "Timestamp", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "date" + }, + { + "pattern": "Hidden", + "type": "hidden" + } + ] + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -545,7 +761,47 @@ "group": "table", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "columns": [ + { + "text": "Average", + "value": "avg" + }, + { + "text": "Maximum", + "value": "max" + }, + { + "text": "Minimum", + "value": "min" + }, + { + "text": "Total", + "value": "total" + }, + { + "text": "Current", + "value": "current" + }, + { + "text": "Count", + "value": "count" + } + ], + "styles": [ + { + "decimals": 1, + "pattern": "/.*/", + "unit": "percent" + } + ], + "transform": "timeseries_aggregations" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -591,7 +847,20 @@ "group": "table", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "styles": [ + { + "pattern": "/.*/", + "unit": "short" + } + ], + "transform": "timeseries_to_rows" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -637,7 +906,20 @@ "group": "table", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "styles": [ + { + "pattern": "/.*/", + "unit": "bytes" + } + ], + "transform": "timeseries_to_columns" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -683,7 +965,20 @@ "group": "table", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "styles": [ + { + "align": "auto", + "pattern": "/.*/" + } + ], + "transform": "table" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -744,7 +1039,20 @@ "group": "table", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "styles": [ + { + "pattern": "/.*/", + "unit": "short" + } + ], + "transform": "timeseries_to_rows" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -790,7 +1098,29 @@ "group": "table", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "styles": [ + { + "colors": [ + "green", + "yellow", + "orange", + "red" + ], + "pattern": "/.*/", + "thresholds": [ + 10, + "20", + 30.5 + ] + } + ] + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -836,7 +1166,31 @@ "group": "table", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "styles": [ + { + "colorMode": "cell", + "pattern": "/.*/" + }, + { + "colorMode": "cell", + "pattern": "CellColumn" + }, + { + "colorMode": "row", + "pattern": "RowColumn" + }, + { + "colorMode": "value", + "pattern": "ValueColumn" + } + ] + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v25.no-op-migration.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v25.no-op-migration.v42.v2alpha1.json index 35c94ad87bc..618d1193a1c 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v25.no-op-migration.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v25.no-op-migration.v42.v2alpha1.json @@ -123,7 +123,18 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "yAxes": [ + { + "show": true + } + ] + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v25.no-op-migration.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v25.no-op-migration.v42.v2beta1.json index 1cdd7407a2d..7fd6cdec538 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v25.no-op-migration.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v25.no-op-migration.v42.v2beta1.json @@ -130,7 +130,18 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "yAxes": [ + { + "show": true + } + ] + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v26.text2_to_text.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v26.text2_to_text.v42.v2alpha1.json index d15f179ac31..c7298296064 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v26.text2_to_text.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v26.text2_to_text.v42.v2alpha1.json @@ -110,7 +110,15 @@ "kind": "text", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "text", + "originalOptions": { + "content": "# Angular Text Panel\n# $constant\n\nFor markdown syntax help: [commonmark.org/help](https://commonmark.org/help/)\n\n## $text\n\n", + "mode": "markdown" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v26.text2_to_text.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v26.text2_to_text.v42.v2beta1.json index 59aad2fdb0b..db2cfcb916e 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v26.text2_to_text.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v26.text2_to_text.v42.v2beta1.json @@ -115,7 +115,15 @@ "group": "text", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "text", + "originalOptions": { + "content": "# Angular Text Panel\n# $constant\n\nFor markdown syntax help: [commonmark.org/help](https://commonmark.org/help/)\n\n## $text\n\n", + "mode": "markdown" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v27.repeated_panels_and_constant_variable.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v27.repeated_panels_and_constant_variable.v42.v2alpha1.json index 1c1b3d0d39b..bab8c53ac6a 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v27.repeated_panels_and_constant_variable.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v27.repeated_panels_and_constant_variable.v42.v2alpha1.json @@ -66,7 +66,12 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": {} + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -94,7 +99,12 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": {} + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v27.repeated_panels_and_constant_variable.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v27.repeated_panels_and_constant_variable.v42.v2beta1.json index b8596415db8..79dab4989d1 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v27.repeated_panels_and_constant_variable.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v27.repeated_panels_and_constant_variable.v42.v2beta1.json @@ -69,7 +69,12 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": {} + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -98,7 +103,12 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": {} + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v28.singlestat_and_variable_properties.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v28.singlestat_and_variable_properties.v42.v2alpha1.json index 78df8e5bf3a..14e59bfc9bc 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v28.singlestat_and_variable_properties.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v28.singlestat_and_variable_properties.v42.v2alpha1.json @@ -81,7 +81,24 @@ "kind": "stat", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "singlestat", + "originalOptions": { + "colors": [ + "#FF0000", + "green", + "orange" + ], + "grid": { + "max": 10, + "min": 1 + }, + "legend": true, + "thresholds": "10,20,30" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -125,7 +142,28 @@ "kind": "stat", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "singlestat", + "originalOptions": { + "colors": [ + "#FF0000", + "green", + "orange" + ], + "gauge": { + "show": true, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "grid": { + "max": 10, + "min": 1 + }, + "thresholds": "10,20,30" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -184,7 +222,47 @@ "kind": "stat", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "singlestat", + "originalOptions": { + "colors": [ + "#FF0000", + "green", + "orange" + ], + "grid": { + "max": 10, + "min": 1 + }, + "legend": true, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + } + ], + "thresholds": "10,20,30", + "valueMaps": [ + { + "op": "=", + "text": "test", + "value": "20" + }, + { + "op": "=", + "text": "test1", + "value": "30" + }, + { + "op": "=", + "text": "50", + "value": "40" + } + ] + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v28.singlestat_and_variable_properties.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v28.singlestat_and_variable_properties.v42.v2beta1.json index f9b06083b63..4f376187bba 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v28.singlestat_and_variable_properties.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v28.singlestat_and_variable_properties.v42.v2beta1.json @@ -85,7 +85,24 @@ "group": "stat", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "singlestat", + "originalOptions": { + "colors": [ + "#FF0000", + "green", + "orange" + ], + "grid": { + "max": 10, + "min": 1 + }, + "legend": true, + "thresholds": "10,20,30" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -131,7 +148,28 @@ "group": "stat", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "singlestat", + "originalOptions": { + "colors": [ + "#FF0000", + "green", + "orange" + ], + "gauge": { + "show": true, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "grid": { + "max": 10, + "min": 1 + }, + "thresholds": "10,20,30" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -193,7 +231,47 @@ "group": "stat", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "singlestat", + "originalOptions": { + "colors": [ + "#FF0000", + "green", + "orange" + ], + "grid": { + "max": 10, + "min": 1 + }, + "legend": true, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + } + ], + "thresholds": "10,20,30", + "valueMaps": [ + { + "op": "=", + "text": "test", + "value": "20" + }, + { + "op": "=", + "text": "test1", + "value": "30" + }, + { + "op": "=", + "text": "50", + "value": "40" + } + ] + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v28.singlestat_migration.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v28.singlestat_migration.v42.v2alpha1.json index 7fa4e5ae944..195ceebb6cc 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v28.singlestat_migration.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v28.singlestat_migration.v42.v2alpha1.json @@ -81,7 +81,24 @@ "kind": "stat", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "singlestat", + "originalOptions": { + "colors": [ + "#FF0000", + "green", + "orange" + ], + "grid": { + "max": 10, + "min": 1 + }, + "legend": true, + "thresholds": "10,20,30" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -140,7 +157,24 @@ "kind": "stat", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "singlestat", + "originalOptions": { + "colors": [ + "#FF0000", + "green", + "orange" + ], + "grid": { + "max": 10, + "min": 1 + }, + "legend": true, + "thresholds": "" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -184,7 +218,28 @@ "kind": "stat", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "singlestat", + "originalOptions": { + "colors": [ + "#FF0000", + "green", + "orange" + ], + "gauge": { + "show": true, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "grid": { + "max": 10, + "min": 1 + }, + "thresholds": "10,20,30" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -243,7 +298,47 @@ "kind": "stat", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "singlestat", + "originalOptions": { + "colors": [ + "#FF0000", + "green", + "orange" + ], + "grid": { + "max": 10, + "min": 1 + }, + "legend": true, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + } + ], + "thresholds": "10,20,30", + "valueMaps": [ + { + "op": "=", + "text": "test", + "value": "20" + }, + { + "op": "=", + "text": "test1", + "value": "30" + }, + { + "op": "=", + "text": "50", + "value": "40" + } + ] + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -289,7 +384,68 @@ "kind": "stat", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "grafana-singlestat-panel", + "originalOptions": { + "colorBackground": false, + "colorValue": true, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "format": "areaF2", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "nullPointMode": "connected", + "postfix": "b", + "postfixFontSize": "50%", + "prefix": "a", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "thresholds": "", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v28.singlestat_migration.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v28.singlestat_migration.v42.v2beta1.json index 5aaff274c67..fb221254e90 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v28.singlestat_migration.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v28.singlestat_migration.v42.v2beta1.json @@ -85,7 +85,24 @@ "group": "stat", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "singlestat", + "originalOptions": { + "colors": [ + "#FF0000", + "green", + "orange" + ], + "grid": { + "max": 10, + "min": 1 + }, + "legend": true, + "thresholds": "10,20,30" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -147,7 +164,24 @@ "group": "stat", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "singlestat", + "originalOptions": { + "colors": [ + "#FF0000", + "green", + "orange" + ], + "grid": { + "max": 10, + "min": 1 + }, + "legend": true, + "thresholds": "" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -193,7 +227,28 @@ "group": "stat", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "singlestat", + "originalOptions": { + "colors": [ + "#FF0000", + "green", + "orange" + ], + "gauge": { + "show": true, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "grid": { + "max": 10, + "min": 1 + }, + "thresholds": "10,20,30" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -255,7 +310,47 @@ "group": "stat", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "singlestat", + "originalOptions": { + "colors": [ + "#FF0000", + "green", + "orange" + ], + "grid": { + "max": 10, + "min": 1 + }, + "legend": true, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + } + ], + "thresholds": "10,20,30", + "valueMaps": [ + { + "op": "=", + "text": "test", + "value": "20" + }, + { + "op": "=", + "text": "test1", + "value": "30" + }, + { + "op": "=", + "text": "50", + "value": "40" + } + ] + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -303,7 +398,68 @@ "group": "stat", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "grafana-singlestat-panel", + "originalOptions": { + "colorBackground": false, + "colorValue": true, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "format": "areaF2", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "nullPointMode": "connected", + "postfix": "b", + "postfixFontSize": "50%", + "prefix": "a", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "thresholds": "", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v30.value_mappings_and_tooltip_options.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v30.value_mappings_and_tooltip_options.v42.v2alpha1.json index c657d8796c3..40e4072138c 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v30.value_mappings_and_tooltip_options.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v30.value_mappings_and_tooltip_options.v42.v2alpha1.json @@ -280,6 +280,10 @@ "spec": { "pluginVersion": "", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": {} + }, "tooltip": { "mode": "single" } diff --git a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v30.value_mappings_and_tooltip_options.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v30.value_mappings_and_tooltip_options.v42.v2beta1.json index be92e718d44..9f5630252bf 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v30.value_mappings_and_tooltip_options.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v30.value_mappings_and_tooltip_options.v42.v2beta1.json @@ -289,6 +289,10 @@ "version": "", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": {} + }, "tooltip": { "mode": "single" } diff --git a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v32.no_op_migration.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v32.no_op_migration.v42.v2alpha1.json index 2042cc9aa49..369db4327b7 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v32.no_op_migration.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v32.no_op_migration.v42.v2alpha1.json @@ -144,7 +144,18 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "yAxes": [ + { + "show": true + } + ] + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v32.no_op_migration.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v32.no_op_migration.v42.v2beta1.json index 7a90cf0c2ac..1fd5d1638ec 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v32.no_op_migration.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v32.no_op_migration.v42.v2beta1.json @@ -151,7 +151,18 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "yAxes": [ + { + "show": true + } + ] + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v33.panel_ds_name_to_ref.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v33.panel_ds_name_to_ref.v42.v2alpha1.json index 6043004b0eb..b21c071f750 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v33.panel_ds_name_to_ref.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v33.panel_ds_name_to_ref.v42.v2alpha1.json @@ -345,7 +345,12 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": {} + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v33.panel_ds_name_to_ref.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v33.panel_ds_name_to_ref.v42.v2beta1.json index af689d56d45..c541c51dc42 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v33.panel_ds_name_to_ref.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v33.panel_ds_name_to_ref.v42.v2beta1.json @@ -361,7 +361,12 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": {} + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v37.legend_normalization.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v37.legend_normalization.v42.v2alpha1.json index 62c7806854a..7dc1d5c7069 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v37.legend_normalization.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v37.legend_normalization.v42.v2alpha1.json @@ -111,6 +111,10 @@ "spec": { "pluginVersion": "", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": {} + }, "legend": { "displayMode": "list", "showLegend": false @@ -207,6 +211,10 @@ "spec": { "pluginVersion": "", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": {} + }, "legend": { "displayMode": "list", "showLegend": false diff --git a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v37.legend_normalization.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v37.legend_normalization.v42.v2beta1.json index 9e112233023..ba78f73005d 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v37.legend_normalization.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v37.legend_normalization.v42.v2beta1.json @@ -115,6 +115,10 @@ "version": "", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": {} + }, "legend": { "displayMode": "list", "showLegend": false @@ -214,6 +218,10 @@ "version": "", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": {} + }, "legend": { "displayMode": "list", "showLegend": false diff --git a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v38.table_displaymode_comprehensive.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v38.table_displaymode_comprehensive.v42.v2alpha1.json index dd8087721a9..89dd54e3bf6 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v38.table_displaymode_comprehensive.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v38.table_displaymode_comprehensive.v42.v2alpha1.json @@ -443,7 +443,12 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": {} + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v38.table_displaymode_comprehensive.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v38.table_displaymode_comprehensive.v42.v2beta1.json index 3a75ab8b887..546c73663d6 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v38.table_displaymode_comprehensive.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v38.table_displaymode_comprehensive.v42.v2beta1.json @@ -455,7 +455,12 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": {} + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v38.timeseries_table_display_mode.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v38.timeseries_table_display_mode.v42.v2alpha1.json index f7ed9a945bf..92dce415c0d 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v38.timeseries_table_display_mode.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v38.timeseries_table_display_mode.v42.v2alpha1.json @@ -443,7 +443,12 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": {} + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v38.timeseries_table_display_mode.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v38.timeseries_table_display_mode.v42.v2beta1.json index f8eb9ef3616..7d89cc8bbdd 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v38.timeseries_table_display_mode.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v38.timeseries_table_display_mode.v42.v2beta1.json @@ -455,7 +455,12 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": {} + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v39.transform_timeseries_table.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v39.transform_timeseries_table.v42.v2alpha1.json index 368f059af62..8d382676f16 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v39.transform_timeseries_table.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v39.transform_timeseries_table.v42.v2alpha1.json @@ -217,7 +217,12 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": {} + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -396,7 +401,12 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": {} + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v39.transform_timeseries_table.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v39.transform_timeseries_table.v42.v2beta1.json index 99de7609d9a..fe92c7f9537 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v39.transform_timeseries_table.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v39.transform_timeseries_table.v42.v2beta1.json @@ -222,7 +222,12 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": {} + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -406,7 +411,12 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": {} + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v4.no-op.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v4.no-op.v42.v2alpha1.json index 983b06ebf43..45615b7ae44 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v4.no-op.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v4.no-op.v42.v2alpha1.json @@ -66,7 +66,12 @@ "kind": "stat", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "singlestat", + "originalOptions": {} + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -110,7 +115,12 @@ "kind": "stat", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "singlestat", + "originalOptions": {} + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -154,7 +164,12 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": {} + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v4.no-op.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v4.no-op.v42.v2beta1.json index 4e523705cb0..3a7e5420f11 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v4.no-op.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v4.no-op.v42.v2beta1.json @@ -69,7 +69,12 @@ "group": "stat", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "singlestat", + "originalOptions": {} + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -115,7 +120,12 @@ "group": "stat", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "singlestat", + "originalOptions": {} + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -161,7 +171,12 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": {} + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v42.hidefrom_tooltip.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v42.hidefrom_tooltip.v42.v2alpha1.json index f7d9a922468..e019782a68b 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v42.hidefrom_tooltip.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v42.hidefrom_tooltip.v42.v2alpha1.json @@ -94,7 +94,12 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": {} + } + }, "fieldConfig": { "defaults": {}, "overrides": [ diff --git a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v42.hidefrom_tooltip.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v42.hidefrom_tooltip.v42.v2beta1.json index f5eaa04d6ab..f97c257c251 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v42.hidefrom_tooltip.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v42.hidefrom_tooltip.v42.v2beta1.json @@ -97,7 +97,12 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": {} + } + }, "fieldConfig": { "defaults": {}, "overrides": [ diff --git a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v5.no-op.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v5.no-op.v42.v2alpha1.json index d39da494ad0..a1fc7ad4752 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v5.no-op.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v5.no-op.v42.v2alpha1.json @@ -66,7 +66,12 @@ "kind": "stat", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "singlestat", + "originalOptions": {} + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -110,7 +115,12 @@ "kind": "stat", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "singlestat", + "originalOptions": {} + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -154,7 +164,12 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": {} + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v5.no-op.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v5.no-op.v42.v2beta1.json index 4795fc07dc5..860ab47b3ea 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v5.no-op.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v5.no-op.v42.v2beta1.json @@ -69,7 +69,12 @@ "group": "stat", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "singlestat", + "originalOptions": {} + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -115,7 +120,12 @@ "group": "stat", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "singlestat", + "originalOptions": {} + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -161,7 +171,12 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": {} + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v6.pulldowns_and_templating.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v6.pulldowns_and_templating.v42.v2alpha1.json index 60ef3b2ec90..6ca93a6768a 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v6.pulldowns_and_templating.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v6.pulldowns_and_templating.v42.v2alpha1.json @@ -108,7 +108,12 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": {} + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -154,7 +159,12 @@ "kind": "stat", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "singlestat", + "originalOptions": {} + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v6.pulldowns_and_templating.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v6.pulldowns_and_templating.v42.v2beta1.json index 3396e17655d..0fa353e9a30 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v6.pulldowns_and_templating.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v6.pulldowns_and_templating.v42.v2beta1.json @@ -113,7 +113,12 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": {} + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -161,7 +166,12 @@ "group": "stat", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "singlestat", + "originalOptions": {} + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v8.influxdb_query.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v8.influxdb_query.v42.v2alpha1.json index 7b4432f77b5..1bdd08aecf5 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v8.influxdb_query.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v8.influxdb_query.v42.v2alpha1.json @@ -119,7 +119,12 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": {} + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -177,7 +182,12 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": {} + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v8.influxdb_query.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v8.influxdb_query.v42.v2beta1.json index 40d7695e10c..ed5b9515a9f 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v8.influxdb_query.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v8.influxdb_query.v42.v2beta1.json @@ -122,7 +122,12 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": {} + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -182,7 +187,12 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": {} + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v9.no-op.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v9.no-op.v42.v2alpha1.json index e39200fdc8e..b69579db16b 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v9.no-op.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v9.no-op.v42.v2alpha1.json @@ -66,7 +66,12 @@ "kind": "stat", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "singlestat", + "originalOptions": {} + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -110,7 +115,12 @@ "kind": "stat", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "singlestat", + "originalOptions": {} + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -154,7 +164,12 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": {} + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v9.no-op.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v9.no-op.v42.v2beta1.json index 71ba1439de3..2f8f9c79a0b 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v9.no-op.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/migrated_dashboards_output/v1beta1-mig-v9.no-op.v42.v2beta1.json @@ -69,7 +69,12 @@ "group": "stat", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "singlestat", + "originalOptions": {} + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -115,7 +120,12 @@ "group": "stat", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "singlestat", + "originalOptions": {} + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -161,7 +171,12 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": {} + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-influxdb/v0alpha1.influxdb-logs.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-influxdb/v0alpha1.influxdb-logs.v42.v2alpha1.json index 0ed400e5163..d30cf519eb9 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-influxdb/v0alpha1.influxdb-logs.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-influxdb/v0alpha1.influxdb-logs.v42.v2alpha1.json @@ -164,6 +164,65 @@ "spec": { "pluginVersion": "", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": false, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-influxdb/v0alpha1.influxdb-logs.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-influxdb/v0alpha1.influxdb-logs.v42.v2beta1.json index 4bb33313829..def63fe73f1 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-influxdb/v0alpha1.influxdb-logs.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-influxdb/v0alpha1.influxdb-logs.v42.v2beta1.json @@ -170,6 +170,65 @@ "version": "", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": false, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-influxdb/v0alpha1.influxdb-templated.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-influxdb/v0alpha1.influxdb-templated.v42.v2alpha1.json index 63037588772..7bd7146240e 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-influxdb/v0alpha1.influxdb-templated.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-influxdb/v0alpha1.influxdb-templated.v42.v2alpha1.json @@ -113,7 +113,78 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "annotate": { + "enable": false + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "editable": true, + "error": false, + "fill": 2, + "grid": {}, + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "resolution": 100, + "scale": 1, + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "msResolution": false, + "query_as_alias": true, + "shared": false, + "sort": 0, + "value_type": "cumulative" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + }, + "zerofill": true + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-influxdb/v0alpha1.influxdb-templated.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-influxdb/v0alpha1.influxdb-templated.v42.v2beta1.json index 19495974932..943bd4c0a7b 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-influxdb/v0alpha1.influxdb-templated.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-influxdb/v0alpha1.influxdb-templated.v42.v2beta1.json @@ -117,7 +117,78 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "annotate": { + "enable": false + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "editable": true, + "error": false, + "fill": 2, + "grid": {}, + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "resolution": 100, + "scale": 1, + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "msResolution": false, + "query_as_alias": true, + "shared": false, + "sort": 0, + "value_type": "cumulative" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + }, + "zerofill": true + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-mssql/v0alpha1.mssql_fakedata.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-mssql/v0alpha1.mssql_fakedata.v42.v2alpha1.json index d7e3a8f61b9..0f908ced2aa 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-mssql/v0alpha1.mssql_fakedata.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-mssql/v0alpha1.mssql_fakedata.v42.v2alpha1.json @@ -129,6 +129,74 @@ "spec": { "pluginVersion": "", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": { + "total avg": "#6ed0e0" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "total avg", + "fill": 0, + "pointradius": 3, + "points": true + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -178,7 +246,45 @@ "kind": "table", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "columns": [], + "fontSize": "100%", + "scroll": true, + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "align": "auto", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "date" + }, + { + "alias": "", + "align": "auto", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "number", + "unit": "short" + } + ], + "transform": "table" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -227,6 +333,65 @@ "spec": { "pluginVersion": "", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -296,6 +461,65 @@ "spec": { "pluginVersion": "", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-mssql/v0alpha1.mssql_fakedata.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-mssql/v0alpha1.mssql_fakedata.v42.v2beta1.json index 2d66d6ca855..a346f009588 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-mssql/v0alpha1.mssql_fakedata.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-mssql/v0alpha1.mssql_fakedata.v42.v2beta1.json @@ -138,6 +138,74 @@ "version": "", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": { + "total avg": "#6ed0e0" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "total avg", + "fill": 0, + "pointradius": 3, + "points": true + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -189,7 +257,45 @@ "group": "table", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "columns": [], + "fontSize": "100%", + "scroll": true, + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "align": "auto", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "date" + }, + { + "alias": "", + "align": "auto", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "number", + "unit": "short" + } + ], + "transform": "table" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -240,6 +346,65 @@ "version": "", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -312,6 +477,65 @@ "version": "", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-mssql/v0alpha1.mssql_unittest.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-mssql/v0alpha1.mssql_unittest.v42.v2alpha1.json index 69c1c822020..747942f6dc3 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-mssql/v0alpha1.mssql_unittest.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-mssql/v0alpha1.mssql_unittest.v42.v2alpha1.json @@ -147,7 +147,65 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": true, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -195,7 +253,64 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": false, + "linewidth": 2, + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -243,7 +358,64 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": false, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -291,7 +463,69 @@ "kind": "bargauge", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": false, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "series", + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -339,7 +573,69 @@ "kind": "bargauge", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": false, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "series", + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -387,7 +683,64 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": false, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -435,7 +788,69 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "hideEmpty": false, + "hideZero": false, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": true, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -483,7 +898,67 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -531,7 +1006,69 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "hideEmpty": false, + "hideZero": false, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -579,7 +1116,38 @@ "kind": "table", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "columns": [], + "fontSize": "100%", + "scroll": true, + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "alias": "", + "align": "auto", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "string", + "unit": "short" + } + ], + "transform": "table" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -627,7 +1195,67 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": true, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -675,7 +1303,70 @@ "kind": "histogram", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": false, + "total": true, + "values": true + }, + "lines": false, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "buckets": 20, + "mode": "histogram", + "show": true, + "values": [ + "current" + ] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -723,7 +1414,70 @@ "kind": "histogram", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": false, + "total": true, + "values": true + }, + "lines": false, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "buckets": 100, + "mode": "histogram", + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -771,7 +1525,70 @@ "kind": "histogram", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": false, + "total": true, + "values": true + }, + "lines": false, + "linewidth": 1, + "nullPointMode": "null", + "percentage": true, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "buckets": 20, + "mode": "histogram", + "show": true, + "values": [ + "current" + ] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -819,7 +1636,70 @@ "kind": "histogram", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": false, + "total": true, + "values": true + }, + "lines": false, + "linewidth": 1, + "nullPointMode": "null", + "percentage": true, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "buckets": 20, + "mode": "histogram", + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -867,7 +1747,70 @@ "kind": "histogram", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": false, + "total": true, + "values": true + }, + "lines": false, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "buckets": 50, + "mode": "histogram", + "show": true, + "values": [ + "current" + ] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -915,7 +1858,70 @@ "kind": "histogram", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": false, + "total": true, + "values": true + }, + "lines": false, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "buckets": 20, + "mode": "histogram", + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -963,7 +1969,69 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "hideEmpty": false, + "hideZero": false, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1011,7 +2079,67 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1059,7 +2187,69 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "hideEmpty": false, + "hideZero": false, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1107,7 +2297,69 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "hideEmpty": false, + "hideZero": false, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1156,7 +2408,45 @@ "kind": "table", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "columns": [], + "fontSize": "100%", + "scroll": true, + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "align": "auto", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "time", + "type": "date" + }, + { + "alias": "", + "align": "auto", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "number", + "unit": "short" + } + ], + "transform": "table" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1205,7 +2495,45 @@ "kind": "table", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "columns": [], + "fontSize": "100%", + "scroll": true, + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "align": "auto", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "time", + "type": "date" + }, + { + "alias": "", + "align": "auto", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "number", + "unit": "short" + } + ], + "transform": "table" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1254,7 +2582,45 @@ "kind": "table", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "columns": [], + "fontSize": "100%", + "scroll": true, + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "align": "auto", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "time", + "type": "date" + }, + { + "alias": "", + "align": "auto", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "number", + "unit": "short" + } + ], + "transform": "table" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1303,7 +2669,45 @@ "kind": "table", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "columns": [], + "fontSize": "100%", + "scroll": true, + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "align": "auto", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "time", + "type": "date" + }, + { + "alias": "", + "align": "auto", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "number", + "unit": "short" + } + ], + "transform": "table" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1351,7 +2755,65 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 3, + "points": true, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1399,7 +2861,64 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": false, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1447,7 +2966,69 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "hideEmpty": false, + "hideZero": false, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1514,7 +3095,79 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "MovingAverageValueOne", + "dashes": true, + "lines": false + }, + { + "alias": "MovingAverageValueTwo", + "dashes": true, + "lines": false, + "yaxis": 1 + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1562,7 +3215,69 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "hideEmpty": false, + "hideZero": false, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1629,7 +3344,79 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "MovingAverageValueOne", + "dashes": true, + "lines": false + }, + { + "alias": "MovingAverageValueTwo", + "dashes": true, + "lines": false, + "yaxis": 1 + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1677,7 +3464,65 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": true, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1725,7 +3570,65 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 3, + "points": true, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-mssql/v0alpha1.mssql_unittest.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-mssql/v0alpha1.mssql_unittest.v42.v2beta1.json index 5ddf1d701a7..fa5c52ae871 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-mssql/v0alpha1.mssql_unittest.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-mssql/v0alpha1.mssql_unittest.v42.v2beta1.json @@ -159,7 +159,65 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": true, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -209,7 +267,64 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": false, + "linewidth": 2, + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -259,7 +374,64 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": false, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -309,7 +481,69 @@ "group": "bargauge", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": false, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "series", + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -359,7 +593,69 @@ "group": "bargauge", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": false, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "series", + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -409,7 +705,64 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": false, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -459,7 +812,69 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "hideEmpty": false, + "hideZero": false, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": true, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -509,7 +924,67 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -559,7 +1034,69 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "hideEmpty": false, + "hideZero": false, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -609,7 +1146,38 @@ "group": "table", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "columns": [], + "fontSize": "100%", + "scroll": true, + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "alias": "", + "align": "auto", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "string", + "unit": "short" + } + ], + "transform": "table" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -659,7 +1227,67 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": true, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -709,7 +1337,70 @@ "group": "histogram", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": false, + "total": true, + "values": true + }, + "lines": false, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "buckets": 20, + "mode": "histogram", + "show": true, + "values": [ + "current" + ] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -759,7 +1450,70 @@ "group": "histogram", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": false, + "total": true, + "values": true + }, + "lines": false, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "buckets": 100, + "mode": "histogram", + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -809,7 +1563,70 @@ "group": "histogram", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": false, + "total": true, + "values": true + }, + "lines": false, + "linewidth": 1, + "nullPointMode": "null", + "percentage": true, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "buckets": 20, + "mode": "histogram", + "show": true, + "values": [ + "current" + ] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -859,7 +1676,70 @@ "group": "histogram", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": false, + "total": true, + "values": true + }, + "lines": false, + "linewidth": 1, + "nullPointMode": "null", + "percentage": true, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "buckets": 20, + "mode": "histogram", + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -909,7 +1789,70 @@ "group": "histogram", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": false, + "total": true, + "values": true + }, + "lines": false, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "buckets": 50, + "mode": "histogram", + "show": true, + "values": [ + "current" + ] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -959,7 +1902,70 @@ "group": "histogram", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": false, + "total": true, + "values": true + }, + "lines": false, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "buckets": 20, + "mode": "histogram", + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1009,7 +2015,69 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "hideEmpty": false, + "hideZero": false, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1059,7 +2127,67 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1109,7 +2237,69 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "hideEmpty": false, + "hideZero": false, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1159,7 +2349,69 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "hideEmpty": false, + "hideZero": false, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1210,7 +2462,45 @@ "group": "table", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "columns": [], + "fontSize": "100%", + "scroll": true, + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "align": "auto", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "time", + "type": "date" + }, + { + "alias": "", + "align": "auto", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "number", + "unit": "short" + } + ], + "transform": "table" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1261,7 +2551,45 @@ "group": "table", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "columns": [], + "fontSize": "100%", + "scroll": true, + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "align": "auto", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "time", + "type": "date" + }, + { + "alias": "", + "align": "auto", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "number", + "unit": "short" + } + ], + "transform": "table" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1312,7 +2640,45 @@ "group": "table", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "columns": [], + "fontSize": "100%", + "scroll": true, + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "align": "auto", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "time", + "type": "date" + }, + { + "alias": "", + "align": "auto", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "number", + "unit": "short" + } + ], + "transform": "table" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1363,7 +2729,45 @@ "group": "table", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "columns": [], + "fontSize": "100%", + "scroll": true, + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "align": "auto", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "time", + "type": "date" + }, + { + "alias": "", + "align": "auto", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "number", + "unit": "short" + } + ], + "transform": "table" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1413,7 +2817,65 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 3, + "points": true, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1463,7 +2925,64 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": false, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1513,7 +3032,69 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "hideEmpty": false, + "hideZero": false, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1583,7 +3164,79 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "MovingAverageValueOne", + "dashes": true, + "lines": false + }, + { + "alias": "MovingAverageValueTwo", + "dashes": true, + "lines": false, + "yaxis": 1 + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1633,7 +3286,69 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "hideEmpty": false, + "hideZero": false, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1703,7 +3418,79 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "MovingAverageValueOne", + "dashes": true, + "lines": false + }, + { + "alias": "MovingAverageValueTwo", + "dashes": true, + "lines": false, + "yaxis": 1 + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1753,7 +3540,65 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": true, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1803,7 +3648,65 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 3, + "points": true, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-mysql/v0alpha1.mysql_fakedata.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-mysql/v0alpha1.mysql_fakedata.v42.v2alpha1.json index 6dc4619db1d..59f1c712177 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-mysql/v0alpha1.mysql_fakedata.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-mysql/v0alpha1.mysql_fakedata.v42.v2alpha1.json @@ -128,6 +128,74 @@ "spec": { "pluginVersion": "", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": { + "total avg": "#6ed0e0" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "total avg", + "fill": 0, + "pointradius": 3, + "points": true + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -179,6 +247,65 @@ "spec": { "pluginVersion": "", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "percent", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -249,6 +376,65 @@ "spec": { "pluginVersion": "", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -299,7 +485,46 @@ "kind": "table", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "columns": [], + "fontSize": "100%", + "scroll": true, + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "align": "auto", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "link": false, + "pattern": "Time", + "type": "date" + }, + { + "alias": "", + "align": "auto", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "number", + "unit": "short" + } + ], + "transform": "table" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-mysql/v0alpha1.mysql_fakedata.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-mysql/v0alpha1.mysql_fakedata.v42.v2beta1.json index ff02a8b9af0..3f782078e85 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-mysql/v0alpha1.mysql_fakedata.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-mysql/v0alpha1.mysql_fakedata.v42.v2beta1.json @@ -137,6 +137,74 @@ "version": "", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": { + "total avg": "#6ed0e0" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "total avg", + "fill": 0, + "pointradius": 3, + "points": true + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -190,6 +258,65 @@ "version": "", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "percent", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -263,6 +390,65 @@ "version": "", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -315,7 +501,46 @@ "group": "table", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "columns": [], + "fontSize": "100%", + "scroll": true, + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "align": "auto", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "link": false, + "pattern": "Time", + "type": "date" + }, + { + "alias": "", + "align": "auto", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "number", + "unit": "short" + } + ], + "transform": "table" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-mysql/v0alpha1.mysql_unittest.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-mysql/v0alpha1.mysql_unittest.v42.v2alpha1.json index 631815cbc3f..ccfd35d981e 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-mysql/v0alpha1.mysql_unittest.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-mysql/v0alpha1.mysql_unittest.v42.v2alpha1.json @@ -147,7 +147,65 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": true, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -195,7 +253,64 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": false, + "linewidth": 2, + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -243,7 +358,64 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": false, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -291,7 +463,69 @@ "kind": "bargauge", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": false, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "series", + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -339,7 +573,69 @@ "kind": "bargauge", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": false, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "series", + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -387,7 +683,64 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": false, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -435,7 +788,69 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "hideEmpty": false, + "hideZero": false, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": true, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -483,7 +898,67 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -531,7 +1006,69 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "hideEmpty": false, + "hideZero": false, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -579,7 +1116,38 @@ "kind": "table", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "columns": [], + "fontSize": "100%", + "scroll": true, + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "alias": "", + "align": "auto", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "string", + "unit": "short" + } + ], + "transform": "table" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -627,7 +1195,67 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": true, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -675,7 +1303,70 @@ "kind": "histogram", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": false, + "total": true, + "values": true + }, + "lines": false, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "buckets": 20, + "mode": "histogram", + "show": true, + "values": [ + "current" + ] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -723,7 +1414,70 @@ "kind": "histogram", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": false, + "total": true, + "values": true + }, + "lines": false, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "buckets": 100, + "mode": "histogram", + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -771,7 +1525,70 @@ "kind": "histogram", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": false, + "total": true, + "values": true + }, + "lines": false, + "linewidth": 1, + "nullPointMode": "null", + "percentage": true, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "buckets": 20, + "mode": "histogram", + "show": true, + "values": [ + "current" + ] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -819,7 +1636,70 @@ "kind": "histogram", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": false, + "total": true, + "values": true + }, + "lines": false, + "linewidth": 1, + "nullPointMode": "null", + "percentage": true, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "buckets": 20, + "mode": "histogram", + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -867,7 +1747,70 @@ "kind": "histogram", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": false, + "total": true, + "values": true + }, + "lines": false, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "buckets": 50, + "mode": "histogram", + "show": true, + "values": [ + "current" + ] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -915,7 +1858,70 @@ "kind": "histogram", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": false, + "total": true, + "values": true + }, + "lines": false, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "buckets": 20, + "mode": "histogram", + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -963,7 +1969,69 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "hideEmpty": false, + "hideZero": false, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1011,7 +2079,67 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1060,7 +2188,45 @@ "kind": "table", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "columns": [], + "fontSize": "100%", + "scroll": true, + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "align": "auto", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "time_sec", + "type": "date" + }, + { + "alias": "", + "align": "auto", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "number", + "unit": "short" + } + ], + "transform": "table" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1109,7 +2275,45 @@ "kind": "table", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "columns": [], + "fontSize": "100%", + "scroll": true, + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "align": "auto", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "time_sec", + "type": "date" + }, + { + "alias": "", + "align": "auto", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "number", + "unit": "short" + } + ], + "transform": "table" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1158,7 +2362,45 @@ "kind": "table", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "columns": [], + "fontSize": "100%", + "scroll": true, + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "align": "auto", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "time_sec", + "type": "date" + }, + { + "alias": "", + "align": "auto", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "number", + "unit": "short" + } + ], + "transform": "table" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1207,7 +2449,45 @@ "kind": "table", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "columns": [], + "fontSize": "100%", + "scroll": true, + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "align": "auto", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "time", + "type": "date" + }, + { + "alias": "", + "align": "auto", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "number", + "unit": "short" + } + ], + "transform": "table" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1255,7 +2535,65 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": true, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1303,7 +2641,64 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": false, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1351,7 +2746,69 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "hideEmpty": false, + "hideZero": false, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1399,7 +2856,79 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "MovingAverageValueOne", + "dashes": true, + "lines": false + }, + { + "alias": "MovingAverageValueTwo", + "dashes": true, + "lines": false, + "yaxis": 1 + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1447,7 +2976,69 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "hideEmpty": false, + "hideZero": false, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1495,7 +3086,79 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "MovingAverageValueOne", + "dashes": true, + "lines": false + }, + { + "alias": "MovingAverageValueTwo", + "dashes": true, + "lines": false, + "yaxis": 1 + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1543,7 +3206,65 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": true, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1591,7 +3312,65 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 3, + "points": true, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-mysql/v0alpha1.mysql_unittest.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-mysql/v0alpha1.mysql_unittest.v42.v2beta1.json index 6ab6536924f..643298fb85c 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-mysql/v0alpha1.mysql_unittest.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-mysql/v0alpha1.mysql_unittest.v42.v2beta1.json @@ -159,7 +159,65 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": true, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -209,7 +267,64 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": false, + "linewidth": 2, + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -259,7 +374,64 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": false, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -309,7 +481,69 @@ "group": "bargauge", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": false, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "series", + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -359,7 +593,69 @@ "group": "bargauge", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": false, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "series", + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -409,7 +705,64 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": false, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -459,7 +812,69 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "hideEmpty": false, + "hideZero": false, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": true, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -509,7 +924,67 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -559,7 +1034,69 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "hideEmpty": false, + "hideZero": false, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -609,7 +1146,38 @@ "group": "table", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "columns": [], + "fontSize": "100%", + "scroll": true, + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "alias": "", + "align": "auto", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "string", + "unit": "short" + } + ], + "transform": "table" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -659,7 +1227,67 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": true, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -709,7 +1337,70 @@ "group": "histogram", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": false, + "total": true, + "values": true + }, + "lines": false, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "buckets": 20, + "mode": "histogram", + "show": true, + "values": [ + "current" + ] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -759,7 +1450,70 @@ "group": "histogram", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": false, + "total": true, + "values": true + }, + "lines": false, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "buckets": 100, + "mode": "histogram", + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -809,7 +1563,70 @@ "group": "histogram", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": false, + "total": true, + "values": true + }, + "lines": false, + "linewidth": 1, + "nullPointMode": "null", + "percentage": true, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "buckets": 20, + "mode": "histogram", + "show": true, + "values": [ + "current" + ] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -859,7 +1676,70 @@ "group": "histogram", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": false, + "total": true, + "values": true + }, + "lines": false, + "linewidth": 1, + "nullPointMode": "null", + "percentage": true, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "buckets": 20, + "mode": "histogram", + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -909,7 +1789,70 @@ "group": "histogram", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": false, + "total": true, + "values": true + }, + "lines": false, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "buckets": 50, + "mode": "histogram", + "show": true, + "values": [ + "current" + ] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -959,7 +1902,70 @@ "group": "histogram", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": false, + "total": true, + "values": true + }, + "lines": false, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "buckets": 20, + "mode": "histogram", + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1009,7 +2015,69 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "hideEmpty": false, + "hideZero": false, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1059,7 +2127,67 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1110,7 +2238,45 @@ "group": "table", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "columns": [], + "fontSize": "100%", + "scroll": true, + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "align": "auto", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "time_sec", + "type": "date" + }, + { + "alias": "", + "align": "auto", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "number", + "unit": "short" + } + ], + "transform": "table" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1161,7 +2327,45 @@ "group": "table", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "columns": [], + "fontSize": "100%", + "scroll": true, + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "align": "auto", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "time_sec", + "type": "date" + }, + { + "alias": "", + "align": "auto", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "number", + "unit": "short" + } + ], + "transform": "table" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1212,7 +2416,45 @@ "group": "table", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "columns": [], + "fontSize": "100%", + "scroll": true, + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "align": "auto", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "time_sec", + "type": "date" + }, + { + "alias": "", + "align": "auto", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "number", + "unit": "short" + } + ], + "transform": "table" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1263,7 +2505,45 @@ "group": "table", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "columns": [], + "fontSize": "100%", + "scroll": true, + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "align": "auto", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "time", + "type": "date" + }, + { + "alias": "", + "align": "auto", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "number", + "unit": "short" + } + ], + "transform": "table" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1313,7 +2593,65 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": true, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1363,7 +2701,64 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": false, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1413,7 +2808,69 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "hideEmpty": false, + "hideZero": false, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1463,7 +2920,79 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "MovingAverageValueOne", + "dashes": true, + "lines": false + }, + { + "alias": "MovingAverageValueTwo", + "dashes": true, + "lines": false, + "yaxis": 1 + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1513,7 +3042,69 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "hideEmpty": false, + "hideZero": false, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1563,7 +3154,79 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "MovingAverageValueOne", + "dashes": true, + "lines": false + }, + { + "alias": "MovingAverageValueTwo", + "dashes": true, + "lines": false, + "yaxis": 1 + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1613,7 +3276,65 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": true, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1663,7 +3384,65 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 3, + "points": true, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-opentsdb/v0alpha1.opentsdb.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-opentsdb/v0alpha1.opentsdb.v42.v2alpha1.json index 7f3926d803e..893d135c144 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-opentsdb/v0alpha1.opentsdb.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-opentsdb/v0alpha1.opentsdb.v42.v2alpha1.json @@ -68,6 +68,65 @@ "spec": { "pluginVersion": "", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -119,6 +178,65 @@ "spec": { "pluginVersion": "", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-opentsdb/v0alpha1.opentsdb.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-opentsdb/v0alpha1.opentsdb.v42.v2beta1.json index 2959bf4ca8d..5086e9f987d 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-opentsdb/v0alpha1.opentsdb.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-opentsdb/v0alpha1.opentsdb.v42.v2beta1.json @@ -72,6 +72,65 @@ "version": "", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -125,6 +184,65 @@ "version": "", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-opentsdb/v0alpha1.opentsdb_v23.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-opentsdb/v0alpha1.opentsdb_v23.v42.v2alpha1.json index 03a415d2b4d..deb7d353db8 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-opentsdb/v0alpha1.opentsdb_v23.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-opentsdb/v0alpha1.opentsdb_v23.v42.v2alpha1.json @@ -84,6 +84,65 @@ "spec": { "pluginVersion": "8.1.0-pre", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "alertThreshold": true }, "fieldConfig": { @@ -148,6 +207,65 @@ "spec": { "pluginVersion": "8.1.0-pre", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "alertThreshold": true }, "fieldConfig": { diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-opentsdb/v0alpha1.opentsdb_v23.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-opentsdb/v0alpha1.opentsdb_v23.v42.v2beta1.json index d3b15a72cf9..342f5a0a94c 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-opentsdb/v0alpha1.opentsdb_v23.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-opentsdb/v0alpha1.opentsdb_v23.v42.v2beta1.json @@ -88,6 +88,65 @@ "version": "8.1.0-pre", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "alertThreshold": true }, "fieldConfig": { @@ -154,6 +213,65 @@ "version": "8.1.0-pre", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "alertThreshold": true }, "fieldConfig": { diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-postgres/v0alpha1.postgres_fakedata.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-postgres/v0alpha1.postgres_fakedata.v42.v2alpha1.json index 15b1ad08458..0e222d96742 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-postgres/v0alpha1.postgres_fakedata.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-postgres/v0alpha1.postgres_fakedata.v42.v2alpha1.json @@ -170,6 +170,74 @@ "spec": { "pluginVersion": "", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": { + "total avg": "#6ed0e0" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "total avg", + "fill": 0, + "pointradius": 3, + "points": true + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -221,6 +289,65 @@ "spec": { "pluginVersion": "", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "percent", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -291,6 +418,65 @@ "spec": { "pluginVersion": "", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -341,7 +527,46 @@ "kind": "table", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "columns": [], + "fontSize": "100%", + "scroll": true, + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "align": "auto", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "link": false, + "pattern": "Time", + "type": "date" + }, + { + "alias": "", + "align": "auto", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "number", + "unit": "short" + } + ], + "transform": "table" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-postgres/v0alpha1.postgres_fakedata.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-postgres/v0alpha1.postgres_fakedata.v42.v2beta1.json index d3572facb36..9ece61d256d 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-postgres/v0alpha1.postgres_fakedata.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-postgres/v0alpha1.postgres_fakedata.v42.v2beta1.json @@ -179,6 +179,74 @@ "version": "", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": { + "total avg": "#6ed0e0" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "total avg", + "fill": 0, + "pointradius": 3, + "points": true + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -232,6 +300,65 @@ "version": "", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "percent", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -305,6 +432,65 @@ "version": "", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -357,7 +543,46 @@ "group": "table", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "columns": [], + "fontSize": "100%", + "scroll": true, + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "align": "auto", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "link": false, + "pattern": "Time", + "type": "date" + }, + { + "alias": "", + "align": "auto", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "number", + "unit": "short" + } + ], + "transform": "table" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-postgres/v0alpha1.postgres_unittest.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-postgres/v0alpha1.postgres_unittest.v42.v2alpha1.json index 2ac583af244..a7bec316030 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-postgres/v0alpha1.postgres_unittest.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-postgres/v0alpha1.postgres_unittest.v42.v2alpha1.json @@ -147,7 +147,65 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": true, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -195,7 +253,64 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": false, + "linewidth": 2, + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -243,7 +358,64 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": false, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -291,7 +463,69 @@ "kind": "bargauge", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": false, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "series", + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -339,7 +573,69 @@ "kind": "bargauge", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": false, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "series", + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -387,7 +683,64 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": false, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -435,7 +788,69 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "hideEmpty": false, + "hideZero": false, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": true, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -483,7 +898,67 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -531,7 +1006,69 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "hideEmpty": false, + "hideZero": false, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -579,7 +1116,38 @@ "kind": "table", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "columns": [], + "fontSize": "100%", + "scroll": true, + "showHeader": true, + "sort": { + "col": 1, + "desc": false + }, + "styles": [ + { + "alias": "", + "align": "auto", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "string", + "unit": "short" + } + ], + "transform": "table" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -627,7 +1195,67 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": true, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -675,7 +1303,70 @@ "kind": "histogram", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": false, + "total": true, + "values": true + }, + "lines": false, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "buckets": 20, + "mode": "histogram", + "show": true, + "values": [ + "current" + ] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -723,7 +1414,70 @@ "kind": "histogram", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": false, + "total": true, + "values": true + }, + "lines": false, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "buckets": 100, + "mode": "histogram", + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -771,7 +1525,70 @@ "kind": "histogram", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": false, + "total": true, + "values": true + }, + "lines": false, + "linewidth": 1, + "nullPointMode": "null", + "percentage": true, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "buckets": 20, + "mode": "histogram", + "show": true, + "values": [ + "current" + ] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -819,7 +1636,70 @@ "kind": "histogram", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": false, + "total": true, + "values": true + }, + "lines": false, + "linewidth": 1, + "nullPointMode": "null", + "percentage": true, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "buckets": 20, + "mode": "histogram", + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -867,7 +1747,70 @@ "kind": "histogram", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": false, + "total": true, + "values": true + }, + "lines": false, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "buckets": 50, + "mode": "histogram", + "show": true, + "values": [ + "current" + ] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -915,7 +1858,70 @@ "kind": "histogram", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": false, + "total": true, + "values": true + }, + "lines": false, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "buckets": 20, + "mode": "histogram", + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -963,7 +1969,69 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "hideEmpty": false, + "hideZero": false, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1011,7 +2079,67 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1060,7 +2188,45 @@ "kind": "table", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "columns": [], + "fontSize": "100%", + "scroll": true, + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "align": "auto", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "time", + "type": "date" + }, + { + "alias": "", + "align": "auto", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "number", + "unit": "short" + } + ], + "transform": "table" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1109,7 +2275,45 @@ "kind": "table", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "columns": [], + "fontSize": "100%", + "scroll": true, + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "align": "auto", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "time", + "type": "date" + }, + { + "alias": "", + "align": "auto", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "number", + "unit": "short" + } + ], + "transform": "table" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1158,7 +2362,45 @@ "kind": "table", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "columns": [], + "fontSize": "100%", + "scroll": true, + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "align": "auto", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "time", + "type": "date" + }, + { + "alias": "", + "align": "auto", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "number", + "unit": "short" + } + ], + "transform": "table" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1207,7 +2449,45 @@ "kind": "table", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "columns": [], + "fontSize": "100%", + "scroll": true, + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "align": "auto", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "time", + "type": "date" + }, + { + "alias": "", + "align": "auto", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "number", + "unit": "short" + } + ], + "transform": "table" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1255,7 +2535,65 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": true, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1303,7 +2641,64 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": false, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1351,7 +2746,69 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "hideEmpty": false, + "hideZero": false, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1399,7 +2856,67 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1447,7 +2964,69 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "hideEmpty": false, + "hideZero": false, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1495,7 +3074,67 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1543,7 +3182,65 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": true, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1591,7 +3288,65 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 3, + "points": true, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-postgres/v0alpha1.postgres_unittest.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-postgres/v0alpha1.postgres_unittest.v42.v2beta1.json index 9a9dea7f6f3..ce0dd08d44d 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-postgres/v0alpha1.postgres_unittest.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/datasource-postgres/v0alpha1.postgres_unittest.v42.v2beta1.json @@ -159,7 +159,65 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": true, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -209,7 +267,64 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": false, + "linewidth": 2, + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -259,7 +374,64 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": false, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -309,7 +481,69 @@ "group": "bargauge", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": false, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "series", + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -359,7 +593,69 @@ "group": "bargauge", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": false, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "series", + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -409,7 +705,64 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": false, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -459,7 +812,69 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "hideEmpty": false, + "hideZero": false, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": true, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -509,7 +924,67 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -559,7 +1034,69 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "hideEmpty": false, + "hideZero": false, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -609,7 +1146,38 @@ "group": "table", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "columns": [], + "fontSize": "100%", + "scroll": true, + "showHeader": true, + "sort": { + "col": 1, + "desc": false + }, + "styles": [ + { + "alias": "", + "align": "auto", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "string", + "unit": "short" + } + ], + "transform": "table" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -659,7 +1227,67 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": true, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -709,7 +1337,70 @@ "group": "histogram", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": false, + "total": true, + "values": true + }, + "lines": false, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "buckets": 20, + "mode": "histogram", + "show": true, + "values": [ + "current" + ] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -759,7 +1450,70 @@ "group": "histogram", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": false, + "total": true, + "values": true + }, + "lines": false, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "buckets": 100, + "mode": "histogram", + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -809,7 +1563,70 @@ "group": "histogram", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": false, + "total": true, + "values": true + }, + "lines": false, + "linewidth": 1, + "nullPointMode": "null", + "percentage": true, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "buckets": 20, + "mode": "histogram", + "show": true, + "values": [ + "current" + ] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -859,7 +1676,70 @@ "group": "histogram", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": false, + "total": true, + "values": true + }, + "lines": false, + "linewidth": 1, + "nullPointMode": "null", + "percentage": true, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "buckets": 20, + "mode": "histogram", + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -909,7 +1789,70 @@ "group": "histogram", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": false, + "total": true, + "values": true + }, + "lines": false, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "buckets": 50, + "mode": "histogram", + "show": true, + "values": [ + "current" + ] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -959,7 +1902,70 @@ "group": "histogram", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": false, + "total": true, + "values": true + }, + "lines": false, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "buckets": 20, + "mode": "histogram", + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1009,7 +2015,69 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "hideEmpty": false, + "hideZero": false, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1059,7 +2127,67 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1110,7 +2238,45 @@ "group": "table", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "columns": [], + "fontSize": "100%", + "scroll": true, + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "align": "auto", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "time", + "type": "date" + }, + { + "alias": "", + "align": "auto", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "number", + "unit": "short" + } + ], + "transform": "table" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1161,7 +2327,45 @@ "group": "table", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "columns": [], + "fontSize": "100%", + "scroll": true, + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "align": "auto", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "time", + "type": "date" + }, + { + "alias": "", + "align": "auto", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "number", + "unit": "short" + } + ], + "transform": "table" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1212,7 +2416,45 @@ "group": "table", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "columns": [], + "fontSize": "100%", + "scroll": true, + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "align": "auto", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "time", + "type": "date" + }, + { + "alias": "", + "align": "auto", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "number", + "unit": "short" + } + ], + "transform": "table" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1263,7 +2505,45 @@ "group": "table", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "columns": [], + "fontSize": "100%", + "scroll": true, + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "align": "auto", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "time", + "type": "date" + }, + { + "alias": "", + "align": "auto", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "number", + "unit": "short" + } + ], + "transform": "table" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1313,7 +2593,65 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": true, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1363,7 +2701,64 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": false, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1413,7 +2808,69 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "hideEmpty": false, + "hideZero": false, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1463,7 +2920,67 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1513,7 +3030,69 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "hideEmpty": false, + "hideZero": false, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1563,7 +3142,67 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1613,7 +3252,65 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 3, + "points": true, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1663,7 +3360,65 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 3, + "points": true, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": true, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/feature-templating/v0alpha1.testdata-datalinks.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/feature-templating/v0alpha1.testdata-datalinks.v42.v2alpha1.json index 36419c8e892..4a9e24d85f6 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/feature-templating/v0alpha1.testdata-datalinks.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/feature-templating/v0alpha1.testdata-datalinks.v42.v2alpha1.json @@ -86,6 +86,64 @@ "spec": { "pluginVersion": "", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [ { "targetBlank": false, @@ -303,7 +361,15 @@ "kind": "text", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "text", + "originalOptions": { + "content": "## Data link variables overview\n\nThis dashboard presents variables that one can use when creating *data links*. All links redirect to this dashboard and this panel represents the values that were interpolated in the link that was clicked.\n\n\n#### Series variables\n1. **Name:** \u003cspan style=\"color: orange;\"\u003e$seriesName\u003c/span\u003e\n2. **label.datacenter:** \u003cspan style=\"color: orange;\"\u003e$labelDatacenter\u003c/span\u003e\n3. **label.datacenter.region:** \u003cspan style=\"color: orange;\"\u003e$labelDatacenterRegion\u003c/span\u003e\n\n#### Field variables\n1. **Name:** \u003cspan style=\"color: orange;\"\u003e$fieldName\u003c/span\u003e\n\n#### Value variables\n1. **Time:** \u003cspan style=\"color: orange;\"\u003e$valueTime\u003c/span\u003e\n2. **Numeric:** \u003cspan style=\"color: orange;\"\u003e$valueNumeric\u003c/span\u003e\n3. **Text:** \u003cspan style=\"color: orange;\"\u003e$valueText\u003c/span\u003e\n4. **Calc:** \u003cspan style=\"color: orange;\"\u003e$valueCalc\u003c/span\u003e\n\n", + "mode": "markdown" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -354,6 +420,64 @@ "spec": { "pluginVersion": "", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [ { "targetBlank": false, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/feature-templating/v0alpha1.testdata-datalinks.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/feature-templating/v0alpha1.testdata-datalinks.v42.v2beta1.json index 2450d74b2f2..62b30aa6480 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/feature-templating/v0alpha1.testdata-datalinks.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/feature-templating/v0alpha1.testdata-datalinks.v42.v2beta1.json @@ -91,6 +91,64 @@ "version": "", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [ { "targetBlank": false, @@ -314,7 +372,15 @@ "group": "text", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "text", + "originalOptions": { + "content": "## Data link variables overview\n\nThis dashboard presents variables that one can use when creating *data links*. All links redirect to this dashboard and this panel represents the values that were interpolated in the link that was clicked.\n\n\n#### Series variables\n1. **Name:** \u003cspan style=\"color: orange;\"\u003e$seriesName\u003c/span\u003e\n2. **label.datacenter:** \u003cspan style=\"color: orange;\"\u003e$labelDatacenter\u003c/span\u003e\n3. **label.datacenter.region:** \u003cspan style=\"color: orange;\"\u003e$labelDatacenterRegion\u003c/span\u003e\n\n#### Field variables\n1. **Name:** \u003cspan style=\"color: orange;\"\u003e$fieldName\u003c/span\u003e\n\n#### Value variables\n1. **Time:** \u003cspan style=\"color: orange;\"\u003e$valueTime\u003c/span\u003e\n2. **Numeric:** \u003cspan style=\"color: orange;\"\u003e$valueNumeric\u003c/span\u003e\n3. **Text:** \u003cspan style=\"color: orange;\"\u003e$valueText\u003c/span\u003e\n4. **Calc:** \u003cspan style=\"color: orange;\"\u003e$valueCalc\u003c/span\u003e\n\n", + "mode": "markdown" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -367,6 +433,64 @@ "version": "", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [ { "targetBlank": false, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/feature-templating/v0alpha1.testdata-nested-variables-drilldown.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/feature-templating/v0alpha1.testdata-nested-variables-drilldown.v42.v2alpha1.json index 710a4bc0280..f754cbd766a 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/feature-templating/v0alpha1.testdata-nested-variables-drilldown.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/feature-templating/v0alpha1.testdata-nested-variables-drilldown.v42.v2alpha1.json @@ -62,6 +62,64 @@ "spec": { "pluginVersion": "", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -109,7 +167,15 @@ "kind": "text", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "text", + "originalOptions": { + "content": "## Data center = $datacenter\n\n### server = $server\n\n#### pod = $pod", + "mode": "markdown" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -163,7 +229,68 @@ "kind": "stat", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "singlestat", + "originalOptions": { + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "nullPointMode": "connected", + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "thresholds": "", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/feature-templating/v0alpha1.testdata-nested-variables-drilldown.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/feature-templating/v0alpha1.testdata-nested-variables-drilldown.v42.v2beta1.json index d93a4dca40f..8a8cffdf465 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/feature-templating/v0alpha1.testdata-nested-variables-drilldown.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/feature-templating/v0alpha1.testdata-nested-variables-drilldown.v42.v2beta1.json @@ -67,6 +67,64 @@ "version": "", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -116,7 +174,15 @@ "group": "text", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "text", + "originalOptions": { + "content": "## Data center = $datacenter\n\n### server = $server\n\n#### pod = $pod", + "mode": "markdown" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -172,7 +238,68 @@ "group": "stat", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "singlestat", + "originalOptions": { + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "nullPointMode": "connected", + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "thresholds": "", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/feature-templating/v0alpha1.testdata-nested-variables.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/feature-templating/v0alpha1.testdata-nested-variables.v42.v2alpha1.json index 1fb39d454b9..89857905689 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/feature-templating/v0alpha1.testdata-nested-variables.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/feature-templating/v0alpha1.testdata-nested-variables.v42.v2alpha1.json @@ -167,6 +167,65 @@ "spec": { "pluginVersion": "", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -214,7 +273,15 @@ "kind": "text", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "text", + "originalOptions": { + "content": "## Data center = $datacenter\n\n### server = $server\n\n#### pod = $pod", + "mode": "markdown" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -264,7 +331,59 @@ "kind": "stat", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "singlestat", + "originalOptions": { + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "mappingType": 1, + "mappingTypes": [], + "nullPointMode": "connected", + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "thresholds": "", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/feature-templating/v0alpha1.testdata-nested-variables.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/feature-templating/v0alpha1.testdata-nested-variables.v42.v2beta1.json index ed73f35670a..13320b47904 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/feature-templating/v0alpha1.testdata-nested-variables.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/feature-templating/v0alpha1.testdata-nested-variables.v42.v2beta1.json @@ -174,6 +174,65 @@ "version": "", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -223,7 +282,15 @@ "group": "text", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "text", + "originalOptions": { + "content": "## Data center = $datacenter\n\n### server = $server\n\n#### pod = $pod", + "mode": "markdown" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -276,7 +343,59 @@ "group": "stat", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "singlestat", + "originalOptions": { + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "mappingType": 1, + "mappingTypes": [], + "nullPointMode": "connected", + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "thresholds": "", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/feature-templating/v0alpha1.testdata-variables-textbox.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/feature-templating/v0alpha1.testdata-variables-textbox.v42.v2alpha1.json index 3b34a0fd26e..81d61c2509b 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/feature-templating/v0alpha1.testdata-variables-textbox.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/feature-templating/v0alpha1.testdata-variables-textbox.v42.v2alpha1.json @@ -171,6 +171,65 @@ "spec": { "pluginVersion": "7.2.0-pre", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "alertThreshold": true }, "fieldConfig": { diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/feature-templating/v0alpha1.testdata-variables-textbox.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/feature-templating/v0alpha1.testdata-variables-textbox.v42.v2beta1.json index 6379e2a3191..01936dded6b 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/feature-templating/v0alpha1.testdata-variables-textbox.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/feature-templating/v0alpha1.testdata-variables-textbox.v42.v2beta1.json @@ -177,6 +177,65 @@ "version": "7.2.0-pre", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "alertThreshold": true }, "fieldConfig": { diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/feature-templating/v0alpha1.testdata-variables-that-update-on-time-change.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/feature-templating/v0alpha1.testdata-variables-that-update-on-time-change.v42.v2alpha1.json index 67579b40d8c..7eb15579259 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/feature-templating/v0alpha1.testdata-variables-that-update-on-time-change.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/feature-templating/v0alpha1.testdata-variables-that-update-on-time-change.v42.v2alpha1.json @@ -84,6 +84,67 @@ "spec": { "pluginVersion": "", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": true, + "rightSide": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/feature-templating/v0alpha1.testdata-variables-that-update-on-time-change.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/feature-templating/v0alpha1.testdata-variables-that-update-on-time-change.v42.v2beta1.json index d7c1db61b49..c89000daee7 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/feature-templating/v0alpha1.testdata-variables-that-update-on-time-change.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/feature-templating/v0alpha1.testdata-variables-that-update-on-time-change.v42.v2beta1.json @@ -89,6 +89,67 @@ "version": "", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": true, + "rightSide": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/migrations/v0alpha1.migrations.v42.v1beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/migrations/v0alpha1.migrations.v42.v1beta1.json index 5ae52076acc..7542cf17652 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/migrations/v0alpha1.migrations.v42.v1beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/migrations/v0alpha1.migrations.v42.v1beta1.json @@ -296,6 +296,7 @@ } }, { + "content": "# Graph panel \u003e\u003e Timeseries panel\n\nKnown issues:\n* hiding null/empty series\n* time regions", "datasource": { "type": "grafana-testdata-datasource" }, @@ -306,15 +307,7 @@ "y": 0 }, "id": 6, - "options": { - "code": { - "language": "plaintext", - "showLineNumbers": false, - "showMiniMap": false - }, - "content": "# Graph panel \u003e\u003e Timeseries panel\n\nKnown issues:\n* hiding null/empty series\n* time regions", - "mode": "markdown" - }, + "mode": "markdown", "pluginVersion": "11.0.0-pre", "targets": [ { diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/migrations/v0alpha1.migrations.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/migrations/v0alpha1.migrations.v42.v2alpha1.json index 2ad3f371914..21d45e91f10 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/migrations/v0alpha1.migrations.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/migrations/v0alpha1.migrations.v42.v2alpha1.json @@ -123,6 +123,42 @@ "spec": { "pluginVersion": "9.5.0-pre", "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "columns": [], + "fontSize": "100%", + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "align": "auto", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "date" + }, + { + "alias": "", + "align": "right", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "number", + "unit": "short" + } + ], + "transform": "table" + } + }, "cellHeight": "sm", "footer": { "countRows": false, @@ -270,6 +306,10 @@ "spec": { "pluginVersion": "9.5.0-pre", "options": { + "__angularMigration": { + "autoMigrateFrom": "grafana-piechart-panel", + "originalOptions": {} + }, "legend": { "displayMode": "list", "placement": "bottom", @@ -402,6 +442,41 @@ "spec": { "pluginVersion": "10.4.0-pre", "options": { + "__angularMigration": { + "autoMigrateFrom": "grafana-worldmap-panel", + "originalOptions": { + "circleMaxSize": 30, + "circleMinSize": 2, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 0, + "esMetric": "Count", + "hideEmpty": false, + "hideZero": false, + "initialZoom": 1, + "locationData": "countries", + "mapCenter": "(0°, 0°)", + "mapCenterLatitude": 0, + "mapCenterLongitude": 0, + "mouseWheelZoom": false, + "showLegend": true, + "stickyLabels": false, + "tableQueryOptions": { + "geohashField": "geohash", + "latitudeField": "latitude", + "longitudeField": "longitude", + "metricField": "metric", + "queryType": "geohash" + }, + "thresholds": "0,10", + "unitPlural": "", + "unitSingle": "", + "valueName": "total" + } + }, "basemap": { "name": "Basemap", "type": "default" @@ -562,6 +637,69 @@ "spec": { "pluginVersion": "11.0.0-pre", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": false, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "series", + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "$$hashKey": "object:88", + "format": "short", + "logBase": 1, + "show": true + }, + { + "$$hashKey": "object:89", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "alertThreshold": true, "legend": { "calcs": [], @@ -667,6 +805,67 @@ "spec": { "pluginVersion": "11.0.0-pre", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": false, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "histogram", + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:193", + "format": "short", + "logBase": 1, + "show": true + }, + { + "$$hashKey": "object:194", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "alertThreshold": true, "legend": { "calcs": [], @@ -775,6 +974,70 @@ "spec": { "pluginVersion": "11.3.0-pre", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": false, + "show": true, + "total": false, + "values": true + }, + "lines": false, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "series", + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "$$hashKey": "object:88", + "format": "short", + "logBase": 1, + "show": true + }, + { + "$$hashKey": "object:89", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "alertThreshold": true, "legend": { "calcs": [], @@ -880,6 +1143,65 @@ "spec": { "pluginVersion": "11.0.0-pre", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "alertThreshold": true, "legend": { "calcs": [], @@ -934,13 +1256,13 @@ "spec": { "pluginVersion": "11.0.0-pre", "options": { - "code": { - "language": "plaintext", - "showLineNumbers": false, - "showMiniMap": false - }, - "content": "# Graph panel \u003e\u003e Timeseries panel\n\nKnown issues:\n* hiding null/empty series\n* time regions", - "mode": "markdown" + "__angularMigration": { + "autoMigrateFrom": "text", + "originalOptions": { + "content": "# Graph panel \u003e\u003e Timeseries panel\n\nKnown issues:\n* hiding null/empty series\n* time regions", + "mode": "markdown" + } + } }, "fieldConfig": { "defaults": {}, @@ -1031,7 +1353,68 @@ "kind": "stat", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "grafana-singlestat-panel", + "originalOptions": { + "colorBackground": false, + "colorValue": true, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "format": "areaF2", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "nullPointMode": "connected", + "postfix": "b", + "postfixFontSize": "50%", + "prefix": "a", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "thresholds": "", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/migrations/v0alpha1.migrations.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/migrations/v0alpha1.migrations.v42.v2beta1.json index 5e8d1db63c1..ed7123f5e38 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/migrations/v0alpha1.migrations.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/migrations/v0alpha1.migrations.v42.v2beta1.json @@ -130,6 +130,42 @@ "version": "9.5.0-pre", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "columns": [], + "fontSize": "100%", + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "align": "auto", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "date" + }, + { + "alias": "", + "align": "right", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "number", + "unit": "short" + } + ], + "transform": "table" + } + }, "cellHeight": "sm", "footer": { "countRows": false, @@ -283,6 +319,10 @@ "version": "9.5.0-pre", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "grafana-piechart-panel", + "originalOptions": {} + }, "legend": { "displayMode": "list", "placement": "bottom", @@ -421,6 +461,41 @@ "version": "10.4.0-pre", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "grafana-worldmap-panel", + "originalOptions": { + "circleMaxSize": 30, + "circleMinSize": 2, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 0, + "esMetric": "Count", + "hideEmpty": false, + "hideZero": false, + "initialZoom": 1, + "locationData": "countries", + "mapCenter": "(0°, 0°)", + "mapCenterLatitude": 0, + "mapCenterLongitude": 0, + "mouseWheelZoom": false, + "showLegend": true, + "stickyLabels": false, + "tableQueryOptions": { + "geohashField": "geohash", + "latitudeField": "latitude", + "longitudeField": "longitude", + "metricField": "metric", + "queryType": "geohash" + }, + "thresholds": "0,10", + "unitPlural": "", + "unitSingle": "", + "valueName": "total" + } + }, "basemap": { "name": "Basemap", "type": "default" @@ -587,6 +662,69 @@ "version": "11.0.0-pre", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": false, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "series", + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "$$hashKey": "object:88", + "format": "short", + "logBase": 1, + "show": true + }, + { + "$$hashKey": "object:89", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "alertThreshold": true, "legend": { "calcs": [], @@ -698,6 +836,67 @@ "version": "11.0.0-pre", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": false, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "histogram", + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:193", + "format": "short", + "logBase": 1, + "show": true + }, + { + "$$hashKey": "object:194", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "alertThreshold": true, "legend": { "calcs": [], @@ -811,6 +1010,70 @@ "version": "11.3.0-pre", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": false, + "show": true, + "total": false, + "values": true + }, + "lines": false, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "series", + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "$$hashKey": "object:88", + "format": "short", + "logBase": 1, + "show": true + }, + { + "$$hashKey": "object:89", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "alertThreshold": true, "legend": { "calcs": [], @@ -922,6 +1185,65 @@ "version": "11.0.0-pre", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "alertThreshold": true, "legend": { "calcs": [], @@ -979,13 +1301,13 @@ "version": "11.0.0-pre", "spec": { "options": { - "code": { - "language": "plaintext", - "showLineNumbers": false, - "showMiniMap": false - }, - "content": "# Graph panel \u003e\u003e Timeseries panel\n\nKnown issues:\n* hiding null/empty series\n* time regions", - "mode": "markdown" + "__angularMigration": { + "autoMigrateFrom": "text", + "originalOptions": { + "content": "# Graph panel \u003e\u003e Timeseries panel\n\nKnown issues:\n* hiding null/empty series\n* time regions", + "mode": "markdown" + } + } }, "fieldConfig": { "defaults": {}, @@ -1082,7 +1404,68 @@ "group": "stat", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "grafana-singlestat-panel", + "originalOptions": { + "colorBackground": false, + "colorValue": true, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "format": "areaF2", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "nullPointMode": "connected", + "postfix": "b", + "postfixFontSize": "50%", + "prefix": "a", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "thresholds": "", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-common/v0alpha1.auto_decimals.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-common/v0alpha1.auto_decimals.v42.v2alpha1.json index 1cb5a102169..42c2a374b1c 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-common/v0alpha1.auto_decimals.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-common/v0alpha1.auto_decimals.v42.v2alpha1.json @@ -66,6 +66,66 @@ "spec": { "pluginVersion": "", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": "", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -115,6 +175,66 @@ "spec": { "pluginVersion": "", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "logBase": 1, + "max": "10000", + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -164,6 +284,66 @@ "spec": { "pluginVersion": "", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "none", + "logBase": 1, + "max": "10000", + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -213,6 +393,66 @@ "spec": { "pluginVersion": "", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "logBase": 1, + "max": "10000", + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -262,6 +502,64 @@ "spec": { "pluginVersion": "", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "µs", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -311,6 +609,66 @@ "spec": { "pluginVersion": "", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "max": "10000", + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -360,6 +718,64 @@ "spec": { "pluginVersion": "", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -409,6 +825,66 @@ "spec": { "pluginVersion": "", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "none", + "logBase": 1, + "max": "10000", + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -458,6 +934,66 @@ "spec": { "pluginVersion": "", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "logBase": 1, + "max": "10000", + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -507,6 +1043,64 @@ "spec": { "pluginVersion": "", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -556,6 +1150,66 @@ "spec": { "pluginVersion": "", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "max": "10000", + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -605,6 +1259,64 @@ "spec": { "pluginVersion": "", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -654,6 +1366,65 @@ "spec": { "pluginVersion": "", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-common/v0alpha1.auto_decimals.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-common/v0alpha1.auto_decimals.v42.v2beta1.json index 6def9ba580b..c1013a5bdcd 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-common/v0alpha1.auto_decimals.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-common/v0alpha1.auto_decimals.v42.v2beta1.json @@ -70,6 +70,66 @@ "version": "", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": "", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -121,6 +181,66 @@ "version": "", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "logBase": 1, + "max": "10000", + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -172,6 +292,66 @@ "version": "", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "none", + "logBase": 1, + "max": "10000", + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -223,6 +403,66 @@ "version": "", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "logBase": 1, + "max": "10000", + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -274,6 +514,64 @@ "version": "", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "µs", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -325,6 +623,66 @@ "version": "", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "max": "10000", + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -376,6 +734,64 @@ "version": "", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -427,6 +843,66 @@ "version": "", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "none", + "logBase": 1, + "max": "10000", + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -478,6 +954,66 @@ "version": "", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "logBase": 1, + "max": "10000", + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -529,6 +1065,64 @@ "version": "", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -580,6 +1174,66 @@ "version": "", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "max": "10000", + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -631,6 +1285,64 @@ "version": "", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -682,6 +1394,65 @@ "version": "", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-common/v0alpha1.lazy_loading.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-common/v0alpha1.lazy_loading.v42.v2alpha1.json index e394514efd5..92b60103171 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-common/v0alpha1.lazy_loading.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-common/v0alpha1.lazy_loading.v42.v2alpha1.json @@ -132,7 +132,68 @@ "kind": "stat", "spec": { "pluginVersion": "6.2.0-pre", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "singlestat", + "originalOptions": { + "colorBackground": false, + "colorValue": true, + "colors": [ + "#299c46", + "#73BF69", + "#d44a3a" + ], + "format": "ms", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "nullPointMode": "connected", + "postfix": "", + "postfixFontSize": "50%", + "prefix": "p99", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "thresholds": "", + "valueFontSize": "120%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -176,7 +237,68 @@ "kind": "stat", "spec": { "pluginVersion": "6.2.0-pre", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "singlestat", + "originalOptions": { + "colorBackground": false, + "colorValue": true, + "colors": [ + "#299c46", + "#73BF69", + "#d44a3a" + ], + "format": "ms", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "nullPointMode": "connected", + "postfix": "", + "postfixFontSize": "50%", + "prefix": "p95", + "prefixFontSize": "80%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "thresholds": "", + "valueFontSize": "120%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -220,7 +342,68 @@ "kind": "stat", "spec": { "pluginVersion": "6.2.0-pre", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "singlestat", + "originalOptions": { + "colorBackground": false, + "colorValue": true, + "colors": [ + "#299c46", + "#73BF69", + "#d44a3a" + ], + "format": "ms", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "nullPointMode": "connected", + "postfix": "", + "postfixFontSize": "50%", + "prefix": "p90", + "prefixFontSize": "80%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "thresholds": "", + "valueFontSize": "120%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -302,6 +485,71 @@ "spec": { "pluginVersion": "6.2.0-pre", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": { + "A-series": "blue", + "B-series": "dark-purple", + "C-series": "purple", + "Q-series": "dark-blue" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 3, + "fillGradient": 0, + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -347,6 +595,66 @@ "spec": { "pluginVersion": "", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": { + "A-series": "blue" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 5, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -392,6 +700,66 @@ "spec": { "pluginVersion": "", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": { + "A-series": "red" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 10, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -476,6 +844,71 @@ "spec": { "pluginVersion": "6.2.0-pre", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": { + "A-series": "blue", + "B-series": "dark-purple", + "C-series": "purple", + "Q-series": "dark-blue" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 3, + "fillGradient": 0, + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -521,6 +954,64 @@ "spec": { "pluginVersion": "", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 8, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -566,7 +1057,68 @@ "kind": "stat", "spec": { "pluginVersion": "6.2.0-pre", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "singlestat", + "originalOptions": { + "colorBackground": false, + "colorValue": true, + "colors": [ + "#299c46", + "#73BF69", + "#d44a3a" + ], + "format": "ms", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "nullPointMode": "connected", + "postfix": "", + "postfixFontSize": "50%", + "prefix": "p90", + "prefixFontSize": "80%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "thresholds": "", + "valueFontSize": "120%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -610,6 +1162,66 @@ "spec": { "pluginVersion": "", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": { + "A-series": "green" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 5, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -655,6 +1267,66 @@ "spec": { "pluginVersion": "", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": { + "A-series": "blue" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 5, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -700,6 +1372,66 @@ "spec": { "pluginVersion": "", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": { + "A-series": "green" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 5, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -745,6 +1477,66 @@ "spec": { "pluginVersion": "", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": { + "A-series": "green" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 5, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -790,6 +1582,66 @@ "spec": { "pluginVersion": "", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": { + "A-series": "blue" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 5, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -835,6 +1687,66 @@ "spec": { "pluginVersion": "", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": { + "A-series": "purple" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 5, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -880,6 +1792,66 @@ "spec": { "pluginVersion": "", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": { + "A-series": "orange" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 5, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -964,6 +1936,71 @@ "spec": { "pluginVersion": "6.2.0-pre", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": { + "A-series": "blue", + "B-series": "dark-purple", + "C-series": "purple", + "Q-series": "dark-blue" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 3, + "fillGradient": 0, + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -1009,6 +2046,66 @@ "spec": { "pluginVersion": "", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": { + "A-series": "green" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 5, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -1054,6 +2151,66 @@ "spec": { "pluginVersion": "", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": { + "A-series": "blue" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 5, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -1099,6 +2256,66 @@ "spec": { "pluginVersion": "", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": { + "A-series": "purple" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 5, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -1144,6 +2361,66 @@ "spec": { "pluginVersion": "", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": { + "A-series": "orange" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 5, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-common/v0alpha1.lazy_loading.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-common/v0alpha1.lazy_loading.v42.v2beta1.json index eb82d064496..b1b07fa0f56 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-common/v0alpha1.lazy_loading.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-common/v0alpha1.lazy_loading.v42.v2beta1.json @@ -140,7 +140,68 @@ "group": "stat", "version": "6.2.0-pre", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "singlestat", + "originalOptions": { + "colorBackground": false, + "colorValue": true, + "colors": [ + "#299c46", + "#73BF69", + "#d44a3a" + ], + "format": "ms", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "nullPointMode": "connected", + "postfix": "", + "postfixFontSize": "50%", + "prefix": "p99", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "thresholds": "", + "valueFontSize": "120%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -187,7 +248,68 @@ "group": "stat", "version": "6.2.0-pre", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "singlestat", + "originalOptions": { + "colorBackground": false, + "colorValue": true, + "colors": [ + "#299c46", + "#73BF69", + "#d44a3a" + ], + "format": "ms", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "nullPointMode": "connected", + "postfix": "", + "postfixFontSize": "50%", + "prefix": "p95", + "prefixFontSize": "80%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "thresholds": "", + "valueFontSize": "120%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -234,7 +356,68 @@ "group": "stat", "version": "6.2.0-pre", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "singlestat", + "originalOptions": { + "colorBackground": false, + "colorValue": true, + "colors": [ + "#299c46", + "#73BF69", + "#d44a3a" + ], + "format": "ms", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "nullPointMode": "connected", + "postfix": "", + "postfixFontSize": "50%", + "prefix": "p90", + "prefixFontSize": "80%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "thresholds": "", + "valueFontSize": "120%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -325,6 +508,71 @@ "version": "6.2.0-pre", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": { + "A-series": "blue", + "B-series": "dark-purple", + "C-series": "purple", + "Q-series": "dark-blue" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 3, + "fillGradient": 0, + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -373,6 +621,66 @@ "version": "", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": { + "A-series": "blue" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 5, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -421,6 +729,66 @@ "version": "", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": { + "A-series": "red" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 10, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -514,6 +882,71 @@ "version": "6.2.0-pre", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": { + "A-series": "blue", + "B-series": "dark-purple", + "C-series": "purple", + "Q-series": "dark-blue" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 3, + "fillGradient": 0, + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -562,6 +995,64 @@ "version": "", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 8, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -610,7 +1101,68 @@ "group": "stat", "version": "6.2.0-pre", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "singlestat", + "originalOptions": { + "colorBackground": false, + "colorValue": true, + "colors": [ + "#299c46", + "#73BF69", + "#d44a3a" + ], + "format": "ms", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "nullPointMode": "connected", + "postfix": "", + "postfixFontSize": "50%", + "prefix": "p90", + "prefixFontSize": "80%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "thresholds": "", + "valueFontSize": "120%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -657,6 +1209,66 @@ "version": "", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": { + "A-series": "green" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 5, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -705,6 +1317,66 @@ "version": "", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": { + "A-series": "blue" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 5, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -753,6 +1425,66 @@ "version": "", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": { + "A-series": "green" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 5, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -801,6 +1533,66 @@ "version": "", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": { + "A-series": "green" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 5, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -849,6 +1641,66 @@ "version": "", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": { + "A-series": "blue" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 5, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -897,6 +1749,66 @@ "version": "", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": { + "A-series": "purple" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 5, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -945,6 +1857,66 @@ "version": "", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": { + "A-series": "orange" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 5, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -1038,6 +2010,71 @@ "version": "6.2.0-pre", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": { + "A-series": "blue", + "B-series": "dark-purple", + "C-series": "purple", + "Q-series": "dark-blue" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 3, + "fillGradient": 0, + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -1086,6 +2123,66 @@ "version": "", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": { + "A-series": "green" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 5, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -1134,6 +2231,66 @@ "version": "", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": { + "A-series": "blue" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 5, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -1182,6 +2339,66 @@ "version": "", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": { + "A-series": "purple" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 5, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -1230,6 +2447,66 @@ "version": "", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": { + "A-series": "orange" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 5, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-common/v0alpha1.panels_without_title.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-common/v0alpha1.panels_without_title.v42.v2alpha1.json index d759c27c39b..0572d6b73c0 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-common/v0alpha1.panels_without_title.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-common/v0alpha1.panels_without_title.v42.v2alpha1.json @@ -67,7 +67,68 @@ "kind": "stat", "spec": { "pluginVersion": "6.2.0-pre", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "singlestat", + "originalOptions": { + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": true, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "nullPointMode": "connected", + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "thresholds": "", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -258,7 +319,65 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -354,7 +473,68 @@ "kind": "stat", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "singlestat", + "originalOptions": { + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "#5794F2", + "#d44a3a" + ], + "format": "ms", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "nullPointMode": "connected", + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "100%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "thresholds": "", + "valueFontSize": "120%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -515,7 +695,68 @@ "kind": "stat", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "singlestat", + "originalOptions": { + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "#5794F2", + "#d44a3a" + ], + "format": "ms", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "nullPointMode": "connected", + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "100%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "thresholds": "", + "valueFontSize": "120%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -676,7 +917,65 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -819,7 +1118,68 @@ "kind": "stat", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "singlestat", + "originalOptions": { + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "#5794F2", + "#d44a3a" + ], + "format": "ms", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "nullPointMode": "connected", + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "100%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "thresholds": "", + "valueFontSize": "120%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-common/v0alpha1.panels_without_title.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-common/v0alpha1.panels_without_title.v42.v2beta1.json index 1143716a2b3..deca04a6634 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-common/v0alpha1.panels_without_title.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-common/v0alpha1.panels_without_title.v42.v2beta1.json @@ -71,7 +71,68 @@ "group": "stat", "version": "6.2.0-pre", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "singlestat", + "originalOptions": { + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": true, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "nullPointMode": "connected", + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": false + }, + "tableColumn": "", + "thresholds": "", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -268,7 +329,65 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -368,7 +487,68 @@ "group": "stat", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "singlestat", + "originalOptions": { + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "#5794F2", + "#d44a3a" + ], + "format": "ms", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "nullPointMode": "connected", + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "100%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "thresholds": "", + "valueFontSize": "120%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -534,7 +714,68 @@ "group": "stat", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "singlestat", + "originalOptions": { + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "#5794F2", + "#d44a3a" + ], + "format": "ms", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "nullPointMode": "connected", + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "100%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "thresholds": "", + "valueFontSize": "120%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -700,7 +941,65 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -847,7 +1146,68 @@ "group": "stat", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "singlestat", + "originalOptions": { + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "#5794F2", + "#d44a3a" + ], + "format": "ms", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "nullPointMode": "connected", + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "100%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "thresholds": "", + "valueFontSize": "120%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-gauge/v0alpha1.gauge_tests.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-gauge/v0alpha1.gauge_tests.v42.v2alpha1.json index 77874ee6291..fe4271d08e7 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-gauge/v0alpha1.gauge_tests.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-gauge/v0alpha1.gauge_tests.v42.v2alpha1.json @@ -62,6 +62,12 @@ "spec": { "pluginVersion": "7.4.0-pre", "options": { + "__angularMigration": { + "autoMigrateFrom": "gauge", + "originalOptions": { + "nullPointMode": "null" + } + }, "baseColor": "#299c46", "reduceOptions": { "calcs": [ @@ -151,6 +157,12 @@ "spec": { "pluginVersion": "7.4.0-pre", "options": { + "__angularMigration": { + "autoMigrateFrom": "gauge", + "originalOptions": { + "nullPointMode": "null" + } + }, "baseColor": "#299c46", "reduceOptions": { "calcs": [ @@ -241,6 +253,12 @@ "spec": { "pluginVersion": "7.4.0-pre", "options": { + "__angularMigration": { + "autoMigrateFrom": "gauge", + "originalOptions": { + "nullPointMode": "null" + } + }, "baseColor": "#299c46", "reduceOptions": { "calcs": [ @@ -320,6 +338,12 @@ "spec": { "pluginVersion": "7.4.0-pre", "options": { + "__angularMigration": { + "autoMigrateFrom": "gauge", + "originalOptions": { + "nullPointMode": "null" + } + }, "baseColor": "#299c46", "reduceOptions": { "calcs": [ @@ -401,6 +425,12 @@ "spec": { "pluginVersion": "7.4.0-pre", "options": { + "__angularMigration": { + "autoMigrateFrom": "gauge", + "originalOptions": { + "nullPointMode": "null" + } + }, "baseColor": "#299c46", "reduceOptions": { "calcs": [ @@ -480,6 +510,12 @@ "spec": { "pluginVersion": "7.4.0-pre", "options": { + "__angularMigration": { + "autoMigrateFrom": "gauge", + "originalOptions": { + "nullPointMode": "null" + } + }, "baseColor": "#299c46", "reduceOptions": { "calcs": [ @@ -559,6 +595,12 @@ "spec": { "pluginVersion": "7.4.0-pre", "options": { + "__angularMigration": { + "autoMigrateFrom": "gauge", + "originalOptions": { + "nullPointMode": "null" + } + }, "baseColor": "#299c46", "reduceOptions": { "calcs": [ @@ -639,6 +681,12 @@ "spec": { "pluginVersion": "7.4.0-pre", "options": { + "__angularMigration": { + "autoMigrateFrom": "gauge", + "originalOptions": { + "nullPointMode": "null" + } + }, "baseColor": "#299c46", "reduceOptions": { "calcs": [ @@ -730,6 +778,12 @@ "spec": { "pluginVersion": "7.4.0-pre", "options": { + "__angularMigration": { + "autoMigrateFrom": "gauge", + "originalOptions": { + "nullPointMode": "null" + } + }, "baseColor": "#299c46", "reduceOptions": { "calcs": [ @@ -927,6 +981,12 @@ "spec": { "pluginVersion": "7.4.0-pre", "options": { + "__angularMigration": { + "autoMigrateFrom": "gauge", + "originalOptions": { + "nullPointMode": "null" + } + }, "baseColor": "#299c46", "reduceOptions": { "calcs": [ @@ -1006,6 +1066,12 @@ "spec": { "pluginVersion": "7.4.0-pre", "options": { + "__angularMigration": { + "autoMigrateFrom": "gauge", + "originalOptions": { + "nullPointMode": "null" + } + }, "baseColor": "#299c46", "reduceOptions": { "calcs": [ @@ -1085,6 +1151,12 @@ "spec": { "pluginVersion": "7.4.0-pre", "options": { + "__angularMigration": { + "autoMigrateFrom": "gauge", + "originalOptions": { + "nullPointMode": "null" + } + }, "baseColor": "#299c46", "reduceOptions": { "calcs": [ diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-gauge/v0alpha1.gauge_tests.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-gauge/v0alpha1.gauge_tests.v42.v2beta1.json index 663abfbf74c..261cd5228db 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-gauge/v0alpha1.gauge_tests.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-gauge/v0alpha1.gauge_tests.v42.v2beta1.json @@ -67,6 +67,12 @@ "version": "7.4.0-pre", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "gauge", + "originalOptions": { + "nullPointMode": "null" + } + }, "baseColor": "#299c46", "reduceOptions": { "calcs": [ @@ -159,6 +165,12 @@ "version": "7.4.0-pre", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "gauge", + "originalOptions": { + "nullPointMode": "null" + } + }, "baseColor": "#299c46", "reduceOptions": { "calcs": [ @@ -252,6 +264,12 @@ "version": "7.4.0-pre", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "gauge", + "originalOptions": { + "nullPointMode": "null" + } + }, "baseColor": "#299c46", "reduceOptions": { "calcs": [ @@ -334,6 +352,12 @@ "version": "7.4.0-pre", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "gauge", + "originalOptions": { + "nullPointMode": "null" + } + }, "baseColor": "#299c46", "reduceOptions": { "calcs": [ @@ -418,6 +442,12 @@ "version": "7.4.0-pre", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "gauge", + "originalOptions": { + "nullPointMode": "null" + } + }, "baseColor": "#299c46", "reduceOptions": { "calcs": [ @@ -500,6 +530,12 @@ "version": "7.4.0-pre", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "gauge", + "originalOptions": { + "nullPointMode": "null" + } + }, "baseColor": "#299c46", "reduceOptions": { "calcs": [ @@ -582,6 +618,12 @@ "version": "7.4.0-pre", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "gauge", + "originalOptions": { + "nullPointMode": "null" + } + }, "baseColor": "#299c46", "reduceOptions": { "calcs": [ @@ -665,6 +707,12 @@ "version": "7.4.0-pre", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "gauge", + "originalOptions": { + "nullPointMode": "null" + } + }, "baseColor": "#299c46", "reduceOptions": { "calcs": [ @@ -759,6 +807,12 @@ "version": "7.4.0-pre", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "gauge", + "originalOptions": { + "nullPointMode": "null" + } + }, "baseColor": "#299c46", "reduceOptions": { "calcs": [ @@ -961,6 +1015,12 @@ "version": "7.4.0-pre", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "gauge", + "originalOptions": { + "nullPointMode": "null" + } + }, "baseColor": "#299c46", "reduceOptions": { "calcs": [ @@ -1043,6 +1103,12 @@ "version": "7.4.0-pre", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "gauge", + "originalOptions": { + "nullPointMode": "null" + } + }, "baseColor": "#299c46", "reduceOptions": { "calcs": [ @@ -1125,6 +1191,12 @@ "version": "7.4.0-pre", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "gauge", + "originalOptions": { + "nullPointMode": "null" + } + }, "baseColor": "#299c46", "reduceOptions": { "calcs": [ diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-graph/v0alpha1.graph-gradient-area-fills.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-graph/v0alpha1.graph-gradient-area-fills.v42.v2alpha1.json index 12c84560a90..ef393dae560 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-graph/v0alpha1.graph-gradient-area-fills.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-graph/v0alpha1.graph-gradient-area-fills.v42.v2alpha1.json @@ -66,7 +66,68 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": { + "A-series": "green" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "fillGradient": 10, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -114,7 +175,68 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": { + "A-series": "rgb(87, 186, 242)" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 4, + "fillGradient": 4, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -162,7 +284,68 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": { + "A-series": "rgb(48, 139, 237)" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 5, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -210,7 +393,68 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": { + "A-series": "red" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 5, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decgbytes", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-graph/v0alpha1.graph-gradient-area-fills.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-graph/v0alpha1.graph-gradient-area-fills.v42.v2beta1.json index 9ae939f5d4f..e6def19e038 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-graph/v0alpha1.graph-gradient-area-fills.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-graph/v0alpha1.graph-gradient-area-fills.v42.v2beta1.json @@ -70,7 +70,68 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": { + "A-series": "green" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "fillGradient": 10, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 0, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -120,7 +181,68 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": { + "A-series": "rgb(87, 186, 242)" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 4, + "fillGradient": 4, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -170,7 +292,68 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": { + "A-series": "rgb(48, 139, 237)" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 5, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -220,7 +403,68 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": { + "A-series": "red" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 5, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decgbytes", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-graph/v0alpha1.graph-shared-tooltips.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-graph/v0alpha1.graph-shared-tooltips.v42.v2alpha1.json index e0203a652e2..6aab259eb23 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-graph/v0alpha1.graph-shared-tooltips.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-graph/v0alpha1.graph-shared-tooltips.v42.v2alpha1.json @@ -63,6 +63,65 @@ "spec": { "pluginVersion": "7.5.0-pre", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "alertThreshold": true }, "fieldConfig": { @@ -700,6 +759,65 @@ "spec": { "pluginVersion": "7.5.0-pre", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "celsius", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "alertThreshold": true }, "fieldConfig": { diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-graph/v0alpha1.graph-shared-tooltips.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-graph/v0alpha1.graph-shared-tooltips.v42.v2beta1.json index fe835b1b44e..2ba9ec92cb6 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-graph/v0alpha1.graph-shared-tooltips.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-graph/v0alpha1.graph-shared-tooltips.v42.v2beta1.json @@ -67,6 +67,65 @@ "version": "7.5.0-pre", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "alertThreshold": true }, "fieldConfig": { @@ -717,6 +776,65 @@ "version": "7.5.0-pre", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "celsius", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "alertThreshold": true }, "fieldConfig": { diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-graph/v0alpha1.graph-time-regions.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-graph/v0alpha1.graph-time-regions.v42.v2alpha1.json index e09a03ec44a..894c33abef1 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-graph/v0alpha1.graph-time-regions.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-graph/v0alpha1.graph-time-regions.v42.v2alpha1.json @@ -61,7 +61,78 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [ + { + "colorMode": "gray", + "fill": true, + "fillColor": "rgba(255, 255, 255, 0.03)", + "from": "08:30", + "fromDayOfWeek": 1, + "line": false, + "lineColor": "rgba(255, 255, 255, 0.2)", + "op": "time", + "to": "16:45", + "toDayOfWeek": 5 + } + ], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -104,7 +175,140 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": { + "A-series": "#d683ce" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 0.5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [ + { + "colorMode": "custom", + "fill": true, + "fillColor": "rgba(255, 0, 0, 0.22)", + "from": "", + "fromDayOfWeek": 1, + "line": true, + "lineColor": "rgba(255, 0, 0, 0.32)", + "op": "time", + "to": "", + "toDayOfWeek": 1 + }, + { + "colorMode": "custom", + "fill": true, + "fillColor": "rgba(255, 127, 0, 0.22)", + "fromDayOfWeek": 2, + "line": true, + "lineColor": "rgba(255, 127, 0, 0.32)", + "op": "time", + "toDayOfWeek": 2 + }, + { + "colorMode": "custom", + "fill": true, + "fillColor": "rgba(255, 255, 0, 0.22)", + "fromDayOfWeek": 3, + "line": true, + "lineColor": "rgba(255, 255, 0, 0.22)", + "op": "time", + "toDayOfWeek": 3 + }, + { + "colorMode": "custom", + "fill": true, + "fillColor": "rgba(0, 255, 0, 0.22)", + "fromDayOfWeek": 4, + "line": true, + "lineColor": "rgba(0, 255, 0, 0.32)", + "op": "time", + "toDayOfWeek": 4 + }, + { + "colorMode": "custom", + "fill": true, + "fillColor": "rgba(0, 0, 255, 0.22)", + "fromDayOfWeek": 5, + "line": true, + "lineColor": "rgba(0, 0, 255, 0.32)", + "op": "time", + "toDayOfWeek": 5 + }, + { + "colorMode": "custom", + "fill": true, + "fillColor": "rgba(75, 0, 130, 0.22)", + "fromDayOfWeek": 6, + "line": true, + "lineColor": "rgba(75, 0, 130, 0.32)", + "op": "time", + "toDayOfWeek": 6 + }, + { + "colorMode": "custom", + "fill": true, + "fillColor": "rgba(148, 0, 211, 0.22)", + "fromDayOfWeek": 7, + "line": true, + "lineColor": "rgba(148, 0, 211, 0.32)", + "op": "time", + "toDayOfWeek": 7 + } + ], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -150,7 +354,78 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [ + { + "colorMode": "red", + "fill": true, + "fillColor": "rgba(255, 255, 255, 0.03)", + "from": "20:00", + "fromDayOfWeek": 7, + "line": false, + "lineColor": "rgba(255, 255, 255, 0.2)", + "op": "time", + "to": "23:00", + "toDayOfWeek": 7 + } + ], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -196,7 +471,73 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [ + { + "colorMode": "red", + "fill": false, + "from": "05:00", + "line": true, + "op": "time" + } + ], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -238,7 +579,76 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [ + { + "colorMode": "gray", + "fill": true, + "fillColor": "rgba(234, 112, 112, 0.12)", + "from": "22:00", + "line": false, + "lineColor": "rgba(237, 46, 24, 0.60)", + "op": "time", + "to": "00:30" + } + ], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-graph/v0alpha1.graph-time-regions.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-graph/v0alpha1.graph-time-regions.v42.v2beta1.json index f6eaa477161..69aceb23017 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-graph/v0alpha1.graph-time-regions.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-graph/v0alpha1.graph-time-regions.v42.v2beta1.json @@ -66,7 +66,78 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [ + { + "colorMode": "gray", + "fill": true, + "fillColor": "rgba(255, 255, 255, 0.03)", + "from": "08:30", + "fromDayOfWeek": 1, + "line": false, + "lineColor": "rgba(255, 255, 255, 0.2)", + "op": "time", + "to": "16:45", + "toDayOfWeek": 5 + } + ], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -112,7 +183,140 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": { + "A-series": "#d683ce" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 0.5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [ + { + "colorMode": "custom", + "fill": true, + "fillColor": "rgba(255, 0, 0, 0.22)", + "from": "", + "fromDayOfWeek": 1, + "line": true, + "lineColor": "rgba(255, 0, 0, 0.32)", + "op": "time", + "to": "", + "toDayOfWeek": 1 + }, + { + "colorMode": "custom", + "fill": true, + "fillColor": "rgba(255, 127, 0, 0.22)", + "fromDayOfWeek": 2, + "line": true, + "lineColor": "rgba(255, 127, 0, 0.32)", + "op": "time", + "toDayOfWeek": 2 + }, + { + "colorMode": "custom", + "fill": true, + "fillColor": "rgba(255, 255, 0, 0.22)", + "fromDayOfWeek": 3, + "line": true, + "lineColor": "rgba(255, 255, 0, 0.22)", + "op": "time", + "toDayOfWeek": 3 + }, + { + "colorMode": "custom", + "fill": true, + "fillColor": "rgba(0, 255, 0, 0.22)", + "fromDayOfWeek": 4, + "line": true, + "lineColor": "rgba(0, 255, 0, 0.32)", + "op": "time", + "toDayOfWeek": 4 + }, + { + "colorMode": "custom", + "fill": true, + "fillColor": "rgba(0, 0, 255, 0.22)", + "fromDayOfWeek": 5, + "line": true, + "lineColor": "rgba(0, 0, 255, 0.32)", + "op": "time", + "toDayOfWeek": 5 + }, + { + "colorMode": "custom", + "fill": true, + "fillColor": "rgba(75, 0, 130, 0.22)", + "fromDayOfWeek": 6, + "line": true, + "lineColor": "rgba(75, 0, 130, 0.32)", + "op": "time", + "toDayOfWeek": 6 + }, + { + "colorMode": "custom", + "fill": true, + "fillColor": "rgba(148, 0, 211, 0.22)", + "fromDayOfWeek": 7, + "line": true, + "lineColor": "rgba(148, 0, 211, 0.32)", + "op": "time", + "toDayOfWeek": 7 + } + ], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -161,7 +365,78 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [ + { + "colorMode": "red", + "fill": true, + "fillColor": "rgba(255, 255, 255, 0.03)", + "from": "20:00", + "fromDayOfWeek": 7, + "line": false, + "lineColor": "rgba(255, 255, 255, 0.2)", + "op": "time", + "to": "23:00", + "toDayOfWeek": 7 + } + ], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -210,7 +485,73 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [ + { + "colorMode": "red", + "fill": false, + "from": "05:00", + "line": true, + "op": "time" + } + ], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -255,7 +596,76 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [ + { + "colorMode": "gray", + "fill": true, + "fillColor": "rgba(234, 112, 112, 0.12)", + "from": "22:00", + "line": false, + "lineColor": "rgba(237, 46, 24, 0.60)", + "op": "time", + "to": "00:30" + } + ], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-graph/v0alpha1.graph_tests.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-graph/v0alpha1.graph_tests.v42.v2alpha1.json index e67e659b5e8..fa1ae3a63d8 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-graph/v0alpha1.graph_tests.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-graph/v0alpha1.graph_tests.v42.v2alpha1.json @@ -62,7 +62,67 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "editable": true, + "error": false, + "fill": 1, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -106,7 +166,67 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "editable": true, + "error": false, + "fill": 1, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -183,7 +303,72 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "editable": true, + "error": false, + "fill": 1, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "B-series", + "zindex": -3 + } + ], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -227,7 +412,17 @@ "kind": "text", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "text", + "originalOptions": { + "content": "Should be a long line connecting the null region in the `connected` mode, and in zero it should just be a line with zero value at the null points. ", + "editable": true, + "error": false, + "mode": "markdown" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -271,7 +466,17 @@ "kind": "text", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "text", + "originalOptions": { + "content": "Stacking values on top of nulls, should treat the null values as zero. ", + "editable": true, + "error": false, + "mode": "markdown" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -315,7 +520,17 @@ "kind": "text", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "text", + "originalOptions": { + "content": "Stacking when all values are null should leave a gap in the graph", + "editable": true, + "error": false, + "mode": "markdown" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -404,7 +619,66 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "decimals": 3, + "fill": 1, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -583,7 +857,66 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "decimals": 3, + "fill": 1, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -672,7 +1005,67 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "decimals": 3, + "fill": 1, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -881,7 +1274,67 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "decimals": 3, + "fill": 1, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -925,7 +1378,67 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "editable": true, + "error": false, + "fill": 1, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -969,7 +1482,66 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "decimals": 3, + "fill": 1, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1030,7 +1602,72 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "editable": true, + "error": false, + "fill": 0, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "C-series", + "steppedLine": true + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1074,7 +1711,17 @@ "kind": "text", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "text", + "originalOptions": { + "content": "Left is showing null between values for a normal line graph and staircase graph. Orphaned data points should be rendered as points", + "editable": true, + "error": false, + "mode": "markdown" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1118,7 +1765,67 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "editable": true, + "error": false, + "fill": 1, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1164,7 +1871,67 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "editable": true, + "error": false, + "fill": 1, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1223,7 +1990,74 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "editable": true, + "error": false, + "fill": 1, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "B-series", + "yaxis": 2 + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "percent", + "label": "Percent", + "logBase": 1, + "show": true + }, + { + "format": "short", + "label": "Pressure", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1267,7 +2101,17 @@ "kind": "text", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "text", + "originalOptions": { + "content": "Just verify that the tooltip time has millisecond resolution ", + "editable": true, + "error": false, + "mode": "markdown" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1311,7 +2155,17 @@ "kind": "text", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "text", + "originalOptions": { + "content": "Verify that axis labels look ok", + "editable": true, + "error": false, + "mode": "markdown" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1355,7 +2209,67 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "editable": true, + "error": false, + "fill": 1, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1431,7 +2345,72 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "editable": true, + "error": false, + "fill": 1, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "B-series", + "zindex": -3 + } + ], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-graph/v0alpha1.graph_tests.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-graph/v0alpha1.graph_tests.v42.v2beta1.json index 7a94d1842a5..5a580bbaa59 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-graph/v0alpha1.graph_tests.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-graph/v0alpha1.graph_tests.v42.v2beta1.json @@ -67,7 +67,67 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "editable": true, + "error": false, + "fill": 1, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -114,7 +174,67 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "editable": true, + "error": false, + "fill": 1, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -198,7 +318,72 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "editable": true, + "error": false, + "fill": 1, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "B-series", + "zindex": -3 + } + ], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -244,7 +429,17 @@ "group": "text", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "text", + "originalOptions": { + "content": "Should be a long line connecting the null region in the `connected` mode, and in zero it should just be a line with zero value at the null points. ", + "editable": true, + "error": false, + "mode": "markdown" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -290,7 +485,17 @@ "group": "text", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "text", + "originalOptions": { + "content": "Stacking values on top of nulls, should treat the null values as zero. ", + "editable": true, + "error": false, + "mode": "markdown" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -336,7 +541,17 @@ "group": "text", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "text", + "originalOptions": { + "content": "Stacking when all values are null should leave a gap in the graph", + "editable": true, + "error": false, + "mode": "markdown" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -434,7 +649,66 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "decimals": 3, + "fill": 1, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -634,7 +908,66 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "decimals": 3, + "fill": 1, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -732,7 +1065,67 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "decimals": 3, + "fill": 1, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -966,7 +1359,67 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "decimals": 3, + "fill": 1, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1013,7 +1466,67 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "editable": true, + "error": false, + "fill": 1, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1060,7 +1573,66 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "decimals": 3, + "fill": 1, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1126,7 +1698,72 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "editable": true, + "error": false, + "fill": 0, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "C-series", + "steppedLine": true + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1172,7 +1809,17 @@ "group": "text", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "text", + "originalOptions": { + "content": "Left is showing null between values for a normal line graph and staircase graph. Orphaned data points should be rendered as points", + "editable": true, + "error": false, + "mode": "markdown" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1219,7 +1866,67 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "editable": true, + "error": false, + "fill": 1, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1268,7 +1975,67 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "editable": true, + "error": false, + "fill": 1, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1332,7 +2099,74 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "editable": true, + "error": false, + "fill": 1, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "B-series", + "yaxis": 2 + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "percent", + "label": "Percent", + "logBase": 1, + "show": true + }, + { + "format": "short", + "label": "Pressure", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1378,7 +2212,17 @@ "group": "text", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "text", + "originalOptions": { + "content": "Just verify that the tooltip time has millisecond resolution ", + "editable": true, + "error": false, + "mode": "markdown" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1424,7 +2268,17 @@ "group": "text", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "text", + "originalOptions": { + "content": "Verify that axis labels look ok", + "editable": true, + "error": false, + "mode": "markdown" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1471,7 +2325,67 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "editable": true, + "error": false, + "fill": 1, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -1554,7 +2468,72 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "editable": true, + "error": false, + "fill": 1, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "B-series", + "zindex": -3 + } + ], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-graph/v0alpha1.graph_y_axis.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-graph/v0alpha1.graph_y_axis.v42.v2alpha1.json index 25ef1324bc4..f060ff213d2 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-graph/v0alpha1.graph_y_axis.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-graph/v0alpha1.graph_y_axis.v42.v2alpha1.json @@ -66,6 +66,66 @@ "spec": { "pluginVersion": "", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": "", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -115,6 +175,66 @@ "spec": { "pluginVersion": "", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "max": "10000", + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -164,6 +284,64 @@ "spec": { "pluginVersion": "", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -213,6 +391,66 @@ "spec": { "pluginVersion": "", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "logBase": 1, + "max": "10000", + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -262,6 +500,66 @@ "spec": { "pluginVersion": "", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "logBase": 1, + "max": "10000", + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -311,6 +609,64 @@ "spec": { "pluginVersion": "", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -360,6 +716,66 @@ "spec": { "pluginVersion": "", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "max": "10000", + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -409,6 +825,64 @@ "spec": { "pluginVersion": "", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -458,6 +932,65 @@ "spec": { "pluginVersion": "", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-graph/v0alpha1.graph_y_axis.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-graph/v0alpha1.graph_y_axis.v42.v2beta1.json index 4534fe38da4..8202a6a7dd7 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-graph/v0alpha1.graph_y_axis.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-graph/v0alpha1.graph_y_axis.v42.v2beta1.json @@ -70,6 +70,66 @@ "version": "", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": "", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -121,6 +181,66 @@ "version": "", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "max": "10000", + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -172,6 +292,64 @@ "version": "", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -223,6 +401,66 @@ "version": "", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "logBase": 1, + "max": "10000", + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -274,6 +512,66 @@ "version": "", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "logBase": 1, + "max": "10000", + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -325,6 +623,64 @@ "version": "", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -376,6 +732,66 @@ "version": "", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "max": "10000", + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -427,6 +843,64 @@ "version": "", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -478,6 +952,65 @@ "version": "", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-heatmap/v0alpha1.heatmap-legacy.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-heatmap/v0alpha1.heatmap-legacy.v42.v2alpha1.json index 4873fe5fc74..8225aec6834 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-heatmap/v0alpha1.heatmap-legacy.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-heatmap/v0alpha1.heatmap-legacy.v42.v2alpha1.json @@ -74,7 +74,44 @@ "kind": "heatmap", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "heatmap", + "originalOptions": { + "cards": {}, + "color": { + "cardColor": "#b4ff00", + "colorScale": "sqrt", + "colorScheme": "interpolateViridis", + "exponent": 0.5, + "mode": "spectrum" + }, + "dataFormat": "timeseries", + "heatmap": {}, + "hideZeroBuckets": false, + "highlightCards": true, + "legend": { + "show": true + }, + "reverseYBuckets": false, + "tooltip": { + "show": true, + "showHistogram": true + }, + "tooltipDecimals": 4, + "xAxis": { + "show": true + }, + "yAxis": { + "decimals": 2, + "format": "areaM2", + "logBase": 1, + "show": true + }, + "yBucketBound": "auto" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -116,7 +153,46 @@ "kind": "heatmap", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "heatmap", + "originalOptions": { + "cards": { + "cardRound": 50 + }, + "color": { + "cardColor": "#1F60C4", + "colorScale": "sqrt", + "colorScheme": "interpolateOranges", + "exponent": 0.5, + "mode": "opacity" + }, + "dataFormat": "tsbuckets", + "heatmap": {}, + "hideZeroBuckets": false, + "highlightCards": true, + "legend": { + "show": true + }, + "reverseYBuckets": false, + "tooltip": { + "show": true, + "showHistogram": false + }, + "xAxis": { + "show": true + }, + "yAxis": { + "decimals": 1, + "format": "kwatt", + "logBase": 1, + "show": true, + "width": "100" + }, + "yBucketBound": "auto" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -158,7 +234,44 @@ "kind": "heatmap", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "heatmap", + "originalOptions": { + "cards": {}, + "color": { + "cardColor": "#1F60C4", + "colorScale": "sqrt", + "colorScheme": "interpolateOranges", + "exponent": 0.5, + "mode": "opacity" + }, + "dataFormat": "tsbuckets", + "heatmap": {}, + "hideZeroBuckets": false, + "highlightCards": true, + "legend": { + "show": true + }, + "reverseYBuckets": true, + "tooltip": { + "show": true, + "showHistogram": false + }, + "xAxis": { + "show": true + }, + "yAxis": { + "decimals": 1, + "format": "kwatt", + "logBase": 1, + "show": true, + "width": "100" + }, + "yBucketBound": "auto" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -204,7 +317,46 @@ "kind": "heatmap", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "heatmap", + "originalOptions": { + "cards": {}, + "color": { + "cardColor": "#b4ff00", + "colorScale": "sqrt", + "colorScheme": "interpolateViridis", + "exponent": 0.5, + "mode": "spectrum" + }, + "dataFormat": "timeseries", + "heatmap": {}, + "hideZeroBuckets": false, + "highlightCards": true, + "legend": { + "show": true + }, + "reverseYBuckets": false, + "tooltip": { + "show": true, + "showHistogram": true + }, + "tooltipDecimals": 4, + "xAxis": { + "show": true + }, + "yAxis": { + "decimals": 2, + "format": "areaM2", + "logBase": 1, + "max": "50", + "min": "20", + "show": true + }, + "yBucketBound": "auto" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -246,7 +398,44 @@ "kind": "heatmap", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "heatmap", + "originalOptions": { + "cards": {}, + "color": { + "cardColor": "#b4ff00", + "colorScale": "sqrt", + "colorScheme": "interpolateBuGn", + "exponent": 0.5, + "mode": "spectrum" + }, + "dataFormat": "timeseries", + "heatmap": {}, + "hideZeroBuckets": true, + "highlightCards": true, + "legend": { + "show": true + }, + "reverseYBuckets": false, + "tooltip": { + "show": true, + "showHistogram": true + }, + "xAxis": { + "show": true + }, + "xBucketNumber": 10, + "yAxis": { + "format": "short", + "logBase": 2, + "show": true, + "splitFactor": 2 + }, + "yBucketBound": "auto" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -288,7 +477,44 @@ "kind": "heatmap", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "heatmap", + "originalOptions": { + "cards": {}, + "color": { + "cardColor": "#b4ff00", + "colorScale": "sqrt", + "colorScheme": "interpolateBuGn", + "exponent": 0.5, + "mode": "spectrum" + }, + "dataFormat": "timeseries", + "heatmap": {}, + "hideZeroBuckets": true, + "highlightCards": true, + "legend": { + "show": true + }, + "reverseYBuckets": false, + "tooltip": { + "show": true, + "showHistogram": true + }, + "xAxis": { + "show": true + }, + "xBucketNumber": 10, + "yAxis": { + "format": "short", + "logBase": 10, + "show": true, + "splitFactor": 5 + }, + "yBucketBound": "auto" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-heatmap/v0alpha1.heatmap-legacy.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-heatmap/v0alpha1.heatmap-legacy.v42.v2beta1.json index 2e11457ec4d..d7ec2abb5e8 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-heatmap/v0alpha1.heatmap-legacy.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-heatmap/v0alpha1.heatmap-legacy.v42.v2beta1.json @@ -78,7 +78,44 @@ "group": "heatmap", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "heatmap", + "originalOptions": { + "cards": {}, + "color": { + "cardColor": "#b4ff00", + "colorScale": "sqrt", + "colorScheme": "interpolateViridis", + "exponent": 0.5, + "mode": "spectrum" + }, + "dataFormat": "timeseries", + "heatmap": {}, + "hideZeroBuckets": false, + "highlightCards": true, + "legend": { + "show": true + }, + "reverseYBuckets": false, + "tooltip": { + "show": true, + "showHistogram": true + }, + "tooltipDecimals": 4, + "xAxis": { + "show": true + }, + "yAxis": { + "decimals": 2, + "format": "areaM2", + "logBase": 1, + "show": true + }, + "yBucketBound": "auto" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -123,7 +160,46 @@ "group": "heatmap", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "heatmap", + "originalOptions": { + "cards": { + "cardRound": 50 + }, + "color": { + "cardColor": "#1F60C4", + "colorScale": "sqrt", + "colorScheme": "interpolateOranges", + "exponent": 0.5, + "mode": "opacity" + }, + "dataFormat": "tsbuckets", + "heatmap": {}, + "hideZeroBuckets": false, + "highlightCards": true, + "legend": { + "show": true + }, + "reverseYBuckets": false, + "tooltip": { + "show": true, + "showHistogram": false + }, + "xAxis": { + "show": true + }, + "yAxis": { + "decimals": 1, + "format": "kwatt", + "logBase": 1, + "show": true, + "width": "100" + }, + "yBucketBound": "auto" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -168,7 +244,44 @@ "group": "heatmap", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "heatmap", + "originalOptions": { + "cards": {}, + "color": { + "cardColor": "#1F60C4", + "colorScale": "sqrt", + "colorScheme": "interpolateOranges", + "exponent": 0.5, + "mode": "opacity" + }, + "dataFormat": "tsbuckets", + "heatmap": {}, + "hideZeroBuckets": false, + "highlightCards": true, + "legend": { + "show": true + }, + "reverseYBuckets": true, + "tooltip": { + "show": true, + "showHistogram": false + }, + "xAxis": { + "show": true + }, + "yAxis": { + "decimals": 1, + "format": "kwatt", + "logBase": 1, + "show": true, + "width": "100" + }, + "yBucketBound": "auto" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -216,7 +329,46 @@ "group": "heatmap", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "heatmap", + "originalOptions": { + "cards": {}, + "color": { + "cardColor": "#b4ff00", + "colorScale": "sqrt", + "colorScheme": "interpolateViridis", + "exponent": 0.5, + "mode": "spectrum" + }, + "dataFormat": "timeseries", + "heatmap": {}, + "hideZeroBuckets": false, + "highlightCards": true, + "legend": { + "show": true + }, + "reverseYBuckets": false, + "tooltip": { + "show": true, + "showHistogram": true + }, + "tooltipDecimals": 4, + "xAxis": { + "show": true + }, + "yAxis": { + "decimals": 2, + "format": "areaM2", + "logBase": 1, + "max": "50", + "min": "20", + "show": true + }, + "yBucketBound": "auto" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -261,7 +413,44 @@ "group": "heatmap", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "heatmap", + "originalOptions": { + "cards": {}, + "color": { + "cardColor": "#b4ff00", + "colorScale": "sqrt", + "colorScheme": "interpolateBuGn", + "exponent": 0.5, + "mode": "spectrum" + }, + "dataFormat": "timeseries", + "heatmap": {}, + "hideZeroBuckets": true, + "highlightCards": true, + "legend": { + "show": true + }, + "reverseYBuckets": false, + "tooltip": { + "show": true, + "showHistogram": true + }, + "xAxis": { + "show": true + }, + "xBucketNumber": 10, + "yAxis": { + "format": "short", + "logBase": 2, + "show": true, + "splitFactor": 2 + }, + "yBucketBound": "auto" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -306,7 +495,44 @@ "group": "heatmap", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "heatmap", + "originalOptions": { + "cards": {}, + "color": { + "cardColor": "#b4ff00", + "colorScale": "sqrt", + "colorScheme": "interpolateBuGn", + "exponent": 0.5, + "mode": "spectrum" + }, + "dataFormat": "timeseries", + "heatmap": {}, + "hideZeroBuckets": true, + "highlightCards": true, + "legend": { + "show": true + }, + "reverseYBuckets": false, + "tooltip": { + "show": true, + "showHistogram": true + }, + "xAxis": { + "show": true + }, + "xBucketNumber": 10, + "yAxis": { + "format": "short", + "logBase": 10, + "show": true, + "splitFactor": 5 + }, + "yBucketBound": "auto" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-library/v0alpha1.panel-library.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-library/v0alpha1.panel-library.v42.v2alpha1.json index 2277a05c6bb..dc0aab46631 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-library/v0alpha1.panel-library.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-library/v0alpha1.panel-library.v42.v2alpha1.json @@ -109,6 +109,65 @@ "spec": { "pluginVersion": "7.4.0-pre", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "alertThreshold": true }, "fieldConfig": { diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-library/v0alpha1.panel-library.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-library/v0alpha1.panel-library.v42.v2beta1.json index 2f61f5977d3..50419f5a194 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-library/v0alpha1.panel-library.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-library/v0alpha1.panel-library.v42.v2beta1.json @@ -113,6 +113,65 @@ "version": "7.4.0-pre", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "alertThreshold": true }, "fieldConfig": { diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-polystat/v0alpha1.polystat_test.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-polystat/v0alpha1.polystat_test.v42.v2alpha1.json index 68c7c2b6529..636612934c4 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-polystat/v0alpha1.polystat_test.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-polystat/v0alpha1.polystat_test.v42.v2alpha1.json @@ -119,7 +119,1073 @@ "kind": "grafana-polystat-panel", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "grafana-polystat-panel", + "originalOptions": { + "animationModes": [ + { + "text": "Show All", + "value": "all" + }, + { + "text": "Show Triggered", + "value": "triggered" + } + ], + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "d3DivId": "d3_svg_2", + "decimals": 2, + "displayModes": [ + { + "text": "Show All", + "value": "all" + }, + { + "text": "Show Triggered", + "value": "triggered" + } + ], + "fontSizes": [ + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 22, + 24, + 26, + 28, + 30, + 32, + 34, + 36, + 38, + 40, + 42, + 44, + 46, + 48, + 50, + 52, + 54, + 56, + 58, + 60, + 62, + 64, + 66, + 68, + 70 + ], + "fontTypes": [ + "Open Sans", + "Arial", + "Avant Garde", + "Bookman", + "Consolas", + "Courier", + "Courier New", + "Futura", + "Garamond", + "Helvetica", + "Palatino", + "Times", + "Times New Roman", + "Verdana" + ], + "format": "none", + "notcolors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "operatorName": "avg", + "operatorOptions": [ + { + "text": "Average", + "value": "avg" + }, + { + "text": "Count", + "value": "count" + }, + { + "text": "Current", + "value": "current" + }, + { + "text": "Delta", + "value": "delta" + }, + { + "text": "Difference", + "value": "diff" + }, + { + "text": "First", + "value": "first" + }, + { + "text": "Log Min", + "value": "logmin" + }, + { + "text": "Max", + "value": "max" + }, + { + "text": "Min", + "value": "min" + }, + { + "text": "Name", + "value": "name" + }, + { + "text": "Time of Last Point", + "value": "last_time" + }, + { + "text": "Time Step", + "value": "time_step" + }, + { + "text": "Total", + "value": "total" + } + ], + "polystat": { + "animationSpeed": 2500, + "columnAutoSize": true, + "columns": 1, + "defaultClickThrough": "", + "defaultClickThroughSanitize": true, + "displayLimit": 100, + "fontAutoScale": true, + "fontSize": 12, + "globalDisplayMode": "all", + "globalOperatorName": "avg", + "gradientEnabled": true, + "hexagonSortByDirection": "asc", + "hexagonSortByField": "name", + "maxMetrics": 0, + "polygonBorderColor": "black", + "polygonBorderSize": 2, + "radius": "", + "radiusAutoSize": true, + "rowAutoSize": true, + "rows": 1, + "shape": "hexagon_pointed_top", + "tooltipDisplayMode": "all", + "tooltipDisplayTextTriggeredEmpty": "OK", + "tooltipFontSize": 12, + "tooltipFontType": "Open Sans", + "tooltipPrimarySortDirection": "desc", + "tooltipPrimarySortField": "thresholdLevel", + "tooltipSecondarySortDirection": "desc", + "tooltipSecondarySortField": "value", + "tooltipTimestampEnabled": true + }, + "savedComposites": [], + "savedOverrides": [], + "shapes": [ + { + "text": "Hexagon Pointed Top", + "value": "hexagon_pointed_top" + }, + { + "text": "Hexagon Flat Top", + "value": "hexagon_flat_top" + }, + { + "text": "Circle", + "value": "circle" + }, + { + "text": "Cross", + "value": "cross" + }, + { + "text": "Diamond", + "value": "diamond" + }, + { + "text": "Square", + "value": "square" + }, + { + "text": "Star", + "value": "star" + }, + { + "text": "Triangle", + "value": "triangle" + }, + { + "text": "Wye", + "value": "wye" + } + ], + "sortDirections": [ + { + "text": "Ascending", + "value": "asc" + }, + { + "text": "Descending", + "value": "desc" + } + ], + "sortFields": [ + { + "text": "Name", + "value": "name" + }, + { + "text": "Threshold Level", + "value": "thresholdLevel" + }, + { + "text": "Value", + "value": "value" + } + ], + "svgContainer": {}, + "thresholdStates": [ + { + "text": "ok", + "value": 0 + }, + { + "text": "warning", + "value": 1 + }, + { + "text": "critical", + "value": 2 + }, + { + "text": "custom", + "value": 3 + } + ], + "unitFormats": [ + { + "submenu": [ + { + "text": "none", + "value": "none" + }, + { + "text": "short", + "value": "short" + }, + { + "text": "percent (0-100)", + "value": "percent" + }, + { + "text": "percent (0.0-1.0)", + "value": "percentunit" + }, + { + "text": "Humidity (%H)", + "value": "humidity" + }, + { + "text": "decibel", + "value": "dB" + }, + { + "text": "hexadecimal (0x)", + "value": "hex0x" + }, + { + "text": "hexadecimal", + "value": "hex" + }, + { + "text": "scientific notation", + "value": "sci" + }, + { + "text": "locale format", + "value": "locale" + } + ], + "text": "none" + }, + { + "submenu": [ + { + "text": "Dollars ($)", + "value": "currencyUSD" + }, + { + "text": "Pounds (£)", + "value": "currencyGBP" + }, + { + "text": "Euro (€)", + "value": "currencyEUR" + }, + { + "text": "Yen (¥)", + "value": "currencyJPY" + }, + { + "text": "Rubles (₽)", + "value": "currencyRUB" + }, + { + "text": "Hryvnias (₴)", + "value": "currencyUAH" + }, + { + "text": "Real (R$)", + "value": "currencyBRL" + }, + { + "text": "Danish Krone (kr)", + "value": "currencyDKK" + }, + { + "text": "Icelandic Króna (kr)", + "value": "currencyISK" + }, + { + "text": "Norwegian Krone (kr)", + "value": "currencyNOK" + }, + { + "text": "Swedish Krona (kr)", + "value": "currencySEK" + }, + { + "text": "Czech koruna (czk)", + "value": "currencyCZK" + }, + { + "text": "Swiss franc (CHF)", + "value": "currencyCHF" + }, + { + "text": "Polish Złoty (PLN)", + "value": "currencyPLN" + }, + { + "text": "Bitcoin (฿)", + "value": "currencyBTC" + }, + { + "text": "Vietnamese Dong (VND)", + "value": "currencyVND" + }, + { + "text": "Malaysian Ringgit (RM)", + "value": "currencyMYR" + }, + { + "text": "Bulgarian Lev (BGN)", + "value": "currencyBGN" + } + ], + "text": "currency" + }, + { + "submenu": [ + { + "text": "Hertz (1/s)", + "value": "hertz" + }, + { + "text": "nanoseconds (ns)", + "value": "ns" + }, + { + "text": "microseconds (µs)", + "value": "µs" + }, + { + "text": "milliseconds (ms)", + "value": "ms" + }, + { + "text": "seconds (s)", + "value": "s" + }, + { + "text": "minutes (m)", + "value": "m" + }, + { + "text": "hours (h)", + "value": "h" + }, + { + "text": "days (d)", + "value": "d" + }, + { + "text": "duration (ms)", + "value": "dtdurationms" + }, + { + "text": "duration (s)", + "value": "dtdurations" + }, + { + "text": "duration (hh:mm:ss)", + "value": "dthms" + }, + { + "text": "Timeticks (s/100)", + "value": "timeticks" + } + ], + "text": "time" + }, + { + "submenu": [ + { + "text": "YYYY-MM-DD HH:mm:ss", + "value": "dateTimeAsIso" + }, + { + "text": "DD/MM/YYYY h:mm:ss a", + "value": "dateTimeAsUS" + }, + { + "text": "From Now", + "value": "dateTimeFromNow" + } + ], + "text": "date \u0026 time" + }, + { + "submenu": [ + { + "text": "bits", + "value": "bits" + }, + { + "text": "bytes", + "value": "bytes" + }, + { + "text": "kibibytes", + "value": "kbytes" + }, + { + "text": "mebibytes", + "value": "mbytes" + }, + { + "text": "gibibytes", + "value": "gbytes" + } + ], + "text": "data (IEC)" + }, + { + "submenu": [ + { + "text": "bits", + "value": "decbits" + }, + { + "text": "bytes", + "value": "decbytes" + }, + { + "text": "kilobytes", + "value": "deckbytes" + }, + { + "text": "megabytes", + "value": "decmbytes" + }, + { + "text": "gigabytes", + "value": "decgbytes" + } + ], + "text": "data (Metric)" + }, + { + "submenu": [ + { + "text": "packets/sec", + "value": "pps" + }, + { + "text": "bits/sec", + "value": "bps" + }, + { + "text": "bytes/sec", + "value": "Bps" + }, + { + "text": "kilobits/sec", + "value": "Kbits" + }, + { + "text": "kilobytes/sec", + "value": "KBs" + }, + { + "text": "megabits/sec", + "value": "Mbits" + }, + { + "text": "megabytes/sec", + "value": "MBs" + }, + { + "text": "gigabytes/sec", + "value": "GBs" + }, + { + "text": "gigabits/sec", + "value": "Gbits" + } + ], + "text": "data rate" + }, + { + "submenu": [ + { + "text": "hashes/sec", + "value": "Hs" + }, + { + "text": "kilohashes/sec", + "value": "KHs" + }, + { + "text": "megahashes/sec", + "value": "MHs" + }, + { + "text": "gigahashes/sec", + "value": "GHs" + }, + { + "text": "terahashes/sec", + "value": "THs" + }, + { + "text": "petahashes/sec", + "value": "PHs" + }, + { + "text": "exahashes/sec", + "value": "EHs" + } + ], + "text": "hash rate" + }, + { + "submenu": [ + { + "text": "ops/sec (ops)", + "value": "ops" + }, + { + "text": "requests/sec (rps)", + "value": "reqps" + }, + { + "text": "reads/sec (rps)", + "value": "rps" + }, + { + "text": "writes/sec (wps)", + "value": "wps" + }, + { + "text": "I/O ops/sec (iops)", + "value": "iops" + }, + { + "text": "ops/min (opm)", + "value": "opm" + }, + { + "text": "requests/min (rpm)", + "value": "reqpm" + }, + { + "text": "reads/min (rpm)", + "value": "rpm" + }, + { + "text": "writes/min (wpm)", + "value": "wpm" + } + ], + "text": "throughput" + }, + { + "submenu": [ + { + "text": "millimetre (mm)", + "value": "lengthmm" + }, + { + "text": "meter (m)", + "value": "lengthm" + }, + { + "text": "inch (in)", + "value": "lengthin" + }, + { + "text": "feet (ft)", + "value": "lengthft" + }, + { + "text": "kilometer (km)", + "value": "lengthkm" + }, + { + "text": "mile (mi)", + "value": "lengthmi" + } + ], + "text": "length" + }, + { + "submenu": [ + { + "text": "Square Meters (m²)", + "value": "areaM2" + }, + { + "text": "Square Feet (ft²)", + "value": "areaF2" + }, + { + "text": "Square Miles (mi²)", + "value": "areaMI2" + } + ], + "text": "area" + }, + { + "submenu": [ + { + "text": "milligram (mg)", + "value": "massmg" + }, + { + "text": "gram (g)", + "value": "massg" + }, + { + "text": "pound (lb)", + "value": "masslb" + }, + { + "text": "kilogram (kg)", + "value": "masskg" + }, + { + "text": "metric ton (t)", + "value": "masst" + } + ], + "text": "mass" + }, + { + "submenu": [ + { + "text": "metres/second (m/s)", + "value": "velocityms" + }, + { + "text": "kilometers/hour (km/h)", + "value": "velocitykmh" + }, + { + "text": "miles/hour (mph)", + "value": "velocitymph" + }, + { + "text": "knot (kn)", + "value": "velocityknot" + } + ], + "text": "velocity" + }, + { + "submenu": [ + { + "text": "millilitre (mL)", + "value": "mlitre" + }, + { + "text": "litre (L)", + "value": "litre" + }, + { + "text": "cubic metre", + "value": "m3" + }, + { + "text": "Normal cubic metre", + "value": "Nm3" + }, + { + "text": "cubic decimetre", + "value": "dm3" + }, + { + "text": "gallons", + "value": "gallons" + } + ], + "text": "volume" + }, + { + "submenu": [ + { + "text": "Watt (W)", + "value": "watt" + }, + { + "text": "Kilowatt (kW)", + "value": "kwatt" + }, + { + "text": "Milliwatt (mW)", + "value": "mwatt" + }, + { + "text": "Watt per square metre (W/m²)", + "value": "Wm2" + }, + { + "text": "Volt-ampere (VA)", + "value": "voltamp" + }, + { + "text": "Kilovolt-ampere (kVA)", + "value": "kvoltamp" + }, + { + "text": "Volt-ampere reactive (var)", + "value": "voltampreact" + }, + { + "text": "Kilovolt-ampere reactive (kvar)", + "value": "kvoltampreact" + }, + { + "text": "Watt-hour (Wh)", + "value": "watth" + }, + { + "text": "Kilowatt-hour (kWh)", + "value": "kwatth" + }, + { + "text": "Kilowatt-min (kWm)", + "value": "kwattm" + }, + { + "text": "Joule (J)", + "value": "joule" + }, + { + "text": "Electron volt (eV)", + "value": "ev" + }, + { + "text": "Ampere (A)", + "value": "amp" + }, + { + "text": "Kiloampere (kA)", + "value": "kamp" + }, + { + "text": "Milliampere (mA)", + "value": "mamp" + }, + { + "text": "Volt (V)", + "value": "volt" + }, + { + "text": "Kilovolt (kV)", + "value": "kvolt" + }, + { + "text": "Millivolt (mV)", + "value": "mvolt" + }, + { + "text": "Decibel-milliwatt (dBm)", + "value": "dBm" + }, + { + "text": "Ohm (Ω)", + "value": "ohm" + }, + { + "text": "Lumens (Lm)", + "value": "lumens" + } + ], + "text": "energy" + }, + { + "submenu": [ + { + "text": "Celsius (°C)", + "value": "celsius" + }, + { + "text": "Fahrenheit (°F)", + "value": "fahrenheit" + }, + { + "text": "Kelvin (K)", + "value": "kelvin" + } + ], + "text": "temperature" + }, + { + "submenu": [ + { + "text": "Millibars", + "value": "pressurembar" + }, + { + "text": "Bars", + "value": "pressurebar" + }, + { + "text": "Kilobars", + "value": "pressurekbar" + }, + { + "text": "Hectopascals", + "value": "pressurehpa" + }, + { + "text": "Kilopascals", + "value": "pressurekpa" + }, + { + "text": "Inches of mercury", + "value": "pressurehg" + }, + { + "text": "PSI", + "value": "pressurepsi" + } + ], + "text": "pressure" + }, + { + "submenu": [ + { + "text": "Newton-meters (Nm)", + "value": "forceNm" + }, + { + "text": "Kilonewton-meters (kNm)", + "value": "forcekNm" + }, + { + "text": "Newtons (N)", + "value": "forceN" + }, + { + "text": "Kilonewtons (kN)", + "value": "forcekN" + } + ], + "text": "force" + }, + { + "submenu": [ + { + "text": "Gallons/min (gpm)", + "value": "flowgpm" + }, + { + "text": "Cubic meters/sec (cms)", + "value": "flowcms" + }, + { + "text": "Cubic feet/sec (cfs)", + "value": "flowcfs" + }, + { + "text": "Cubic feet/min (cfm)", + "value": "flowcfm" + }, + { + "text": "Litre/hour", + "value": "litreh" + }, + { + "text": "Litre/min (l/min)", + "value": "flowlpm" + }, + { + "text": "milliLitre/min (mL/min)", + "value": "flowmlpm" + } + ], + "text": "flow" + }, + { + "submenu": [ + { + "text": "Degrees (°)", + "value": "degree" + }, + { + "text": "Radians", + "value": "radian" + }, + { + "text": "Gradian", + "value": "grad" + } + ], + "text": "angle" + }, + { + "submenu": [ + { + "text": "Meters/sec²", + "value": "accMS2" + }, + { + "text": "Feet/sec²", + "value": "accFS2" + }, + { + "text": "G unit", + "value": "accG" + } + ], + "text": "acceleration" + }, + { + "submenu": [ + { + "text": "Becquerel (Bq)", + "value": "radbq" + }, + { + "text": "curie (Ci)", + "value": "radci" + }, + { + "text": "Gray (Gy)", + "value": "radgy" + }, + { + "text": "rad", + "value": "radrad" + }, + { + "text": "Sievert (Sv)", + "value": "radsv" + }, + { + "text": "rem", + "value": "radrem" + }, + { + "text": "Exposure (C/kg)", + "value": "radexpckg" + }, + { + "text": "roentgen (R)", + "value": "radr" + }, + { + "text": "Sievert/hour (Sv/h)", + "value": "radsvh" + } + ], + "text": "radiation" + }, + { + "submenu": [ + { + "text": "parts-per-million (ppm)", + "value": "ppm" + }, + { + "text": "parts-per-billion (ppb)", + "value": "conppb" + }, + { + "text": "nanogram per cubic metre (ng/m³)", + "value": "conngm3" + }, + { + "text": "nanogram per normal cubic metre (ng/Nm³)", + "value": "conngNm3" + }, + { + "text": "microgram per cubic metre (μg/m³)", + "value": "conμgm3" + }, + { + "text": "microgram per normal cubic metre (μg/Nm³)", + "value": "conμgNm3" + }, + { + "text": "milligram per cubic metre (mg/m³)", + "value": "conmgm3" + }, + { + "text": "milligram per normal cubic metre (mg/Nm³)", + "value": "conmgNm3" + }, + { + "text": "gram per cubic metre (g/m³)", + "value": "congm3" + }, + { + "text": "gram per normal cubic metre (g/Nm³)", + "value": "congNm3" + } + ], + "text": "concentration" + } + ] + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -228,7 +1294,1129 @@ "kind": "grafana-polystat-panel", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "grafana-polystat-panel", + "originalOptions": { + "animationModes": [ + { + "text": "Show All", + "value": "all" + }, + { + "text": "Show Triggered", + "value": "triggered" + } + ], + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "d3DivId": "d3_svg_4", + "decimals": 2, + "displayModes": [ + { + "text": "Show All", + "value": "all" + }, + { + "text": "Show Triggered", + "value": "triggered" + } + ], + "fontSizes": [ + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 22, + 24, + 26, + 28, + 30, + 32, + 34, + 36, + 38, + 40, + 42, + 44, + 46, + 48, + 50, + 52, + 54, + 56, + 58, + 60, + 62, + 64, + 66, + 68, + 70 + ], + "fontTypes": [ + "Open Sans", + "Arial", + "Avant Garde", + "Bookman", + "Consolas", + "Courier", + "Courier New", + "Futura", + "Garamond", + "Helvetica", + "Palatino", + "Times", + "Times New Roman", + "Verdana" + ], + "format": "none", + "notcolors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "operatorName": "avg", + "operatorOptions": [ + { + "text": "Average", + "value": "avg" + }, + { + "text": "Count", + "value": "count" + }, + { + "text": "Current", + "value": "current" + }, + { + "text": "Delta", + "value": "delta" + }, + { + "text": "Difference", + "value": "diff" + }, + { + "text": "First", + "value": "first" + }, + { + "text": "Log Min", + "value": "logmin" + }, + { + "text": "Max", + "value": "max" + }, + { + "text": "Min", + "value": "min" + }, + { + "text": "Name", + "value": "name" + }, + { + "text": "Time of Last Point", + "value": "last_time" + }, + { + "text": "Time Step", + "value": "time_step" + }, + { + "text": "Total", + "value": "total" + } + ], + "polystat": { + "animationSpeed": 2500, + "columnAutoSize": true, + "columns": "", + "defaultClickThrough": "", + "defaultClickThroughSanitize": true, + "displayLimit": 100, + "fontAutoScale": true, + "fontSize": 12, + "globalDisplayMode": "all", + "globalOperatorName": "avg", + "gradientEnabled": true, + "hexagonSortByDirection": "asc", + "hexagonSortByField": "name", + "maxMetrics": 0, + "polygonBorderColor": "black", + "polygonBorderSize": 2, + "radius": "", + "radiusAutoSize": true, + "rowAutoSize": true, + "rows": "", + "shape": "hexagon_pointed_top", + "tooltipDisplayMode": "all", + "tooltipDisplayTextTriggeredEmpty": "OK", + "tooltipFontSize": 12, + "tooltipFontType": "Open Sans", + "tooltipPrimarySortDirection": "desc", + "tooltipPrimarySortField": "thresholdLevel", + "tooltipSecondarySortDirection": "desc", + "tooltipSecondarySortField": "value", + "tooltipTimestampEnabled": true + }, + "savedComposites": [], + "savedOverrides": [], + "shapes": [ + { + "text": "Hexagon Pointed Top", + "value": "hexagon_pointed_top" + }, + { + "text": "Hexagon Flat Top", + "value": "hexagon_flat_top" + }, + { + "text": "Circle", + "value": "circle" + }, + { + "text": "Cross", + "value": "cross" + }, + { + "text": "Diamond", + "value": "diamond" + }, + { + "text": "Square", + "value": "square" + }, + { + "text": "Star", + "value": "star" + }, + { + "text": "Triangle", + "value": "triangle" + }, + { + "text": "Wye", + "value": "wye" + } + ], + "sortDirections": [ + { + "text": "Ascending", + "value": "asc" + }, + { + "text": "Descending", + "value": "desc" + } + ], + "sortFields": [ + { + "text": "Name", + "value": "name" + }, + { + "text": "Threshold Level", + "value": "thresholdLevel" + }, + { + "text": "Value", + "value": "value" + } + ], + "svgContainer": {}, + "thresholdStates": [ + { + "text": "ok", + "value": 0 + }, + { + "text": "warning", + "value": 1 + }, + { + "text": "critical", + "value": 2 + }, + { + "text": "custom", + "value": 3 + } + ], + "unitFormats": [ + { + "submenu": [ + { + "text": "none", + "value": "none" + }, + { + "text": "short", + "value": "short" + }, + { + "text": "percent (0-100)", + "value": "percent" + }, + { + "text": "percent (0.0-1.0)", + "value": "percentunit" + }, + { + "text": "Humidity (%H)", + "value": "humidity" + }, + { + "text": "decibel", + "value": "dB" + }, + { + "text": "hexadecimal (0x)", + "value": "hex0x" + }, + { + "text": "hexadecimal", + "value": "hex" + }, + { + "text": "scientific notation", + "value": "sci" + }, + { + "text": "locale format", + "value": "locale" + } + ], + "text": "none" + }, + { + "submenu": [ + { + "text": "Dollars ($)", + "value": "currencyUSD" + }, + { + "text": "Pounds (£)", + "value": "currencyGBP" + }, + { + "text": "Euro (€)", + "value": "currencyEUR" + }, + { + "text": "Yen (¥)", + "value": "currencyJPY" + }, + { + "text": "Rubles (₽)", + "value": "currencyRUB" + }, + { + "text": "Hryvnias (₴)", + "value": "currencyUAH" + }, + { + "text": "Real (R$)", + "value": "currencyBRL" + }, + { + "text": "Danish Krone (kr)", + "value": "currencyDKK" + }, + { + "text": "Icelandic Króna (kr)", + "value": "currencyISK" + }, + { + "text": "Norwegian Krone (kr)", + "value": "currencyNOK" + }, + { + "text": "Swedish Krona (kr)", + "value": "currencySEK" + }, + { + "text": "Czech koruna (czk)", + "value": "currencyCZK" + }, + { + "text": "Swiss franc (CHF)", + "value": "currencyCHF" + }, + { + "text": "Polish Złoty (PLN)", + "value": "currencyPLN" + }, + { + "text": "Bitcoin (฿)", + "value": "currencyBTC" + }, + { + "text": "Milli Bitcoin (mBTC)", + "value": "currencymBTC" + }, + { + "text": "Micro Bitcoin (μBTC)", + "value": "currencyμBTC" + }, + { + "text": "Vietnamese Dong (VND)", + "value": "currencyVND" + }, + { + "text": "Turkish Lira (₺)", + "value": "currencyTRY" + }, + { + "text": "Malaysian Ringgit (RM)", + "value": "currencyMYR" + }, + { + "text": "CFP franc (XPF)", + "value": "currencyXPF" + }, + { + "text": "Bulgarian Lev (BGN)", + "value": "currencyBGN" + } + ], + "text": "currency" + }, + { + "submenu": [ + { + "text": "Hertz (1/s)", + "value": "hertz" + }, + { + "text": "nanoseconds (ns)", + "value": "ns" + }, + { + "text": "microseconds (µs)", + "value": "µs" + }, + { + "text": "milliseconds (ms)", + "value": "ms" + }, + { + "text": "seconds (s)", + "value": "s" + }, + { + "text": "minutes (m)", + "value": "m" + }, + { + "text": "hours (h)", + "value": "h" + }, + { + "text": "days (d)", + "value": "d" + }, + { + "text": "duration (ms)", + "value": "dtdurationms" + }, + { + "text": "duration (s)", + "value": "dtdurations" + }, + { + "text": "duration (hh:mm:ss)", + "value": "dthms" + }, + { + "text": "Timeticks (s/100)", + "value": "timeticks" + } + ], + "text": "time" + }, + { + "submenu": [ + { + "text": "YYYY-MM-DD HH:mm:ss", + "value": "dateTimeAsIso" + }, + { + "text": "DD/MM/YYYY h:mm:ss a", + "value": "dateTimeAsUS" + }, + { + "text": "From Now", + "value": "dateTimeFromNow" + } + ], + "text": "date \u0026 time" + }, + { + "submenu": [ + { + "text": "bits", + "value": "bits" + }, + { + "text": "bytes", + "value": "bytes" + }, + { + "text": "kibibytes", + "value": "kbytes" + }, + { + "text": "mebibytes", + "value": "mbytes" + }, + { + "text": "gibibytes", + "value": "gbytes" + } + ], + "text": "data (IEC)" + }, + { + "submenu": [ + { + "text": "bits", + "value": "decbits" + }, + { + "text": "bytes", + "value": "decbytes" + }, + { + "text": "kilobytes", + "value": "deckbytes" + }, + { + "text": "megabytes", + "value": "decmbytes" + }, + { + "text": "gigabytes", + "value": "decgbytes" + } + ], + "text": "data (Metric)" + }, + { + "submenu": [ + { + "text": "packets/sec", + "value": "pps" + }, + { + "text": "bits/sec", + "value": "bps" + }, + { + "text": "bytes/sec", + "value": "Bps" + }, + { + "text": "kilobits/sec", + "value": "Kbits" + }, + { + "text": "kilobytes/sec", + "value": "KBs" + }, + { + "text": "megabits/sec", + "value": "Mbits" + }, + { + "text": "megabytes/sec", + "value": "MBs" + }, + { + "text": "gigabytes/sec", + "value": "GBs" + }, + { + "text": "gigabits/sec", + "value": "Gbits" + } + ], + "text": "data rate" + }, + { + "submenu": [ + { + "text": "hashes/sec", + "value": "Hs" + }, + { + "text": "kilohashes/sec", + "value": "KHs" + }, + { + "text": "megahashes/sec", + "value": "MHs" + }, + { + "text": "gigahashes/sec", + "value": "GHs" + }, + { + "text": "terahashes/sec", + "value": "THs" + }, + { + "text": "petahashes/sec", + "value": "PHs" + }, + { + "text": "exahashes/sec", + "value": "EHs" + } + ], + "text": "hash rate" + }, + { + "submenu": [ + { + "text": "counts/sec (cps)", + "value": "cps" + }, + { + "text": "ops/sec (ops)", + "value": "ops" + }, + { + "text": "requests/sec (rps)", + "value": "reqps" + }, + { + "text": "reads/sec (rps)", + "value": "rps" + }, + { + "text": "writes/sec (wps)", + "value": "wps" + }, + { + "text": "I/O ops/sec (iops)", + "value": "iops" + }, + { + "text": "events/sec (eps)", + "value": "eps" + }, + { + "text": "messages/sec (mps)", + "value": "mps" + }, + { + "text": "records/sec (rps)", + "value": "recps" + }, + { + "text": "rows/sec (rps)", + "value": "rowsps" + }, + { + "text": "counts/min (cpm)", + "value": "cpm" + }, + { + "text": "ops/min (opm)", + "value": "opm" + }, + { + "text": "requests/min (rpm)", + "value": "reqpm" + }, + { + "text": "reads/min (rpm)", + "value": "rpm" + }, + { + "text": "writes/min (wpm)", + "value": "wpm" + }, + { + "text": "events/min (epm)", + "value": "epm" + }, + { + "text": "messages/min (mpm)", + "value": "mpm" + }, + { + "text": "records/min (rpm)", + "value": "recpm" + }, + { + "text": "rows/min (rpm)", + "value": "rowspm" + } + ], + "text": "throughput" + }, + { + "submenu": [ + { + "text": "millimetre (mm)", + "value": "lengthmm" + }, + { + "text": "meter (m)", + "value": "lengthm" + }, + { + "text": "inch (in)", + "value": "lengthin" + }, + { + "text": "feet (ft)", + "value": "lengthft" + }, + { + "text": "kilometer (km)", + "value": "lengthkm" + }, + { + "text": "mile (mi)", + "value": "lengthmi" + } + ], + "text": "length" + }, + { + "submenu": [ + { + "text": "Square Meters (m²)", + "value": "areaM2" + }, + { + "text": "Square Feet (ft²)", + "value": "areaF2" + }, + { + "text": "Square Miles (mi²)", + "value": "areaMI2" + } + ], + "text": "area" + }, + { + "submenu": [ + { + "text": "milligram (mg)", + "value": "massmg" + }, + { + "text": "gram (g)", + "value": "massg" + }, + { + "text": "pound (lb)", + "value": "masslb" + }, + { + "text": "kilogram (kg)", + "value": "masskg" + }, + { + "text": "metric ton (t)", + "value": "masst" + } + ], + "text": "mass" + }, + { + "submenu": [ + { + "text": "metres/second (m/s)", + "value": "velocityms" + }, + { + "text": "kilometers/hour (km/h)", + "value": "velocitykmh" + }, + { + "text": "miles/hour (mph)", + "value": "velocitymph" + }, + { + "text": "knot (kn)", + "value": "velocityknot" + } + ], + "text": "velocity" + }, + { + "submenu": [ + { + "text": "millilitre (mL)", + "value": "mlitre" + }, + { + "text": "litre (L)", + "value": "litre" + }, + { + "text": "cubic metre", + "value": "m3" + }, + { + "text": "Normal cubic metre", + "value": "Nm3" + }, + { + "text": "cubic decimetre", + "value": "dm3" + }, + { + "text": "gallons", + "value": "gallons" + } + ], + "text": "volume" + }, + { + "submenu": [ + { + "text": "Watt (W)", + "value": "watt" + }, + { + "text": "Kilowatt (kW)", + "value": "kwatt" + }, + { + "text": "Milliwatt (mW)", + "value": "mwatt" + }, + { + "text": "Watt per square metre (W/m²)", + "value": "Wm2" + }, + { + "text": "Volt-Ampere (VA)", + "value": "voltamp" + }, + { + "text": "Kilovolt-Ampere (kVA)", + "value": "kvoltamp" + }, + { + "text": "Volt-Ampere reactive (VAr)", + "value": "voltampreact" + }, + { + "text": "Kilovolt-Ampere reactive (kVAr)", + "value": "kvoltampreact" + }, + { + "text": "Watt-hour (Wh)", + "value": "watth" + }, + { + "text": "Kilowatt-hour (kWh)", + "value": "kwatth" + }, + { + "text": "Kilowatt-min (kWm)", + "value": "kwattm" + }, + { + "text": "Joule (J)", + "value": "joule" + }, + { + "text": "Electron volt (eV)", + "value": "ev" + }, + { + "text": "Ampere (A)", + "value": "amp" + }, + { + "text": "Kiloampere (kA)", + "value": "kamp" + }, + { + "text": "Milliampere (mA)", + "value": "mamp" + }, + { + "text": "Volt (V)", + "value": "volt" + }, + { + "text": "Kilovolt (kV)", + "value": "kvolt" + }, + { + "text": "Millivolt (mV)", + "value": "mvolt" + }, + { + "text": "Decibel-milliwatt (dBm)", + "value": "dBm" + }, + { + "text": "Ohm (Ω)", + "value": "ohm" + }, + { + "text": "Lumens (Lm)", + "value": "lumens" + } + ], + "text": "energy" + }, + { + "submenu": [ + { + "text": "Celsius (°C)", + "value": "celsius" + }, + { + "text": "Fahrenheit (°F)", + "value": "fahrenheit" + }, + { + "text": "Kelvin (K)", + "value": "kelvin" + } + ], + "text": "temperature" + }, + { + "submenu": [ + { + "text": "Millibars", + "value": "pressurembar" + }, + { + "text": "Bars", + "value": "pressurebar" + }, + { + "text": "Kilobars", + "value": "pressurekbar" + }, + { + "text": "Hectopascals", + "value": "pressurehpa" + }, + { + "text": "Kilopascals", + "value": "pressurekpa" + }, + { + "text": "Inches of mercury", + "value": "pressurehg" + }, + { + "text": "PSI", + "value": "pressurepsi" + } + ], + "text": "pressure" + }, + { + "submenu": [ + { + "text": "Newton-meters (Nm)", + "value": "forceNm" + }, + { + "text": "Kilonewton-meters (kNm)", + "value": "forcekNm" + }, + { + "text": "Newtons (N)", + "value": "forceN" + }, + { + "text": "Kilonewtons (kN)", + "value": "forcekN" + } + ], + "text": "force" + }, + { + "submenu": [ + { + "text": "Gallons/min (gpm)", + "value": "flowgpm" + }, + { + "text": "Cubic meters/sec (cms)", + "value": "flowcms" + }, + { + "text": "Cubic feet/sec (cfs)", + "value": "flowcfs" + }, + { + "text": "Cubic feet/min (cfm)", + "value": "flowcfm" + }, + { + "text": "Litre/hour", + "value": "litreh" + }, + { + "text": "Litre/min (l/min)", + "value": "flowlpm" + }, + { + "text": "milliLitre/min (mL/min)", + "value": "flowmlpm" + } + ], + "text": "flow" + }, + { + "submenu": [ + { + "text": "Degrees (°)", + "value": "degree" + }, + { + "text": "Radians", + "value": "radian" + }, + { + "text": "Gradian", + "value": "grad" + } + ], + "text": "angle" + }, + { + "submenu": [ + { + "text": "Meters/sec²", + "value": "accMS2" + }, + { + "text": "Feet/sec²", + "value": "accFS2" + }, + { + "text": "G unit", + "value": "accG" + } + ], + "text": "acceleration" + }, + { + "submenu": [ + { + "text": "Becquerel (Bq)", + "value": "radbq" + }, + { + "text": "curie (Ci)", + "value": "radci" + }, + { + "text": "Gray (Gy)", + "value": "radgy" + }, + { + "text": "rad", + "value": "radrad" + }, + { + "text": "Sievert (Sv)", + "value": "radsv" + }, + { + "text": "rem", + "value": "radrem" + }, + { + "text": "Exposure (C/kg)", + "value": "radexpckg" + }, + { + "text": "roentgen (R)", + "value": "radr" + }, + { + "text": "Sievert/hour (Sv/h)", + "value": "radsvh" + } + ], + "text": "radiation" + }, + { + "submenu": [ + { + "text": "parts-per-million (ppm)", + "value": "ppm" + }, + { + "text": "parts-per-billion (ppb)", + "value": "conppb" + }, + { + "text": "nanogram per cubic metre (ng/m³)", + "value": "conngm3" + }, + { + "text": "nanogram per normal cubic metre (ng/Nm³)", + "value": "conngNm3" + }, + { + "text": "microgram per cubic metre (μg/m³)", + "value": "conμgm3" + }, + { + "text": "microgram per normal cubic metre (μg/Nm³)", + "value": "conμgNm3" + }, + { + "text": "milligram per cubic metre (mg/m³)", + "value": "conmgm3" + }, + { + "text": "milligram per normal cubic metre (mg/Nm³)", + "value": "conmgNm3" + }, + { + "text": "gram per cubic metre (g/m³)", + "value": "congm3" + }, + { + "text": "gram per normal cubic metre (g/Nm³)", + "value": "congNm3" + } + ], + "text": "concentration" + } + ] + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -337,7 +2525,1090 @@ "kind": "grafana-polystat-panel", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "grafana-polystat-panel", + "originalOptions": { + "animationModes": [ + { + "text": "Show All", + "value": "all" + }, + { + "text": "Show Triggered", + "value": "triggered" + } + ], + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "d3DivId": "d3_svg_5", + "decimals": 2, + "displayModes": [ + { + "text": "Show All", + "value": "all" + }, + { + "text": "Show Triggered", + "value": "triggered" + } + ], + "fontSizes": [ + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 22, + 24, + 26, + 28, + 30, + 32, + 34, + 36, + 38, + 40, + 42, + 44, + 46, + 48, + 50, + 52, + 54, + 56, + 58, + 60, + 62, + 64, + 66, + 68, + 70 + ], + "fontTypes": [ + "Open Sans", + "Arial", + "Avant Garde", + "Bookman", + "Consolas", + "Courier", + "Courier New", + "Futura", + "Garamond", + "Helvetica", + "Palatino", + "Times", + "Times New Roman", + "Verdana" + ], + "format": "none", + "notcolors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "operatorName": "avg", + "operatorOptions": [ + { + "text": "Average", + "value": "avg" + }, + { + "text": "Count", + "value": "count" + }, + { + "text": "Current", + "value": "current" + }, + { + "text": "Delta", + "value": "delta" + }, + { + "text": "Difference", + "value": "diff" + }, + { + "text": "First", + "value": "first" + }, + { + "text": "Log Min", + "value": "logmin" + }, + { + "text": "Max", + "value": "max" + }, + { + "text": "Min", + "value": "min" + }, + { + "text": "Name", + "value": "name" + }, + { + "text": "Time of Last Point", + "value": "last_time" + }, + { + "text": "Time Step", + "value": "time_step" + }, + { + "text": "Total", + "value": "total" + } + ], + "polystat": { + "animationSpeed": 2500, + "columnAutoSize": true, + "columns": "", + "defaultClickThrough": "", + "defaultClickThroughSanitize": true, + "displayLimit": 100, + "fontAutoScale": true, + "fontSize": 12, + "globalDisplayMode": "all", + "globalOperatorName": "avg", + "gradientEnabled": true, + "hexagonSortByDirection": "asc", + "hexagonSortByField": "name", + "maxMetrics": 0, + "polygonBorderColor": "black", + "polygonBorderSize": 2, + "radius": "", + "radiusAutoSize": true, + "rowAutoSize": true, + "rows": "", + "shape": "hexagon_pointed_top", + "tooltipDisplayMode": "all", + "tooltipDisplayTextTriggeredEmpty": "OK", + "tooltipFontSize": 12, + "tooltipFontType": "Open Sans", + "tooltipPrimarySortDirection": "desc", + "tooltipPrimarySortField": "thresholdLevel", + "tooltipSecondarySortDirection": "desc", + "tooltipSecondarySortField": "value", + "tooltipTimestampEnabled": true + }, + "savedComposites": [ + { + "animateMode": "all", + "clickThrough": "", + "compositeName": "comp", + "enabled": true, + "hideMembers": true, + "members": [ + { + "seriesName": "A-series" + }, + { + "seriesName": "B-series" + } + ], + "sanitizeURLEnabled": true, + "sanitizedURL": "", + "showName": true, + "showValue": true, + "thresholdLevel": 0 + } + ], + "savedOverrides": [], + "shapes": [ + { + "text": "Hexagon Pointed Top", + "value": "hexagon_pointed_top" + }, + { + "text": "Hexagon Flat Top", + "value": "hexagon_flat_top" + }, + { + "text": "Circle", + "value": "circle" + }, + { + "text": "Cross", + "value": "cross" + }, + { + "text": "Diamond", + "value": "diamond" + }, + { + "text": "Square", + "value": "square" + }, + { + "text": "Star", + "value": "star" + }, + { + "text": "Triangle", + "value": "triangle" + }, + { + "text": "Wye", + "value": "wye" + } + ], + "sortDirections": [ + { + "text": "Ascending", + "value": "asc" + }, + { + "text": "Descending", + "value": "desc" + } + ], + "sortFields": [ + { + "text": "Name", + "value": "name" + }, + { + "text": "Threshold Level", + "value": "thresholdLevel" + }, + { + "text": "Value", + "value": "value" + } + ], + "svgContainer": {}, + "thresholdStates": [ + { + "text": "ok", + "value": 0 + }, + { + "text": "warning", + "value": 1 + }, + { + "text": "critical", + "value": 2 + }, + { + "text": "custom", + "value": 3 + } + ], + "unitFormats": [ + { + "submenu": [ + { + "text": "none", + "value": "none" + }, + { + "text": "short", + "value": "short" + }, + { + "text": "percent (0-100)", + "value": "percent" + }, + { + "text": "percent (0.0-1.0)", + "value": "percentunit" + }, + { + "text": "Humidity (%H)", + "value": "humidity" + }, + { + "text": "decibel", + "value": "dB" + }, + { + "text": "hexadecimal (0x)", + "value": "hex0x" + }, + { + "text": "hexadecimal", + "value": "hex" + }, + { + "text": "scientific notation", + "value": "sci" + }, + { + "text": "locale format", + "value": "locale" + } + ], + "text": "none" + }, + { + "submenu": [ + { + "text": "Dollars ($)", + "value": "currencyUSD" + }, + { + "text": "Pounds (£)", + "value": "currencyGBP" + }, + { + "text": "Euro (€)", + "value": "currencyEUR" + }, + { + "text": "Yen (¥)", + "value": "currencyJPY" + }, + { + "text": "Rubles (₽)", + "value": "currencyRUB" + }, + { + "text": "Hryvnias (₴)", + "value": "currencyUAH" + }, + { + "text": "Real (R$)", + "value": "currencyBRL" + }, + { + "text": "Danish Krone (kr)", + "value": "currencyDKK" + }, + { + "text": "Icelandic Króna (kr)", + "value": "currencyISK" + }, + { + "text": "Norwegian Krone (kr)", + "value": "currencyNOK" + }, + { + "text": "Swedish Krona (kr)", + "value": "currencySEK" + }, + { + "text": "Czech koruna (czk)", + "value": "currencyCZK" + }, + { + "text": "Swiss franc (CHF)", + "value": "currencyCHF" + }, + { + "text": "Polish Złoty (PLN)", + "value": "currencyPLN" + }, + { + "text": "Bitcoin (฿)", + "value": "currencyBTC" + }, + { + "text": "Vietnamese Dong (VND)", + "value": "currencyVND" + }, + { + "text": "Malaysian Ringgit (RM)", + "value": "currencyMYR" + }, + { + "text": "Bulgarian Lev (BGN)", + "value": "currencyBGN" + } + ], + "text": "currency" + }, + { + "submenu": [ + { + "text": "Hertz (1/s)", + "value": "hertz" + }, + { + "text": "nanoseconds (ns)", + "value": "ns" + }, + { + "text": "microseconds (µs)", + "value": "µs" + }, + { + "text": "milliseconds (ms)", + "value": "ms" + }, + { + "text": "seconds (s)", + "value": "s" + }, + { + "text": "minutes (m)", + "value": "m" + }, + { + "text": "hours (h)", + "value": "h" + }, + { + "text": "days (d)", + "value": "d" + }, + { + "text": "duration (ms)", + "value": "dtdurationms" + }, + { + "text": "duration (s)", + "value": "dtdurations" + }, + { + "text": "duration (hh:mm:ss)", + "value": "dthms" + }, + { + "text": "Timeticks (s/100)", + "value": "timeticks" + } + ], + "text": "time" + }, + { + "submenu": [ + { + "text": "YYYY-MM-DD HH:mm:ss", + "value": "dateTimeAsIso" + }, + { + "text": "DD/MM/YYYY h:mm:ss a", + "value": "dateTimeAsUS" + }, + { + "text": "From Now", + "value": "dateTimeFromNow" + } + ], + "text": "date \u0026 time" + }, + { + "submenu": [ + { + "text": "bits", + "value": "bits" + }, + { + "text": "bytes", + "value": "bytes" + }, + { + "text": "kibibytes", + "value": "kbytes" + }, + { + "text": "mebibytes", + "value": "mbytes" + }, + { + "text": "gibibytes", + "value": "gbytes" + } + ], + "text": "data (IEC)" + }, + { + "submenu": [ + { + "text": "bits", + "value": "decbits" + }, + { + "text": "bytes", + "value": "decbytes" + }, + { + "text": "kilobytes", + "value": "deckbytes" + }, + { + "text": "megabytes", + "value": "decmbytes" + }, + { + "text": "gigabytes", + "value": "decgbytes" + } + ], + "text": "data (Metric)" + }, + { + "submenu": [ + { + "text": "packets/sec", + "value": "pps" + }, + { + "text": "bits/sec", + "value": "bps" + }, + { + "text": "bytes/sec", + "value": "Bps" + }, + { + "text": "kilobits/sec", + "value": "Kbits" + }, + { + "text": "kilobytes/sec", + "value": "KBs" + }, + { + "text": "megabits/sec", + "value": "Mbits" + }, + { + "text": "megabytes/sec", + "value": "MBs" + }, + { + "text": "gigabytes/sec", + "value": "GBs" + }, + { + "text": "gigabits/sec", + "value": "Gbits" + } + ], + "text": "data rate" + }, + { + "submenu": [ + { + "text": "hashes/sec", + "value": "Hs" + }, + { + "text": "kilohashes/sec", + "value": "KHs" + }, + { + "text": "megahashes/sec", + "value": "MHs" + }, + { + "text": "gigahashes/sec", + "value": "GHs" + }, + { + "text": "terahashes/sec", + "value": "THs" + }, + { + "text": "petahashes/sec", + "value": "PHs" + }, + { + "text": "exahashes/sec", + "value": "EHs" + } + ], + "text": "hash rate" + }, + { + "submenu": [ + { + "text": "ops/sec (ops)", + "value": "ops" + }, + { + "text": "requests/sec (rps)", + "value": "reqps" + }, + { + "text": "reads/sec (rps)", + "value": "rps" + }, + { + "text": "writes/sec (wps)", + "value": "wps" + }, + { + "text": "I/O ops/sec (iops)", + "value": "iops" + }, + { + "text": "ops/min (opm)", + "value": "opm" + }, + { + "text": "reads/min (rpm)", + "value": "rpm" + }, + { + "text": "writes/min (wpm)", + "value": "wpm" + } + ], + "text": "throughput" + }, + { + "submenu": [ + { + "text": "millimetre (mm)", + "value": "lengthmm" + }, + { + "text": "meter (m)", + "value": "lengthm" + }, + { + "text": "inch (in)", + "value": "lengthin" + }, + { + "text": "feet (ft)", + "value": "lengthft" + }, + { + "text": "kilometer (km)", + "value": "lengthkm" + }, + { + "text": "mile (mi)", + "value": "lengthmi" + } + ], + "text": "length" + }, + { + "submenu": [ + { + "text": "Square Meters (m²)", + "value": "areaM2" + }, + { + "text": "Square Feet (ft²)", + "value": "areaF2" + }, + { + "text": "Square Miles (mi²)", + "value": "areaMI2" + } + ], + "text": "area" + }, + { + "submenu": [ + { + "text": "milligram (mg)", + "value": "massmg" + }, + { + "text": "gram (g)", + "value": "massg" + }, + { + "text": "pound (lb)", + "value": "masslb" + }, + { + "text": "kilogram (kg)", + "value": "masskg" + }, + { + "text": "metric ton (t)", + "value": "masst" + } + ], + "text": "mass" + }, + { + "submenu": [ + { + "text": "metres/second (m/s)", + "value": "velocityms" + }, + { + "text": "kilometers/hour (km/h)", + "value": "velocitykmh" + }, + { + "text": "miles/hour (mph)", + "value": "velocitymph" + }, + { + "text": "knot (kn)", + "value": "velocityknot" + } + ], + "text": "velocity" + }, + { + "submenu": [ + { + "text": "millilitre (mL)", + "value": "mlitre" + }, + { + "text": "litre (L)", + "value": "litre" + }, + { + "text": "cubic metre", + "value": "m3" + }, + { + "text": "Normal cubic metre", + "value": "Nm3" + }, + { + "text": "cubic decimetre", + "value": "dm3" + }, + { + "text": "gallons", + "value": "gallons" + } + ], + "text": "volume" + }, + { + "submenu": [ + { + "text": "Watt (W)", + "value": "watt" + }, + { + "text": "Kilowatt (kW)", + "value": "kwatt" + }, + { + "text": "Milliwatt (mW)", + "value": "mwatt" + }, + { + "text": "Watt per square metre (W/m²)", + "value": "Wm2" + }, + { + "text": "Volt-ampere (VA)", + "value": "voltamp" + }, + { + "text": "Kilovolt-ampere (kVA)", + "value": "kvoltamp" + }, + { + "text": "Volt-ampere reactive (var)", + "value": "voltampreact" + }, + { + "text": "Kilovolt-ampere reactive (kvar)", + "value": "kvoltampreact" + }, + { + "text": "Watt-hour (Wh)", + "value": "watth" + }, + { + "text": "Kilowatt-hour (kWh)", + "value": "kwatth" + }, + { + "text": "Kilowatt-min (kWm)", + "value": "kwattm" + }, + { + "text": "Joule (J)", + "value": "joule" + }, + { + "text": "Electron volt (eV)", + "value": "ev" + }, + { + "text": "Ampere (A)", + "value": "amp" + }, + { + "text": "Kiloampere (kA)", + "value": "kamp" + }, + { + "text": "Milliampere (mA)", + "value": "mamp" + }, + { + "text": "Volt (V)", + "value": "volt" + }, + { + "text": "Kilovolt (kV)", + "value": "kvolt" + }, + { + "text": "Millivolt (mV)", + "value": "mvolt" + }, + { + "text": "Decibel-milliwatt (dBm)", + "value": "dBm" + }, + { + "text": "Ohm (Ω)", + "value": "ohm" + }, + { + "text": "Lumens (Lm)", + "value": "lumens" + } + ], + "text": "energy" + }, + { + "submenu": [ + { + "text": "Celsius (°C)", + "value": "celsius" + }, + { + "text": "Fahrenheit (°F)", + "value": "fahrenheit" + }, + { + "text": "Kelvin (K)", + "value": "kelvin" + } + ], + "text": "temperature" + }, + { + "submenu": [ + { + "text": "Millibars", + "value": "pressurembar" + }, + { + "text": "Bars", + "value": "pressurebar" + }, + { + "text": "Kilobars", + "value": "pressurekbar" + }, + { + "text": "Hectopascals", + "value": "pressurehpa" + }, + { + "text": "Kilopascals", + "value": "pressurekpa" + }, + { + "text": "Inches of mercury", + "value": "pressurehg" + }, + { + "text": "PSI", + "value": "pressurepsi" + } + ], + "text": "pressure" + }, + { + "submenu": [ + { + "text": "Newton-meters (Nm)", + "value": "forceNm" + }, + { + "text": "Kilonewton-meters (kNm)", + "value": "forcekNm" + }, + { + "text": "Newtons (N)", + "value": "forceN" + }, + { + "text": "Kilonewtons (kN)", + "value": "forcekN" + } + ], + "text": "force" + }, + { + "submenu": [ + { + "text": "Gallons/min (gpm)", + "value": "flowgpm" + }, + { + "text": "Cubic meters/sec (cms)", + "value": "flowcms" + }, + { + "text": "Cubic feet/sec (cfs)", + "value": "flowcfs" + }, + { + "text": "Cubic feet/min (cfm)", + "value": "flowcfm" + }, + { + "text": "Litre/hour", + "value": "litreh" + }, + { + "text": "Litre/min (l/min)", + "value": "flowlpm" + }, + { + "text": "milliLitre/min (mL/min)", + "value": "flowmlpm" + } + ], + "text": "flow" + }, + { + "submenu": [ + { + "text": "Degrees (°)", + "value": "degree" + }, + { + "text": "Radians", + "value": "radian" + }, + { + "text": "Gradian", + "value": "grad" + } + ], + "text": "angle" + }, + { + "submenu": [ + { + "text": "Meters/sec²", + "value": "accMS2" + }, + { + "text": "Feet/sec²", + "value": "accFS2" + }, + { + "text": "G unit", + "value": "accG" + } + ], + "text": "acceleration" + }, + { + "submenu": [ + { + "text": "Becquerel (Bq)", + "value": "radbq" + }, + { + "text": "curie (Ci)", + "value": "radci" + }, + { + "text": "Gray (Gy)", + "value": "radgy" + }, + { + "text": "rad", + "value": "radrad" + }, + { + "text": "Sievert (Sv)", + "value": "radsv" + }, + { + "text": "rem", + "value": "radrem" + }, + { + "text": "Exposure (C/kg)", + "value": "radexpckg" + }, + { + "text": "roentgen (R)", + "value": "radr" + }, + { + "text": "Sievert/hour (Sv/h)", + "value": "radsvh" + } + ], + "text": "radiation" + }, + { + "submenu": [ + { + "text": "parts-per-million (ppm)", + "value": "ppm" + }, + { + "text": "parts-per-billion (ppb)", + "value": "conppb" + }, + { + "text": "nanogram per cubic metre (ng/m³)", + "value": "conngm3" + }, + { + "text": "nanogram per normal cubic metre (ng/Nm³)", + "value": "conngNm3" + }, + { + "text": "microgram per cubic metre (μg/m³)", + "value": "conμgm3" + }, + { + "text": "microgram per normal cubic metre (μg/Nm³)", + "value": "conμgNm3" + }, + { + "text": "milligram per cubic metre (mg/m³)", + "value": "conmgm3" + }, + { + "text": "milligram per normal cubic metre (mg/Nm³)", + "value": "conmgNm3" + }, + { + "text": "gram per cubic metre (g/m³)", + "value": "congm3" + }, + { + "text": "gram per normal cubic metre (g/Nm³)", + "value": "congNm3" + } + ], + "text": "concentration" + } + ] + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-polystat/v0alpha1.polystat_test.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-polystat/v0alpha1.polystat_test.v42.v2beta1.json index f72f1e3b485..5916250ffd5 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-polystat/v0alpha1.polystat_test.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-polystat/v0alpha1.polystat_test.v42.v2beta1.json @@ -130,7 +130,1073 @@ "group": "grafana-polystat-panel", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "grafana-polystat-panel", + "originalOptions": { + "animationModes": [ + { + "text": "Show All", + "value": "all" + }, + { + "text": "Show Triggered", + "value": "triggered" + } + ], + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "d3DivId": "d3_svg_2", + "decimals": 2, + "displayModes": [ + { + "text": "Show All", + "value": "all" + }, + { + "text": "Show Triggered", + "value": "triggered" + } + ], + "fontSizes": [ + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 22, + 24, + 26, + 28, + 30, + 32, + 34, + 36, + 38, + 40, + 42, + 44, + 46, + 48, + 50, + 52, + 54, + 56, + 58, + 60, + 62, + 64, + 66, + 68, + 70 + ], + "fontTypes": [ + "Open Sans", + "Arial", + "Avant Garde", + "Bookman", + "Consolas", + "Courier", + "Courier New", + "Futura", + "Garamond", + "Helvetica", + "Palatino", + "Times", + "Times New Roman", + "Verdana" + ], + "format": "none", + "notcolors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "operatorName": "avg", + "operatorOptions": [ + { + "text": "Average", + "value": "avg" + }, + { + "text": "Count", + "value": "count" + }, + { + "text": "Current", + "value": "current" + }, + { + "text": "Delta", + "value": "delta" + }, + { + "text": "Difference", + "value": "diff" + }, + { + "text": "First", + "value": "first" + }, + { + "text": "Log Min", + "value": "logmin" + }, + { + "text": "Max", + "value": "max" + }, + { + "text": "Min", + "value": "min" + }, + { + "text": "Name", + "value": "name" + }, + { + "text": "Time of Last Point", + "value": "last_time" + }, + { + "text": "Time Step", + "value": "time_step" + }, + { + "text": "Total", + "value": "total" + } + ], + "polystat": { + "animationSpeed": 2500, + "columnAutoSize": true, + "columns": 1, + "defaultClickThrough": "", + "defaultClickThroughSanitize": true, + "displayLimit": 100, + "fontAutoScale": true, + "fontSize": 12, + "globalDisplayMode": "all", + "globalOperatorName": "avg", + "gradientEnabled": true, + "hexagonSortByDirection": "asc", + "hexagonSortByField": "name", + "maxMetrics": 0, + "polygonBorderColor": "black", + "polygonBorderSize": 2, + "radius": "", + "radiusAutoSize": true, + "rowAutoSize": true, + "rows": 1, + "shape": "hexagon_pointed_top", + "tooltipDisplayMode": "all", + "tooltipDisplayTextTriggeredEmpty": "OK", + "tooltipFontSize": 12, + "tooltipFontType": "Open Sans", + "tooltipPrimarySortDirection": "desc", + "tooltipPrimarySortField": "thresholdLevel", + "tooltipSecondarySortDirection": "desc", + "tooltipSecondarySortField": "value", + "tooltipTimestampEnabled": true + }, + "savedComposites": [], + "savedOverrides": [], + "shapes": [ + { + "text": "Hexagon Pointed Top", + "value": "hexagon_pointed_top" + }, + { + "text": "Hexagon Flat Top", + "value": "hexagon_flat_top" + }, + { + "text": "Circle", + "value": "circle" + }, + { + "text": "Cross", + "value": "cross" + }, + { + "text": "Diamond", + "value": "diamond" + }, + { + "text": "Square", + "value": "square" + }, + { + "text": "Star", + "value": "star" + }, + { + "text": "Triangle", + "value": "triangle" + }, + { + "text": "Wye", + "value": "wye" + } + ], + "sortDirections": [ + { + "text": "Ascending", + "value": "asc" + }, + { + "text": "Descending", + "value": "desc" + } + ], + "sortFields": [ + { + "text": "Name", + "value": "name" + }, + { + "text": "Threshold Level", + "value": "thresholdLevel" + }, + { + "text": "Value", + "value": "value" + } + ], + "svgContainer": {}, + "thresholdStates": [ + { + "text": "ok", + "value": 0 + }, + { + "text": "warning", + "value": 1 + }, + { + "text": "critical", + "value": 2 + }, + { + "text": "custom", + "value": 3 + } + ], + "unitFormats": [ + { + "submenu": [ + { + "text": "none", + "value": "none" + }, + { + "text": "short", + "value": "short" + }, + { + "text": "percent (0-100)", + "value": "percent" + }, + { + "text": "percent (0.0-1.0)", + "value": "percentunit" + }, + { + "text": "Humidity (%H)", + "value": "humidity" + }, + { + "text": "decibel", + "value": "dB" + }, + { + "text": "hexadecimal (0x)", + "value": "hex0x" + }, + { + "text": "hexadecimal", + "value": "hex" + }, + { + "text": "scientific notation", + "value": "sci" + }, + { + "text": "locale format", + "value": "locale" + } + ], + "text": "none" + }, + { + "submenu": [ + { + "text": "Dollars ($)", + "value": "currencyUSD" + }, + { + "text": "Pounds (£)", + "value": "currencyGBP" + }, + { + "text": "Euro (€)", + "value": "currencyEUR" + }, + { + "text": "Yen (¥)", + "value": "currencyJPY" + }, + { + "text": "Rubles (₽)", + "value": "currencyRUB" + }, + { + "text": "Hryvnias (₴)", + "value": "currencyUAH" + }, + { + "text": "Real (R$)", + "value": "currencyBRL" + }, + { + "text": "Danish Krone (kr)", + "value": "currencyDKK" + }, + { + "text": "Icelandic Króna (kr)", + "value": "currencyISK" + }, + { + "text": "Norwegian Krone (kr)", + "value": "currencyNOK" + }, + { + "text": "Swedish Krona (kr)", + "value": "currencySEK" + }, + { + "text": "Czech koruna (czk)", + "value": "currencyCZK" + }, + { + "text": "Swiss franc (CHF)", + "value": "currencyCHF" + }, + { + "text": "Polish Złoty (PLN)", + "value": "currencyPLN" + }, + { + "text": "Bitcoin (฿)", + "value": "currencyBTC" + }, + { + "text": "Vietnamese Dong (VND)", + "value": "currencyVND" + }, + { + "text": "Malaysian Ringgit (RM)", + "value": "currencyMYR" + }, + { + "text": "Bulgarian Lev (BGN)", + "value": "currencyBGN" + } + ], + "text": "currency" + }, + { + "submenu": [ + { + "text": "Hertz (1/s)", + "value": "hertz" + }, + { + "text": "nanoseconds (ns)", + "value": "ns" + }, + { + "text": "microseconds (µs)", + "value": "µs" + }, + { + "text": "milliseconds (ms)", + "value": "ms" + }, + { + "text": "seconds (s)", + "value": "s" + }, + { + "text": "minutes (m)", + "value": "m" + }, + { + "text": "hours (h)", + "value": "h" + }, + { + "text": "days (d)", + "value": "d" + }, + { + "text": "duration (ms)", + "value": "dtdurationms" + }, + { + "text": "duration (s)", + "value": "dtdurations" + }, + { + "text": "duration (hh:mm:ss)", + "value": "dthms" + }, + { + "text": "Timeticks (s/100)", + "value": "timeticks" + } + ], + "text": "time" + }, + { + "submenu": [ + { + "text": "YYYY-MM-DD HH:mm:ss", + "value": "dateTimeAsIso" + }, + { + "text": "DD/MM/YYYY h:mm:ss a", + "value": "dateTimeAsUS" + }, + { + "text": "From Now", + "value": "dateTimeFromNow" + } + ], + "text": "date \u0026 time" + }, + { + "submenu": [ + { + "text": "bits", + "value": "bits" + }, + { + "text": "bytes", + "value": "bytes" + }, + { + "text": "kibibytes", + "value": "kbytes" + }, + { + "text": "mebibytes", + "value": "mbytes" + }, + { + "text": "gibibytes", + "value": "gbytes" + } + ], + "text": "data (IEC)" + }, + { + "submenu": [ + { + "text": "bits", + "value": "decbits" + }, + { + "text": "bytes", + "value": "decbytes" + }, + { + "text": "kilobytes", + "value": "deckbytes" + }, + { + "text": "megabytes", + "value": "decmbytes" + }, + { + "text": "gigabytes", + "value": "decgbytes" + } + ], + "text": "data (Metric)" + }, + { + "submenu": [ + { + "text": "packets/sec", + "value": "pps" + }, + { + "text": "bits/sec", + "value": "bps" + }, + { + "text": "bytes/sec", + "value": "Bps" + }, + { + "text": "kilobits/sec", + "value": "Kbits" + }, + { + "text": "kilobytes/sec", + "value": "KBs" + }, + { + "text": "megabits/sec", + "value": "Mbits" + }, + { + "text": "megabytes/sec", + "value": "MBs" + }, + { + "text": "gigabytes/sec", + "value": "GBs" + }, + { + "text": "gigabits/sec", + "value": "Gbits" + } + ], + "text": "data rate" + }, + { + "submenu": [ + { + "text": "hashes/sec", + "value": "Hs" + }, + { + "text": "kilohashes/sec", + "value": "KHs" + }, + { + "text": "megahashes/sec", + "value": "MHs" + }, + { + "text": "gigahashes/sec", + "value": "GHs" + }, + { + "text": "terahashes/sec", + "value": "THs" + }, + { + "text": "petahashes/sec", + "value": "PHs" + }, + { + "text": "exahashes/sec", + "value": "EHs" + } + ], + "text": "hash rate" + }, + { + "submenu": [ + { + "text": "ops/sec (ops)", + "value": "ops" + }, + { + "text": "requests/sec (rps)", + "value": "reqps" + }, + { + "text": "reads/sec (rps)", + "value": "rps" + }, + { + "text": "writes/sec (wps)", + "value": "wps" + }, + { + "text": "I/O ops/sec (iops)", + "value": "iops" + }, + { + "text": "ops/min (opm)", + "value": "opm" + }, + { + "text": "requests/min (rpm)", + "value": "reqpm" + }, + { + "text": "reads/min (rpm)", + "value": "rpm" + }, + { + "text": "writes/min (wpm)", + "value": "wpm" + } + ], + "text": "throughput" + }, + { + "submenu": [ + { + "text": "millimetre (mm)", + "value": "lengthmm" + }, + { + "text": "meter (m)", + "value": "lengthm" + }, + { + "text": "inch (in)", + "value": "lengthin" + }, + { + "text": "feet (ft)", + "value": "lengthft" + }, + { + "text": "kilometer (km)", + "value": "lengthkm" + }, + { + "text": "mile (mi)", + "value": "lengthmi" + } + ], + "text": "length" + }, + { + "submenu": [ + { + "text": "Square Meters (m²)", + "value": "areaM2" + }, + { + "text": "Square Feet (ft²)", + "value": "areaF2" + }, + { + "text": "Square Miles (mi²)", + "value": "areaMI2" + } + ], + "text": "area" + }, + { + "submenu": [ + { + "text": "milligram (mg)", + "value": "massmg" + }, + { + "text": "gram (g)", + "value": "massg" + }, + { + "text": "pound (lb)", + "value": "masslb" + }, + { + "text": "kilogram (kg)", + "value": "masskg" + }, + { + "text": "metric ton (t)", + "value": "masst" + } + ], + "text": "mass" + }, + { + "submenu": [ + { + "text": "metres/second (m/s)", + "value": "velocityms" + }, + { + "text": "kilometers/hour (km/h)", + "value": "velocitykmh" + }, + { + "text": "miles/hour (mph)", + "value": "velocitymph" + }, + { + "text": "knot (kn)", + "value": "velocityknot" + } + ], + "text": "velocity" + }, + { + "submenu": [ + { + "text": "millilitre (mL)", + "value": "mlitre" + }, + { + "text": "litre (L)", + "value": "litre" + }, + { + "text": "cubic metre", + "value": "m3" + }, + { + "text": "Normal cubic metre", + "value": "Nm3" + }, + { + "text": "cubic decimetre", + "value": "dm3" + }, + { + "text": "gallons", + "value": "gallons" + } + ], + "text": "volume" + }, + { + "submenu": [ + { + "text": "Watt (W)", + "value": "watt" + }, + { + "text": "Kilowatt (kW)", + "value": "kwatt" + }, + { + "text": "Milliwatt (mW)", + "value": "mwatt" + }, + { + "text": "Watt per square metre (W/m²)", + "value": "Wm2" + }, + { + "text": "Volt-ampere (VA)", + "value": "voltamp" + }, + { + "text": "Kilovolt-ampere (kVA)", + "value": "kvoltamp" + }, + { + "text": "Volt-ampere reactive (var)", + "value": "voltampreact" + }, + { + "text": "Kilovolt-ampere reactive (kvar)", + "value": "kvoltampreact" + }, + { + "text": "Watt-hour (Wh)", + "value": "watth" + }, + { + "text": "Kilowatt-hour (kWh)", + "value": "kwatth" + }, + { + "text": "Kilowatt-min (kWm)", + "value": "kwattm" + }, + { + "text": "Joule (J)", + "value": "joule" + }, + { + "text": "Electron volt (eV)", + "value": "ev" + }, + { + "text": "Ampere (A)", + "value": "amp" + }, + { + "text": "Kiloampere (kA)", + "value": "kamp" + }, + { + "text": "Milliampere (mA)", + "value": "mamp" + }, + { + "text": "Volt (V)", + "value": "volt" + }, + { + "text": "Kilovolt (kV)", + "value": "kvolt" + }, + { + "text": "Millivolt (mV)", + "value": "mvolt" + }, + { + "text": "Decibel-milliwatt (dBm)", + "value": "dBm" + }, + { + "text": "Ohm (Ω)", + "value": "ohm" + }, + { + "text": "Lumens (Lm)", + "value": "lumens" + } + ], + "text": "energy" + }, + { + "submenu": [ + { + "text": "Celsius (°C)", + "value": "celsius" + }, + { + "text": "Fahrenheit (°F)", + "value": "fahrenheit" + }, + { + "text": "Kelvin (K)", + "value": "kelvin" + } + ], + "text": "temperature" + }, + { + "submenu": [ + { + "text": "Millibars", + "value": "pressurembar" + }, + { + "text": "Bars", + "value": "pressurebar" + }, + { + "text": "Kilobars", + "value": "pressurekbar" + }, + { + "text": "Hectopascals", + "value": "pressurehpa" + }, + { + "text": "Kilopascals", + "value": "pressurekpa" + }, + { + "text": "Inches of mercury", + "value": "pressurehg" + }, + { + "text": "PSI", + "value": "pressurepsi" + } + ], + "text": "pressure" + }, + { + "submenu": [ + { + "text": "Newton-meters (Nm)", + "value": "forceNm" + }, + { + "text": "Kilonewton-meters (kNm)", + "value": "forcekNm" + }, + { + "text": "Newtons (N)", + "value": "forceN" + }, + { + "text": "Kilonewtons (kN)", + "value": "forcekN" + } + ], + "text": "force" + }, + { + "submenu": [ + { + "text": "Gallons/min (gpm)", + "value": "flowgpm" + }, + { + "text": "Cubic meters/sec (cms)", + "value": "flowcms" + }, + { + "text": "Cubic feet/sec (cfs)", + "value": "flowcfs" + }, + { + "text": "Cubic feet/min (cfm)", + "value": "flowcfm" + }, + { + "text": "Litre/hour", + "value": "litreh" + }, + { + "text": "Litre/min (l/min)", + "value": "flowlpm" + }, + { + "text": "milliLitre/min (mL/min)", + "value": "flowmlpm" + } + ], + "text": "flow" + }, + { + "submenu": [ + { + "text": "Degrees (°)", + "value": "degree" + }, + { + "text": "Radians", + "value": "radian" + }, + { + "text": "Gradian", + "value": "grad" + } + ], + "text": "angle" + }, + { + "submenu": [ + { + "text": "Meters/sec²", + "value": "accMS2" + }, + { + "text": "Feet/sec²", + "value": "accFS2" + }, + { + "text": "G unit", + "value": "accG" + } + ], + "text": "acceleration" + }, + { + "submenu": [ + { + "text": "Becquerel (Bq)", + "value": "radbq" + }, + { + "text": "curie (Ci)", + "value": "radci" + }, + { + "text": "Gray (Gy)", + "value": "radgy" + }, + { + "text": "rad", + "value": "radrad" + }, + { + "text": "Sievert (Sv)", + "value": "radsv" + }, + { + "text": "rem", + "value": "radrem" + }, + { + "text": "Exposure (C/kg)", + "value": "radexpckg" + }, + { + "text": "roentgen (R)", + "value": "radr" + }, + { + "text": "Sievert/hour (Sv/h)", + "value": "radsvh" + } + ], + "text": "radiation" + }, + { + "submenu": [ + { + "text": "parts-per-million (ppm)", + "value": "ppm" + }, + { + "text": "parts-per-billion (ppb)", + "value": "conppb" + }, + { + "text": "nanogram per cubic metre (ng/m³)", + "value": "conngm3" + }, + { + "text": "nanogram per normal cubic metre (ng/Nm³)", + "value": "conngNm3" + }, + { + "text": "microgram per cubic metre (μg/m³)", + "value": "conμgm3" + }, + { + "text": "microgram per normal cubic metre (μg/Nm³)", + "value": "conμgNm3" + }, + { + "text": "milligram per cubic metre (mg/m³)", + "value": "conmgm3" + }, + { + "text": "milligram per normal cubic metre (mg/Nm³)", + "value": "conmgNm3" + }, + { + "text": "gram per cubic metre (g/m³)", + "value": "congm3" + }, + { + "text": "gram per normal cubic metre (g/Nm³)", + "value": "congNm3" + } + ], + "text": "concentration" + } + ] + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -250,7 +1316,1129 @@ "group": "grafana-polystat-panel", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "grafana-polystat-panel", + "originalOptions": { + "animationModes": [ + { + "text": "Show All", + "value": "all" + }, + { + "text": "Show Triggered", + "value": "triggered" + } + ], + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "d3DivId": "d3_svg_4", + "decimals": 2, + "displayModes": [ + { + "text": "Show All", + "value": "all" + }, + { + "text": "Show Triggered", + "value": "triggered" + } + ], + "fontSizes": [ + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 22, + 24, + 26, + 28, + 30, + 32, + 34, + 36, + 38, + 40, + 42, + 44, + 46, + 48, + 50, + 52, + 54, + 56, + 58, + 60, + 62, + 64, + 66, + 68, + 70 + ], + "fontTypes": [ + "Open Sans", + "Arial", + "Avant Garde", + "Bookman", + "Consolas", + "Courier", + "Courier New", + "Futura", + "Garamond", + "Helvetica", + "Palatino", + "Times", + "Times New Roman", + "Verdana" + ], + "format": "none", + "notcolors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "operatorName": "avg", + "operatorOptions": [ + { + "text": "Average", + "value": "avg" + }, + { + "text": "Count", + "value": "count" + }, + { + "text": "Current", + "value": "current" + }, + { + "text": "Delta", + "value": "delta" + }, + { + "text": "Difference", + "value": "diff" + }, + { + "text": "First", + "value": "first" + }, + { + "text": "Log Min", + "value": "logmin" + }, + { + "text": "Max", + "value": "max" + }, + { + "text": "Min", + "value": "min" + }, + { + "text": "Name", + "value": "name" + }, + { + "text": "Time of Last Point", + "value": "last_time" + }, + { + "text": "Time Step", + "value": "time_step" + }, + { + "text": "Total", + "value": "total" + } + ], + "polystat": { + "animationSpeed": 2500, + "columnAutoSize": true, + "columns": "", + "defaultClickThrough": "", + "defaultClickThroughSanitize": true, + "displayLimit": 100, + "fontAutoScale": true, + "fontSize": 12, + "globalDisplayMode": "all", + "globalOperatorName": "avg", + "gradientEnabled": true, + "hexagonSortByDirection": "asc", + "hexagonSortByField": "name", + "maxMetrics": 0, + "polygonBorderColor": "black", + "polygonBorderSize": 2, + "radius": "", + "radiusAutoSize": true, + "rowAutoSize": true, + "rows": "", + "shape": "hexagon_pointed_top", + "tooltipDisplayMode": "all", + "tooltipDisplayTextTriggeredEmpty": "OK", + "tooltipFontSize": 12, + "tooltipFontType": "Open Sans", + "tooltipPrimarySortDirection": "desc", + "tooltipPrimarySortField": "thresholdLevel", + "tooltipSecondarySortDirection": "desc", + "tooltipSecondarySortField": "value", + "tooltipTimestampEnabled": true + }, + "savedComposites": [], + "savedOverrides": [], + "shapes": [ + { + "text": "Hexagon Pointed Top", + "value": "hexagon_pointed_top" + }, + { + "text": "Hexagon Flat Top", + "value": "hexagon_flat_top" + }, + { + "text": "Circle", + "value": "circle" + }, + { + "text": "Cross", + "value": "cross" + }, + { + "text": "Diamond", + "value": "diamond" + }, + { + "text": "Square", + "value": "square" + }, + { + "text": "Star", + "value": "star" + }, + { + "text": "Triangle", + "value": "triangle" + }, + { + "text": "Wye", + "value": "wye" + } + ], + "sortDirections": [ + { + "text": "Ascending", + "value": "asc" + }, + { + "text": "Descending", + "value": "desc" + } + ], + "sortFields": [ + { + "text": "Name", + "value": "name" + }, + { + "text": "Threshold Level", + "value": "thresholdLevel" + }, + { + "text": "Value", + "value": "value" + } + ], + "svgContainer": {}, + "thresholdStates": [ + { + "text": "ok", + "value": 0 + }, + { + "text": "warning", + "value": 1 + }, + { + "text": "critical", + "value": 2 + }, + { + "text": "custom", + "value": 3 + } + ], + "unitFormats": [ + { + "submenu": [ + { + "text": "none", + "value": "none" + }, + { + "text": "short", + "value": "short" + }, + { + "text": "percent (0-100)", + "value": "percent" + }, + { + "text": "percent (0.0-1.0)", + "value": "percentunit" + }, + { + "text": "Humidity (%H)", + "value": "humidity" + }, + { + "text": "decibel", + "value": "dB" + }, + { + "text": "hexadecimal (0x)", + "value": "hex0x" + }, + { + "text": "hexadecimal", + "value": "hex" + }, + { + "text": "scientific notation", + "value": "sci" + }, + { + "text": "locale format", + "value": "locale" + } + ], + "text": "none" + }, + { + "submenu": [ + { + "text": "Dollars ($)", + "value": "currencyUSD" + }, + { + "text": "Pounds (£)", + "value": "currencyGBP" + }, + { + "text": "Euro (€)", + "value": "currencyEUR" + }, + { + "text": "Yen (¥)", + "value": "currencyJPY" + }, + { + "text": "Rubles (₽)", + "value": "currencyRUB" + }, + { + "text": "Hryvnias (₴)", + "value": "currencyUAH" + }, + { + "text": "Real (R$)", + "value": "currencyBRL" + }, + { + "text": "Danish Krone (kr)", + "value": "currencyDKK" + }, + { + "text": "Icelandic Króna (kr)", + "value": "currencyISK" + }, + { + "text": "Norwegian Krone (kr)", + "value": "currencyNOK" + }, + { + "text": "Swedish Krona (kr)", + "value": "currencySEK" + }, + { + "text": "Czech koruna (czk)", + "value": "currencyCZK" + }, + { + "text": "Swiss franc (CHF)", + "value": "currencyCHF" + }, + { + "text": "Polish Złoty (PLN)", + "value": "currencyPLN" + }, + { + "text": "Bitcoin (฿)", + "value": "currencyBTC" + }, + { + "text": "Milli Bitcoin (mBTC)", + "value": "currencymBTC" + }, + { + "text": "Micro Bitcoin (μBTC)", + "value": "currencyμBTC" + }, + { + "text": "Vietnamese Dong (VND)", + "value": "currencyVND" + }, + { + "text": "Turkish Lira (₺)", + "value": "currencyTRY" + }, + { + "text": "Malaysian Ringgit (RM)", + "value": "currencyMYR" + }, + { + "text": "CFP franc (XPF)", + "value": "currencyXPF" + }, + { + "text": "Bulgarian Lev (BGN)", + "value": "currencyBGN" + } + ], + "text": "currency" + }, + { + "submenu": [ + { + "text": "Hertz (1/s)", + "value": "hertz" + }, + { + "text": "nanoseconds (ns)", + "value": "ns" + }, + { + "text": "microseconds (µs)", + "value": "µs" + }, + { + "text": "milliseconds (ms)", + "value": "ms" + }, + { + "text": "seconds (s)", + "value": "s" + }, + { + "text": "minutes (m)", + "value": "m" + }, + { + "text": "hours (h)", + "value": "h" + }, + { + "text": "days (d)", + "value": "d" + }, + { + "text": "duration (ms)", + "value": "dtdurationms" + }, + { + "text": "duration (s)", + "value": "dtdurations" + }, + { + "text": "duration (hh:mm:ss)", + "value": "dthms" + }, + { + "text": "Timeticks (s/100)", + "value": "timeticks" + } + ], + "text": "time" + }, + { + "submenu": [ + { + "text": "YYYY-MM-DD HH:mm:ss", + "value": "dateTimeAsIso" + }, + { + "text": "DD/MM/YYYY h:mm:ss a", + "value": "dateTimeAsUS" + }, + { + "text": "From Now", + "value": "dateTimeFromNow" + } + ], + "text": "date \u0026 time" + }, + { + "submenu": [ + { + "text": "bits", + "value": "bits" + }, + { + "text": "bytes", + "value": "bytes" + }, + { + "text": "kibibytes", + "value": "kbytes" + }, + { + "text": "mebibytes", + "value": "mbytes" + }, + { + "text": "gibibytes", + "value": "gbytes" + } + ], + "text": "data (IEC)" + }, + { + "submenu": [ + { + "text": "bits", + "value": "decbits" + }, + { + "text": "bytes", + "value": "decbytes" + }, + { + "text": "kilobytes", + "value": "deckbytes" + }, + { + "text": "megabytes", + "value": "decmbytes" + }, + { + "text": "gigabytes", + "value": "decgbytes" + } + ], + "text": "data (Metric)" + }, + { + "submenu": [ + { + "text": "packets/sec", + "value": "pps" + }, + { + "text": "bits/sec", + "value": "bps" + }, + { + "text": "bytes/sec", + "value": "Bps" + }, + { + "text": "kilobits/sec", + "value": "Kbits" + }, + { + "text": "kilobytes/sec", + "value": "KBs" + }, + { + "text": "megabits/sec", + "value": "Mbits" + }, + { + "text": "megabytes/sec", + "value": "MBs" + }, + { + "text": "gigabytes/sec", + "value": "GBs" + }, + { + "text": "gigabits/sec", + "value": "Gbits" + } + ], + "text": "data rate" + }, + { + "submenu": [ + { + "text": "hashes/sec", + "value": "Hs" + }, + { + "text": "kilohashes/sec", + "value": "KHs" + }, + { + "text": "megahashes/sec", + "value": "MHs" + }, + { + "text": "gigahashes/sec", + "value": "GHs" + }, + { + "text": "terahashes/sec", + "value": "THs" + }, + { + "text": "petahashes/sec", + "value": "PHs" + }, + { + "text": "exahashes/sec", + "value": "EHs" + } + ], + "text": "hash rate" + }, + { + "submenu": [ + { + "text": "counts/sec (cps)", + "value": "cps" + }, + { + "text": "ops/sec (ops)", + "value": "ops" + }, + { + "text": "requests/sec (rps)", + "value": "reqps" + }, + { + "text": "reads/sec (rps)", + "value": "rps" + }, + { + "text": "writes/sec (wps)", + "value": "wps" + }, + { + "text": "I/O ops/sec (iops)", + "value": "iops" + }, + { + "text": "events/sec (eps)", + "value": "eps" + }, + { + "text": "messages/sec (mps)", + "value": "mps" + }, + { + "text": "records/sec (rps)", + "value": "recps" + }, + { + "text": "rows/sec (rps)", + "value": "rowsps" + }, + { + "text": "counts/min (cpm)", + "value": "cpm" + }, + { + "text": "ops/min (opm)", + "value": "opm" + }, + { + "text": "requests/min (rpm)", + "value": "reqpm" + }, + { + "text": "reads/min (rpm)", + "value": "rpm" + }, + { + "text": "writes/min (wpm)", + "value": "wpm" + }, + { + "text": "events/min (epm)", + "value": "epm" + }, + { + "text": "messages/min (mpm)", + "value": "mpm" + }, + { + "text": "records/min (rpm)", + "value": "recpm" + }, + { + "text": "rows/min (rpm)", + "value": "rowspm" + } + ], + "text": "throughput" + }, + { + "submenu": [ + { + "text": "millimetre (mm)", + "value": "lengthmm" + }, + { + "text": "meter (m)", + "value": "lengthm" + }, + { + "text": "inch (in)", + "value": "lengthin" + }, + { + "text": "feet (ft)", + "value": "lengthft" + }, + { + "text": "kilometer (km)", + "value": "lengthkm" + }, + { + "text": "mile (mi)", + "value": "lengthmi" + } + ], + "text": "length" + }, + { + "submenu": [ + { + "text": "Square Meters (m²)", + "value": "areaM2" + }, + { + "text": "Square Feet (ft²)", + "value": "areaF2" + }, + { + "text": "Square Miles (mi²)", + "value": "areaMI2" + } + ], + "text": "area" + }, + { + "submenu": [ + { + "text": "milligram (mg)", + "value": "massmg" + }, + { + "text": "gram (g)", + "value": "massg" + }, + { + "text": "pound (lb)", + "value": "masslb" + }, + { + "text": "kilogram (kg)", + "value": "masskg" + }, + { + "text": "metric ton (t)", + "value": "masst" + } + ], + "text": "mass" + }, + { + "submenu": [ + { + "text": "metres/second (m/s)", + "value": "velocityms" + }, + { + "text": "kilometers/hour (km/h)", + "value": "velocitykmh" + }, + { + "text": "miles/hour (mph)", + "value": "velocitymph" + }, + { + "text": "knot (kn)", + "value": "velocityknot" + } + ], + "text": "velocity" + }, + { + "submenu": [ + { + "text": "millilitre (mL)", + "value": "mlitre" + }, + { + "text": "litre (L)", + "value": "litre" + }, + { + "text": "cubic metre", + "value": "m3" + }, + { + "text": "Normal cubic metre", + "value": "Nm3" + }, + { + "text": "cubic decimetre", + "value": "dm3" + }, + { + "text": "gallons", + "value": "gallons" + } + ], + "text": "volume" + }, + { + "submenu": [ + { + "text": "Watt (W)", + "value": "watt" + }, + { + "text": "Kilowatt (kW)", + "value": "kwatt" + }, + { + "text": "Milliwatt (mW)", + "value": "mwatt" + }, + { + "text": "Watt per square metre (W/m²)", + "value": "Wm2" + }, + { + "text": "Volt-Ampere (VA)", + "value": "voltamp" + }, + { + "text": "Kilovolt-Ampere (kVA)", + "value": "kvoltamp" + }, + { + "text": "Volt-Ampere reactive (VAr)", + "value": "voltampreact" + }, + { + "text": "Kilovolt-Ampere reactive (kVAr)", + "value": "kvoltampreact" + }, + { + "text": "Watt-hour (Wh)", + "value": "watth" + }, + { + "text": "Kilowatt-hour (kWh)", + "value": "kwatth" + }, + { + "text": "Kilowatt-min (kWm)", + "value": "kwattm" + }, + { + "text": "Joule (J)", + "value": "joule" + }, + { + "text": "Electron volt (eV)", + "value": "ev" + }, + { + "text": "Ampere (A)", + "value": "amp" + }, + { + "text": "Kiloampere (kA)", + "value": "kamp" + }, + { + "text": "Milliampere (mA)", + "value": "mamp" + }, + { + "text": "Volt (V)", + "value": "volt" + }, + { + "text": "Kilovolt (kV)", + "value": "kvolt" + }, + { + "text": "Millivolt (mV)", + "value": "mvolt" + }, + { + "text": "Decibel-milliwatt (dBm)", + "value": "dBm" + }, + { + "text": "Ohm (Ω)", + "value": "ohm" + }, + { + "text": "Lumens (Lm)", + "value": "lumens" + } + ], + "text": "energy" + }, + { + "submenu": [ + { + "text": "Celsius (°C)", + "value": "celsius" + }, + { + "text": "Fahrenheit (°F)", + "value": "fahrenheit" + }, + { + "text": "Kelvin (K)", + "value": "kelvin" + } + ], + "text": "temperature" + }, + { + "submenu": [ + { + "text": "Millibars", + "value": "pressurembar" + }, + { + "text": "Bars", + "value": "pressurebar" + }, + { + "text": "Kilobars", + "value": "pressurekbar" + }, + { + "text": "Hectopascals", + "value": "pressurehpa" + }, + { + "text": "Kilopascals", + "value": "pressurekpa" + }, + { + "text": "Inches of mercury", + "value": "pressurehg" + }, + { + "text": "PSI", + "value": "pressurepsi" + } + ], + "text": "pressure" + }, + { + "submenu": [ + { + "text": "Newton-meters (Nm)", + "value": "forceNm" + }, + { + "text": "Kilonewton-meters (kNm)", + "value": "forcekNm" + }, + { + "text": "Newtons (N)", + "value": "forceN" + }, + { + "text": "Kilonewtons (kN)", + "value": "forcekN" + } + ], + "text": "force" + }, + { + "submenu": [ + { + "text": "Gallons/min (gpm)", + "value": "flowgpm" + }, + { + "text": "Cubic meters/sec (cms)", + "value": "flowcms" + }, + { + "text": "Cubic feet/sec (cfs)", + "value": "flowcfs" + }, + { + "text": "Cubic feet/min (cfm)", + "value": "flowcfm" + }, + { + "text": "Litre/hour", + "value": "litreh" + }, + { + "text": "Litre/min (l/min)", + "value": "flowlpm" + }, + { + "text": "milliLitre/min (mL/min)", + "value": "flowmlpm" + } + ], + "text": "flow" + }, + { + "submenu": [ + { + "text": "Degrees (°)", + "value": "degree" + }, + { + "text": "Radians", + "value": "radian" + }, + { + "text": "Gradian", + "value": "grad" + } + ], + "text": "angle" + }, + { + "submenu": [ + { + "text": "Meters/sec²", + "value": "accMS2" + }, + { + "text": "Feet/sec²", + "value": "accFS2" + }, + { + "text": "G unit", + "value": "accG" + } + ], + "text": "acceleration" + }, + { + "submenu": [ + { + "text": "Becquerel (Bq)", + "value": "radbq" + }, + { + "text": "curie (Ci)", + "value": "radci" + }, + { + "text": "Gray (Gy)", + "value": "radgy" + }, + { + "text": "rad", + "value": "radrad" + }, + { + "text": "Sievert (Sv)", + "value": "radsv" + }, + { + "text": "rem", + "value": "radrem" + }, + { + "text": "Exposure (C/kg)", + "value": "radexpckg" + }, + { + "text": "roentgen (R)", + "value": "radr" + }, + { + "text": "Sievert/hour (Sv/h)", + "value": "radsvh" + } + ], + "text": "radiation" + }, + { + "submenu": [ + { + "text": "parts-per-million (ppm)", + "value": "ppm" + }, + { + "text": "parts-per-billion (ppb)", + "value": "conppb" + }, + { + "text": "nanogram per cubic metre (ng/m³)", + "value": "conngm3" + }, + { + "text": "nanogram per normal cubic metre (ng/Nm³)", + "value": "conngNm3" + }, + { + "text": "microgram per cubic metre (μg/m³)", + "value": "conμgm3" + }, + { + "text": "microgram per normal cubic metre (μg/Nm³)", + "value": "conμgNm3" + }, + { + "text": "milligram per cubic metre (mg/m³)", + "value": "conmgm3" + }, + { + "text": "milligram per normal cubic metre (mg/Nm³)", + "value": "conmgNm3" + }, + { + "text": "gram per cubic metre (g/m³)", + "value": "congm3" + }, + { + "text": "gram per normal cubic metre (g/Nm³)", + "value": "congNm3" + } + ], + "text": "concentration" + } + ] + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -370,7 +2558,1090 @@ "group": "grafana-polystat-panel", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "grafana-polystat-panel", + "originalOptions": { + "animationModes": [ + { + "text": "Show All", + "value": "all" + }, + { + "text": "Show Triggered", + "value": "triggered" + } + ], + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "d3DivId": "d3_svg_5", + "decimals": 2, + "displayModes": [ + { + "text": "Show All", + "value": "all" + }, + { + "text": "Show Triggered", + "value": "triggered" + } + ], + "fontSizes": [ + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 22, + 24, + 26, + 28, + 30, + 32, + 34, + 36, + 38, + 40, + 42, + 44, + 46, + 48, + 50, + 52, + 54, + 56, + 58, + 60, + 62, + 64, + 66, + 68, + 70 + ], + "fontTypes": [ + "Open Sans", + "Arial", + "Avant Garde", + "Bookman", + "Consolas", + "Courier", + "Courier New", + "Futura", + "Garamond", + "Helvetica", + "Palatino", + "Times", + "Times New Roman", + "Verdana" + ], + "format": "none", + "notcolors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "operatorName": "avg", + "operatorOptions": [ + { + "text": "Average", + "value": "avg" + }, + { + "text": "Count", + "value": "count" + }, + { + "text": "Current", + "value": "current" + }, + { + "text": "Delta", + "value": "delta" + }, + { + "text": "Difference", + "value": "diff" + }, + { + "text": "First", + "value": "first" + }, + { + "text": "Log Min", + "value": "logmin" + }, + { + "text": "Max", + "value": "max" + }, + { + "text": "Min", + "value": "min" + }, + { + "text": "Name", + "value": "name" + }, + { + "text": "Time of Last Point", + "value": "last_time" + }, + { + "text": "Time Step", + "value": "time_step" + }, + { + "text": "Total", + "value": "total" + } + ], + "polystat": { + "animationSpeed": 2500, + "columnAutoSize": true, + "columns": "", + "defaultClickThrough": "", + "defaultClickThroughSanitize": true, + "displayLimit": 100, + "fontAutoScale": true, + "fontSize": 12, + "globalDisplayMode": "all", + "globalOperatorName": "avg", + "gradientEnabled": true, + "hexagonSortByDirection": "asc", + "hexagonSortByField": "name", + "maxMetrics": 0, + "polygonBorderColor": "black", + "polygonBorderSize": 2, + "radius": "", + "radiusAutoSize": true, + "rowAutoSize": true, + "rows": "", + "shape": "hexagon_pointed_top", + "tooltipDisplayMode": "all", + "tooltipDisplayTextTriggeredEmpty": "OK", + "tooltipFontSize": 12, + "tooltipFontType": "Open Sans", + "tooltipPrimarySortDirection": "desc", + "tooltipPrimarySortField": "thresholdLevel", + "tooltipSecondarySortDirection": "desc", + "tooltipSecondarySortField": "value", + "tooltipTimestampEnabled": true + }, + "savedComposites": [ + { + "animateMode": "all", + "clickThrough": "", + "compositeName": "comp", + "enabled": true, + "hideMembers": true, + "members": [ + { + "seriesName": "A-series" + }, + { + "seriesName": "B-series" + } + ], + "sanitizeURLEnabled": true, + "sanitizedURL": "", + "showName": true, + "showValue": true, + "thresholdLevel": 0 + } + ], + "savedOverrides": [], + "shapes": [ + { + "text": "Hexagon Pointed Top", + "value": "hexagon_pointed_top" + }, + { + "text": "Hexagon Flat Top", + "value": "hexagon_flat_top" + }, + { + "text": "Circle", + "value": "circle" + }, + { + "text": "Cross", + "value": "cross" + }, + { + "text": "Diamond", + "value": "diamond" + }, + { + "text": "Square", + "value": "square" + }, + { + "text": "Star", + "value": "star" + }, + { + "text": "Triangle", + "value": "triangle" + }, + { + "text": "Wye", + "value": "wye" + } + ], + "sortDirections": [ + { + "text": "Ascending", + "value": "asc" + }, + { + "text": "Descending", + "value": "desc" + } + ], + "sortFields": [ + { + "text": "Name", + "value": "name" + }, + { + "text": "Threshold Level", + "value": "thresholdLevel" + }, + { + "text": "Value", + "value": "value" + } + ], + "svgContainer": {}, + "thresholdStates": [ + { + "text": "ok", + "value": 0 + }, + { + "text": "warning", + "value": 1 + }, + { + "text": "critical", + "value": 2 + }, + { + "text": "custom", + "value": 3 + } + ], + "unitFormats": [ + { + "submenu": [ + { + "text": "none", + "value": "none" + }, + { + "text": "short", + "value": "short" + }, + { + "text": "percent (0-100)", + "value": "percent" + }, + { + "text": "percent (0.0-1.0)", + "value": "percentunit" + }, + { + "text": "Humidity (%H)", + "value": "humidity" + }, + { + "text": "decibel", + "value": "dB" + }, + { + "text": "hexadecimal (0x)", + "value": "hex0x" + }, + { + "text": "hexadecimal", + "value": "hex" + }, + { + "text": "scientific notation", + "value": "sci" + }, + { + "text": "locale format", + "value": "locale" + } + ], + "text": "none" + }, + { + "submenu": [ + { + "text": "Dollars ($)", + "value": "currencyUSD" + }, + { + "text": "Pounds (£)", + "value": "currencyGBP" + }, + { + "text": "Euro (€)", + "value": "currencyEUR" + }, + { + "text": "Yen (¥)", + "value": "currencyJPY" + }, + { + "text": "Rubles (₽)", + "value": "currencyRUB" + }, + { + "text": "Hryvnias (₴)", + "value": "currencyUAH" + }, + { + "text": "Real (R$)", + "value": "currencyBRL" + }, + { + "text": "Danish Krone (kr)", + "value": "currencyDKK" + }, + { + "text": "Icelandic Króna (kr)", + "value": "currencyISK" + }, + { + "text": "Norwegian Krone (kr)", + "value": "currencyNOK" + }, + { + "text": "Swedish Krona (kr)", + "value": "currencySEK" + }, + { + "text": "Czech koruna (czk)", + "value": "currencyCZK" + }, + { + "text": "Swiss franc (CHF)", + "value": "currencyCHF" + }, + { + "text": "Polish Złoty (PLN)", + "value": "currencyPLN" + }, + { + "text": "Bitcoin (฿)", + "value": "currencyBTC" + }, + { + "text": "Vietnamese Dong (VND)", + "value": "currencyVND" + }, + { + "text": "Malaysian Ringgit (RM)", + "value": "currencyMYR" + }, + { + "text": "Bulgarian Lev (BGN)", + "value": "currencyBGN" + } + ], + "text": "currency" + }, + { + "submenu": [ + { + "text": "Hertz (1/s)", + "value": "hertz" + }, + { + "text": "nanoseconds (ns)", + "value": "ns" + }, + { + "text": "microseconds (µs)", + "value": "µs" + }, + { + "text": "milliseconds (ms)", + "value": "ms" + }, + { + "text": "seconds (s)", + "value": "s" + }, + { + "text": "minutes (m)", + "value": "m" + }, + { + "text": "hours (h)", + "value": "h" + }, + { + "text": "days (d)", + "value": "d" + }, + { + "text": "duration (ms)", + "value": "dtdurationms" + }, + { + "text": "duration (s)", + "value": "dtdurations" + }, + { + "text": "duration (hh:mm:ss)", + "value": "dthms" + }, + { + "text": "Timeticks (s/100)", + "value": "timeticks" + } + ], + "text": "time" + }, + { + "submenu": [ + { + "text": "YYYY-MM-DD HH:mm:ss", + "value": "dateTimeAsIso" + }, + { + "text": "DD/MM/YYYY h:mm:ss a", + "value": "dateTimeAsUS" + }, + { + "text": "From Now", + "value": "dateTimeFromNow" + } + ], + "text": "date \u0026 time" + }, + { + "submenu": [ + { + "text": "bits", + "value": "bits" + }, + { + "text": "bytes", + "value": "bytes" + }, + { + "text": "kibibytes", + "value": "kbytes" + }, + { + "text": "mebibytes", + "value": "mbytes" + }, + { + "text": "gibibytes", + "value": "gbytes" + } + ], + "text": "data (IEC)" + }, + { + "submenu": [ + { + "text": "bits", + "value": "decbits" + }, + { + "text": "bytes", + "value": "decbytes" + }, + { + "text": "kilobytes", + "value": "deckbytes" + }, + { + "text": "megabytes", + "value": "decmbytes" + }, + { + "text": "gigabytes", + "value": "decgbytes" + } + ], + "text": "data (Metric)" + }, + { + "submenu": [ + { + "text": "packets/sec", + "value": "pps" + }, + { + "text": "bits/sec", + "value": "bps" + }, + { + "text": "bytes/sec", + "value": "Bps" + }, + { + "text": "kilobits/sec", + "value": "Kbits" + }, + { + "text": "kilobytes/sec", + "value": "KBs" + }, + { + "text": "megabits/sec", + "value": "Mbits" + }, + { + "text": "megabytes/sec", + "value": "MBs" + }, + { + "text": "gigabytes/sec", + "value": "GBs" + }, + { + "text": "gigabits/sec", + "value": "Gbits" + } + ], + "text": "data rate" + }, + { + "submenu": [ + { + "text": "hashes/sec", + "value": "Hs" + }, + { + "text": "kilohashes/sec", + "value": "KHs" + }, + { + "text": "megahashes/sec", + "value": "MHs" + }, + { + "text": "gigahashes/sec", + "value": "GHs" + }, + { + "text": "terahashes/sec", + "value": "THs" + }, + { + "text": "petahashes/sec", + "value": "PHs" + }, + { + "text": "exahashes/sec", + "value": "EHs" + } + ], + "text": "hash rate" + }, + { + "submenu": [ + { + "text": "ops/sec (ops)", + "value": "ops" + }, + { + "text": "requests/sec (rps)", + "value": "reqps" + }, + { + "text": "reads/sec (rps)", + "value": "rps" + }, + { + "text": "writes/sec (wps)", + "value": "wps" + }, + { + "text": "I/O ops/sec (iops)", + "value": "iops" + }, + { + "text": "ops/min (opm)", + "value": "opm" + }, + { + "text": "reads/min (rpm)", + "value": "rpm" + }, + { + "text": "writes/min (wpm)", + "value": "wpm" + } + ], + "text": "throughput" + }, + { + "submenu": [ + { + "text": "millimetre (mm)", + "value": "lengthmm" + }, + { + "text": "meter (m)", + "value": "lengthm" + }, + { + "text": "inch (in)", + "value": "lengthin" + }, + { + "text": "feet (ft)", + "value": "lengthft" + }, + { + "text": "kilometer (km)", + "value": "lengthkm" + }, + { + "text": "mile (mi)", + "value": "lengthmi" + } + ], + "text": "length" + }, + { + "submenu": [ + { + "text": "Square Meters (m²)", + "value": "areaM2" + }, + { + "text": "Square Feet (ft²)", + "value": "areaF2" + }, + { + "text": "Square Miles (mi²)", + "value": "areaMI2" + } + ], + "text": "area" + }, + { + "submenu": [ + { + "text": "milligram (mg)", + "value": "massmg" + }, + { + "text": "gram (g)", + "value": "massg" + }, + { + "text": "pound (lb)", + "value": "masslb" + }, + { + "text": "kilogram (kg)", + "value": "masskg" + }, + { + "text": "metric ton (t)", + "value": "masst" + } + ], + "text": "mass" + }, + { + "submenu": [ + { + "text": "metres/second (m/s)", + "value": "velocityms" + }, + { + "text": "kilometers/hour (km/h)", + "value": "velocitykmh" + }, + { + "text": "miles/hour (mph)", + "value": "velocitymph" + }, + { + "text": "knot (kn)", + "value": "velocityknot" + } + ], + "text": "velocity" + }, + { + "submenu": [ + { + "text": "millilitre (mL)", + "value": "mlitre" + }, + { + "text": "litre (L)", + "value": "litre" + }, + { + "text": "cubic metre", + "value": "m3" + }, + { + "text": "Normal cubic metre", + "value": "Nm3" + }, + { + "text": "cubic decimetre", + "value": "dm3" + }, + { + "text": "gallons", + "value": "gallons" + } + ], + "text": "volume" + }, + { + "submenu": [ + { + "text": "Watt (W)", + "value": "watt" + }, + { + "text": "Kilowatt (kW)", + "value": "kwatt" + }, + { + "text": "Milliwatt (mW)", + "value": "mwatt" + }, + { + "text": "Watt per square metre (W/m²)", + "value": "Wm2" + }, + { + "text": "Volt-ampere (VA)", + "value": "voltamp" + }, + { + "text": "Kilovolt-ampere (kVA)", + "value": "kvoltamp" + }, + { + "text": "Volt-ampere reactive (var)", + "value": "voltampreact" + }, + { + "text": "Kilovolt-ampere reactive (kvar)", + "value": "kvoltampreact" + }, + { + "text": "Watt-hour (Wh)", + "value": "watth" + }, + { + "text": "Kilowatt-hour (kWh)", + "value": "kwatth" + }, + { + "text": "Kilowatt-min (kWm)", + "value": "kwattm" + }, + { + "text": "Joule (J)", + "value": "joule" + }, + { + "text": "Electron volt (eV)", + "value": "ev" + }, + { + "text": "Ampere (A)", + "value": "amp" + }, + { + "text": "Kiloampere (kA)", + "value": "kamp" + }, + { + "text": "Milliampere (mA)", + "value": "mamp" + }, + { + "text": "Volt (V)", + "value": "volt" + }, + { + "text": "Kilovolt (kV)", + "value": "kvolt" + }, + { + "text": "Millivolt (mV)", + "value": "mvolt" + }, + { + "text": "Decibel-milliwatt (dBm)", + "value": "dBm" + }, + { + "text": "Ohm (Ω)", + "value": "ohm" + }, + { + "text": "Lumens (Lm)", + "value": "lumens" + } + ], + "text": "energy" + }, + { + "submenu": [ + { + "text": "Celsius (°C)", + "value": "celsius" + }, + { + "text": "Fahrenheit (°F)", + "value": "fahrenheit" + }, + { + "text": "Kelvin (K)", + "value": "kelvin" + } + ], + "text": "temperature" + }, + { + "submenu": [ + { + "text": "Millibars", + "value": "pressurembar" + }, + { + "text": "Bars", + "value": "pressurebar" + }, + { + "text": "Kilobars", + "value": "pressurekbar" + }, + { + "text": "Hectopascals", + "value": "pressurehpa" + }, + { + "text": "Kilopascals", + "value": "pressurekpa" + }, + { + "text": "Inches of mercury", + "value": "pressurehg" + }, + { + "text": "PSI", + "value": "pressurepsi" + } + ], + "text": "pressure" + }, + { + "submenu": [ + { + "text": "Newton-meters (Nm)", + "value": "forceNm" + }, + { + "text": "Kilonewton-meters (kNm)", + "value": "forcekNm" + }, + { + "text": "Newtons (N)", + "value": "forceN" + }, + { + "text": "Kilonewtons (kN)", + "value": "forcekN" + } + ], + "text": "force" + }, + { + "submenu": [ + { + "text": "Gallons/min (gpm)", + "value": "flowgpm" + }, + { + "text": "Cubic meters/sec (cms)", + "value": "flowcms" + }, + { + "text": "Cubic feet/sec (cfs)", + "value": "flowcfs" + }, + { + "text": "Cubic feet/min (cfm)", + "value": "flowcfm" + }, + { + "text": "Litre/hour", + "value": "litreh" + }, + { + "text": "Litre/min (l/min)", + "value": "flowlpm" + }, + { + "text": "milliLitre/min (mL/min)", + "value": "flowmlpm" + } + ], + "text": "flow" + }, + { + "submenu": [ + { + "text": "Degrees (°)", + "value": "degree" + }, + { + "text": "Radians", + "value": "radian" + }, + { + "text": "Gradian", + "value": "grad" + } + ], + "text": "angle" + }, + { + "submenu": [ + { + "text": "Meters/sec²", + "value": "accMS2" + }, + { + "text": "Feet/sec²", + "value": "accFS2" + }, + { + "text": "G unit", + "value": "accG" + } + ], + "text": "acceleration" + }, + { + "submenu": [ + { + "text": "Becquerel (Bq)", + "value": "radbq" + }, + { + "text": "curie (Ci)", + "value": "radci" + }, + { + "text": "Gray (Gy)", + "value": "radgy" + }, + { + "text": "rad", + "value": "radrad" + }, + { + "text": "Sievert (Sv)", + "value": "radsv" + }, + { + "text": "rem", + "value": "radrem" + }, + { + "text": "Exposure (C/kg)", + "value": "radexpckg" + }, + { + "text": "roentgen (R)", + "value": "radr" + }, + { + "text": "Sievert/hour (Sv/h)", + "value": "radsvh" + } + ], + "text": "radiation" + }, + { + "submenu": [ + { + "text": "parts-per-million (ppm)", + "value": "ppm" + }, + { + "text": "parts-per-billion (ppb)", + "value": "conppb" + }, + { + "text": "nanogram per cubic metre (ng/m³)", + "value": "conngm3" + }, + { + "text": "nanogram per normal cubic metre (ng/Nm³)", + "value": "conngNm3" + }, + { + "text": "microgram per cubic metre (μg/m³)", + "value": "conμgm3" + }, + { + "text": "microgram per normal cubic metre (μg/Nm³)", + "value": "conμgNm3" + }, + { + "text": "milligram per cubic metre (mg/m³)", + "value": "conmgm3" + }, + { + "text": "milligram per normal cubic metre (mg/Nm³)", + "value": "conmgNm3" + }, + { + "text": "gram per cubic metre (g/m³)", + "value": "congm3" + }, + { + "text": "gram per normal cubic metre (g/Nm³)", + "value": "congNm3" + } + ], + "text": "concentration" + } + ] + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-table/v0alpha1.table_tests.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-table/v0alpha1.table_tests.v42.v2alpha1.json index 2bcedabe196..c706000d557 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-table/v0alpha1.table_tests.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-table/v0alpha1.table_tests.v42.v2alpha1.json @@ -80,7 +80,85 @@ "kind": "table", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "columns": [], + "fontSize": "100%", + "scroll": true, + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "align": "auto", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "date" + }, + { + "alias": "", + "align": "auto", + "colorMode": "cell", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "ColorCell", + "thresholds": [ + "5", + "10" + ], + "type": "number", + "unit": "currencyUSD" + }, + { + "alias": "", + "align": "auto", + "colorMode": "value", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "ColorValue", + "thresholds": [ + "5", + "10" + ], + "type": "number", + "unit": "Bps" + }, + { + "alias": "", + "align": "auto", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "number", + "unit": "short" + } + ], + "transform": "timeseries_to_columns" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -142,7 +220,86 @@ "kind": "table", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "columns": [], + "fontSize": "100%", + "pageSize": 10, + "scroll": true, + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "align": "auto", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "date" + }, + { + "alias": "", + "align": "auto", + "colorMode": "cell", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "ColorCell", + "thresholds": [ + "5", + "10" + ], + "type": "number", + "unit": "currencyUSD" + }, + { + "alias": "", + "align": "auto", + "colorMode": "value", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "ColorValue", + "thresholds": [ + "5", + "10" + ], + "type": "number", + "unit": "Bps" + }, + { + "alias": "", + "align": "auto", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "number", + "unit": "short" + } + ], + "transform": "timeseries_to_rows" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -204,7 +361,99 @@ "kind": "table", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "columns": [ + { + "text": "Avg", + "value": "avg" + }, + { + "text": "Max", + "value": "max" + }, + { + "text": "Current", + "value": "current" + } + ], + "fontSize": "100%", + "pageSize": 10, + "scroll": true, + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "align": "auto", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "date" + }, + { + "alias": "", + "align": "auto", + "colorMode": "cell", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "ColorCell", + "thresholds": [ + "5", + "10" + ], + "type": "number", + "unit": "currencyUSD" + }, + { + "alias": "", + "align": "auto", + "colorMode": "value", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "ColorValue", + "thresholds": [ + "5", + "10" + ], + "type": "number", + "unit": "Bps" + }, + { + "alias": "", + "align": "auto", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "number", + "unit": "short" + } + ], + "transform": "timeseries_aggregations" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -251,7 +500,65 @@ "kind": "table", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "columns": [], + "fontSize": "100%", + "scroll": true, + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "align": "auto", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "date" + }, + { + "alias": "", + "align": "auto", + "colorMode": "row", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "/Color/", + "thresholds": [ + "5", + "10" + ], + "type": "number", + "unit": "currencyUSD" + }, + { + "alias": "", + "align": "auto", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "number", + "unit": "short" + } + ], + "transform": "timeseries_to_columns" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -313,7 +620,92 @@ "kind": "table", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "columns": [], + "fontSize": "100%", + "pageSize": 20, + "scroll": true, + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "align": "auto", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "date" + }, + { + "alias": "", + "align": "auto", + "colorMode": "cell", + "colors": [ + "rgba(245, 54, 54, 0.5)", + "rgba(237, 129, 40, 0.5)", + "rgba(50, 172, 45, 0.5)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": true, + "linkTargetBlank": true, + "linkTooltip": "", + "linkUrl": "http://www.grafana.com", + "mappingType": 1, + "pattern": "ColorCell", + "thresholds": [ + "5", + "10" + ], + "type": "number", + "unit": "currencyUSD" + }, + { + "alias": "", + "align": "auto", + "colorMode": "value", + "colors": [ + "rgba(245, 54, 54, 0.5)", + "rgba(237, 129, 40, 0.5)", + "rgba(50, 172, 45, 0.5)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": true, + "linkUrl": "http://www.grafana.com", + "mappingType": 1, + "pattern": "ColorValue", + "thresholds": [ + "5", + "10" + ], + "type": "number", + "unit": "Bps" + }, + { + "alias": "", + "align": "auto", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "number", + "unit": "short" + } + ], + "transform": "timeseries_to_columns" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-table/v0alpha1.table_tests.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-table/v0alpha1.table_tests.v42.v2beta1.json index 2d84b370019..3ddb128c20e 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-table/v0alpha1.table_tests.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-table/v0alpha1.table_tests.v42.v2beta1.json @@ -87,7 +87,85 @@ "group": "table", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "columns": [], + "fontSize": "100%", + "scroll": true, + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "align": "auto", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "date" + }, + { + "alias": "", + "align": "auto", + "colorMode": "cell", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "ColorCell", + "thresholds": [ + "5", + "10" + ], + "type": "number", + "unit": "currencyUSD" + }, + { + "alias": "", + "align": "auto", + "colorMode": "value", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "ColorValue", + "thresholds": [ + "5", + "10" + ], + "type": "number", + "unit": "Bps" + }, + { + "alias": "", + "align": "auto", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "number", + "unit": "short" + } + ], + "transform": "timeseries_to_columns" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -154,7 +232,86 @@ "group": "table", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "columns": [], + "fontSize": "100%", + "pageSize": 10, + "scroll": true, + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "align": "auto", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "date" + }, + { + "alias": "", + "align": "auto", + "colorMode": "cell", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "ColorCell", + "thresholds": [ + "5", + "10" + ], + "type": "number", + "unit": "currencyUSD" + }, + { + "alias": "", + "align": "auto", + "colorMode": "value", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "ColorValue", + "thresholds": [ + "5", + "10" + ], + "type": "number", + "unit": "Bps" + }, + { + "alias": "", + "align": "auto", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "number", + "unit": "short" + } + ], + "transform": "timeseries_to_rows" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -221,7 +378,99 @@ "group": "table", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "columns": [ + { + "text": "Avg", + "value": "avg" + }, + { + "text": "Max", + "value": "max" + }, + { + "text": "Current", + "value": "current" + } + ], + "fontSize": "100%", + "pageSize": 10, + "scroll": true, + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "align": "auto", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "date" + }, + { + "alias": "", + "align": "auto", + "colorMode": "cell", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "ColorCell", + "thresholds": [ + "5", + "10" + ], + "type": "number", + "unit": "currencyUSD" + }, + { + "alias": "", + "align": "auto", + "colorMode": "value", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "ColorValue", + "thresholds": [ + "5", + "10" + ], + "type": "number", + "unit": "Bps" + }, + { + "alias": "", + "align": "auto", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "number", + "unit": "short" + } + ], + "transform": "timeseries_aggregations" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -271,7 +520,65 @@ "group": "table", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "columns": [], + "fontSize": "100%", + "scroll": true, + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "align": "auto", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "date" + }, + { + "alias": "", + "align": "auto", + "colorMode": "row", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "mappingType": 1, + "pattern": "/Color/", + "thresholds": [ + "5", + "10" + ], + "type": "number", + "unit": "currencyUSD" + }, + { + "alias": "", + "align": "auto", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "number", + "unit": "short" + } + ], + "transform": "timeseries_to_columns" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -338,7 +645,92 @@ "group": "table", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "columns": [], + "fontSize": "100%", + "pageSize": 20, + "scroll": true, + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "align": "auto", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "date" + }, + { + "alias": "", + "align": "auto", + "colorMode": "cell", + "colors": [ + "rgba(245, 54, 54, 0.5)", + "rgba(237, 129, 40, 0.5)", + "rgba(50, 172, 45, 0.5)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": true, + "linkTargetBlank": true, + "linkTooltip": "", + "linkUrl": "http://www.grafana.com", + "mappingType": 1, + "pattern": "ColorCell", + "thresholds": [ + "5", + "10" + ], + "type": "number", + "unit": "currencyUSD" + }, + { + "alias": "", + "align": "auto", + "colorMode": "value", + "colors": [ + "rgba(245, 54, 54, 0.5)", + "rgba(237, 129, 40, 0.5)", + "rgba(50, 172, 45, 0.5)" + ], + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "decimals": 2, + "link": true, + "linkUrl": "http://www.grafana.com", + "mappingType": 1, + "pattern": "ColorValue", + "thresholds": [ + "5", + "10" + ], + "type": "number", + "unit": "Bps" + }, + { + "alias": "", + "align": "auto", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "number", + "unit": "short" + } + ], + "transform": "timeseries_to_columns" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-timeseries/v0alpha1.timeseries-thresholds.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-timeseries/v0alpha1.timeseries-thresholds.v42.v2alpha1.json index c9a9c26558e..b15dedc73a8 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-timeseries/v0alpha1.timeseries-thresholds.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-timeseries/v0alpha1.timeseries-thresholds.v42.v2alpha1.json @@ -176,6 +176,88 @@ "spec": { "pluginVersion": "7.5.0-pre", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [ + { + "$$hashKey": "object:14", + "colorMode": "critical", + "fill": false, + "line": true, + "op": "gt", + "value": 80, + "yaxis": "left" + }, + { + "$$hashKey": "object:44", + "colorMode": "warning", + "fill": false, + "line": true, + "op": "gt", + "value": 50, + "yaxis": "left" + } + ], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:26", + "format": "short", + "logBase": 1, + "max": "100", + "min": "0", + "show": true + }, + { + "$$hashKey": "object:27", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "alertThreshold": true }, "fieldConfig": { @@ -339,6 +421,88 @@ "spec": { "pluginVersion": "7.5.0-pre", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [ + { + "$$hashKey": "object:109", + "colorMode": "critical", + "fill": true, + "line": true, + "op": "lt", + "value": 20, + "yaxis": "left" + }, + { + "$$hashKey": "object:115", + "colorMode": "warning", + "fill": true, + "line": true, + "op": "lt", + "value": 60, + "yaxis": "left" + } + ], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:26", + "format": "short", + "logBase": 1, + "max": "100", + "min": "0", + "show": true + }, + { + "$$hashKey": "object:27", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "alertThreshold": true }, "fieldConfig": { @@ -826,6 +990,88 @@ "spec": { "pluginVersion": "7.5.0-pre", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [ + { + "$$hashKey": "object:14", + "colorMode": "critical", + "fill": true, + "line": true, + "op": "gt", + "value": 80, + "yaxis": "left" + }, + { + "$$hashKey": "object:44", + "colorMode": "warning", + "fill": true, + "line": true, + "op": "gt", + "value": 50, + "yaxis": "left" + } + ], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:26", + "format": "short", + "logBase": 1, + "max": "100", + "min": "0", + "show": true + }, + { + "$$hashKey": "object:27", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "alertThreshold": true }, "fieldConfig": { @@ -876,6 +1122,88 @@ "spec": { "pluginVersion": "7.5.0-pre", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [ + { + "$$hashKey": "object:109", + "colorMode": "critical", + "fill": true, + "line": false, + "op": "gt", + "value": 80, + "yaxis": "left" + }, + { + "$$hashKey": "object:115", + "colorMode": "warning", + "fill": true, + "line": false, + "op": "gt", + "value": 60, + "yaxis": "left" + } + ], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:26", + "format": "short", + "logBase": 1, + "max": "100", + "min": "0", + "show": true + }, + { + "$$hashKey": "object:27", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "alertThreshold": true }, "fieldConfig": { @@ -928,6 +1256,97 @@ "spec": { "pluginVersion": "7.5.0-pre", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 0, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 1, + "points": true, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [ + { + "$$hashKey": "object:14", + "colorMode": "critical", + "fill": true, + "line": true, + "op": "gt", + "value": 80, + "yaxis": "left" + }, + { + "$$hashKey": "object:44", + "colorMode": "warning", + "fill": true, + "line": true, + "op": "lt", + "value": 40, + "yaxis": "left" + }, + { + "$$hashKey": "object:40", + "colorMode": "critical", + "fill": true, + "line": true, + "op": "lt", + "value": 20, + "yaxis": "left" + } + ], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:26", + "format": "short", + "logBase": 1, + "max": "100", + "min": "0", + "show": true + }, + { + "$$hashKey": "object:27", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "alertThreshold": true }, "fieldConfig": { @@ -980,6 +1399,92 @@ "spec": { "pluginVersion": "7.5.0-pre", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 0, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 1, + "points": true, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [ + { + "$$hashKey": "object:14", + "colorMode": "custom", + "fill": true, + "fillColor": "rgba(50, 161, 230, 0.13)", + "line": true, + "lineColor": "#B877D9", + "op": "gt", + "value": 80, + "yaxis": "left" + }, + { + "$$hashKey": "object:44", + "colorMode": "custom", + "fill": true, + "fillColor": "rgba(184, 119, 217, 0.23)", + "line": true, + "lineColor": "rgba(93, 196, 31, 0.6)", + "op": "lt", + "value": 40, + "yaxis": "left" + } + ], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:26", + "format": "short", + "logBase": 1, + "max": "100", + "min": "0", + "show": true + }, + { + "$$hashKey": "object:27", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "alertThreshold": true }, "fieldConfig": { diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-timeseries/v0alpha1.timeseries-thresholds.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-timeseries/v0alpha1.timeseries-thresholds.v42.v2beta1.json index 55ed3cf155c..0e9b32d82cf 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-timeseries/v0alpha1.timeseries-thresholds.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/panel-timeseries/v0alpha1.timeseries-thresholds.v42.v2beta1.json @@ -182,6 +182,88 @@ "version": "7.5.0-pre", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [ + { + "$$hashKey": "object:14", + "colorMode": "critical", + "fill": false, + "line": true, + "op": "gt", + "value": 80, + "yaxis": "left" + }, + { + "$$hashKey": "object:44", + "colorMode": "warning", + "fill": false, + "line": true, + "op": "gt", + "value": 50, + "yaxis": "left" + } + ], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:26", + "format": "short", + "logBase": 1, + "max": "100", + "min": "0", + "show": true + }, + { + "$$hashKey": "object:27", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "alertThreshold": true }, "fieldConfig": { @@ -349,6 +431,88 @@ "version": "7.5.0-pre", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [ + { + "$$hashKey": "object:109", + "colorMode": "critical", + "fill": true, + "line": true, + "op": "lt", + "value": 20, + "yaxis": "left" + }, + { + "$$hashKey": "object:115", + "colorMode": "warning", + "fill": true, + "line": true, + "op": "lt", + "value": 60, + "yaxis": "left" + } + ], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:26", + "format": "short", + "logBase": 1, + "max": "100", + "min": "0", + "show": true + }, + { + "$$hashKey": "object:27", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "alertThreshold": true }, "fieldConfig": { @@ -846,6 +1010,88 @@ "version": "7.5.0-pre", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [ + { + "$$hashKey": "object:14", + "colorMode": "critical", + "fill": true, + "line": true, + "op": "gt", + "value": 80, + "yaxis": "left" + }, + { + "$$hashKey": "object:44", + "colorMode": "warning", + "fill": true, + "line": true, + "op": "gt", + "value": 50, + "yaxis": "left" + } + ], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:26", + "format": "short", + "logBase": 1, + "max": "100", + "min": "0", + "show": true + }, + { + "$$hashKey": "object:27", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "alertThreshold": true }, "fieldConfig": { @@ -898,6 +1144,88 @@ "version": "7.5.0-pre", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [ + { + "$$hashKey": "object:109", + "colorMode": "critical", + "fill": true, + "line": false, + "op": "gt", + "value": 80, + "yaxis": "left" + }, + { + "$$hashKey": "object:115", + "colorMode": "warning", + "fill": true, + "line": false, + "op": "gt", + "value": 60, + "yaxis": "left" + } + ], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:26", + "format": "short", + "logBase": 1, + "max": "100", + "min": "0", + "show": true + }, + { + "$$hashKey": "object:27", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "alertThreshold": true }, "fieldConfig": { @@ -952,6 +1280,97 @@ "version": "7.5.0-pre", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 0, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 1, + "points": true, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [ + { + "$$hashKey": "object:14", + "colorMode": "critical", + "fill": true, + "line": true, + "op": "gt", + "value": 80, + "yaxis": "left" + }, + { + "$$hashKey": "object:44", + "colorMode": "warning", + "fill": true, + "line": true, + "op": "lt", + "value": 40, + "yaxis": "left" + }, + { + "$$hashKey": "object:40", + "colorMode": "critical", + "fill": true, + "line": true, + "op": "lt", + "value": 20, + "yaxis": "left" + } + ], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:26", + "format": "short", + "logBase": 1, + "max": "100", + "min": "0", + "show": true + }, + { + "$$hashKey": "object:27", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "alertThreshold": true }, "fieldConfig": { @@ -1006,6 +1425,92 @@ "version": "7.5.0-pre", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 0, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 1, + "points": true, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [ + { + "$$hashKey": "object:14", + "colorMode": "custom", + "fill": true, + "fillColor": "rgba(50, 161, 230, 0.13)", + "line": true, + "lineColor": "#B877D9", + "op": "gt", + "value": 80, + "yaxis": "left" + }, + { + "$$hashKey": "object:44", + "colorMode": "custom", + "fill": true, + "fillColor": "rgba(184, 119, 217, 0.23)", + "line": true, + "lineColor": "rgba(93, 196, 31, 0.6)", + "op": "lt", + "value": 40, + "yaxis": "left" + } + ], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:26", + "format": "short", + "logBase": 1, + "max": "100", + "min": "0", + "show": true + }, + { + "$$hashKey": "object:27", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "alertThreshold": true }, "fieldConfig": { diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/scenarios/v0alpha1.slow_queries_and_annotations.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/scenarios/v0alpha1.slow_queries_and_annotations.v42.v2alpha1.json index c8314d47e25..addd25f950f 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/scenarios/v0alpha1.slow_queries_and_annotations.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/scenarios/v0alpha1.slow_queries_and_annotations.v42.v2alpha1.json @@ -86,7 +86,64 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -132,7 +189,64 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -178,7 +292,64 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -224,7 +395,64 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -270,7 +498,64 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -316,7 +601,64 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -362,7 +704,64 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -408,7 +807,64 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -454,7 +910,64 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -500,7 +1013,64 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -546,7 +1116,64 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -592,7 +1219,64 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -638,7 +1322,64 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/scenarios/v0alpha1.slow_queries_and_annotations.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/scenarios/v0alpha1.slow_queries_and_annotations.v42.v2beta1.json index 90ce6da65a3..427a41ec1d7 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/scenarios/v0alpha1.slow_queries_and_annotations.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/scenarios/v0alpha1.slow_queries_and_annotations.v42.v2beta1.json @@ -93,7 +93,64 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -142,7 +199,64 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -191,7 +305,64 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -240,7 +411,64 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -289,7 +517,64 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -338,7 +623,64 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -387,7 +729,64 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -436,7 +835,64 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -485,7 +941,64 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -534,7 +1047,64 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -583,7 +1153,64 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -632,7 +1259,64 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] @@ -681,7 +1365,64 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/scenarios/v0alpha1.time_zone_support.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/scenarios/v0alpha1.time_zone_support.v42.v2alpha1.json index c3413246704..f95a6880b61 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/scenarios/v0alpha1.time_zone_support.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/scenarios/v0alpha1.time_zone_support.v42.v2alpha1.json @@ -108,6 +108,67 @@ "spec": { "pluginVersion": "", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "decimals": 3, + "fill": 1, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -171,6 +232,73 @@ "spec": { "pluginVersion": "", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "editable": true, + "error": false, + "fill": 0, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "C-series", + "steppedLine": true + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -217,6 +345,68 @@ "spec": { "pluginVersion": "", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "editable": true, + "error": false, + "fill": 1, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -265,6 +455,68 @@ "spec": { "pluginVersion": "", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "editable": true, + "error": false, + "fill": 1, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -326,6 +578,75 @@ "spec": { "pluginVersion": "", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "editable": true, + "error": false, + "fill": 1, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "B-series", + "yaxis": 2 + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "percent", + "label": "Perecent", + "logBase": 1, + "show": true + }, + { + "format": "short", + "label": "Pressure", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -404,6 +725,73 @@ "spec": { "pluginVersion": "", "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "editable": true, + "error": false, + "fill": 1, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "B-series", + "zindex": -3 + } + ], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/scenarios/v0alpha1.time_zone_support.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/scenarios/v0alpha1.time_zone_support.v42.v2beta1.json index b2146b3b82a..46da655452b 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/scenarios/v0alpha1.time_zone_support.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/scenarios/v0alpha1.time_zone_support.v42.v2beta1.json @@ -119,6 +119,67 @@ "version": "", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "decimals": 3, + "fill": 1, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -187,6 +248,73 @@ "version": "", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "editable": true, + "error": false, + "fill": 0, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "C-series", + "steppedLine": true + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -236,6 +364,68 @@ "version": "", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "editable": true, + "error": false, + "fill": 1, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -287,6 +477,68 @@ "version": "", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "editable": true, + "error": false, + "fill": 1, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -353,6 +605,75 @@ "version": "", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "editable": true, + "error": false, + "fill": 1, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "connected", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "B-series", + "yaxis": 2 + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "percent", + "label": "Perecent", + "logBase": 1, + "show": true + }, + { + "format": "short", + "label": "Pressure", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { @@ -438,6 +759,73 @@ "version": "", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "editable": true, + "error": false, + "fill": 1, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "B-series", + "zindex": -3 + } + ], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, "dataLinks": [] }, "fieldConfig": { diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/v0alpha1.v1beta1.v1beta1.all-panels.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/v0alpha1.v1beta1.v1beta1.all-panels.v42.v2alpha1.json index 315164a75a3..43ca604b064 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/v0alpha1.v1beta1.v1beta1.all-panels.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/v0alpha1.v1beta1.v1beta1.all-panels.v42.v2alpha1.json @@ -665,7 +665,42 @@ "kind": "heatmap", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "heatmap", + "originalOptions": { + "cards": {}, + "color": { + "cardColor": "#b4ff00", + "colorScale": "sqrt", + "colorScheme": "interpolateOranges", + "exponent": 0.5, + "mode": "spectrum" + }, + "dataFormat": "timeseries", + "heatmap": {}, + "hideZeroBuckets": false, + "highlightCards": true, + "legend": { + "show": false + }, + "reverseYBuckets": false, + "tooltip": { + "show": true, + "showHistogram": false + }, + "xAxis": { + "show": true + }, + "yAxis": { + "format": "short", + "logBase": 1, + "show": true + }, + "yBucketBound": "auto" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/v0alpha1.v1beta1.v1beta1.all-panels.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/v0alpha1.v1beta1.v1beta1.all-panels.v42.v2beta1.json index 94f898bfa16..ae693615b73 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/v0alpha1.v1beta1.v1beta1.all-panels.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/v0alpha1.v1beta1.v1beta1.all-panels.v42.v2beta1.json @@ -691,7 +691,42 @@ "group": "heatmap", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "heatmap", + "originalOptions": { + "cards": {}, + "color": { + "cardColor": "#b4ff00", + "colorScale": "sqrt", + "colorScheme": "interpolateOranges", + "exponent": 0.5, + "mode": "spectrum" + }, + "dataFormat": "timeseries", + "heatmap": {}, + "hideZeroBuckets": false, + "highlightCards": true, + "legend": { + "show": false + }, + "reverseYBuckets": false, + "tooltip": { + "show": true, + "showHistogram": false + }, + "xAxis": { + "show": true + }, + "yAxis": { + "format": "short", + "logBase": 1, + "show": true + }, + "yBucketBound": "auto" + } + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/v0alpha1.v1beta1.v1beta1.home.v42.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/v0alpha1.v1beta1.v1beta1.home.v42.v2alpha1.json index 2a6500f86db..7c77141f891 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/v0alpha1.v1beta1.v1beta1.home.v42.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/v0alpha1.v1beta1.v1beta1.home.v42.v2alpha1.json @@ -56,6 +56,14 @@ "spec": { "pluginVersion": "9.0.0-pre", "options": { + "__angularMigration": { + "autoMigrateFrom": "dashlist", + "originalOptions": { + "tags": [ + "panel-tests" + ] + } + }, "maxItems": 1000, "query": "", "showHeadings": false, @@ -94,6 +102,15 @@ "spec": { "pluginVersion": "9.0.0-pre", "options": { + "__angularMigration": { + "autoMigrateFrom": "dashlist", + "originalOptions": { + "tags": [ + "gdev", + "demo" + ] + } + }, "maxItems": 1000, "query": "", "showHeadings": false, @@ -133,6 +150,15 @@ "spec": { "pluginVersion": "9.0.0-pre", "options": { + "__angularMigration": { + "autoMigrateFrom": "dashlist", + "originalOptions": { + "tags": [ + "templating", + "gdev" + ] + } + }, "maxItems": 1000, "query": "", "showHeadings": false, @@ -172,6 +198,15 @@ "spec": { "pluginVersion": "9.0.0-pre", "options": { + "__angularMigration": { + "autoMigrateFrom": "dashlist", + "originalOptions": { + "tags": [ + "gdev", + "datasource-test" + ] + } + }, "maxItems": 1000, "query": "", "showHeadings": false, @@ -211,6 +246,12 @@ "spec": { "pluginVersion": "9.0.0-pre", "options": { + "__angularMigration": { + "autoMigrateFrom": "dashlist", + "originalOptions": { + "tags": [] + } + }, "maxItems": 100, "query": "", "showHeadings": true, @@ -247,6 +288,15 @@ "spec": { "pluginVersion": "9.0.0-pre", "options": { + "__angularMigration": { + "autoMigrateFrom": "dashlist", + "originalOptions": { + "tags": [ + "gdev", + "demo" + ] + } + }, "maxItems": 1000, "query": "", "showHeadings": false, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/v0alpha1.v1beta1.v1beta1.home.v42.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/v0alpha1.v1beta1.v1beta1.home.v42.v2beta1.json index 0580a517cb2..5cec6a9741b 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/v0alpha1.v1beta1.v1beta1.home.v42.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/migrated_dev_dashboards/v0alpha1.v1beta1.v1beta1.home.v42.v2beta1.json @@ -58,6 +58,14 @@ "version": "9.0.0-pre", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "dashlist", + "originalOptions": { + "tags": [ + "panel-tests" + ] + } + }, "maxItems": 1000, "query": "", "showHeadings": false, @@ -97,6 +105,15 @@ "version": "9.0.0-pre", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "dashlist", + "originalOptions": { + "tags": [ + "gdev", + "demo" + ] + } + }, "maxItems": 1000, "query": "", "showHeadings": false, @@ -137,6 +154,15 @@ "version": "9.0.0-pre", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "dashlist", + "originalOptions": { + "tags": [ + "templating", + "gdev" + ] + } + }, "maxItems": 1000, "query": "", "showHeadings": false, @@ -177,6 +203,15 @@ "version": "9.0.0-pre", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "dashlist", + "originalOptions": { + "tags": [ + "gdev", + "datasource-test" + ] + } + }, "maxItems": 1000, "query": "", "showHeadings": false, @@ -217,6 +252,12 @@ "version": "9.0.0-pre", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "dashlist", + "originalOptions": { + "tags": [] + } + }, "maxItems": 100, "query": "", "showHeadings": true, @@ -254,6 +295,15 @@ "version": "9.0.0-pre", "spec": { "options": { + "__angularMigration": { + "autoMigrateFrom": "dashlist", + "originalOptions": { + "tags": [ + "gdev", + "demo" + ] + } + }, "maxItems": 1000, "query": "", "showHeadings": false, diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/v1beta1.angular-migrations.v0alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/v1beta1.angular-migrations.v0alpha1.json new file mode 100644 index 00000000000..d1253a0a81d --- /dev/null +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/v1beta1.angular-migrations.v0alpha1.json @@ -0,0 +1,1310 @@ +{ + "kind": "Dashboard", + "apiVersion": "dashboard.grafana.app/v0alpha1", + "metadata": { + "name": "angular-migrations-test" + }, + "spec": { + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations \u0026 Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "links": [ + { + "asDropdown": false, + "icon": "external link", + "includeVars": false, + "keepTime": false, + "tags": [], + "targetBlank": true, + "title": "Auto migrate graph panel (TRUE)", + "tooltip": "", + "type": "link", + "url": " /d/cdd412c4/?__feature.autoMigrateGraphPanel=true" + }, + { + "asDropdown": false, + "icon": "external link", + "includeVars": false, + "keepTime": false, + "tags": [], + "targetBlank": true, + "title": "Auto migrate graph panel (FALSE)", + "tooltip": "", + "type": "link", + "url": " /d/cdd412c4/?__feature.autoMigrateGraphPanel=false" + }, + { + "asDropdown": false, + "icon": "external link", + "includeVars": false, + "keepTime": false, + "tags": [], + "targetBlank": true, + "title": "Auto migrate table (old) panel (TRUE)", + "tooltip": "", + "type": "link", + "url": " /d/cdd412c4/?__feature.autoMigrateTablePanel=true" + }, + { + "asDropdown": false, + "icon": "external link", + "includeVars": false, + "keepTime": false, + "tags": [], + "targetBlank": true, + "title": "Auto migrate table (old) panel (FALSE)", + "tooltip": "", + "type": "link", + "url": " /d/cdd412c4/?__feature.autoMigrateTablePanel=false" + }, + { + "asDropdown": false, + "icon": "external link", + "includeVars": false, + "keepTime": false, + "tags": [], + "targetBlank": true, + "title": "Auto migrate piechart panel (TRUE)", + "tooltip": "", + "type": "link", + "url": " /d/cdd412c4/?__feature.autoMigratePiechartPanel=true" + }, + { + "asDropdown": false, + "icon": "external link", + "includeVars": false, + "keepTime": false, + "tags": [], + "targetBlank": true, + "title": "Auto migrate piechart panel (FALSE)", + "tooltip": "", + "type": "link", + "url": " /d/cdd412c4/?__feature.autoMigratePiechartPanel=false" + }, + { + "asDropdown": false, + "icon": "external link", + "includeVars": false, + "keepTime": false, + "tags": [], + "targetBlank": true, + "title": "Auto migrate worldmap panel (TRUE)", + "tooltip": "", + "type": "link", + "url": " /d/cdd412c4/?__feature.autoMigrateWorldmapPanel=true" + }, + { + "asDropdown": false, + "icon": "external link", + "includeVars": false, + "keepTime": false, + "tags": [], + "targetBlank": true, + "title": "Auto migrate worldmap panel (FALSE)", + "tooltip": "", + "type": "link", + "url": " /d/cdd412c4/?__feature.autoMigrateWorldmapPanel=false" + }, + { + "asDropdown": false, + "icon": "external link", + "includeVars": false, + "keepTime": false, + "tags": [], + "targetBlank": true, + "title": "Auto migrate stat panel (TRUE)", + "tooltip": "", + "type": "link", + "url": " /d/cdd412c4/?__feature.autoMigrateStatPanel=true" + }, + { + "asDropdown": false, + "icon": "external link", + "includeVars": false, + "keepTime": false, + "tags": [], + "targetBlank": true, + "title": "Auto migrate stat panel (FALSE)", + "tooltip": "", + "type": "link", + "url": " /d/cdd412c4/?__feature.autoMigrateStatPanel=false" + }, + { + "asDropdown": false, + "icon": "external link", + "includeVars": false, + "keepTime": false, + "tags": [], + "targetBlank": true, + "title": "Auto migrate (TRUE)", + "tooltip": "", + "type": "link", + "url": "/d/cdd412c4/?__feature.autoMigrateOldPanels=true" + }, + { + "asDropdown": false, + "icon": "external link", + "includeVars": false, + "keepTime": false, + "tags": [], + "targetBlank": true, + "title": "Auto migrate (FALSE)", + "tooltip": "", + "type": "link", + "url": "/d/cdd412c4/?__feature.autoMigrateOldPanels=false" + }, + { + "asDropdown": false, + "icon": "external link", + "includeVars": false, + "keepTime": false, + "tags": [], + "targetBlank": true, + "title": "Disable angular (TRUE)", + "tooltip": "", + "type": "link", + "url": "/d/cdd412c4/?__feature.disableAngular=true" + }, + { + "asDropdown": false, + "icon": "external link", + "includeVars": false, + "keepTime": false, + "tags": [], + "targetBlank": true, + "title": "Disable angular (FALSE)", + "tooltip": "", + "type": "link", + "url": "/d/cdd412c4/?__feature.disableAngular=false" + } + ], + "liveNow": false, + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "type": "grafana-testdata-datasource" + }, + "fieldConfig": { + "defaults": { + "unit": "short" + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 11, + "w": 16, + "x": 0, + "y": 0 + }, + "hiddenSeries": false, + "id": 4, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "percentage": false, + "pluginVersion": "11.0.0-pre", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "datasource": { + "type": "grafana-testdata-datasource" + }, + "refId": "A", + "scenarioId": "random_walk", + "seriesCount": 3 + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Flot graph", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + }, + { + "datasource": { + "type": "grafana-testdata-datasource" + }, + "gridPos": { + "h": 11, + "w": 8, + "x": 16, + "y": 0 + }, + "id": 6, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "# Graph panel \u003e\u003e Timeseries panel\n\nKnown issues:\n* hiding null/empty series\n* time regions", + "mode": "markdown" + }, + "pluginVersion": "11.0.0-pre", + "targets": [ + { + "datasource": { + "type": "grafana-testdata-datasource" + }, + "refId": "A" + } + ], + "title": "Status + Notes", + "type": "text" + }, + { + "aliasColors": {}, + "autoMigrateFrom": "graph", + "bars": true, + "dashLength": 10, + "dashes": false, + "datasource": { + "type": "grafana-testdata-datasource" + }, + "fieldConfig": { + "defaults": { + "unit": "short" + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 11, + "w": 16, + "x": 0, + "y": 11 + }, + "hiddenSeries": false, + "id": 28, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": false, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "percentage": false, + "pluginVersion": "11.0.0-pre", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "datasource": { + "type": "grafana-testdata-datasource" + }, + "rawFrameContent": "[\n {\n \"schema\": {\n \"refId\": \"A\",\n \"meta\": {\n \"typeVersion\": [\n 0,\n 0\n ],\n \"custom\": {\n \"customStat\": 10\n }\n },\n \"fields\": [\n {\n \"name\": \"time\",\n \"type\": \"time\",\n \"typeInfo\": {\n \"frame\": \"time.Time\",\n \"nullable\": true\n },\n \"config\": {\n \"interval\": 3600000\n }\n },\n {\n \"name\": \"Value\",\n \"type\": \"number\",\n \"typeInfo\": {\n \"frame\": \"float64\",\n \"nullable\": true\n },\n \"labels\": {\n \"pod\": \"A-pod\"\n },\n \"config\": {}\n }\n ]\n },\n \"data\": {\n \"values\": [\n [\n 1727107111901,\n 1727110711901,\n 1727114311901,\n 1727117911901,\n 1727121511901,\n 1727125111901\n ],\n [\n 1.907286825122581,\n 2.260951647569786,\n 1.887442338051216,\n 2.1526144400893514,\n 1.7287721375237766,\n 1.7262902137793208\n ]\n ]\n }\n },\n {\n \"schema\": {\n \"refId\": \"A\",\n \"meta\": {\n \"typeVersion\": [\n 0,\n 0\n ],\n \"custom\": {\n \"customStat\": 10\n }\n },\n \"fields\": [\n {\n \"name\": \"time\",\n \"type\": \"time\",\n \"typeInfo\": {\n \"frame\": \"time.Time\",\n \"nullable\": true\n },\n \"config\": {\n \"interval\": 3600000\n }\n },\n {\n \"name\": \"Value\",\n \"type\": \"number\",\n \"typeInfo\": {\n \"frame\": \"float64\",\n \"nullable\": true\n },\n \"labels\": {\n \"pod\": \"A-pod1\"\n },\n \"config\": {}\n }\n ]\n },\n \"data\": {\n \"values\": [\n [\n 1727107111901,\n 1727110711901,\n 1727114311901,\n 1727117911901,\n 1727121511901,\n 1727125111901\n ],\n [\n 1.907286825122581,\n 1.589539045095202,\n 1.5914283506847613,\n 1.8976990616650726,\n 1.758223085999124,\n 2.2294649594813816\n ]\n ]\n }\n },\n {\n \"schema\": {\n \"refId\": \"A\",\n \"meta\": {\n \"typeVersion\": [\n 0,\n 0\n ],\n \"custom\": {\n \"customStat\": 10\n }\n },\n \"fields\": [\n {\n \"name\": \"time\",\n \"type\": \"time\",\n \"typeInfo\": {\n \"frame\": \"time.Time\",\n \"nullable\": true\n },\n \"config\": {\n \"interval\": 3600000\n }\n },\n {\n \"name\": \"Value\",\n \"type\": \"number\",\n \"typeInfo\": {\n \"frame\": \"float64\",\n \"nullable\": true\n },\n \"labels\": {\n \"pod\": \"A-pod2\"\n },\n \"config\": {}\n }\n ]\n },\n \"data\": {\n \"values\": [\n [\n 1727107111901,\n 1727110711901,\n 1727114311901,\n 1727117911901,\n 1727121511901,\n 1727125111901\n ],\n [\n 1.907286825122581,\n 2.0914263380328766,\n 1.8164545521094575,\n 1.621111084665713,\n 1.3902653996444705,\n 1.482803315949775\n ]\n ]\n }\n }\n]", + "refId": "A", + "scenarioId": "raw_frame" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Flot graph - x axis series mode", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "barchart", + "xaxis": { + "mode": "series", + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "$$hashKey": "object:88", + "format": "short", + "logBase": 1, + "show": true + }, + { + "$$hashKey": "object:89", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + }, + { + "datasource": { + "type": "grafana-testdata-datasource" + }, + "gridPos": { + "h": 11, + "w": 8, + "x": 16, + "y": 11 + }, + "id": 29, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "# Graph panel \u003e\u003e Bar chart panel\n", + "mode": "markdown" + }, + "pluginVersion": "11.0.0-pre", + "targets": [ + { + "datasource": { + "type": "grafana-testdata-datasource" + }, + "refId": "A" + } + ], + "title": "Status + Notes", + "type": "text" + }, + { + "aliasColors": {}, + "autoMigrateFrom": "graph", + "bars": true, + "dashLength": 10, + "dashes": false, + "datasource": { + "default": false, + "type": "datasource", + "uid": "-- Dashboard --" + }, + "fieldConfig": { + "defaults": { + "unit": "short" + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 11, + "w": 16, + "x": 0, + "y": 22 + }, + "hiddenSeries": false, + "id": 32, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": false, + "show": true, + "total": false, + "values": true + }, + "lines": false, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "percentage": false, + "pluginVersion": "11.3.0-pre", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "panelId": 28, + "refId": "A" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Flot graph - x axis series mode (with legend calcs)", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "bargauge", + "xaxis": { + "mode": "series", + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "$$hashKey": "object:88", + "format": "short", + "logBase": 1, + "show": true + }, + { + "$$hashKey": "object:89", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + }, + { + "aliasColors": {}, + "autoMigrateFrom": "graph", + "bars": true, + "dashLength": 10, + "dashes": false, + "datasource": { + "type": "grafana-testdata-datasource" + }, + "fieldConfig": { + "defaults": { + "unit": "short" + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 11, + "w": 16, + "x": 0, + "y": 22 + }, + "hiddenSeries": false, + "id": 30, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": false, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "percentage": false, + "pluginVersion": "11.0.0-pre", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "datasource": { + "type": "grafana-testdata-datasource" + }, + "refId": "A", + "scenarioId": "random_walk", + "seriesCount": 3 + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Flot graph - x axis histogram mode", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "histogram", + "xaxis": { + "mode": "histogram", + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:193", + "format": "short", + "logBase": 1, + "show": true + }, + { + "$$hashKey": "object:194", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + }, + { + "datasource": { + "type": "grafana-testdata-datasource" + }, + "gridPos": { + "h": 11, + "w": 8, + "x": 16, + "y": 22 + }, + "id": 33, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "# Graph panel \u003e\u003e Bar gauge panel\n", + "mode": "markdown" + }, + "pluginVersion": "11.3.0-pre", + "targets": [ + { + "datasource": { + "type": "grafana-testdata-datasource" + }, + "refId": "A" + } + ], + "title": "Status + Notes", + "type": "text" + }, + { + "datasource": { + "type": "grafana-testdata-datasource" + }, + "gridPos": { + "h": 11, + "w": 8, + "x": 16, + "y": 22 + }, + "id": 31, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "# Graph panel \u003e\u003e Histogram panel\n", + "mode": "markdown" + }, + "pluginVersion": "11.0.0-pre", + "targets": [ + { + "datasource": { + "type": "grafana-testdata-datasource" + }, + "refId": "A" + } + ], + "title": "Status + Notes", + "type": "text" + }, + { + "autoMigrateFrom": "table-old", + "columns": [], + "datasource": { + "type": "grafana-testdata-datasource" + }, + "fontSize": "100%", + "gridPos": { + "h": 10, + "w": 16, + "x": 0, + "y": 33 + }, + "id": 2, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true, + "showRowNums": false + }, + "pluginVersion": "9.5.0-pre", + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "align": "auto", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "date" + }, + { + "alias": "", + "align": "right", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "number", + "unit": "short" + } + ], + "targets": [ + { + "datasource": { + "type": "grafana-testdata-datasource" + }, + "refId": "A", + "scenarioId": "random_walk_table" + } + ], + "title": "Table (old)", + "transform": "table", + "transformations": [ + { + "id": "merge", + "options": { + "reducers": [] + } + } + ], + "type": "table" + }, + { + "datasource": { + "type": "grafana-testdata-datasource" + }, + "gridPos": { + "h": 10, + "w": 8, + "x": 16, + "y": 33 + }, + "id": 7, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "# Table (old) \u003e\u003e Table\n\nKnown issues:\n* wrapping text\n* style changes", + "mode": "markdown" + }, + "pluginVersion": "11.0.0-pre", + "targets": [ + { + "datasource": { + "type": "grafana-testdata-datasource" + }, + "refId": "A" + } + ], + "title": "Status + Notes", + "type": "text" + }, + { + "autoMigrateFrom": "grafana-singlestat-panel", + "colorBackground": false, + "colorValue": true, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": { + "type": "grafana-testdata-datasource" + }, + "format": "areaF2", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 43 + }, + "id": 9, + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "postfix": "b", + "postfixFontSize": "50%", + "prefix": "a", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "datasource": { + "type": "grafana-testdata-datasource" + }, + "refId": "A" + } + ], + "thresholds": "", + "title": "grafana-singlestat-panel", + "type": "stat", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + }, + { + "datasource": { + "type": "grafana-testdata-datasource" + }, + "fieldConfig": { + "defaults": { + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "ms" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 43 + }, + "id": 23, + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "mean" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "11.0.0-pre", + "targets": [ + { + "datasource": { + "type": "grafana-testdata-datasource" + }, + "refId": "A" + } + ], + "title": "singlestat (old, internal. Migrated if schema \u003c 28)", + "type": "stat" + }, + { + "datasource": { + "type": "grafana-testdata-datasource" + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 43 + }, + "id": 10, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "# Singlestat \u003e\u003e Stat\n\nKnown issues:\n* limited options", + "mode": "markdown" + }, + "pluginVersion": "11.0.0-pre", + "targets": [ + { + "datasource": { + "type": "grafana-testdata-datasource" + }, + "refId": "A" + } + ], + "title": "Status + Notes", + "type": "text" + }, + { + "autoMigrateFrom": "grafana-piechart-panel", + "datasource": { + "type": "grafana-testdata-datasource" + }, + "gridPos": { + "h": 10, + "w": 16, + "x": 0, + "y": 51 + }, + "id": 24, + "options": { + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "pieType": "pie", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "9.5.0-pre", + "targets": [ + { + "datasource": { + "type": "grafana-testdata-datasource" + }, + "refId": "A", + "scenarioId": "random_walk_table" + } + ], + "title": "grafana-piechart-panel", + "transformations": [ + { + "id": "merge", + "options": { + "reducers": [] + } + } + ], + "type": "piechart" + }, + { + "datasource": { + "type": "grafana-testdata-datasource" + }, + "gridPos": { + "h": 10, + "w": 8, + "x": 16, + "y": 51 + }, + "id": 25, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "# grafana-piechart-panel \u003e\u003e piechart\n\nKnown issues:\n* TBD", + "mode": "markdown" + }, + "pluginVersion": "11.0.0-pre", + "targets": [ + { + "datasource": { + "type": "grafana-testdata-datasource" + }, + "refId": "A" + } + ], + "title": "Status + Notes", + "type": "text" + }, + { + "autoMigrateFrom": "grafana-worldmap-panel", + "circleMaxSize": 30, + "circleMinSize": 2, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "datasource": { + "type": "grafana-testdata-datasource" + }, + "decimals": 0, + "esMetric": "Count", + "gridPos": { + "h": 10, + "w": 16, + "x": 0, + "y": 61 + }, + "hideEmpty": false, + "hideZero": false, + "id": 26, + "initialZoom": 1, + "locationData": "countries", + "mapCenter": "(0°, 0°)", + "mapCenterLatitude": 0, + "mapCenterLongitude": 0, + "maxDataPoints": 1, + "mouseWheelZoom": false, + "options": { + "basemap": { + "name": "Basemap", + "type": "default" + }, + "controls": { + "mouseWheelZoom": false, + "showAttribution": true, + "showDebug": false, + "showMeasure": false, + "showScale": false, + "showZoom": true + }, + "layers": [ + { + "config": { + "showLegend": true, + "style": { + "color": { + "fixed": "dark-green" + }, + "opacity": 0.4, + "rotation": { + "fixed": 0, + "max": 360, + "min": -360, + "mode": "mod" + }, + "size": { + "fixed": 5, + "max": 30, + "min": 2 + }, + "symbol": { + "fixed": "img/icons/marker/circle.svg", + "mode": "fixed" + }, + "symbolAlign": { + "horizontal": "center", + "vertical": "center" + }, + "textConfig": { + "fontSize": 12, + "offsetX": 0, + "offsetY": 0, + "textAlign": "center", + "textBaseline": "middle" + } + } + }, + "location": { + "gazetteer": "public/gazetteer/countries.json", + "mode": "lookup" + }, + "name": "Layer 0", + "tooltip": true, + "type": "markers" + } + ], + "tooltip": { + "mode": "details" + }, + "view": { + "allLayers": true, + "id": "zero", + "lat": 0, + "lon": 0, + "zoom": 1 + } + }, + "pluginVersion": "10.4.0-pre", + "showLegend": true, + "stickyLabels": false, + "tableQueryOptions": { + "geohashField": "geohash", + "latitudeField": "latitude", + "longitudeField": "longitude", + "metricField": "metric", + "queryType": "geohash" + }, + "targets": [ + { + "csvFileName": "flight_info_by_state.csv", + "datasource": { + "type": "grafana-testdata-datasource" + }, + "refId": "A", + "scenarioId": "csv_file" + } + ], + "thresholds": "0,10", + "title": "grafana-worldmap-panel", + "transformations": [ + { + "id": "merge", + "options": { + "reducers": [] + } + }, + { + "id": "reduce", + "options": { + "reducers": [ + "sum" + ] + } + } + ], + "type": "geomap", + "unitPlural": "", + "unitSingle": "", + "valueName": "total" + }, + { + "datasource": { + "type": "grafana-testdata-datasource" + }, + "gridPos": { + "h": 10, + "w": 8, + "x": 16, + "y": 61 + }, + "id": 27, + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "# grafana-worldmap-panel \u003e\u003e geomap\n\nKnown issues:\n* TBD", + "mode": "markdown" + }, + "pluginVersion": "11.0.0-pre", + "targets": [ + { + "datasource": { + "type": "grafana-testdata-datasource" + }, + "refId": "A" + } + ], + "title": "Status + Notes", + "type": "text" + } + ], + "refresh": "", + "schemaVersion": 42, + "tags": [ + "gdev", + "migrations", + "angular" + ], + "templating": { + "list": [] + }, + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "Devenv - Panel migrations", + "uid": "cdd412c4", + "weekStart": "" + }, + "status": { + "conversion": { + "failed": false, + "storedVersion": "v1beta1" + } + } +} \ No newline at end of file diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/v1beta1.angular-migrations.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/v1beta1.angular-migrations.v2alpha1.json new file mode 100644 index 00000000000..d9e72ec700a --- /dev/null +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/v1beta1.angular-migrations.v2alpha1.json @@ -0,0 +1,1861 @@ +{ + "kind": "Dashboard", + "apiVersion": "dashboard.grafana.app/v2alpha1", + "metadata": { + "name": "angular-migrations-test" + }, + "spec": { + "annotations": [ + { + "kind": "AnnotationQuery", + "spec": { + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "query": { + "kind": "grafana", + "spec": {} + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations \u0026 Alerts", + "builtIn": true, + "legacyOptions": { + "type": "dashboard" + } + } + } + ], + "cursorSync": "Off", + "editable": true, + "elements": { + "panel-10": { + "kind": "Panel", + "spec": { + "id": 10, + "title": "Status + Notes", + "description": "", + "links": [], + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "grafana-testdata-datasource", + "spec": {} + }, + "refId": "A", + "hidden": false + } + } + ], + "transformations": [], + "queryOptions": {} + } + }, + "vizConfig": { + "kind": "text", + "spec": { + "pluginVersion": "11.0.0-pre", + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "# Singlestat \u003e\u003e Stat\n\nKnown issues:\n* limited options", + "mode": "markdown" + }, + "fieldConfig": { + "defaults": {}, + "overrides": [] + } + } + } + } + }, + "panel-2": { + "kind": "Panel", + "spec": { + "id": 2, + "title": "Table (old)", + "description": "", + "links": [], + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "grafana-testdata-datasource", + "spec": { + "scenarioId": "random_walk_table" + } + }, + "refId": "A", + "hidden": false + } + } + ], + "transformations": [ + { + "kind": "merge", + "spec": { + "id": "merge", + "options": { + "reducers": [] + } + } + } + ], + "queryOptions": {} + } + }, + "vizConfig": { + "kind": "table", + "spec": { + "pluginVersion": "9.5.0-pre", + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "columns": [], + "fontSize": "100%", + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "align": "auto", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "date" + }, + { + "alias": "", + "align": "right", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "number", + "unit": "short" + } + ], + "transform": "table" + } + }, + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true, + "showRowNums": false + }, + "fieldConfig": { + "defaults": {}, + "overrides": [] + } + } + } + } + }, + "panel-23": { + "kind": "Panel", + "spec": { + "id": 23, + "title": "singlestat (old, internal. Migrated if schema \u003c 28)", + "description": "", + "links": [], + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "grafana-testdata-datasource", + "spec": {} + }, + "refId": "A", + "hidden": false + } + } + ], + "transformations": [], + "queryOptions": { + "maxDataPoints": 100 + } + } + }, + "vizConfig": { + "kind": "stat", + "spec": { + "pluginVersion": "11.0.0-pre", + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "mean" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "fieldConfig": { + "defaults": { + "unit": "ms", + "mappings": [ + { + "type": "special", + "options": { + "match": "null", + "result": { + "text": "N/A" + } + } + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "value": null, + "color": "green" + }, + { + "value": 80, + "color": "red" + } + ] + } + }, + "overrides": [] + } + } + } + } + }, + "panel-24": { + "kind": "Panel", + "spec": { + "id": 24, + "title": "grafana-piechart-panel", + "description": "", + "links": [], + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "grafana-testdata-datasource", + "spec": { + "scenarioId": "random_walk_table" + } + }, + "refId": "A", + "hidden": false + } + } + ], + "transformations": [ + { + "kind": "merge", + "spec": { + "id": "merge", + "options": { + "reducers": [] + } + } + } + ], + "queryOptions": {} + } + }, + "vizConfig": { + "kind": "piechart", + "spec": { + "pluginVersion": "9.5.0-pre", + "options": { + "__angularMigration": { + "autoMigrateFrom": "grafana-piechart-panel", + "originalOptions": {} + }, + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "pieType": "pie", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "fieldConfig": { + "defaults": {}, + "overrides": [] + } + } + } + } + }, + "panel-25": { + "kind": "Panel", + "spec": { + "id": 25, + "title": "Status + Notes", + "description": "", + "links": [], + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "grafana-testdata-datasource", + "spec": {} + }, + "refId": "A", + "hidden": false + } + } + ], + "transformations": [], + "queryOptions": {} + } + }, + "vizConfig": { + "kind": "text", + "spec": { + "pluginVersion": "11.0.0-pre", + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "# grafana-piechart-panel \u003e\u003e piechart\n\nKnown issues:\n* TBD", + "mode": "markdown" + }, + "fieldConfig": { + "defaults": {}, + "overrides": [] + } + } + } + } + }, + "panel-26": { + "kind": "Panel", + "spec": { + "id": 26, + "title": "grafana-worldmap-panel", + "description": "", + "links": [], + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "grafana-testdata-datasource", + "spec": { + "csvFileName": "flight_info_by_state.csv", + "scenarioId": "csv_file" + } + }, + "refId": "A", + "hidden": false + } + } + ], + "transformations": [ + { + "kind": "merge", + "spec": { + "id": "merge", + "options": { + "reducers": [] + } + } + }, + { + "kind": "reduce", + "spec": { + "id": "reduce", + "options": { + "reducers": [ + "sum" + ] + } + } + } + ], + "queryOptions": { + "maxDataPoints": 1 + } + } + }, + "vizConfig": { + "kind": "geomap", + "spec": { + "pluginVersion": "10.4.0-pre", + "options": { + "__angularMigration": { + "autoMigrateFrom": "grafana-worldmap-panel", + "originalOptions": { + "circleMaxSize": 30, + "circleMinSize": 2, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 0, + "esMetric": "Count", + "hideEmpty": false, + "hideZero": false, + "initialZoom": 1, + "locationData": "countries", + "mapCenter": "(0°, 0°)", + "mapCenterLatitude": 0, + "mapCenterLongitude": 0, + "mouseWheelZoom": false, + "showLegend": true, + "stickyLabels": false, + "tableQueryOptions": { + "geohashField": "geohash", + "latitudeField": "latitude", + "longitudeField": "longitude", + "metricField": "metric", + "queryType": "geohash" + }, + "thresholds": "0,10", + "unitPlural": "", + "unitSingle": "", + "valueName": "total" + } + }, + "basemap": { + "name": "Basemap", + "type": "default" + }, + "controls": { + "mouseWheelZoom": false, + "showAttribution": true, + "showDebug": false, + "showMeasure": false, + "showScale": false, + "showZoom": true + }, + "layers": [ + { + "config": { + "showLegend": true, + "style": { + "color": { + "fixed": "dark-green" + }, + "opacity": 0.4, + "rotation": { + "fixed": 0, + "max": 360, + "min": -360, + "mode": "mod" + }, + "size": { + "fixed": 5, + "max": 30, + "min": 2 + }, + "symbol": { + "fixed": "img/icons/marker/circle.svg", + "mode": "fixed" + }, + "symbolAlign": { + "horizontal": "center", + "vertical": "center" + }, + "textConfig": { + "fontSize": 12, + "offsetX": 0, + "offsetY": 0, + "textAlign": "center", + "textBaseline": "middle" + } + } + }, + "location": { + "gazetteer": "public/gazetteer/countries.json", + "mode": "lookup" + }, + "name": "Layer 0", + "tooltip": true, + "type": "markers" + } + ], + "tooltip": { + "mode": "details" + }, + "view": { + "allLayers": true, + "id": "zero", + "lat": 0, + "lon": 0, + "zoom": 1 + } + }, + "fieldConfig": { + "defaults": {}, + "overrides": [] + } + } + } + } + }, + "panel-27": { + "kind": "Panel", + "spec": { + "id": 27, + "title": "Status + Notes", + "description": "", + "links": [], + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "grafana-testdata-datasource", + "spec": {} + }, + "refId": "A", + "hidden": false + } + } + ], + "transformations": [], + "queryOptions": {} + } + }, + "vizConfig": { + "kind": "text", + "spec": { + "pluginVersion": "11.0.0-pre", + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "# grafana-worldmap-panel \u003e\u003e geomap\n\nKnown issues:\n* TBD", + "mode": "markdown" + }, + "fieldConfig": { + "defaults": {}, + "overrides": [] + } + } + } + } + }, + "panel-28": { + "kind": "Panel", + "spec": { + "id": 28, + "title": "Flot graph - x axis series mode", + "description": "", + "links": [], + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "grafana-testdata-datasource", + "spec": { + "rawFrameContent": "[\n {\n \"schema\": {\n \"refId\": \"A\",\n \"meta\": {\n \"typeVersion\": [\n 0,\n 0\n ],\n \"custom\": {\n \"customStat\": 10\n }\n },\n \"fields\": [\n {\n \"name\": \"time\",\n \"type\": \"time\",\n \"typeInfo\": {\n \"frame\": \"time.Time\",\n \"nullable\": true\n },\n \"config\": {\n \"interval\": 3600000\n }\n },\n {\n \"name\": \"Value\",\n \"type\": \"number\",\n \"typeInfo\": {\n \"frame\": \"float64\",\n \"nullable\": true\n },\n \"labels\": {\n \"pod\": \"A-pod\"\n },\n \"config\": {}\n }\n ]\n },\n \"data\": {\n \"values\": [\n [\n 1727107111901,\n 1727110711901,\n 1727114311901,\n 1727117911901,\n 1727121511901,\n 1727125111901\n ],\n [\n 1.907286825122581,\n 2.260951647569786,\n 1.887442338051216,\n 2.1526144400893514,\n 1.7287721375237766,\n 1.7262902137793208\n ]\n ]\n }\n },\n {\n \"schema\": {\n \"refId\": \"A\",\n \"meta\": {\n \"typeVersion\": [\n 0,\n 0\n ],\n \"custom\": {\n \"customStat\": 10\n }\n },\n \"fields\": [\n {\n \"name\": \"time\",\n \"type\": \"time\",\n \"typeInfo\": {\n \"frame\": \"time.Time\",\n \"nullable\": true\n },\n \"config\": {\n \"interval\": 3600000\n }\n },\n {\n \"name\": \"Value\",\n \"type\": \"number\",\n \"typeInfo\": {\n \"frame\": \"float64\",\n \"nullable\": true\n },\n \"labels\": {\n \"pod\": \"A-pod1\"\n },\n \"config\": {}\n }\n ]\n },\n \"data\": {\n \"values\": [\n [\n 1727107111901,\n 1727110711901,\n 1727114311901,\n 1727117911901,\n 1727121511901,\n 1727125111901\n ],\n [\n 1.907286825122581,\n 1.589539045095202,\n 1.5914283506847613,\n 1.8976990616650726,\n 1.758223085999124,\n 2.2294649594813816\n ]\n ]\n }\n },\n {\n \"schema\": {\n \"refId\": \"A\",\n \"meta\": {\n \"typeVersion\": [\n 0,\n 0\n ],\n \"custom\": {\n \"customStat\": 10\n }\n },\n \"fields\": [\n {\n \"name\": \"time\",\n \"type\": \"time\",\n \"typeInfo\": {\n \"frame\": \"time.Time\",\n \"nullable\": true\n },\n \"config\": {\n \"interval\": 3600000\n }\n },\n {\n \"name\": \"Value\",\n \"type\": \"number\",\n \"typeInfo\": {\n \"frame\": \"float64\",\n \"nullable\": true\n },\n \"labels\": {\n \"pod\": \"A-pod2\"\n },\n \"config\": {}\n }\n ]\n },\n \"data\": {\n \"values\": [\n [\n 1727107111901,\n 1727110711901,\n 1727114311901,\n 1727117911901,\n 1727121511901,\n 1727125111901\n ],\n [\n 1.907286825122581,\n 2.0914263380328766,\n 1.8164545521094575,\n 1.621111084665713,\n 1.3902653996444705,\n 1.482803315949775\n ]\n ]\n }\n }\n]", + "scenarioId": "raw_frame" + } + }, + "refId": "A", + "hidden": false + } + } + ], + "transformations": [], + "queryOptions": {} + } + }, + "vizConfig": { + "kind": "barchart", + "spec": { + "pluginVersion": "11.0.0-pre", + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": false, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "series", + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "$$hashKey": "object:88", + "format": "short", + "logBase": 1, + "show": true + }, + { + "$$hashKey": "object:89", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, + "alertThreshold": true, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "fieldConfig": { + "defaults": { + "unit": "short" + }, + "overrides": [] + } + } + } + } + }, + "panel-29": { + "kind": "Panel", + "spec": { + "id": 29, + "title": "Status + Notes", + "description": "", + "links": [], + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "grafana-testdata-datasource", + "spec": {} + }, + "refId": "A", + "hidden": false + } + } + ], + "transformations": [], + "queryOptions": {} + } + }, + "vizConfig": { + "kind": "text", + "spec": { + "pluginVersion": "11.0.0-pre", + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "# Graph panel \u003e\u003e Bar chart panel\n", + "mode": "markdown" + }, + "fieldConfig": { + "defaults": {}, + "overrides": [] + } + } + } + } + }, + "panel-30": { + "kind": "Panel", + "spec": { + "id": 30, + "title": "Flot graph - x axis histogram mode", + "description": "", + "links": [], + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "grafana-testdata-datasource", + "spec": { + "scenarioId": "random_walk", + "seriesCount": 3 + } + }, + "refId": "A", + "hidden": false + } + } + ], + "transformations": [], + "queryOptions": {} + } + }, + "vizConfig": { + "kind": "histogram", + "spec": { + "pluginVersion": "11.0.0-pre", + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": false, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "histogram", + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:193", + "format": "short", + "logBase": 1, + "show": true + }, + { + "$$hashKey": "object:194", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, + "alertThreshold": true, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "fieldConfig": { + "defaults": { + "unit": "short" + }, + "overrides": [] + } + } + } + } + }, + "panel-31": { + "kind": "Panel", + "spec": { + "id": 31, + "title": "Status + Notes", + "description": "", + "links": [], + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "grafana-testdata-datasource", + "spec": {} + }, + "refId": "A", + "hidden": false + } + } + ], + "transformations": [], + "queryOptions": {} + } + }, + "vizConfig": { + "kind": "text", + "spec": { + "pluginVersion": "11.0.0-pre", + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "# Graph panel \u003e\u003e Histogram panel\n", + "mode": "markdown" + }, + "fieldConfig": { + "defaults": {}, + "overrides": [] + } + } + } + } + }, + "panel-32": { + "kind": "Panel", + "spec": { + "id": 32, + "title": "Flot graph - x axis series mode (with legend calcs)", + "description": "", + "links": [], + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "datasource", + "spec": { + "panelId": 28 + } + }, + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "refId": "A", + "hidden": false + } + } + ], + "transformations": [], + "queryOptions": {} + } + }, + "vizConfig": { + "kind": "bargauge", + "spec": { + "pluginVersion": "11.3.0-pre", + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": false, + "show": true, + "total": false, + "values": true + }, + "lines": false, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "series", + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "$$hashKey": "object:88", + "format": "short", + "logBase": 1, + "show": true + }, + { + "$$hashKey": "object:89", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, + "alertThreshold": true, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "fieldConfig": { + "defaults": { + "unit": "short" + }, + "overrides": [] + } + } + } + } + }, + "panel-33": { + "kind": "Panel", + "spec": { + "id": 33, + "title": "Status + Notes", + "description": "", + "links": [], + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "grafana-testdata-datasource", + "spec": {} + }, + "refId": "A", + "hidden": false + } + } + ], + "transformations": [], + "queryOptions": {} + } + }, + "vizConfig": { + "kind": "text", + "spec": { + "pluginVersion": "11.3.0-pre", + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "# Graph panel \u003e\u003e Bar gauge panel\n", + "mode": "markdown" + }, + "fieldConfig": { + "defaults": {}, + "overrides": [] + } + } + } + } + }, + "panel-4": { + "kind": "Panel", + "spec": { + "id": 4, + "title": "Flot graph", + "description": "", + "links": [], + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "grafana-testdata-datasource", + "spec": { + "scenarioId": "random_walk", + "seriesCount": 3 + } + }, + "refId": "A", + "hidden": false + } + } + ], + "transformations": [], + "queryOptions": {} + } + }, + "vizConfig": { + "kind": "timeseries", + "spec": { + "pluginVersion": "11.0.0-pre", + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, + "alertThreshold": true, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "fieldConfig": { + "defaults": { + "unit": "short" + }, + "overrides": [] + } + } + } + } + }, + "panel-6": { + "kind": "Panel", + "spec": { + "id": 6, + "title": "Status + Notes", + "description": "", + "links": [], + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "grafana-testdata-datasource", + "spec": {} + }, + "refId": "A", + "hidden": false + } + } + ], + "transformations": [], + "queryOptions": {} + } + }, + "vizConfig": { + "kind": "text", + "spec": { + "pluginVersion": "11.0.0-pre", + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "# Graph panel \u003e\u003e Timeseries panel\n\nKnown issues:\n* hiding null/empty series\n* time regions", + "mode": "markdown" + }, + "fieldConfig": { + "defaults": {}, + "overrides": [] + } + } + } + } + }, + "panel-7": { + "kind": "Panel", + "spec": { + "id": 7, + "title": "Status + Notes", + "description": "", + "links": [], + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "grafana-testdata-datasource", + "spec": {} + }, + "refId": "A", + "hidden": false + } + } + ], + "transformations": [], + "queryOptions": {} + } + }, + "vizConfig": { + "kind": "text", + "spec": { + "pluginVersion": "11.0.0-pre", + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "# Table (old) \u003e\u003e Table\n\nKnown issues:\n* wrapping text\n* style changes", + "mode": "markdown" + }, + "fieldConfig": { + "defaults": {}, + "overrides": [] + } + } + } + } + }, + "panel-9": { + "kind": "Panel", + "spec": { + "id": 9, + "title": "grafana-singlestat-panel", + "description": "", + "links": [], + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "grafana-testdata-datasource", + "spec": {} + }, + "refId": "A", + "hidden": false + } + } + ], + "transformations": [], + "queryOptions": { + "maxDataPoints": 100 + } + } + }, + "vizConfig": { + "kind": "stat", + "spec": { + "pluginVersion": "", + "options": { + "__angularMigration": { + "autoMigrateFrom": "grafana-singlestat-panel", + "originalOptions": { + "colorBackground": false, + "colorValue": true, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "format": "areaF2", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "nullPointMode": "connected", + "postfix": "b", + "postfixFontSize": "50%", + "prefix": "a", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "thresholds": "", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + } + } + }, + "fieldConfig": { + "defaults": {}, + "overrides": [] + } + } + } + } + } + }, + "layout": { + "kind": "GridLayout", + "spec": { + "items": [ + { + "kind": "GridLayoutItem", + "spec": { + "x": 0, + "y": 0, + "width": 16, + "height": 11, + "element": { + "kind": "ElementReference", + "name": "panel-4" + } + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "x": 16, + "y": 0, + "width": 8, + "height": 11, + "element": { + "kind": "ElementReference", + "name": "panel-6" + } + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "x": 0, + "y": 11, + "width": 16, + "height": 11, + "element": { + "kind": "ElementReference", + "name": "panel-28" + } + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "x": 16, + "y": 11, + "width": 8, + "height": 11, + "element": { + "kind": "ElementReference", + "name": "panel-29" + } + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "x": 0, + "y": 22, + "width": 16, + "height": 11, + "element": { + "kind": "ElementReference", + "name": "panel-32" + } + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "x": 0, + "y": 22, + "width": 16, + "height": 11, + "element": { + "kind": "ElementReference", + "name": "panel-30" + } + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "x": 16, + "y": 22, + "width": 8, + "height": 11, + "element": { + "kind": "ElementReference", + "name": "panel-33" + } + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "x": 16, + "y": 22, + "width": 8, + "height": 11, + "element": { + "kind": "ElementReference", + "name": "panel-31" + } + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "x": 0, + "y": 33, + "width": 16, + "height": 10, + "element": { + "kind": "ElementReference", + "name": "panel-2" + } + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "x": 16, + "y": 33, + "width": 8, + "height": 10, + "element": { + "kind": "ElementReference", + "name": "panel-7" + } + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "x": 0, + "y": 43, + "width": 8, + "height": 8, + "element": { + "kind": "ElementReference", + "name": "panel-9" + } + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "x": 8, + "y": 43, + "width": 8, + "height": 8, + "element": { + "kind": "ElementReference", + "name": "panel-23" + } + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "x": 16, + "y": 43, + "width": 8, + "height": 8, + "element": { + "kind": "ElementReference", + "name": "panel-10" + } + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "x": 0, + "y": 51, + "width": 16, + "height": 10, + "element": { + "kind": "ElementReference", + "name": "panel-24" + } + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "x": 16, + "y": 51, + "width": 8, + "height": 10, + "element": { + "kind": "ElementReference", + "name": "panel-25" + } + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "x": 0, + "y": 61, + "width": 16, + "height": 10, + "element": { + "kind": "ElementReference", + "name": "panel-26" + } + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "x": 16, + "y": 61, + "width": 8, + "height": 10, + "element": { + "kind": "ElementReference", + "name": "panel-27" + } + } + } + ] + } + }, + "links": [ + { + "title": "Auto migrate graph panel (TRUE)", + "type": "link", + "icon": "external link", + "tooltip": "", + "url": " /d/cdd412c4/?__feature.autoMigrateGraphPanel=true", + "tags": [], + "asDropdown": false, + "targetBlank": true, + "includeVars": false, + "keepTime": false + }, + { + "title": "Auto migrate graph panel (FALSE)", + "type": "link", + "icon": "external link", + "tooltip": "", + "url": " /d/cdd412c4/?__feature.autoMigrateGraphPanel=false", + "tags": [], + "asDropdown": false, + "targetBlank": true, + "includeVars": false, + "keepTime": false + }, + { + "title": "Auto migrate table (old) panel (TRUE)", + "type": "link", + "icon": "external link", + "tooltip": "", + "url": " /d/cdd412c4/?__feature.autoMigrateTablePanel=true", + "tags": [], + "asDropdown": false, + "targetBlank": true, + "includeVars": false, + "keepTime": false + }, + { + "title": "Auto migrate table (old) panel (FALSE)", + "type": "link", + "icon": "external link", + "tooltip": "", + "url": " /d/cdd412c4/?__feature.autoMigrateTablePanel=false", + "tags": [], + "asDropdown": false, + "targetBlank": true, + "includeVars": false, + "keepTime": false + }, + { + "title": "Auto migrate piechart panel (TRUE)", + "type": "link", + "icon": "external link", + "tooltip": "", + "url": " /d/cdd412c4/?__feature.autoMigratePiechartPanel=true", + "tags": [], + "asDropdown": false, + "targetBlank": true, + "includeVars": false, + "keepTime": false + }, + { + "title": "Auto migrate piechart panel (FALSE)", + "type": "link", + "icon": "external link", + "tooltip": "", + "url": " /d/cdd412c4/?__feature.autoMigratePiechartPanel=false", + "tags": [], + "asDropdown": false, + "targetBlank": true, + "includeVars": false, + "keepTime": false + }, + { + "title": "Auto migrate worldmap panel (TRUE)", + "type": "link", + "icon": "external link", + "tooltip": "", + "url": " /d/cdd412c4/?__feature.autoMigrateWorldmapPanel=true", + "tags": [], + "asDropdown": false, + "targetBlank": true, + "includeVars": false, + "keepTime": false + }, + { + "title": "Auto migrate worldmap panel (FALSE)", + "type": "link", + "icon": "external link", + "tooltip": "", + "url": " /d/cdd412c4/?__feature.autoMigrateWorldmapPanel=false", + "tags": [], + "asDropdown": false, + "targetBlank": true, + "includeVars": false, + "keepTime": false + }, + { + "title": "Auto migrate stat panel (TRUE)", + "type": "link", + "icon": "external link", + "tooltip": "", + "url": " /d/cdd412c4/?__feature.autoMigrateStatPanel=true", + "tags": [], + "asDropdown": false, + "targetBlank": true, + "includeVars": false, + "keepTime": false + }, + { + "title": "Auto migrate stat panel (FALSE)", + "type": "link", + "icon": "external link", + "tooltip": "", + "url": " /d/cdd412c4/?__feature.autoMigrateStatPanel=false", + "tags": [], + "asDropdown": false, + "targetBlank": true, + "includeVars": false, + "keepTime": false + }, + { + "title": "Auto migrate (TRUE)", + "type": "link", + "icon": "external link", + "tooltip": "", + "url": "/d/cdd412c4/?__feature.autoMigrateOldPanels=true", + "tags": [], + "asDropdown": false, + "targetBlank": true, + "includeVars": false, + "keepTime": false + }, + { + "title": "Auto migrate (FALSE)", + "type": "link", + "icon": "external link", + "tooltip": "", + "url": "/d/cdd412c4/?__feature.autoMigrateOldPanels=false", + "tags": [], + "asDropdown": false, + "targetBlank": true, + "includeVars": false, + "keepTime": false + }, + { + "title": "Disable angular (TRUE)", + "type": "link", + "icon": "external link", + "tooltip": "", + "url": "/d/cdd412c4/?__feature.disableAngular=true", + "tags": [], + "asDropdown": false, + "targetBlank": true, + "includeVars": false, + "keepTime": false + }, + { + "title": "Disable angular (FALSE)", + "type": "link", + "icon": "external link", + "tooltip": "", + "url": "/d/cdd412c4/?__feature.disableAngular=false", + "tags": [], + "asDropdown": false, + "targetBlank": true, + "includeVars": false, + "keepTime": false + } + ], + "liveNow": false, + "preload": false, + "tags": [ + "gdev", + "migrations", + "angular" + ], + "timeSettings": { + "timezone": "", + "from": "now-6h", + "to": "now", + "autoRefresh": "", + "autoRefreshIntervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "hideTimepicker": false, + "fiscalYearStartMonth": 0 + }, + "title": "Devenv - Panel migrations", + "variables": [] + }, + "status": { + "conversion": { + "failed": false, + "storedVersion": "v1beta1" + } + } +} \ No newline at end of file diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/v1beta1.angular-migrations.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/v1beta1.angular-migrations.v2beta1.json new file mode 100644 index 00000000000..63447487dca --- /dev/null +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/v1beta1.angular-migrations.v2beta1.json @@ -0,0 +1,1912 @@ +{ + "kind": "Dashboard", + "apiVersion": "dashboard.grafana.app/v2beta1", + "metadata": { + "name": "angular-migrations-test" + }, + "spec": { + "annotations": [ + { + "kind": "AnnotationQuery", + "spec": { + "query": { + "kind": "DataQuery", + "group": "grafana", + "version": "v0", + "datasource": { + "name": "-- Grafana --" + }, + "spec": {} + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations \u0026 Alerts", + "builtIn": true, + "legacyOptions": { + "type": "dashboard" + } + } + } + ], + "cursorSync": "Off", + "editable": true, + "elements": { + "panel-10": { + "kind": "Panel", + "spec": { + "id": 10, + "title": "Status + Notes", + "description": "", + "links": [], + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "DataQuery", + "group": "grafana-testdata-datasource", + "version": "v0", + "spec": {} + }, + "refId": "A", + "hidden": false + } + } + ], + "transformations": [], + "queryOptions": {} + } + }, + "vizConfig": { + "kind": "VizConfig", + "group": "text", + "version": "11.0.0-pre", + "spec": { + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "# Singlestat \u003e\u003e Stat\n\nKnown issues:\n* limited options", + "mode": "markdown" + }, + "fieldConfig": { + "defaults": {}, + "overrides": [] + } + } + } + } + }, + "panel-2": { + "kind": "Panel", + "spec": { + "id": 2, + "title": "Table (old)", + "description": "", + "links": [], + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "DataQuery", + "group": "grafana-testdata-datasource", + "version": "v0", + "spec": { + "scenarioId": "random_walk_table" + } + }, + "refId": "A", + "hidden": false + } + } + ], + "transformations": [ + { + "kind": "merge", + "spec": { + "id": "merge", + "options": { + "reducers": [] + } + } + } + ], + "queryOptions": {} + } + }, + "vizConfig": { + "kind": "VizConfig", + "group": "table", + "version": "9.5.0-pre", + "spec": { + "options": { + "__angularMigration": { + "autoMigrateFrom": "table-old", + "originalOptions": { + "columns": [], + "fontSize": "100%", + "showHeader": true, + "sort": { + "col": 0, + "desc": true + }, + "styles": [ + { + "alias": "Time", + "align": "auto", + "dateFormat": "YYYY-MM-DD HH:mm:ss", + "pattern": "Time", + "type": "date" + }, + { + "alias": "", + "align": "right", + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 2, + "pattern": "/.*/", + "thresholds": [], + "type": "number", + "unit": "short" + } + ], + "transform": "table" + } + }, + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true, + "showRowNums": false + }, + "fieldConfig": { + "defaults": {}, + "overrides": [] + } + } + } + } + }, + "panel-23": { + "kind": "Panel", + "spec": { + "id": 23, + "title": "singlestat (old, internal. Migrated if schema \u003c 28)", + "description": "", + "links": [], + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "DataQuery", + "group": "grafana-testdata-datasource", + "version": "v0", + "spec": {} + }, + "refId": "A", + "hidden": false + } + } + ], + "transformations": [], + "queryOptions": { + "maxDataPoints": 100 + } + } + }, + "vizConfig": { + "kind": "VizConfig", + "group": "stat", + "version": "11.0.0-pre", + "spec": { + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "mean" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "fieldConfig": { + "defaults": { + "unit": "ms", + "mappings": [ + { + "type": "special", + "options": { + "match": "null", + "result": { + "text": "N/A" + } + } + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "value": null, + "color": "green" + }, + { + "value": 80, + "color": "red" + } + ] + } + }, + "overrides": [] + } + } + } + } + }, + "panel-24": { + "kind": "Panel", + "spec": { + "id": 24, + "title": "grafana-piechart-panel", + "description": "", + "links": [], + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "DataQuery", + "group": "grafana-testdata-datasource", + "version": "v0", + "spec": { + "scenarioId": "random_walk_table" + } + }, + "refId": "A", + "hidden": false + } + } + ], + "transformations": [ + { + "kind": "merge", + "spec": { + "id": "merge", + "options": { + "reducers": [] + } + } + } + ], + "queryOptions": {} + } + }, + "vizConfig": { + "kind": "VizConfig", + "group": "piechart", + "version": "9.5.0-pre", + "spec": { + "options": { + "__angularMigration": { + "autoMigrateFrom": "grafana-piechart-panel", + "originalOptions": {} + }, + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "pieType": "pie", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "fieldConfig": { + "defaults": {}, + "overrides": [] + } + } + } + } + }, + "panel-25": { + "kind": "Panel", + "spec": { + "id": 25, + "title": "Status + Notes", + "description": "", + "links": [], + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "DataQuery", + "group": "grafana-testdata-datasource", + "version": "v0", + "spec": {} + }, + "refId": "A", + "hidden": false + } + } + ], + "transformations": [], + "queryOptions": {} + } + }, + "vizConfig": { + "kind": "VizConfig", + "group": "text", + "version": "11.0.0-pre", + "spec": { + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "# grafana-piechart-panel \u003e\u003e piechart\n\nKnown issues:\n* TBD", + "mode": "markdown" + }, + "fieldConfig": { + "defaults": {}, + "overrides": [] + } + } + } + } + }, + "panel-26": { + "kind": "Panel", + "spec": { + "id": 26, + "title": "grafana-worldmap-panel", + "description": "", + "links": [], + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "DataQuery", + "group": "grafana-testdata-datasource", + "version": "v0", + "spec": { + "csvFileName": "flight_info_by_state.csv", + "scenarioId": "csv_file" + } + }, + "refId": "A", + "hidden": false + } + } + ], + "transformations": [ + { + "kind": "merge", + "spec": { + "id": "merge", + "options": { + "reducers": [] + } + } + }, + { + "kind": "reduce", + "spec": { + "id": "reduce", + "options": { + "reducers": [ + "sum" + ] + } + } + } + ], + "queryOptions": { + "maxDataPoints": 1 + } + } + }, + "vizConfig": { + "kind": "VizConfig", + "group": "geomap", + "version": "10.4.0-pre", + "spec": { + "options": { + "__angularMigration": { + "autoMigrateFrom": "grafana-worldmap-panel", + "originalOptions": { + "circleMaxSize": 30, + "circleMinSize": 2, + "colors": [ + "rgba(245, 54, 54, 0.9)", + "rgba(237, 129, 40, 0.89)", + "rgba(50, 172, 45, 0.97)" + ], + "decimals": 0, + "esMetric": "Count", + "hideEmpty": false, + "hideZero": false, + "initialZoom": 1, + "locationData": "countries", + "mapCenter": "(0°, 0°)", + "mapCenterLatitude": 0, + "mapCenterLongitude": 0, + "mouseWheelZoom": false, + "showLegend": true, + "stickyLabels": false, + "tableQueryOptions": { + "geohashField": "geohash", + "latitudeField": "latitude", + "longitudeField": "longitude", + "metricField": "metric", + "queryType": "geohash" + }, + "thresholds": "0,10", + "unitPlural": "", + "unitSingle": "", + "valueName": "total" + } + }, + "basemap": { + "name": "Basemap", + "type": "default" + }, + "controls": { + "mouseWheelZoom": false, + "showAttribution": true, + "showDebug": false, + "showMeasure": false, + "showScale": false, + "showZoom": true + }, + "layers": [ + { + "config": { + "showLegend": true, + "style": { + "color": { + "fixed": "dark-green" + }, + "opacity": 0.4, + "rotation": { + "fixed": 0, + "max": 360, + "min": -360, + "mode": "mod" + }, + "size": { + "fixed": 5, + "max": 30, + "min": 2 + }, + "symbol": { + "fixed": "img/icons/marker/circle.svg", + "mode": "fixed" + }, + "symbolAlign": { + "horizontal": "center", + "vertical": "center" + }, + "textConfig": { + "fontSize": 12, + "offsetX": 0, + "offsetY": 0, + "textAlign": "center", + "textBaseline": "middle" + } + } + }, + "location": { + "gazetteer": "public/gazetteer/countries.json", + "mode": "lookup" + }, + "name": "Layer 0", + "tooltip": true, + "type": "markers" + } + ], + "tooltip": { + "mode": "details" + }, + "view": { + "allLayers": true, + "id": "zero", + "lat": 0, + "lon": 0, + "zoom": 1 + } + }, + "fieldConfig": { + "defaults": {}, + "overrides": [] + } + } + } + } + }, + "panel-27": { + "kind": "Panel", + "spec": { + "id": 27, + "title": "Status + Notes", + "description": "", + "links": [], + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "DataQuery", + "group": "grafana-testdata-datasource", + "version": "v0", + "spec": {} + }, + "refId": "A", + "hidden": false + } + } + ], + "transformations": [], + "queryOptions": {} + } + }, + "vizConfig": { + "kind": "VizConfig", + "group": "text", + "version": "11.0.0-pre", + "spec": { + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "# grafana-worldmap-panel \u003e\u003e geomap\n\nKnown issues:\n* TBD", + "mode": "markdown" + }, + "fieldConfig": { + "defaults": {}, + "overrides": [] + } + } + } + } + }, + "panel-28": { + "kind": "Panel", + "spec": { + "id": 28, + "title": "Flot graph - x axis series mode", + "description": "", + "links": [], + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "DataQuery", + "group": "grafana-testdata-datasource", + "version": "v0", + "spec": { + "rawFrameContent": "[\n {\n \"schema\": {\n \"refId\": \"A\",\n \"meta\": {\n \"typeVersion\": [\n 0,\n 0\n ],\n \"custom\": {\n \"customStat\": 10\n }\n },\n \"fields\": [\n {\n \"name\": \"time\",\n \"type\": \"time\",\n \"typeInfo\": {\n \"frame\": \"time.Time\",\n \"nullable\": true\n },\n \"config\": {\n \"interval\": 3600000\n }\n },\n {\n \"name\": \"Value\",\n \"type\": \"number\",\n \"typeInfo\": {\n \"frame\": \"float64\",\n \"nullable\": true\n },\n \"labels\": {\n \"pod\": \"A-pod\"\n },\n \"config\": {}\n }\n ]\n },\n \"data\": {\n \"values\": [\n [\n 1727107111901,\n 1727110711901,\n 1727114311901,\n 1727117911901,\n 1727121511901,\n 1727125111901\n ],\n [\n 1.907286825122581,\n 2.260951647569786,\n 1.887442338051216,\n 2.1526144400893514,\n 1.7287721375237766,\n 1.7262902137793208\n ]\n ]\n }\n },\n {\n \"schema\": {\n \"refId\": \"A\",\n \"meta\": {\n \"typeVersion\": [\n 0,\n 0\n ],\n \"custom\": {\n \"customStat\": 10\n }\n },\n \"fields\": [\n {\n \"name\": \"time\",\n \"type\": \"time\",\n \"typeInfo\": {\n \"frame\": \"time.Time\",\n \"nullable\": true\n },\n \"config\": {\n \"interval\": 3600000\n }\n },\n {\n \"name\": \"Value\",\n \"type\": \"number\",\n \"typeInfo\": {\n \"frame\": \"float64\",\n \"nullable\": true\n },\n \"labels\": {\n \"pod\": \"A-pod1\"\n },\n \"config\": {}\n }\n ]\n },\n \"data\": {\n \"values\": [\n [\n 1727107111901,\n 1727110711901,\n 1727114311901,\n 1727117911901,\n 1727121511901,\n 1727125111901\n ],\n [\n 1.907286825122581,\n 1.589539045095202,\n 1.5914283506847613,\n 1.8976990616650726,\n 1.758223085999124,\n 2.2294649594813816\n ]\n ]\n }\n },\n {\n \"schema\": {\n \"refId\": \"A\",\n \"meta\": {\n \"typeVersion\": [\n 0,\n 0\n ],\n \"custom\": {\n \"customStat\": 10\n }\n },\n \"fields\": [\n {\n \"name\": \"time\",\n \"type\": \"time\",\n \"typeInfo\": {\n \"frame\": \"time.Time\",\n \"nullable\": true\n },\n \"config\": {\n \"interval\": 3600000\n }\n },\n {\n \"name\": \"Value\",\n \"type\": \"number\",\n \"typeInfo\": {\n \"frame\": \"float64\",\n \"nullable\": true\n },\n \"labels\": {\n \"pod\": \"A-pod2\"\n },\n \"config\": {}\n }\n ]\n },\n \"data\": {\n \"values\": [\n [\n 1727107111901,\n 1727110711901,\n 1727114311901,\n 1727117911901,\n 1727121511901,\n 1727125111901\n ],\n [\n 1.907286825122581,\n 2.0914263380328766,\n 1.8164545521094575,\n 1.621111084665713,\n 1.3902653996444705,\n 1.482803315949775\n ]\n ]\n }\n }\n]", + "scenarioId": "raw_frame" + } + }, + "refId": "A", + "hidden": false + } + } + ], + "transformations": [], + "queryOptions": {} + } + }, + "vizConfig": { + "kind": "VizConfig", + "group": "barchart", + "version": "11.0.0-pre", + "spec": { + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": false, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "series", + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "$$hashKey": "object:88", + "format": "short", + "logBase": 1, + "show": true + }, + { + "$$hashKey": "object:89", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, + "alertThreshold": true, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "fieldConfig": { + "defaults": { + "unit": "short" + }, + "overrides": [] + } + } + } + } + }, + "panel-29": { + "kind": "Panel", + "spec": { + "id": 29, + "title": "Status + Notes", + "description": "", + "links": [], + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "DataQuery", + "group": "grafana-testdata-datasource", + "version": "v0", + "spec": {} + }, + "refId": "A", + "hidden": false + } + } + ], + "transformations": [], + "queryOptions": {} + } + }, + "vizConfig": { + "kind": "VizConfig", + "group": "text", + "version": "11.0.0-pre", + "spec": { + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "# Graph panel \u003e\u003e Bar chart panel\n", + "mode": "markdown" + }, + "fieldConfig": { + "defaults": {}, + "overrides": [] + } + } + } + } + }, + "panel-30": { + "kind": "Panel", + "spec": { + "id": 30, + "title": "Flot graph - x axis histogram mode", + "description": "", + "links": [], + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "DataQuery", + "group": "grafana-testdata-datasource", + "version": "v0", + "spec": { + "scenarioId": "random_walk", + "seriesCount": 3 + } + }, + "refId": "A", + "hidden": false + } + } + ], + "transformations": [], + "queryOptions": {} + } + }, + "vizConfig": { + "kind": "VizConfig", + "group": "histogram", + "version": "11.0.0-pre", + "spec": { + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": false, + "total": false, + "values": false + }, + "lines": false, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "histogram", + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:193", + "format": "short", + "logBase": 1, + "show": true + }, + { + "$$hashKey": "object:194", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, + "alertThreshold": true, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "fieldConfig": { + "defaults": { + "unit": "short" + }, + "overrides": [] + } + } + } + } + }, + "panel-31": { + "kind": "Panel", + "spec": { + "id": 31, + "title": "Status + Notes", + "description": "", + "links": [], + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "DataQuery", + "group": "grafana-testdata-datasource", + "version": "v0", + "spec": {} + }, + "refId": "A", + "hidden": false + } + } + ], + "transformations": [], + "queryOptions": {} + } + }, + "vizConfig": { + "kind": "VizConfig", + "group": "text", + "version": "11.0.0-pre", + "spec": { + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "# Graph panel \u003e\u003e Histogram panel\n", + "mode": "markdown" + }, + "fieldConfig": { + "defaults": {}, + "overrides": [] + } + } + } + } + }, + "panel-32": { + "kind": "Panel", + "spec": { + "id": 32, + "title": "Flot graph - x axis series mode (with legend calcs)", + "description": "", + "links": [], + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "DataQuery", + "group": "datasource", + "version": "v0", + "datasource": { + "name": "-- Dashboard --" + }, + "spec": { + "panelId": 28 + } + }, + "refId": "A", + "hidden": false + } + } + ], + "transformations": [], + "queryOptions": {} + } + }, + "vizConfig": { + "kind": "VizConfig", + "group": "bargauge", + "version": "11.3.0-pre", + "spec": { + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": false, + "show": true, + "total": false, + "values": true + }, + "lines": false, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "series", + "show": true, + "values": [ + "total" + ] + }, + "yaxes": [ + { + "$$hashKey": "object:88", + "format": "short", + "logBase": 1, + "show": true + }, + { + "$$hashKey": "object:89", + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, + "alertThreshold": true, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "fieldConfig": { + "defaults": { + "unit": "short" + }, + "overrides": [] + } + } + } + } + }, + "panel-33": { + "kind": "Panel", + "spec": { + "id": 33, + "title": "Status + Notes", + "description": "", + "links": [], + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "DataQuery", + "group": "grafana-testdata-datasource", + "version": "v0", + "spec": {} + }, + "refId": "A", + "hidden": false + } + } + ], + "transformations": [], + "queryOptions": {} + } + }, + "vizConfig": { + "kind": "VizConfig", + "group": "text", + "version": "11.3.0-pre", + "spec": { + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "# Graph panel \u003e\u003e Bar gauge panel\n", + "mode": "markdown" + }, + "fieldConfig": { + "defaults": {}, + "overrides": [] + } + } + } + } + }, + "panel-4": { + "kind": "Panel", + "spec": { + "id": 4, + "title": "Flot graph", + "description": "", + "links": [], + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "DataQuery", + "group": "grafana-testdata-datasource", + "version": "v0", + "spec": { + "scenarioId": "random_walk", + "seriesCount": 3 + } + }, + "refId": "A", + "hidden": false + } + } + ], + "transformations": [], + "queryOptions": {} + } + }, + "vizConfig": { + "kind": "VizConfig", + "group": "timeseries", + "version": "11.0.0-pre", + "spec": { + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "fill": 1, + "fillGradient": 0, + "hiddenSeries": false, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "thresholds": [], + "timeRegions": [], + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + } + }, + "alertThreshold": true, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "fieldConfig": { + "defaults": { + "unit": "short" + }, + "overrides": [] + } + } + } + } + }, + "panel-6": { + "kind": "Panel", + "spec": { + "id": 6, + "title": "Status + Notes", + "description": "", + "links": [], + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "DataQuery", + "group": "grafana-testdata-datasource", + "version": "v0", + "spec": {} + }, + "refId": "A", + "hidden": false + } + } + ], + "transformations": [], + "queryOptions": {} + } + }, + "vizConfig": { + "kind": "VizConfig", + "group": "text", + "version": "11.0.0-pre", + "spec": { + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "# Graph panel \u003e\u003e Timeseries panel\n\nKnown issues:\n* hiding null/empty series\n* time regions", + "mode": "markdown" + }, + "fieldConfig": { + "defaults": {}, + "overrides": [] + } + } + } + } + }, + "panel-7": { + "kind": "Panel", + "spec": { + "id": 7, + "title": "Status + Notes", + "description": "", + "links": [], + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "DataQuery", + "group": "grafana-testdata-datasource", + "version": "v0", + "spec": {} + }, + "refId": "A", + "hidden": false + } + } + ], + "transformations": [], + "queryOptions": {} + } + }, + "vizConfig": { + "kind": "VizConfig", + "group": "text", + "version": "11.0.0-pre", + "spec": { + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "# Table (old) \u003e\u003e Table\n\nKnown issues:\n* wrapping text\n* style changes", + "mode": "markdown" + }, + "fieldConfig": { + "defaults": {}, + "overrides": [] + } + } + } + } + }, + "panel-9": { + "kind": "Panel", + "spec": { + "id": 9, + "title": "grafana-singlestat-panel", + "description": "", + "links": [], + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "DataQuery", + "group": "grafana-testdata-datasource", + "version": "v0", + "spec": {} + }, + "refId": "A", + "hidden": false + } + } + ], + "transformations": [], + "queryOptions": { + "maxDataPoints": 100 + } + } + }, + "vizConfig": { + "kind": "VizConfig", + "group": "stat", + "version": "", + "spec": { + "options": { + "__angularMigration": { + "autoMigrateFrom": "grafana-singlestat-panel", + "originalOptions": { + "colorBackground": false, + "colorValue": true, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "format": "areaF2", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "nullPointMode": "connected", + "postfix": "b", + "postfixFontSize": "50%", + "prefix": "a", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": false, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", + "thresholds": "", + "valueFontSize": "80%", + "valueMaps": [ + { + "op": "=", + "text": "N/A", + "value": "null" + } + ], + "valueName": "avg" + } + } + }, + "fieldConfig": { + "defaults": {}, + "overrides": [] + } + } + } + } + } + }, + "layout": { + "kind": "GridLayout", + "spec": { + "items": [ + { + "kind": "GridLayoutItem", + "spec": { + "x": 0, + "y": 0, + "width": 16, + "height": 11, + "element": { + "kind": "ElementReference", + "name": "panel-4" + } + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "x": 16, + "y": 0, + "width": 8, + "height": 11, + "element": { + "kind": "ElementReference", + "name": "panel-6" + } + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "x": 0, + "y": 11, + "width": 16, + "height": 11, + "element": { + "kind": "ElementReference", + "name": "panel-28" + } + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "x": 16, + "y": 11, + "width": 8, + "height": 11, + "element": { + "kind": "ElementReference", + "name": "panel-29" + } + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "x": 0, + "y": 22, + "width": 16, + "height": 11, + "element": { + "kind": "ElementReference", + "name": "panel-32" + } + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "x": 0, + "y": 22, + "width": 16, + "height": 11, + "element": { + "kind": "ElementReference", + "name": "panel-30" + } + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "x": 16, + "y": 22, + "width": 8, + "height": 11, + "element": { + "kind": "ElementReference", + "name": "panel-33" + } + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "x": 16, + "y": 22, + "width": 8, + "height": 11, + "element": { + "kind": "ElementReference", + "name": "panel-31" + } + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "x": 0, + "y": 33, + "width": 16, + "height": 10, + "element": { + "kind": "ElementReference", + "name": "panel-2" + } + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "x": 16, + "y": 33, + "width": 8, + "height": 10, + "element": { + "kind": "ElementReference", + "name": "panel-7" + } + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "x": 0, + "y": 43, + "width": 8, + "height": 8, + "element": { + "kind": "ElementReference", + "name": "panel-9" + } + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "x": 8, + "y": 43, + "width": 8, + "height": 8, + "element": { + "kind": "ElementReference", + "name": "panel-23" + } + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "x": 16, + "y": 43, + "width": 8, + "height": 8, + "element": { + "kind": "ElementReference", + "name": "panel-10" + } + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "x": 0, + "y": 51, + "width": 16, + "height": 10, + "element": { + "kind": "ElementReference", + "name": "panel-24" + } + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "x": 16, + "y": 51, + "width": 8, + "height": 10, + "element": { + "kind": "ElementReference", + "name": "panel-25" + } + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "x": 0, + "y": 61, + "width": 16, + "height": 10, + "element": { + "kind": "ElementReference", + "name": "panel-26" + } + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "x": 16, + "y": 61, + "width": 8, + "height": 10, + "element": { + "kind": "ElementReference", + "name": "panel-27" + } + } + } + ] + } + }, + "links": [ + { + "title": "Auto migrate graph panel (TRUE)", + "type": "link", + "icon": "external link", + "tooltip": "", + "url": " /d/cdd412c4/?__feature.autoMigrateGraphPanel=true", + "tags": [], + "asDropdown": false, + "targetBlank": true, + "includeVars": false, + "keepTime": false + }, + { + "title": "Auto migrate graph panel (FALSE)", + "type": "link", + "icon": "external link", + "tooltip": "", + "url": " /d/cdd412c4/?__feature.autoMigrateGraphPanel=false", + "tags": [], + "asDropdown": false, + "targetBlank": true, + "includeVars": false, + "keepTime": false + }, + { + "title": "Auto migrate table (old) panel (TRUE)", + "type": "link", + "icon": "external link", + "tooltip": "", + "url": " /d/cdd412c4/?__feature.autoMigrateTablePanel=true", + "tags": [], + "asDropdown": false, + "targetBlank": true, + "includeVars": false, + "keepTime": false + }, + { + "title": "Auto migrate table (old) panel (FALSE)", + "type": "link", + "icon": "external link", + "tooltip": "", + "url": " /d/cdd412c4/?__feature.autoMigrateTablePanel=false", + "tags": [], + "asDropdown": false, + "targetBlank": true, + "includeVars": false, + "keepTime": false + }, + { + "title": "Auto migrate piechart panel (TRUE)", + "type": "link", + "icon": "external link", + "tooltip": "", + "url": " /d/cdd412c4/?__feature.autoMigratePiechartPanel=true", + "tags": [], + "asDropdown": false, + "targetBlank": true, + "includeVars": false, + "keepTime": false + }, + { + "title": "Auto migrate piechart panel (FALSE)", + "type": "link", + "icon": "external link", + "tooltip": "", + "url": " /d/cdd412c4/?__feature.autoMigratePiechartPanel=false", + "tags": [], + "asDropdown": false, + "targetBlank": true, + "includeVars": false, + "keepTime": false + }, + { + "title": "Auto migrate worldmap panel (TRUE)", + "type": "link", + "icon": "external link", + "tooltip": "", + "url": " /d/cdd412c4/?__feature.autoMigrateWorldmapPanel=true", + "tags": [], + "asDropdown": false, + "targetBlank": true, + "includeVars": false, + "keepTime": false + }, + { + "title": "Auto migrate worldmap panel (FALSE)", + "type": "link", + "icon": "external link", + "tooltip": "", + "url": " /d/cdd412c4/?__feature.autoMigrateWorldmapPanel=false", + "tags": [], + "asDropdown": false, + "targetBlank": true, + "includeVars": false, + "keepTime": false + }, + { + "title": "Auto migrate stat panel (TRUE)", + "type": "link", + "icon": "external link", + "tooltip": "", + "url": " /d/cdd412c4/?__feature.autoMigrateStatPanel=true", + "tags": [], + "asDropdown": false, + "targetBlank": true, + "includeVars": false, + "keepTime": false + }, + { + "title": "Auto migrate stat panel (FALSE)", + "type": "link", + "icon": "external link", + "tooltip": "", + "url": " /d/cdd412c4/?__feature.autoMigrateStatPanel=false", + "tags": [], + "asDropdown": false, + "targetBlank": true, + "includeVars": false, + "keepTime": false + }, + { + "title": "Auto migrate (TRUE)", + "type": "link", + "icon": "external link", + "tooltip": "", + "url": "/d/cdd412c4/?__feature.autoMigrateOldPanels=true", + "tags": [], + "asDropdown": false, + "targetBlank": true, + "includeVars": false, + "keepTime": false + }, + { + "title": "Auto migrate (FALSE)", + "type": "link", + "icon": "external link", + "tooltip": "", + "url": "/d/cdd412c4/?__feature.autoMigrateOldPanels=false", + "tags": [], + "asDropdown": false, + "targetBlank": true, + "includeVars": false, + "keepTime": false + }, + { + "title": "Disable angular (TRUE)", + "type": "link", + "icon": "external link", + "tooltip": "", + "url": "/d/cdd412c4/?__feature.disableAngular=true", + "tags": [], + "asDropdown": false, + "targetBlank": true, + "includeVars": false, + "keepTime": false + }, + { + "title": "Disable angular (FALSE)", + "type": "link", + "icon": "external link", + "tooltip": "", + "url": "/d/cdd412c4/?__feature.disableAngular=false", + "tags": [], + "asDropdown": false, + "targetBlank": true, + "includeVars": false, + "keepTime": false + } + ], + "liveNow": false, + "preload": false, + "tags": [ + "gdev", + "migrations", + "angular" + ], + "timeSettings": { + "timezone": "", + "from": "now-6h", + "to": "now", + "autoRefresh": "", + "autoRefreshIntervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "hideTimepicker": false, + "fiscalYearStartMonth": 0 + }, + "title": "Devenv - Panel migrations", + "variables": [] + }, + "status": { + "conversion": { + "failed": false, + "storedVersion": "v1beta1" + } + } +} \ No newline at end of file diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/v1beta1.panel-conversions.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/v1beta1.panel-conversions.v2alpha1.json index ae10c4f3807..f1004780fb0 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/v1beta1.panel-conversions.v2alpha1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/v1beta1.panel-conversions.v2alpha1.json @@ -181,7 +181,12 @@ "kind": "timeseries", "spec": { "pluginVersion": "", - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": {} + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/v1beta1.panel-conversions.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/v1beta1.panel-conversions.v2beta1.json index 910dbbe3e1c..84064324429 100644 --- a/apps/dashboard/pkg/migration/conversion/testdata/output/v1beta1.panel-conversions.v2beta1.json +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/v1beta1.panel-conversions.v2beta1.json @@ -186,7 +186,12 @@ "group": "timeseries", "version": "", "spec": { - "options": {}, + "options": { + "__angularMigration": { + "autoMigrateFrom": "graph", + "originalOptions": {} + } + }, "fieldConfig": { "defaults": {}, "overrides": [] diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/v1beta1.panel-target-missing-refid.v0alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/v1beta1.panel-target-missing-refid.v0alpha1.json new file mode 100644 index 00000000000..ad063633f86 --- /dev/null +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/v1beta1.panel-target-missing-refid.v0alpha1.json @@ -0,0 +1,161 @@ +{ + "kind": "Dashboard", + "apiVersion": "dashboard.grafana.app/v0alpha1", + "metadata": { + "name": "ad5vfcn", + "namespace": "default", + "uid": "dlMZZl6GndU8gJLUQSmgZxXBPCNXyXhNBeQJhHXl0r4X", + "resourceVersion": "2", + "generation": 2, + "creationTimestamp": "2025-11-28T10:14:21Z", + "labels": { + "grafana.app/deprecatedInternalID": "288" + }, + "annotations": { + "grafana.app/createdBy": "user:eex2ofwuj0agwd", + "grafana.app/updatedBy": "user:eex2ofwuj0agwd", + "grafana.app/updatedTimestamp": "2025-11-28T10:15:06Z" + } + }, + "spec": { + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations \u0026 Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": 288, + "links": [], + "panels": [ + { + "datasource": { + "type": "testdata", + "uid": "gdev-testdata" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 0 + }, + "id": 1, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.4.0-pre", + "targets": [ + { + "datasource": {}, + "queryType": "randomWalk" + }, + { + "datasource": {}, + "queryType": "randomWalk" + } + ], + "title": "New panel", + "type": "timeseries" + } + ], + "preload": false, + "schemaVersion": 42, + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": {}, + "timezone": "browser", + "title": "Panel ds inheritance ", + "uid": "ad5vfcn", + "version": 2 + }, + "status": { + "conversion": { + "failed": false, + "storedVersion": "v1beta1" + } + } +} \ No newline at end of file diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/v1beta1.panel-target-missing-refid.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/v1beta1.panel-target-missing-refid.v2alpha1.json new file mode 100644 index 00000000000..a8ce2b6a42b --- /dev/null +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/v1beta1.panel-target-missing-refid.v2alpha1.json @@ -0,0 +1,227 @@ +{ + "kind": "Dashboard", + "apiVersion": "dashboard.grafana.app/v2alpha1", + "metadata": { + "name": "ad5vfcn", + "namespace": "default", + "uid": "dlMZZl6GndU8gJLUQSmgZxXBPCNXyXhNBeQJhHXl0r4X", + "resourceVersion": "2", + "generation": 2, + "creationTimestamp": "2025-11-28T10:14:21Z", + "labels": { + "grafana.app/deprecatedInternalID": "288" + }, + "annotations": { + "grafana.app/createdBy": "user:eex2ofwuj0agwd", + "grafana.app/updatedBy": "user:eex2ofwuj0agwd", + "grafana.app/updatedTimestamp": "2025-11-28T10:15:06Z" + } + }, + "spec": { + "annotations": [ + { + "kind": "AnnotationQuery", + "spec": { + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "query": { + "kind": "grafana", + "spec": {} + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations \u0026 Alerts", + "builtIn": true, + "legacyOptions": { + "type": "dashboard" + } + } + } + ], + "cursorSync": "Off", + "editable": true, + "elements": { + "panel-1": { + "kind": "Panel", + "spec": { + "id": 1, + "title": "New panel", + "description": "", + "links": [], + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "testdata", + "spec": { + "queryType": "randomWalk" + } + }, + "datasource": { + "type": "testdata", + "uid": "gdev-testdata" + }, + "refId": "A", + "hidden": false + } + }, + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "testdata", + "spec": { + "queryType": "randomWalk" + } + }, + "datasource": { + "type": "testdata", + "uid": "gdev-testdata" + }, + "refId": "B", + "hidden": false + } + } + ], + "transformations": [], + "queryOptions": {} + } + }, + "vizConfig": { + "kind": "timeseries", + "spec": { + "pluginVersion": "12.4.0-pre", + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "fieldConfig": { + "defaults": { + "thresholds": { + "mode": "absolute", + "steps": [ + { + "value": 0, + "color": "green" + }, + { + "value": 80, + "color": "red" + } + ] + }, + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + } + }, + "overrides": [] + } + } + } + } + } + }, + "layout": { + "kind": "GridLayout", + "spec": { + "items": [ + { + "kind": "GridLayoutItem", + "spec": { + "x": 0, + "y": 0, + "width": 12, + "height": 8, + "element": { + "kind": "ElementReference", + "name": "panel-1" + } + } + } + ] + } + }, + "links": [], + "liveNow": false, + "preload": false, + "tags": [], + "timeSettings": { + "timezone": "browser", + "from": "now-6h", + "to": "now", + "autoRefresh": "", + "autoRefreshIntervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "hideTimepicker": false, + "fiscalYearStartMonth": 0 + }, + "title": "Panel ds inheritance ", + "variables": [] + }, + "status": { + "conversion": { + "failed": false, + "storedVersion": "v1beta1" + } + } +} \ No newline at end of file diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/v1beta1.panel-target-missing-refid.v2beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/v1beta1.panel-target-missing-refid.v2beta1.json new file mode 100644 index 00000000000..c407d612154 --- /dev/null +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/v1beta1.panel-target-missing-refid.v2beta1.json @@ -0,0 +1,231 @@ +{ + "kind": "Dashboard", + "apiVersion": "dashboard.grafana.app/v2beta1", + "metadata": { + "name": "ad5vfcn", + "namespace": "default", + "uid": "dlMZZl6GndU8gJLUQSmgZxXBPCNXyXhNBeQJhHXl0r4X", + "resourceVersion": "2", + "generation": 2, + "creationTimestamp": "2025-11-28T10:14:21Z", + "labels": { + "grafana.app/deprecatedInternalID": "288" + }, + "annotations": { + "grafana.app/createdBy": "user:eex2ofwuj0agwd", + "grafana.app/updatedBy": "user:eex2ofwuj0agwd", + "grafana.app/updatedTimestamp": "2025-11-28T10:15:06Z" + } + }, + "spec": { + "annotations": [ + { + "kind": "AnnotationQuery", + "spec": { + "query": { + "kind": "DataQuery", + "group": "grafana", + "version": "v0", + "datasource": { + "name": "-- Grafana --" + }, + "spec": {} + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations \u0026 Alerts", + "builtIn": true, + "legacyOptions": { + "type": "dashboard" + } + } + } + ], + "cursorSync": "Off", + "editable": true, + "elements": { + "panel-1": { + "kind": "Panel", + "spec": { + "id": 1, + "title": "New panel", + "description": "", + "links": [], + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "DataQuery", + "group": "testdata", + "version": "v0", + "datasource": { + "name": "gdev-testdata" + }, + "spec": { + "queryType": "randomWalk" + } + }, + "refId": "A", + "hidden": false + } + }, + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "DataQuery", + "group": "testdata", + "version": "v0", + "datasource": { + "name": "gdev-testdata" + }, + "spec": { + "queryType": "randomWalk" + } + }, + "refId": "B", + "hidden": false + } + } + ], + "transformations": [], + "queryOptions": {} + } + }, + "vizConfig": { + "kind": "VizConfig", + "group": "timeseries", + "version": "12.4.0-pre", + "spec": { + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "fieldConfig": { + "defaults": { + "thresholds": { + "mode": "absolute", + "steps": [ + { + "value": 0, + "color": "green" + }, + { + "value": 80, + "color": "red" + } + ] + }, + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + } + }, + "overrides": [] + } + } + } + } + } + }, + "layout": { + "kind": "GridLayout", + "spec": { + "items": [ + { + "kind": "GridLayoutItem", + "spec": { + "x": 0, + "y": 0, + "width": 12, + "height": 8, + "element": { + "kind": "ElementReference", + "name": "panel-1" + } + } + } + ] + } + }, + "links": [], + "liveNow": false, + "preload": false, + "tags": [], + "timeSettings": { + "timezone": "browser", + "from": "now-6h", + "to": "now", + "autoRefresh": "", + "autoRefreshIntervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "hideTimepicker": false, + "fiscalYearStartMonth": 0 + }, + "title": "Panel ds inheritance ", + "variables": [] + }, + "status": { + "conversion": { + "failed": false, + "storedVersion": "v1beta1" + } + } +} \ No newline at end of file diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.value-mapping-and-overrides.v0alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.value-mapping-and-overrides.v0alpha1.json new file mode 100644 index 00000000000..bd8e440efb2 --- /dev/null +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.value-mapping-and-overrides.v0alpha1.json @@ -0,0 +1,640 @@ +{ + "kind": "DashboardWithAccessInfo", + "apiVersion": "dashboard.grafana.app/v0alpha1", + "metadata": { + "name": "value-mapping-test", + "namespace": "default", + "uid": "value-mapping-test", + "resourceVersion": "1765384157199094", + "generation": 2, + "creationTimestamp": "2025-11-19T20:09:28Z", + "labels": { + "grafana.app/deprecatedInternalID": "646372978987008" + } + }, + "spec": { + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations \u0026 Alerts", + "type": "dashboard" + } + ] + }, + "description": "Test dashboard for all value mapping types and override matcher types", + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "liveNow": false, + "panels": [ + { + "description": "Panel with ValueMap mapping type - maps specific text values to colors and display text", + "fieldConfig": { + "defaults": { + "mappings": [ + { + "options": { + "critical": { + "color": "red", + "index": 0, + "text": "Critical!" + }, + "ok": { + "color": "green", + "index": 2, + "text": "OK" + }, + "warning": { + "color": "orange", + "index": 1, + "text": "Warning" + } + }, + "type": "value" + } + ] + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "status" + }, + "properties": [ + { + "id": "custom.width", + "value": 100 + }, + { + "id": "custom.align", + "value": "center" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 0 + }, + "id": 1, + "options": {}, + "pluginVersion": "", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus-uid" + }, + "expr": "up", + "refId": "A" + } + ], + "title": "ValueMap Example", + "type": "stat" + }, + { + "description": "Panel with RangeMap mapping type - maps numerical ranges to colors and display text", + "fieldConfig": { + "defaults": { + "mappings": [ + { + "options": { + "from": 0, + "result": { + "color": "green", + "index": 0, + "text": "Low" + }, + "to": 50 + }, + "type": "range" + }, + { + "options": { + "from": 50, + "result": { + "color": "orange", + "index": 1, + "text": "Medium" + }, + "to": 80 + }, + "type": "range" + }, + { + "options": { + "from": 80, + "result": { + "color": "red", + "index": 2, + "text": "High" + }, + "to": 100 + }, + "type": "range" + } + ] + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^cpu_/" + }, + "properties": [ + { + "id": "unit", + "value": "percent" + }, + { + "id": "decimals", + "value": 2 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 0 + }, + "id": 2, + "options": {}, + "pluginVersion": "", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus-uid" + }, + "expr": "cpu_usage_percent", + "refId": "A" + } + ], + "title": "RangeMap Example", + "type": "gauge" + }, + { + "description": "Panel with RegexMap mapping type - maps values matching regex patterns to colors", + "fieldConfig": { + "defaults": { + "mappings": [ + { + "options": { + "pattern": "/^error.*/", + "result": { + "color": "red", + "index": 0, + "text": "Error" + } + }, + "type": "regex" + }, + { + "options": { + "pattern": "/^warn.*/", + "result": { + "color": "orange", + "index": 1, + "text": "Warning" + } + }, + "type": "regex" + }, + { + "options": { + "pattern": "/^info.*/", + "result": { + "color": "blue", + "index": 2, + "text": "Info" + } + }, + "type": "regex" + } + ] + }, + "overrides": [ + { + "matcher": { + "id": "byType", + "options": "string" + }, + "properties": [ + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 8 + }, + "id": 3, + "options": {}, + "pluginVersion": "", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus-uid" + }, + "expr": "log_level", + "refId": "A" + } + ], + "title": "RegexMap Example", + "type": "stat" + }, + { + "description": "Panel with SpecialValueMap mapping type - maps special values like null, NaN, true, false to display text", + "fieldConfig": { + "defaults": { + "mappings": [ + { + "options": { + "match": "null", + "result": { + "color": "gray", + "index": 0, + "text": "No Data" + } + }, + "type": "special" + }, + { + "options": { + "match": "nan", + "result": { + "color": "gray", + "index": 1, + "text": "Not a Number" + } + }, + "type": "special" + }, + { + "options": { + "match": "null+nan", + "result": { + "color": "gray", + "index": 2, + "text": "N/A" + } + }, + "type": "special" + }, + { + "options": { + "match": "true", + "result": { + "color": "green", + "index": 3, + "text": "Yes" + } + }, + "type": "special" + }, + { + "options": { + "match": "false", + "result": { + "color": "red", + "index": 4, + "text": "No" + } + }, + "type": "special" + }, + { + "options": { + "match": "empty", + "result": { + "color": "gray", + "index": 5, + "text": "Empty" + } + }, + "type": "special" + } + ] + }, + "overrides": [ + { + "matcher": { + "id": "byFrameRefID", + "options": "A" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 8 + }, + "id": 4, + "options": {}, + "pluginVersion": "", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus-uid" + }, + "expr": "some_metric", + "refId": "A" + } + ], + "title": "SpecialValueMap Example", + "type": "stat" + }, + { + "description": "Panel with all mapping types combined - demonstrates mixing different mapping types and multiple override matchers", + "fieldConfig": { + "defaults": { + "mappings": [ + { + "options": { + "failure": { + "color": "red", + "index": 1, + "text": "Failure" + }, + "success": { + "color": "green", + "index": 0, + "text": "Success" + } + }, + "type": "value" + }, + { + "options": { + "from": 0, + "result": { + "color": "blue", + "index": 2, + "text": "In Range" + }, + "to": 100 + }, + "type": "range" + }, + { + "options": { + "pattern": "/^[A-Z]{3}-\\d+$/", + "result": { + "color": "purple", + "index": 3, + "text": "ID Format" + } + }, + "type": "regex" + }, + { + "options": { + "match": "null", + "result": { + "color": "gray", + "index": 4, + "text": "Missing" + } + }, + "type": "special" + } + ] + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "status" + }, + "properties": [ + { + "id": "custom.width", + "value": 120 + }, + { + "id": "custom.cellOptions", + "value": { + "type": "color-background" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^value_/" + }, + "properties": [ + { + "id": "unit", + "value": "short" + }, + { + "id": "min", + "value": 0 + }, + { + "id": "max", + "value": 100 + } + ] + }, + { + "matcher": { + "id": "byType", + "options": "number" + }, + "properties": [ + { + "id": "decimals", + "value": 2 + }, + { + "id": "thresholds", + "value": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 50 + }, + { + "color": "red", + "value": 80 + } + ] + } + } + ] + }, + { + "matcher": { + "id": "byFrameRefID", + "options": "B" + }, + "properties": [ + { + "id": "displayName", + "value": "Secondary Query" + } + ] + }, + { + "matcher": { + "id": "byValue", + "options": { + "op": "gte", + "reducer": "allIsNull", + "value": 0 + } + }, + "properties": [ + { + "id": "custom.hidden", + "value": true + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 16 + }, + "id": 5, + "options": {}, + "pluginVersion": "", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus-uid" + }, + "expr": "combined_metric", + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus-uid" + }, + "expr": "secondary_metric", + "refId": "B" + } + ], + "title": "Combined Mappings and Overrides Example", + "type": "table" + }, + { + "description": "Panel with override that has empty properties array - tests conversion of overrides without any property modifications", + "fieldConfig": { + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "field_with_empty_override" + }, + "properties": [] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 24 + }, + "id": 6, + "options": {}, + "pluginVersion": "", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus-uid" + }, + "expr": "empty_override_metric", + "refId": "A" + } + ], + "title": "Empty Properties Override Example", + "type": "stat" + } + ], + "preload": false, + "refresh": "", + "schemaVersion": 42, + "tags": [ + "value-mapping", + "overrides", + "test" + ], + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ] + }, + "timezone": "browser", + "title": "Value Mapping and Overrides Test" + }, + "status": { + "conversion": { + "failed": false, + "storedVersion": "v2beta1" + } + } +} \ No newline at end of file diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.value-mapping-and-overrides.v1beta1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.value-mapping-and-overrides.v1beta1.json new file mode 100644 index 00000000000..07d899db46c --- /dev/null +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.value-mapping-and-overrides.v1beta1.json @@ -0,0 +1,640 @@ +{ + "kind": "DashboardWithAccessInfo", + "apiVersion": "dashboard.grafana.app/v1beta1", + "metadata": { + "name": "value-mapping-test", + "namespace": "default", + "uid": "value-mapping-test", + "resourceVersion": "1765384157199094", + "generation": 2, + "creationTimestamp": "2025-11-19T20:09:28Z", + "labels": { + "grafana.app/deprecatedInternalID": "646372978987008" + } + }, + "spec": { + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations \u0026 Alerts", + "type": "dashboard" + } + ] + }, + "description": "Test dashboard for all value mapping types and override matcher types", + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "liveNow": false, + "panels": [ + { + "description": "Panel with ValueMap mapping type - maps specific text values to colors and display text", + "fieldConfig": { + "defaults": { + "mappings": [ + { + "options": { + "critical": { + "color": "red", + "index": 0, + "text": "Critical!" + }, + "ok": { + "color": "green", + "index": 2, + "text": "OK" + }, + "warning": { + "color": "orange", + "index": 1, + "text": "Warning" + } + }, + "type": "value" + } + ] + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "status" + }, + "properties": [ + { + "id": "custom.width", + "value": 100 + }, + { + "id": "custom.align", + "value": "center" + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 0 + }, + "id": 1, + "options": {}, + "pluginVersion": "", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus-uid" + }, + "expr": "up", + "refId": "A" + } + ], + "title": "ValueMap Example", + "type": "stat" + }, + { + "description": "Panel with RangeMap mapping type - maps numerical ranges to colors and display text", + "fieldConfig": { + "defaults": { + "mappings": [ + { + "options": { + "from": 0, + "result": { + "color": "green", + "index": 0, + "text": "Low" + }, + "to": 50 + }, + "type": "range" + }, + { + "options": { + "from": 50, + "result": { + "color": "orange", + "index": 1, + "text": "Medium" + }, + "to": 80 + }, + "type": "range" + }, + { + "options": { + "from": 80, + "result": { + "color": "red", + "index": 2, + "text": "High" + }, + "to": 100 + }, + "type": "range" + } + ] + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^cpu_/" + }, + "properties": [ + { + "id": "unit", + "value": "percent" + }, + { + "id": "decimals", + "value": 2 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 0 + }, + "id": 2, + "options": {}, + "pluginVersion": "", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus-uid" + }, + "expr": "cpu_usage_percent", + "refId": "A" + } + ], + "title": "RangeMap Example", + "type": "gauge" + }, + { + "description": "Panel with RegexMap mapping type - maps values matching regex patterns to colors", + "fieldConfig": { + "defaults": { + "mappings": [ + { + "options": { + "pattern": "/^error.*/", + "result": { + "color": "red", + "index": 0, + "text": "Error" + } + }, + "type": "regex" + }, + { + "options": { + "pattern": "/^warn.*/", + "result": { + "color": "orange", + "index": 1, + "text": "Warning" + } + }, + "type": "regex" + }, + { + "options": { + "pattern": "/^info.*/", + "result": { + "color": "blue", + "index": 2, + "text": "Info" + } + }, + "type": "regex" + } + ] + }, + "overrides": [ + { + "matcher": { + "id": "byType", + "options": "string" + }, + "properties": [ + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 8 + }, + "id": 3, + "options": {}, + "pluginVersion": "", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus-uid" + }, + "expr": "log_level", + "refId": "A" + } + ], + "title": "RegexMap Example", + "type": "stat" + }, + { + "description": "Panel with SpecialValueMap mapping type - maps special values like null, NaN, true, false to display text", + "fieldConfig": { + "defaults": { + "mappings": [ + { + "options": { + "match": "null", + "result": { + "color": "gray", + "index": 0, + "text": "No Data" + } + }, + "type": "special" + }, + { + "options": { + "match": "nan", + "result": { + "color": "gray", + "index": 1, + "text": "Not a Number" + } + }, + "type": "special" + }, + { + "options": { + "match": "null+nan", + "result": { + "color": "gray", + "index": 2, + "text": "N/A" + } + }, + "type": "special" + }, + { + "options": { + "match": "true", + "result": { + "color": "green", + "index": 3, + "text": "Yes" + } + }, + "type": "special" + }, + { + "options": { + "match": "false", + "result": { + "color": "red", + "index": 4, + "text": "No" + } + }, + "type": "special" + }, + { + "options": { + "match": "empty", + "result": { + "color": "gray", + "index": 5, + "text": "Empty" + } + }, + "type": "special" + } + ] + }, + "overrides": [ + { + "matcher": { + "id": "byFrameRefID", + "options": "A" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 8 + }, + "id": 4, + "options": {}, + "pluginVersion": "", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus-uid" + }, + "expr": "some_metric", + "refId": "A" + } + ], + "title": "SpecialValueMap Example", + "type": "stat" + }, + { + "description": "Panel with all mapping types combined - demonstrates mixing different mapping types and multiple override matchers", + "fieldConfig": { + "defaults": { + "mappings": [ + { + "options": { + "failure": { + "color": "red", + "index": 1, + "text": "Failure" + }, + "success": { + "color": "green", + "index": 0, + "text": "Success" + } + }, + "type": "value" + }, + { + "options": { + "from": 0, + "result": { + "color": "blue", + "index": 2, + "text": "In Range" + }, + "to": 100 + }, + "type": "range" + }, + { + "options": { + "pattern": "/^[A-Z]{3}-\\d+$/", + "result": { + "color": "purple", + "index": 3, + "text": "ID Format" + } + }, + "type": "regex" + }, + { + "options": { + "match": "null", + "result": { + "color": "gray", + "index": 4, + "text": "Missing" + } + }, + "type": "special" + } + ] + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "status" + }, + "properties": [ + { + "id": "custom.width", + "value": 120 + }, + { + "id": "custom.cellOptions", + "value": { + "type": "color-background" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^value_/" + }, + "properties": [ + { + "id": "unit", + "value": "short" + }, + { + "id": "min", + "value": 0 + }, + { + "id": "max", + "value": 100 + } + ] + }, + { + "matcher": { + "id": "byType", + "options": "number" + }, + "properties": [ + { + "id": "decimals", + "value": 2 + }, + { + "id": "thresholds", + "value": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 50 + }, + { + "color": "red", + "value": 80 + } + ] + } + } + ] + }, + { + "matcher": { + "id": "byFrameRefID", + "options": "B" + }, + "properties": [ + { + "id": "displayName", + "value": "Secondary Query" + } + ] + }, + { + "matcher": { + "id": "byValue", + "options": { + "op": "gte", + "reducer": "allIsNull", + "value": 0 + } + }, + "properties": [ + { + "id": "custom.hidden", + "value": true + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 16 + }, + "id": 5, + "options": {}, + "pluginVersion": "", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus-uid" + }, + "expr": "combined_metric", + "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus-uid" + }, + "expr": "secondary_metric", + "refId": "B" + } + ], + "title": "Combined Mappings and Overrides Example", + "type": "table" + }, + { + "description": "Panel with override that has empty properties array - tests conversion of overrides without any property modifications", + "fieldConfig": { + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "field_with_empty_override" + }, + "properties": [] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 24 + }, + "id": 6, + "options": {}, + "pluginVersion": "", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus-uid" + }, + "expr": "empty_override_metric", + "refId": "A" + } + ], + "title": "Empty Properties Override Example", + "type": "stat" + } + ], + "preload": false, + "refresh": "", + "schemaVersion": 42, + "tags": [ + "value-mapping", + "overrides", + "test" + ], + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ] + }, + "timezone": "browser", + "title": "Value Mapping and Overrides Test" + }, + "status": { + "conversion": { + "failed": false, + "storedVersion": "v2beta1" + } + } +} \ No newline at end of file diff --git a/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.value-mapping-and-overrides.v2alpha1.json b/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.value-mapping-and-overrides.v2alpha1.json new file mode 100644 index 00000000000..425b914eafb --- /dev/null +++ b/apps/dashboard/pkg/migration/conversion/testdata/output/v2beta1.value-mapping-and-overrides.v2alpha1.json @@ -0,0 +1,850 @@ +{ + "kind": "DashboardWithAccessInfo", + "apiVersion": "dashboard.grafana.app/v2alpha1", + "metadata": { + "name": "value-mapping-test", + "namespace": "default", + "uid": "value-mapping-test", + "resourceVersion": "1765384157199094", + "generation": 2, + "creationTimestamp": "2025-11-19T20:09:28Z", + "labels": { + "grafana.app/deprecatedInternalID": "646372978987008" + } + }, + "spec": { + "annotations": [ + { + "kind": "AnnotationQuery", + "spec": { + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "query": { + "kind": "grafana", + "spec": {} + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations \u0026 Alerts", + "builtIn": true, + "legacyOptions": { + "type": "dashboard" + } + } + } + ], + "cursorSync": "Off", + "description": "Test dashboard for all value mapping types and override matcher types", + "editable": true, + "elements": { + "panel-1": { + "kind": "Panel", + "spec": { + "id": 1, + "title": "ValueMap Example", + "description": "Panel with ValueMap mapping type - maps specific text values to colors and display text", + "links": [], + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "prometheus", + "spec": { + "expr": "up" + } + }, + "datasource": { + "type": "prometheus", + "uid": "prometheus-uid" + }, + "refId": "A", + "hidden": false + } + } + ], + "transformations": [], + "queryOptions": {} + } + }, + "vizConfig": { + "kind": "stat", + "spec": { + "pluginVersion": "", + "options": {}, + "fieldConfig": { + "defaults": { + "mappings": [ + { + "type": "value", + "options": { + "critical": { + "text": "Critical!", + "color": "red", + "index": 0 + }, + "ok": { + "text": "OK", + "color": "green", + "index": 2 + }, + "warning": { + "text": "Warning", + "color": "orange", + "index": 1 + } + } + } + ] + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "status" + }, + "properties": [ + { + "id": "custom.width", + "value": 100 + }, + { + "id": "custom.align", + "value": "center" + } + ] + } + ] + } + } + } + } + }, + "panel-2": { + "kind": "Panel", + "spec": { + "id": 2, + "title": "RangeMap Example", + "description": "Panel with RangeMap mapping type - maps numerical ranges to colors and display text", + "links": [], + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "prometheus", + "spec": { + "expr": "cpu_usage_percent" + } + }, + "datasource": { + "type": "prometheus", + "uid": "prometheus-uid" + }, + "refId": "A", + "hidden": false + } + } + ], + "transformations": [], + "queryOptions": {} + } + }, + "vizConfig": { + "kind": "gauge", + "spec": { + "pluginVersion": "", + "options": {}, + "fieldConfig": { + "defaults": { + "mappings": [ + { + "type": "range", + "options": { + "from": 0, + "to": 50, + "result": { + "text": "Low", + "color": "green", + "index": 0 + } + } + }, + { + "type": "range", + "options": { + "from": 50, + "to": 80, + "result": { + "text": "Medium", + "color": "orange", + "index": 1 + } + } + }, + { + "type": "range", + "options": { + "from": 80, + "to": 100, + "result": { + "text": "High", + "color": "red", + "index": 2 + } + } + } + ] + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "/^cpu_/" + }, + "properties": [ + { + "id": "unit", + "value": "percent" + }, + { + "id": "decimals", + "value": 2 + } + ] + } + ] + } + } + } + } + }, + "panel-3": { + "kind": "Panel", + "spec": { + "id": 3, + "title": "RegexMap Example", + "description": "Panel with RegexMap mapping type - maps values matching regex patterns to colors", + "links": [], + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "prometheus", + "spec": { + "expr": "log_level" + } + }, + "datasource": { + "type": "prometheus", + "uid": "prometheus-uid" + }, + "refId": "A", + "hidden": false + } + } + ], + "transformations": [], + "queryOptions": {} + } + }, + "vizConfig": { + "kind": "stat", + "spec": { + "pluginVersion": "", + "options": {}, + "fieldConfig": { + "defaults": { + "mappings": [ + { + "type": "regex", + "options": { + "pattern": "/^error.*/", + "result": { + "text": "Error", + "color": "red", + "index": 0 + } + } + }, + { + "type": "regex", + "options": { + "pattern": "/^warn.*/", + "result": { + "text": "Warning", + "color": "orange", + "index": 1 + } + } + }, + { + "type": "regex", + "options": { + "pattern": "/^info.*/", + "result": { + "text": "Info", + "color": "blue", + "index": 2 + } + } + } + ] + }, + "overrides": [ + { + "matcher": { + "id": "byType", + "options": "string" + }, + "properties": [ + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + } + ] + } + ] + } + } + } + } + }, + "panel-4": { + "kind": "Panel", + "spec": { + "id": 4, + "title": "SpecialValueMap Example", + "description": "Panel with SpecialValueMap mapping type - maps special values like null, NaN, true, false to display text", + "links": [], + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "prometheus", + "spec": { + "expr": "some_metric" + } + }, + "datasource": { + "type": "prometheus", + "uid": "prometheus-uid" + }, + "refId": "A", + "hidden": false + } + } + ], + "transformations": [], + "queryOptions": {} + } + }, + "vizConfig": { + "kind": "stat", + "spec": { + "pluginVersion": "", + "options": {}, + "fieldConfig": { + "defaults": { + "mappings": [ + { + "type": "special", + "options": { + "match": "null", + "result": { + "text": "No Data", + "color": "gray", + "index": 0 + } + } + }, + { + "type": "special", + "options": { + "match": "nan", + "result": { + "text": "Not a Number", + "color": "gray", + "index": 1 + } + } + }, + { + "type": "special", + "options": { + "match": "null+nan", + "result": { + "text": "N/A", + "color": "gray", + "index": 2 + } + } + }, + { + "type": "special", + "options": { + "match": "true", + "result": { + "text": "Yes", + "color": "green", + "index": 3 + } + } + }, + { + "type": "special", + "options": { + "match": "false", + "result": { + "text": "No", + "color": "red", + "index": 4 + } + } + }, + { + "type": "special", + "options": { + "match": "empty", + "result": { + "text": "Empty", + "color": "gray", + "index": 5 + } + } + } + ] + }, + "overrides": [ + { + "matcher": { + "id": "byFrameRefID", + "options": "A" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + } + ] + } + } + } + } + }, + "panel-5": { + "kind": "Panel", + "spec": { + "id": 5, + "title": "Combined Mappings and Overrides Example", + "description": "Panel with all mapping types combined - demonstrates mixing different mapping types and multiple override matchers", + "links": [], + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "prometheus", + "spec": { + "expr": "combined_metric" + } + }, + "datasource": { + "type": "prometheus", + "uid": "prometheus-uid" + }, + "refId": "A", + "hidden": false + } + }, + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "prometheus", + "spec": { + "expr": "secondary_metric" + } + }, + "datasource": { + "type": "prometheus", + "uid": "prometheus-uid" + }, + "refId": "B", + "hidden": false + } + } + ], + "transformations": [], + "queryOptions": {} + } + }, + "vizConfig": { + "kind": "table", + "spec": { + "pluginVersion": "", + "options": {}, + "fieldConfig": { + "defaults": { + "mappings": [ + { + "type": "value", + "options": { + "failure": { + "text": "Failure", + "color": "red", + "index": 1 + }, + "success": { + "text": "Success", + "color": "green", + "index": 0 + } + } + }, + { + "type": "range", + "options": { + "from": 0, + "to": 100, + "result": { + "text": "In Range", + "color": "blue", + "index": 2 + } + } + }, + { + "type": "regex", + "options": { + "pattern": "/^[A-Z]{3}-\\d+$/", + "result": { + "text": "ID Format", + "color": "purple", + "index": 3 + } + } + }, + { + "type": "special", + "options": { + "match": "null", + "result": { + "text": "Missing", + "color": "gray", + "index": 4 + } + } + } + ] + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "status" + }, + "properties": [ + { + "id": "custom.width", + "value": 120 + }, + { + "id": "custom.cellOptions", + "value": { + "type": "color-background" + } + } + ] + }, + { + "matcher": { + "id": "byRegexp", + "options": "/^value_/" + }, + "properties": [ + { + "id": "unit", + "value": "short" + }, + { + "id": "min", + "value": 0 + }, + { + "id": "max", + "value": 100 + } + ] + }, + { + "matcher": { + "id": "byType", + "options": "number" + }, + "properties": [ + { + "id": "decimals", + "value": 2 + }, + { + "id": "thresholds", + "value": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 50 + }, + { + "color": "red", + "value": 80 + } + ] + } + } + ] + }, + { + "matcher": { + "id": "byFrameRefID", + "options": "B" + }, + "properties": [ + { + "id": "displayName", + "value": "Secondary Query" + } + ] + }, + { + "matcher": { + "id": "byValue", + "options": { + "op": "gte", + "reducer": "allIsNull", + "value": 0 + } + }, + "properties": [ + { + "id": "custom.hidden", + "value": true + } + ] + } + ] + } + } + } + } + }, + "panel-6": { + "kind": "Panel", + "spec": { + "id": 6, + "title": "Empty Properties Override Example", + "description": "Panel with override that has empty properties array - tests conversion of overrides without any property modifications", + "links": [], + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "query": { + "kind": "prometheus", + "spec": { + "expr": "empty_override_metric" + } + }, + "datasource": { + "type": "prometheus", + "uid": "prometheus-uid" + }, + "refId": "A", + "hidden": false + } + } + ], + "transformations": [], + "queryOptions": {} + } + }, + "vizConfig": { + "kind": "stat", + "spec": { + "pluginVersion": "", + "options": {}, + "fieldConfig": { + "defaults": {}, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "field_with_empty_override" + }, + "properties": [] + } + ] + } + } + } + } + } + }, + "layout": { + "kind": "GridLayout", + "spec": { + "items": [ + { + "kind": "GridLayoutItem", + "spec": { + "x": 0, + "y": 0, + "width": 12, + "height": 8, + "element": { + "kind": "ElementReference", + "name": "panel-1" + } + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "x": 12, + "y": 0, + "width": 12, + "height": 8, + "element": { + "kind": "ElementReference", + "name": "panel-2" + } + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "x": 0, + "y": 8, + "width": 12, + "height": 8, + "element": { + "kind": "ElementReference", + "name": "panel-3" + } + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "x": 12, + "y": 8, + "width": 12, + "height": 8, + "element": { + "kind": "ElementReference", + "name": "panel-4" + } + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "x": 0, + "y": 16, + "width": 24, + "height": 8, + "element": { + "kind": "ElementReference", + "name": "panel-5" + } + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "x": 0, + "y": 24, + "width": 12, + "height": 8, + "element": { + "kind": "ElementReference", + "name": "panel-6" + } + } + } + ] + } + }, + "links": [], + "liveNow": false, + "preload": false, + "tags": [ + "value-mapping", + "overrides", + "test" + ], + "timeSettings": { + "timezone": "browser", + "from": "now-6h", + "to": "now", + "autoRefresh": "", + "autoRefreshIntervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "hideTimepicker": false, + "fiscalYearStartMonth": 0 + }, + "title": "Value Mapping and Overrides Test", + "variables": [] + }, + "status": { + "conversion": { + "failed": false, + "storedVersion": "v2beta1" + } + } +} \ No newline at end of file diff --git a/apps/dashboard/pkg/migration/conversion/v0alpha1_to_v1beta1.go b/apps/dashboard/pkg/migration/conversion/v0alpha1_to_v1beta1.go index 2154a26e3a2..d0679c76e63 100644 --- a/apps/dashboard/pkg/migration/conversion/v0alpha1_to_v1beta1.go +++ b/apps/dashboard/pkg/migration/conversion/v0alpha1_to_v1beta1.go @@ -2,6 +2,7 @@ package conversion import ( "context" + "strings" "k8s.io/apimachinery/pkg/conversion" "k8s.io/apiserver/pkg/endpoints/request" @@ -79,5 +80,57 @@ func ConvertDashboard_V0_to_V1beta1(in *dashv0.Dashboard, out *dashv1.Dashboard, return schemaversion.NewMigrationError(err.Error(), schemaversion.GetSchemaVersion(in.Spec.Object), schemaversion.LATEST_VERSION, "Convert_V0_to_V1") } + // Normalize template variable datasources from string to object format + // This handles legacy dashboards where query variables have datasource: "$datasource" (string) + // instead of datasource: { uid: "$datasource" } (object) + // our migration pipeline in v36 doesn't address because this was not addressed historically + // in DashboardMigrator - see public/app/features/dashboard/state/DashboardMigrator.ts#L607 + // Which means that we have schemaVersion: 42 dashboards where datasource variable references are still strings + normalizeTemplateVariableDatasources(out.Spec.Object) + return nil } + +// normalizeTemplateVariableDatasources converts template variable string datasources to object format. +// Legacy dashboards may have query variables with datasource: "$datasource" (string). +// This normalizes them to datasource: { uid: "$datasource" } for consistent V1→V2 conversion. +func normalizeTemplateVariableDatasources(dashboard map[string]interface{}) { + templating, ok := dashboard["templating"].(map[string]interface{}) + if !ok { + return + } + + list, ok := templating["list"].([]interface{}) + if !ok { + return + } + + for _, variable := range list { + varMap, ok := variable.(map[string]interface{}) + if !ok { + continue + } + + varType, _ := varMap["type"].(string) + if varType != "query" { + continue + } + + ds := varMap["datasource"] + if dsStr, ok := ds.(string); ok && isTemplateVariableRef(dsStr) { + // Convert string template variable reference to object format + varMap["datasource"] = map[string]interface{}{ + "uid": dsStr, + } + } + } +} + +// isTemplateVariableRef checks if a string is a Grafana template variable reference. +// Template variables can be in the form: $varname or ${varname} +func isTemplateVariableRef(s string) bool { + if s == "" { + return false + } + return strings.HasPrefix(s, "$") || strings.HasPrefix(s, "${") +} diff --git a/apps/dashboard/pkg/migration/conversion/v1beta1_to_v2alpha1.go b/apps/dashboard/pkg/migration/conversion/v1beta1_to_v2alpha1.go index 1135927ed7b..92c5d937fe7 100644 --- a/apps/dashboard/pkg/migration/conversion/v1beta1_to_v2alpha1.go +++ b/apps/dashboard/pkg/migration/conversion/v1beta1_to_v2alpha1.go @@ -1185,6 +1185,10 @@ func buildQueryVariable(ctx context.Context, varMap map[string]interface{}, comm // If no UID and no type, use default datasourceType = getDefaultDatasourceType(ctx, dsIndexProvider) } + } else if dsStr, ok := datasource.(string); ok && isTemplateVariable(dsStr) { + // Handle datasource variable reference (e.g., "$datasource") + // Only process template variables - other string values are not supported in V2 format + datasourceUID = dsStr } else { datasourceType = getDefaultDatasourceType(ctx, dsIndexProvider) } @@ -1532,6 +1536,10 @@ func buildAdhocVariable(ctx context.Context, varMap map[string]interface{}, comm // If no UID and no type, use default datasourceType = getDefaultDatasourceType(ctx, dsIndexProvider) } + } else if dsStr, ok := datasource.(string); ok && isTemplateVariable(dsStr) { + // Handle datasource variable reference (e.g., "$datasource") + // Only process template variables - other string values are not supported in V2 format + datasourceUID = dsStr } else { datasourceType = getDefaultDatasourceType(ctx, dsIndexProvider) } @@ -1709,6 +1717,10 @@ func buildGroupByVariable(ctx context.Context, varMap map[string]interface{}, co // Resolve Grafana datasource UID when type is "datasource" and UID is empty datasourceUID = resolveGrafanaDatasourceUID(datasourceType, datasourceUID) + } else if dsStr, ok := datasource.(string); ok && isTemplateVariable(dsStr) { + // Handle datasource variable reference (e.g., "$datasource") + // Only process template variables - other string values are not supported in V2 format + datasourceUID = dsStr } else { datasourceType = getDefaultDatasourceType(ctx, dsIndexProvider) } @@ -2006,6 +2018,28 @@ func transformPanelQueries(ctx context.Context, panelMap map[string]interface{}, } } + // Ensure each target has a non-empty refId. We only fill missing refIds; + existingRefIds := make(map[string]bool) + for _, target := range targets { + if targetMap, ok := target.(map[string]interface{}); ok { + if refId := schemaversion.GetStringValue(targetMap, "refId"); refId != "" { + existingRefIds[refId] = true + } + } + } + for _, target := range targets { + targetMap, ok := target.(map[string]interface{}) + if !ok { + continue + } + refId := schemaversion.GetStringValue(targetMap, "refId") + if refId == "" { + refId = nextAvailableRefId(existingRefIds) + targetMap["refId"] = refId + existingRefIds[refId] = true + } + } + queries := make([]dashv2alpha1.DashboardPanelQueryKind, 0, len(targets)) for _, target := range targets { @@ -2018,6 +2052,27 @@ func transformPanelQueries(ctx context.Context, panelMap map[string]interface{}, return queries } +// nextAvailableRefId returns the next unused refId using the same sequence as the +// frontend helper (A, B, ..., Z, AA, AB, ...). +func nextAvailableRefId(existing map[string]bool) string { + const letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + + var refIdFromIndex func(num int) string + refIdFromIndex = func(num int) string { + if num < len(letters) { + return string(letters[num]) + } + return refIdFromIndex(num/len(letters)-1) + string(letters[num%len(letters)]) + } + + for i := 0; ; i++ { + refId := refIdFromIndex(i) + if !existing[refId] { + return refId + } + } +} + func transformSingleQuery(ctx context.Context, targetMap map[string]interface{}, panelDatasource *dashv2alpha1.DashboardDataSourceRef, dsIndexProvider schemaversion.DataSourceIndexProvider) dashv2alpha1.DashboardPanelQueryKind { refId := schemaversion.GetStringValue(targetMap, "refId", "A") if refId == "" { @@ -2196,6 +2251,32 @@ func transformDataLinks(panelMap map[string]interface{}) []dashv2alpha1.Dashboar return result } +// knownPanelProperties lists all properties defined in the Panel schema (dashboard_kind.cue) +// that should NOT be passed to Angular migration handlers. Only "unknown" Angular-specific +// properties should be passed to migration handlers. +var knownPanelProperties = map[string]bool{ + "type": true, "id": true, "pluginVersion": true, "targets": true, + "title": true, "description": true, "transparent": true, "datasource": true, + "gridPos": true, "links": true, "repeat": true, "repeatDirection": true, + "maxPerRow": true, "maxDataPoints": true, "transformations": true, + "interval": true, "timeFrom": true, "timeShift": true, "hideTimeOverride": true, + "timeCompare": true, "libraryPanel": true, "cacheTimeout": true, + "queryCachingTTL": true, "options": true, "fieldConfig": true, "autoMigrateFrom": true, +} + +// extractAngularOptions extracts only the Angular-specific options from a panel map, +// filtering out all known Panel schema properties. This is used to pass just the +// Angular options to migration handlers (e.g., sparkline, valueName, format for singlestat). +func extractAngularOptions(panelMap map[string]interface{}) map[string]interface{} { + result := make(map[string]interface{}) + for key, value := range panelMap { + if !knownPanelProperties[key] { + result[key] = value + } + } + return result +} + func buildVizConfig(panelMap map[string]interface{}) dashv2alpha1.DashboardVizConfigKind { panelType := schemaversion.GetStringValue(panelMap, "type", "timeseries") pluginVersion := schemaversion.GetStringValue(panelMap, "pluginVersion") @@ -2208,7 +2289,10 @@ func buildVizConfig(panelMap map[string]interface{}) dashv2alpha1.DashboardVizCo options := make(map[string]interface{}) if opts, ok := panelMap["options"].(map[string]interface{}); ok { - options = opts + // Deep copy options to avoid modifying the original + for k, v := range opts { + options[k] = v + } } // Add frontend-style default options to match frontend behavior @@ -2219,11 +2303,37 @@ func buildVizConfig(panelMap map[string]interface{}) dashv2alpha1.DashboardVizCo options["legend"] = legend } + // Handle Angular panel migrations + // This replicates the v0→v1 migration logic for panels that weren't migrated yet. + // We check two cases: + // 1. Panel already has autoMigrateFrom set (from v0→v1 migration) - panel type already converted + // 2. Panel type is a known Angular panel - need to convert type AND set autoMigrateFrom + // 3. Panel has original options - need to set autoMigrateFrom and originalOptions + autoMigrateFrom, hasAutoMigrateFrom := panelMap["autoMigrateFrom"].(string) + originalOptions := extractAngularOptions(panelMap) + + if !hasAutoMigrateFrom || autoMigrateFrom == "" { + // Check if panel type is an Angular type that needs migration + if newType := getAngularPanelMigration(panelType, panelMap); newType != "" { + autoMigrateFrom = panelType // Original Angular type + panelType = newType // New modern type + } else if len(originalOptions) > 0 { + autoMigrateFrom = panelType + } + } + + if autoMigrateFrom != "" { + options["__angularMigration"] = map[string]interface{}{ + "autoMigrateFrom": autoMigrateFrom, + "originalOptions": originalOptions, + } + } + // Build field config by mapping each field individually fieldConfigSource := extractFieldConfigSource(fieldConfig) return dashv2alpha1.DashboardVizConfigKind{ - Kind: panelType, // Use panelType as Kind (plugin ID) to match schema comment + Kind: panelType, // Use panelType as Kind (plugin ID) - may be converted from Angular type Spec: dashv2alpha1.DashboardVizConfigSpec{ PluginVersion: pluginVersion, FieldConfig: fieldConfigSource, @@ -2664,3 +2774,10 @@ func extractFieldConfigOverrides(fieldConfig map[string]interface{}) []dashv2alp return result } + +// getAngularPanelMigration is a convenience wrapper around schemaversion.GetAngularPanelMigration. +// It checks if a panel type is an Angular panel and returns the new type to migrate to. +// Returns the new panel type if migration is needed, empty string otherwise. +func getAngularPanelMigration(panelType string, panelMap map[string]interface{}) string { + return schemaversion.GetAngularPanelMigration(panelType, panelMap) +} diff --git a/apps/dashboard/pkg/migration/conversion/v1beta1_to_v2alpha1_test.go b/apps/dashboard/pkg/migration/conversion/v1beta1_to_v2alpha1_test.go index a80bf9c8072..6c0e8f4f919 100644 --- a/apps/dashboard/pkg/migration/conversion/v1beta1_to_v2alpha1_test.go +++ b/apps/dashboard/pkg/migration/conversion/v1beta1_to_v2alpha1_test.go @@ -210,6 +210,48 @@ func TestV1beta1ToV2alpha1(t *testing.T) { assert.Equal(t, "", query.Spec.Query.Kind, "Query kind should be empty when datasource is empty object {}") }, }, + { + name: "missing refIds are assigned while existing refIds are preserved", + createV1beta1: func() *dashv1.Dashboard { + return &dashv1.Dashboard{ + Spec: dashv1.DashboardSpec{ + Object: map[string]interface{}{ + "title": "Test Dashboard", + "panels": []interface{}{ + map[string]interface{}{ + "id": 1, + "type": "bargauge", + "targets": []interface{}{ + map[string]interface{}{ + "refId": "", + "scenarioId": "random_walk", + }, + map[string]interface{}{ + "refId": "A", + "scenarioId": "random_walk", + }, + map[string]interface{}{ + "refId": "", + "scenarioId": "random_walk", + }, + }, + }, + }, + }, + }, + } + }, + validateV2alpha1: func(t *testing.T, v2alpha1 *dashv2alpha1.Dashboard) { + require.NotNil(t, v2alpha1.Spec.Elements["panel-1"]) + panel := v2alpha1.Spec.Elements["panel-1"].PanelKind + require.NotNil(t, panel) + + require.Len(t, panel.Spec.Data.Spec.Queries, 3) + assert.Equal(t, "B", panel.Spec.Data.Spec.Queries[0].Spec.RefId) + assert.Equal(t, "A", panel.Spec.Data.Spec.Queries[1].Spec.RefId) + assert.Equal(t, "C", panel.Spec.Data.Spec.Queries[2].Spec.RefId) + }, + }, } for _, tt := range testCases { diff --git a/apps/dashboard/pkg/migration/conversion/v2alpha1_to_v1beta1.go b/apps/dashboard/pkg/migration/conversion/v2alpha1_to_v1beta1.go index 438aad5ead7..e2a3e17843c 100644 --- a/apps/dashboard/pkg/migration/conversion/v2alpha1_to_v1beta1.go +++ b/apps/dashboard/pkg/migration/conversion/v2alpha1_to_v1beta1.go @@ -1973,16 +1973,16 @@ func convertFieldConfigOverridesToV1(overrides []dashv2alpha1.DashboardV2alpha1F "options": override.Matcher.Options, } + properties := make([]map[string]interface{}, 0, len(override.Properties)) if len(override.Properties) > 0 { - properties := make([]map[string]interface{}, 0, len(override.Properties)) for _, prop := range override.Properties { properties = append(properties, map[string]interface{}{ "id": prop.Id, "value": prop.Value, }) } - overrideMap["properties"] = properties } + overrideMap["properties"] = properties result = append(result, overrideMap) } @@ -2074,11 +2074,9 @@ func convertRegexMapToV1(regexMap *dashv2alpha1.DashboardRegexMap) map[string]in return nil } - options := []map[string]interface{}{ - { - "pattern": regexMap.Options.Pattern, - "result": convertValueMappingResultToV1(regexMap.Options.Result), - }, + options := map[string]interface{}{ + "pattern": regexMap.Options.Pattern, + "result": convertValueMappingResultToV1(regexMap.Options.Result), } return map[string]interface{}{ diff --git a/apps/dashboard/pkg/migration/frontend_defaults.go b/apps/dashboard/pkg/migration/frontend_defaults.go index 1df28c4de27..e8c779406a6 100644 --- a/apps/dashboard/pkg/migration/frontend_defaults.go +++ b/apps/dashboard/pkg/migration/frontend_defaults.go @@ -940,31 +940,12 @@ func applyPanelAutoMigration(panel map[string]interface{}) { return } - var newType string - // Graph needs special logic as it can be migrated to multiple panels // Including graphite which was previously migrated to graph in the schema version 2 migration in DashboardMigrator.ts // but this was a bug because in there graphite was set to graph, but since those migrations run // after PanelModel.restoreModel where autoMigrateFrom is set, this caused the graph migration to be skipped. // And this resulted in a dashboard with invalid panels. - if panelType == "graph" || panelType == "graphite" { - // Check xaxis mode for special cases - newType = getGraphAutoMigration(panel) - } else { - // Check autoMigrateAngular mapping - autoMigrateAngular := map[string]string{ - "table-old": "table", - "singlestat": "stat", - "grafana-singlestat-panel": "stat", - "grafana-piechart-panel": "piechart", - "grafana-worldmap-panel": "geomap", - "natel-discrete-panel": "state-timeline", - } - - if mappedType, exists := autoMigrateAngular[panelType]; exists { - newType = mappedType - } - } + newType := schemaversion.GetAngularPanelMigration(panelType, panel) // Apply auto-migration if a new type was determined if newType != "" { @@ -973,36 +954,6 @@ func applyPanelAutoMigration(panel map[string]interface{}) { } } -func getGraphAutoMigration(panel map[string]interface{}) string { - newType := "" - if xaxis, ok := panel["xaxis"].(map[string]interface{}); ok { - if mode, ok := xaxis["mode"].(string); ok { - switch mode { - case "series": - // Check legend values for bargauge - if legend, ok := panel["legend"].(map[string]interface{}); ok { - if values, ok := legend["values"].(bool); ok && values { - newType = "bargauge" - } else { - newType = "barchart" - } - } else { - newType = "barchart" - } - case "histogram": - newType = "histogram" - } - } - } - - // Default graph migration to timeseries - if newType == "" { - newType = "timeseries" - } - - return newType -} - // removeNullValuesRecursively removes null values from nested objects and arrays // This matches the frontend's JSON.stringify/parse behavior func removeNullValuesRecursively(data interface{}) { diff --git a/apps/dashboard/pkg/migration/schemaversion/migration_utils.go b/apps/dashboard/pkg/migration/schemaversion/migration_utils.go index 64dfc61589e..d964fcaf513 100644 --- a/apps/dashboard/pkg/migration/schemaversion/migration_utils.go +++ b/apps/dashboard/pkg/migration/schemaversion/migration_utils.go @@ -102,3 +102,71 @@ func IsArray(value interface{}) bool { _, ok := value.([]interface{}) return ok } + +// AngularPanelMigrations maps deprecated Angular panel types to their modern equivalents. +// Used by both v0→v1 and v1→v2 conversions to ensure consistent migration behavior. +var AngularPanelMigrations = map[string]string{ + "table-old": "table", + "singlestat": "stat", + "grafana-singlestat-panel": "stat", + "grafana-piechart-panel": "piechart", + "grafana-worldmap-panel": "geomap", + "natel-discrete-panel": "state-timeline", +} + +// GetAngularPanelMigration checks if a panel type is an Angular panel and returns the new type to migrate to. +// Returns the new panel type if migration is needed, empty string otherwise. +// This handles both simple mappings and special cases like graph panel. +func GetAngularPanelMigration(panelType string, panel map[string]interface{}) string { + // Handle graph panel specially - it can migrate to different panel types + // based on xaxis.mode + if panelType == "graph" || panelType == "graphite" { + return GetGraphMigrationTarget(panel) + } + + // Check simple Angular panel mappings + if newType, isAngular := AngularPanelMigrations[panelType]; isAngular { + return newType + } + + return "" +} + +// GetGraphMigrationTarget determines the target panel type for graph panel migration. +// Graph panels can migrate to timeseries, barchart, bargauge, or histogram depending on xaxis.mode. +func GetGraphMigrationTarget(panel map[string]interface{}) string { + // Default to timeseries + newType := "timeseries" + + // Check xaxis mode for special cases + if xaxis, ok := panel["xaxis"].(map[string]interface{}); ok { + if mode, ok := xaxis["mode"].(string); ok { + switch mode { + case "series": + // Check legend values for bargauge vs barchart + if legend, ok := panel["legend"].(map[string]interface{}); ok { + if values, ok := legend["values"].(bool); ok && values { + newType = "bargauge" + } else { + newType = "barchart" + } + } else { + newType = "barchart" + } + case "histogram": + newType = "histogram" + } + } + } + + return newType +} + +// IsAngularPanelType checks if a panel type is a known Angular panel type. +func IsAngularPanelType(panelType string) bool { + if panelType == "graph" || panelType == "graphite" { + return true + } + _, isAngular := AngularPanelMigrations[panelType] + return isAngular +} diff --git a/apps/dashboard/pkg/migration/testdata/dev-dashboards-output/migrations/migrations.v42.json b/apps/dashboard/pkg/migration/testdata/dev-dashboards-output/migrations/migrations.v42.json index 89ce80876d2..6ff361f144e 100644 --- a/apps/dashboard/pkg/migration/testdata/dev-dashboards-output/migrations/migrations.v42.json +++ b/apps/dashboard/pkg/migration/testdata/dev-dashboards-output/migrations/migrations.v42.json @@ -290,6 +290,7 @@ } }, { + "content": "# Graph panel \u003e\u003e Timeseries panel\n\nKnown issues:\n* hiding null/empty series\n* time regions", "datasource": { "type": "grafana-testdata-datasource" }, @@ -300,15 +301,7 @@ "y": 0 }, "id": 6, - "options": { - "code": { - "language": "plaintext", - "showLineNumbers": false, - "showMiniMap": false - }, - "content": "# Graph panel \u003e\u003e Timeseries panel\n\nKnown issues:\n* hiding null/empty series\n* time regions", - "mode": "markdown" - }, + "mode": "markdown", "pluginVersion": "11.0.0-pre", "targets": [ { diff --git a/apps/dashboard/pkg/migration/testdata/input/v15.mimir_rollout_debugging.json b/apps/dashboard/pkg/migration/testdata/input/v15.mimir_rollout_debugging.json index dc0ca4e5845..1cc39838eab 100644 --- a/apps/dashboard/pkg/migration/testdata/input/v15.mimir_rollout_debugging.json +++ b/apps/dashboard/pkg/migration/testdata/input/v15.mimir_rollout_debugging.json @@ -654,7 +654,9 @@ "text": "prod", "value": "prod" }, - "datasource": "$datasource", + "datasource": { + "uid": "$datasource" + }, "hide": 0, "includeAll": true, "label": "cluster", @@ -677,7 +679,9 @@ "text": "prod", "value": "prod" }, - "datasource": "$datasource", + "datasource": { + "uid": "$datasource" + }, "hide": 0, "includeAll": false, "label": "namespace", diff --git a/apps/dashboard/pkg/migration/testdata/output/latest_version/v15.mimir_rollout_debugging.v42.json b/apps/dashboard/pkg/migration/testdata/output/latest_version/v15.mimir_rollout_debugging.v42.json index 6f507f5bc47..1195b2bec63 100644 --- a/apps/dashboard/pkg/migration/testdata/output/latest_version/v15.mimir_rollout_debugging.v42.json +++ b/apps/dashboard/pkg/migration/testdata/output/latest_version/v15.mimir_rollout_debugging.v42.json @@ -737,7 +737,9 @@ "text": "prod", "value": "prod" }, - "datasource": "$datasource", + "datasource": { + "uid": "$datasource" + }, "hide": 0, "includeAll": true, "label": "cluster", @@ -758,7 +760,9 @@ "text": "prod", "value": "prod" }, - "datasource": "$datasource", + "datasource": { + "uid": "$datasource" + }, "hide": 0, "includeAll": false, "label": "namespace", diff --git a/apps/dashboard/pkg/migration/testdata/output/single_version/v15.mimir_rollout_debugging.v15.json b/apps/dashboard/pkg/migration/testdata/output/single_version/v15.mimir_rollout_debugging.v15.json index dd9ec62ed85..30186560450 100644 --- a/apps/dashboard/pkg/migration/testdata/output/single_version/v15.mimir_rollout_debugging.v15.json +++ b/apps/dashboard/pkg/migration/testdata/output/single_version/v15.mimir_rollout_debugging.v15.json @@ -717,7 +717,9 @@ "text": "prod", "value": "prod" }, - "datasource": "$datasource", + "datasource": { + "uid": "$datasource" + }, "hide": 0, "includeAll": true, "label": "cluster", @@ -739,7 +741,9 @@ "text": "prod", "value": "prod" }, - "datasource": "$datasource", + "datasource": { + "uid": "$datasource" + }, "hide": 0, "includeAll": false, "label": "namespace", diff --git a/apps/example/go.mod b/apps/example/go.mod index d63d23be302..f2afba81283 100644 --- a/apps/example/go.mod +++ b/apps/example/go.mod @@ -3,17 +3,17 @@ module github.com/grafana/grafana/apps/example go 1.25.5 require ( - github.com/grafana/grafana-app-sdk v0.48.5 - github.com/grafana/grafana-app-sdk/logging v0.48.3 + github.com/grafana/grafana-app-sdk v0.48.7 + github.com/grafana/grafana-app-sdk/logging v0.48.7 github.com/grafana/grafana/pkg/apimachinery v0.0.0-20251017153501-8512b219c5fe - k8s.io/apimachinery v0.34.2 - k8s.io/apiserver v0.34.2 - k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 + k8s.io/apimachinery v0.34.3 + k8s.io/apiserver v0.34.3 + k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e ) require ( github.com/beorn7/perks v1.0.1 // indirect - github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874 // indirect + github.com/bradfitz/gomemcache v0.0.0-20250403215159-8d39553ac7cf // 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 @@ -24,13 +24,23 @@ require ( github.com/go-jose/go-jose/v4 v4.1.3 // 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.1 // indirect - github.com/go-openapi/swag/jsonname v0.25.1 // indirect + github.com/go-openapi/jsonpointer v0.22.4 // indirect + github.com/go-openapi/jsonreference v0.21.4 // indirect + github.com/go-openapi/swag v0.25.4 // indirect + github.com/go-openapi/swag/cmdutils v0.25.4 // indirect + github.com/go-openapi/swag/conv v0.25.4 // indirect + github.com/go-openapi/swag/fileutils v0.25.4 // indirect + github.com/go-openapi/swag/jsonname v0.25.4 // indirect + github.com/go-openapi/swag/jsonutils v0.25.4 // indirect + github.com/go-openapi/swag/loading v0.25.4 // indirect + github.com/go-openapi/swag/mangling v0.25.4 // indirect + github.com/go-openapi/swag/netutils v0.25.4 // indirect + github.com/go-openapi/swag/stringutils v0.25.4 // indirect + github.com/go-openapi/swag/typeutils v0.25.4 // indirect + github.com/go-openapi/swag/yamlutils v0.25.4 // 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/gnostic-models v0.7.1 // 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 @@ -42,7 +52,7 @@ require ( 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/mailru/easyjson v0.9.1 // 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 @@ -56,43 +66,43 @@ require ( 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.3 // indirect - github.com/prometheus/procfs v0.16.1 // indirect + github.com/prometheus/common v0.67.4 // indirect + github.com/prometheus/procfs v0.19.2 // 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/woodsbury/decimal128 v1.4.0 // indirect github.com/x448/float16 v0.8.4 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // 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/otel v1.39.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0 // indirect + go.opentelemetry.io/otel/metric v1.39.0 // indirect + go.opentelemetry.io/otel/sdk v1.39.0 // indirect + go.opentelemetry.io/otel/trace v1.39.0 // indirect go.opentelemetry.io/proto/otlp v1.9.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.47.0 // indirect - golang.org/x/oauth2 v0.33.0 // indirect - golang.org/x/sync v0.18.0 // indirect - golang.org/x/sys v0.38.0 // indirect - golang.org/x/term v0.37.0 // indirect - golang.org/x/text v0.31.0 // indirect + golang.org/x/net v0.48.0 // indirect + golang.org/x/oauth2 v0.34.0 // indirect + golang.org/x/sync v0.19.0 // indirect + golang.org/x/sys v0.39.0 // indirect + golang.org/x/term v0.38.0 // indirect + golang.org/x/text v0.32.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-20251111163417-95abcf5c77ba // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2 // indirect google.golang.org/grpc v1.77.0 // indirect - google.golang.org/protobuf v1.36.10 // indirect + google.golang.org/protobuf v1.36.11 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/api v0.34.2 // indirect - k8s.io/apiextensions-apiserver v0.34.2 // indirect - k8s.io/client-go v0.34.2 // indirect + k8s.io/api v0.34.3 // indirect + k8s.io/apiextensions-apiserver v0.34.3 // indirect + k8s.io/client-go v0.34.3 // 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 + k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 // indirect + sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect sigs.k8s.io/randfill v1.0.0 // indirect sigs.k8s.io/structured-merge-diff/v6 v6.3.1 // indirect sigs.k8s.io/yaml v1.6.0 // indirect diff --git a/apps/example/go.sum b/apps/example/go.sum index 70c83a9fe37..c5110f46829 100644 --- a/apps/example/go.sum +++ b/apps/example/go.sum @@ -1,7 +1,7 @@ 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/bradfitz/gomemcache v0.0.0-20250403215159-8d39553ac7cf h1:TqhNAT4zKbTdLa62d2HDBFdvgSbIGB3eJE8HqhgiL9I= +github.com/bradfitz/gomemcache v0.0.0-20250403215159-8d39553ac7cf/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= @@ -25,14 +25,40 @@ 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.1 h1:lpsStH0n2ittzTnbaSloVZLuB5+fvSY/+hnagBjSNZU= -github.com/go-openapi/swag v0.23.1/go.mod h1:STZs8TbRvEQQKUA+JZNAm3EWlgaOBGpyFDqQnDHMef0= -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/jsonpointer v0.22.4 h1:dZtK82WlNpVLDW2jlA1YCiVJFVqkED1MegOUy9kR5T4= +github.com/go-openapi/jsonpointer v0.22.4/go.mod h1:elX9+UgznpFhgBuaMQ7iu4lvvX1nvNsesQ3oxmYTw80= +github.com/go-openapi/jsonreference v0.21.4 h1:24qaE2y9bx/q3uRK/qN+TDwbok1NhbSmGjjySRCHtC8= +github.com/go-openapi/jsonreference v0.21.4/go.mod h1:rIENPTjDbLpzQmQWCj5kKj3ZlmEh+EFVbz3RTUh30/4= +github.com/go-openapi/swag v0.25.4 h1:OyUPUFYDPDBMkqyxOTkqDYFnrhuhi9NR6QVUvIochMU= +github.com/go-openapi/swag v0.25.4/go.mod h1:zNfJ9WZABGHCFg2RnY0S4IOkAcVTzJ6z2Bi+Q4i6qFQ= +github.com/go-openapi/swag/cmdutils v0.25.4 h1:8rYhB5n6WawR192/BfUu2iVlxqVR9aRgGJP6WaBoW+4= +github.com/go-openapi/swag/cmdutils v0.25.4/go.mod h1:pdae/AFo6WxLl5L0rq87eRzVPm/XRHM3MoYgRMvG4A0= +github.com/go-openapi/swag/conv v0.25.4 h1:/Dd7p0LZXczgUcC/Ikm1+YqVzkEeCc9LnOWjfkpkfe4= +github.com/go-openapi/swag/conv v0.25.4/go.mod h1:3LXfie/lwoAv0NHoEuY1hjoFAYkvlqI/Bn5EQDD3PPU= +github.com/go-openapi/swag/fileutils v0.25.4 h1:2oI0XNW5y6UWZTC7vAxC8hmsK/tOkWXHJQH4lKjqw+Y= +github.com/go-openapi/swag/fileutils v0.25.4/go.mod h1:cdOT/PKbwcysVQ9Tpr0q20lQKH7MGhOEb6EwmHOirUk= +github.com/go-openapi/swag/jsonname v0.25.4 h1:bZH0+MsS03MbnwBXYhuTttMOqk+5KcQ9869Vye1bNHI= +github.com/go-openapi/swag/jsonname v0.25.4/go.mod h1:GPVEk9CWVhNvWhZgrnvRA6utbAltopbKwDu8mXNUMag= +github.com/go-openapi/swag/jsonutils v0.25.4 h1:VSchfbGhD4UTf4vCdR2F4TLBdLwHyUDTd1/q4i+jGZA= +github.com/go-openapi/swag/jsonutils v0.25.4/go.mod h1:7OYGXpvVFPn4PpaSdPHJBtF0iGnbEaTk8AvBkoWnaAY= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4 h1:IACsSvBhiNJwlDix7wq39SS2Fh7lUOCJRmx/4SN4sVo= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4/go.mod h1:Mt0Ost9l3cUzVv4OEZG+WSeoHwjWLnarzMePNDAOBiM= +github.com/go-openapi/swag/loading v0.25.4 h1:jN4MvLj0X6yhCDduRsxDDw1aHe+ZWoLjW+9ZQWIKn2s= +github.com/go-openapi/swag/loading v0.25.4/go.mod h1:rpUM1ZiyEP9+mNLIQUdMiD7dCETXvkkC30z53i+ftTE= +github.com/go-openapi/swag/mangling v0.25.4 h1:2b9kBJk9JvPgxr36V23FxJLdwBrpijI26Bx5JH4Hp48= +github.com/go-openapi/swag/mangling v0.25.4/go.mod h1:6dxwu6QyORHpIIApsdZgb6wBk/DPU15MdyYj/ikn0Hg= +github.com/go-openapi/swag/netutils v0.25.4 h1:Gqe6K71bGRb3ZQLusdI8p/y1KLgV4M/k+/HzVSqT8H0= +github.com/go-openapi/swag/netutils v0.25.4/go.mod h1:m2W8dtdaoX7oj9rEttLyTeEFFEBvnAx9qHd5nJEBzYg= +github.com/go-openapi/swag/stringutils v0.25.4 h1:O6dU1Rd8bej4HPA3/CLPciNBBDwZj9HiEpdVsb8B5A8= +github.com/go-openapi/swag/stringutils v0.25.4/go.mod h1:GTsRvhJW5xM5gkgiFe0fV3PUlFm0dr8vki6/VSRaZK0= +github.com/go-openapi/swag/typeutils v0.25.4 h1:1/fbZOUN472NTc39zpa+YGHn3jzHWhv42wAJSN91wRw= +github.com/go-openapi/swag/typeutils v0.25.4/go.mod h1:Ou7g//Wx8tTLS9vG0UmzfCsjZjKhpjxayRKTHXf2pTE= +github.com/go-openapi/swag/yamlutils v0.25.4 h1:6jdaeSItEUb7ioS9lFoCZ65Cne1/RZtPBZ9A56h92Sw= +github.com/go-openapi/swag/yamlutils v0.25.4/go.mod h1:MNzq1ulQu+yd8Kl7wPOut/YHAAU/H6hL91fF+E2RFwc= +github.com/go-openapi/testify/enable/yaml/v2 v2.0.2 h1:0+Y41Pz1NkbTHz8NngxTuAXxEodtNSI1WG1c/m5Akw4= +github.com/go-openapi/testify/enable/yaml/v2 v2.0.2/go.mod h1:kme83333GCtJQHXQ8UKX3IBZu6z8T5Dvy5+CW3NLUUg= +github.com/go-openapi/testify/v2 v2.0.2 h1:X999g3jeLcoY8qctY/c/Z8iBHTbwLz7R2WXd6Ub6wls= +github.com/go-openapi/testify/v2 v2.0.2/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= 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= @@ -41,8 +67,8 @@ 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/gnostic-models v0.7.1 h1:SisTfuFKJSKM5CPZkffwi6coztzzeYUhc3v4yxLWH8c= +github.com/google/gnostic-models v0.7.1/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= @@ -56,10 +82,10 @@ github.com/grafana/authlib/types v0.0.0-20251119142549-be091cf2f4d4 h1:Muoy+FMGr github.com/grafana/authlib/types v0.0.0-20251119142549-be091cf2f4d4/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.5 h1:MS8l9fTZz+VbTfgApn09jw27GxhQ6fNOWGhC4ydvZmM= -github.com/grafana/grafana-app-sdk v0.48.5/go.mod h1:HJsMOSBmt/D/Ihs1SvagOwmXKi0coBMVHlfvdd+qe9Y= -github.com/grafana/grafana-app-sdk/logging v0.48.3 h1:72NUpGNiJXCNQz/on++YSsl38xuVYYBKv5kKQaOClX4= -github.com/grafana/grafana-app-sdk/logging v0.48.3/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA= +github.com/grafana/grafana-app-sdk v0.48.7 h1:9mF7nqkqP0QUYYDlznoOt+GIyjzj45wGfUHB32u2ZMo= +github.com/grafana/grafana-app-sdk v0.48.7/go.mod h1:DWsaaH39ZMHwSOSoUBaeW8paMrRaYsjRYlLwCJYd78k= +github.com/grafana/grafana-app-sdk/logging v0.48.7 h1:Oa5qg473gka5+W/WQk61Xbw4YdAv+wV2Z4bJtzeCaQw= +github.com/grafana/grafana-app-sdk/logging v0.48.7/go.mod h1:5u3KalezoBAAo2Y3ytDYDAIIPvEqFLLDSxeiK99QxDU= 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.3 h1:NmZ1PKzSTQbuGHw9DGPFomqkkLWMC+vZCkfs+FHv1Vg= @@ -83,8 +109,8 @@ 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/mailru/easyjson v0.9.1 h1:LbtsOm5WAswyWbvTEOqhypdPeZzHavpZx96/n553mR8= +github.com/mailru/easyjson v0.9.1/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= @@ -116,10 +142,10 @@ github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h 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.3 h1:shd26MlnwTw5jksTDhC7rTQIteBxy+ZZDr3t7F2xN2Q= -github.com/prometheus/common v0.67.3/go.mod h1:gP0fq6YjjNCLssJCQp0yk4M8W6ikLURwkdd/YKtTbyI= -github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= -github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= +github.com/prometheus/common v0.67.4 h1:yR3NqWO1/UyO1w2PhUvXlGQs/PtFmoveVO0KZ4+Lvsc= +github.com/prometheus/common v0.67.4/go.mod h1:gP0fq6YjjNCLssJCQp0yk4M8W6ikLURwkdd/YKtTbyI= +github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws= +github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw= 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= @@ -134,30 +160,30 @@ 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/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/woodsbury/decimal128 v1.4.0 h1:xJATj7lLu4f2oObouMt2tgGiElE5gO6mSWUjQsBgUlc= +github.com/woodsbury/decimal128 v1.4.0/go.mod h1:BP46FUrVjVhdTbKT+XuQh2xfQaGki9LMIRJSFuh6THU= 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.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= -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/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48= +go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0 h1:f0cb2XPmrqn4XMy9PNliTgRKJgS5WcL/u0/WRYGz4t0= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0/go.mod h1:vnakAaFckOMiMtOIhFI2MNH4FYrZzXCYxmb1LlhoGz8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0 h1:in9O8ESIOlwJAEGTkkf34DesGRAc/Pn8qJ7k3r/42LM= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0/go.mod h1:Rp0EXBm5tfnv0WL+ARyO/PHBEaEAT8UUHQ6AGJcSq6c= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0 h1:Ckwye2FpXkYgiHX7fyVrN1uA/UYd9ounqqTuSNAv0k4= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0/go.mod h1:teIFJh5pW2y+AN7riv6IBPX2DuesS3HgP39mwOspKwU= +go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0= +go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs= +go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18= +go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE= +go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8= +go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew= +go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI= +go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA= go.opentelemetry.io/proto/otlp v1.9.0 h1:l706jCMITVouPOqEnii2fIAuO3IVGBRPV5ICjceRb/A= go.opentelemetry.io/proto/otlp v1.9.0/go.mod h1:xE+Cx5E/eEHw+ISFkwPLwCZefwVjY+pqKg1qcK03+/4= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= @@ -175,34 +201,34 @@ 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.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= -golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= -golang.org/x/oauth2 v0.33.0 h1:4Q+qn+E5z8gPRJfmRy7C2gGG3T4jIprK6aSYgTXGRpo= -golang.org/x/oauth2 v0.33.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= +golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= +golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= +golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw= +golang.org/x/oauth2 v0.34.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.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= -golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.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.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= -golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU= -golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254= +golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= +golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q= +golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg= 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.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= -golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= +golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= +golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= 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.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ= -golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ= +golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA= +golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc= 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= @@ -211,41 +237,41 @@ 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-20251111163417-95abcf5c77ba h1:B14OtaXuMaCQsl2deSvNkyPKIzq3BjfxQp8d00QyWx4= -google.golang.org/genproto/googleapis/api v0.0.0-20251111163417-95abcf5c77ba/go.mod h1:G5IanEx8/PgI9w6CFcYQf7jMtHQhZruvfM1i3qOqk5U= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba h1:UKgtfRM7Yh93Sya0Fo8ZzhDP4qBckrrxEr2oF5UIVb8= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= +google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2 h1:7LRqPCEdE4TP4/9psdaB7F2nhZFfBiGJomA5sojLWdU= +google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2/go.mod h1:+rXWjjaukWZun3mLfjmVnQi18E1AsFbDN9QdJ5YXLto= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2 h1:2I6GHUeJ/4shcDpoUlLs/2WPnhg7yJwvXtqcMJt9liA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM= google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= -google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= -google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/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/evanphx/json-patch.v4 v4.13.0 h1:czT3CmqEaQ1aanPc5SdlgQrrEIb8w/wwCvWWnfEbYzo= +gopkg.in/evanphx/json-patch.v4 v4.13.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.2 h1:fsSUNZhV+bnL6Aqrp6O7lMTy6o5x2C4XLjnh//8SLYY= -k8s.io/api v0.34.2/go.mod h1:MMBPaWlED2a8w4RSeanD76f7opUoypY8TFYkSM+3XHw= -k8s.io/apiextensions-apiserver v0.34.2 h1:WStKftnGeoKP4AZRz/BaAAEJvYp4mlZGN0UCv+uvsqo= -k8s.io/apiextensions-apiserver v0.34.2/go.mod h1:398CJrsgXF1wytdaanynDpJ67zG4Xq7yj91GrmYN2SE= -k8s.io/apimachinery v0.34.2 h1:zQ12Uk3eMHPxrsbUJgNF8bTauTVR2WgqJsTmwTE/NW4= -k8s.io/apimachinery v0.34.2/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= -k8s.io/apiserver v0.34.2 h1:2/yu8suwkmES7IzwlehAovo8dDE07cFRC7KMDb1+MAE= -k8s.io/apiserver v0.34.2/go.mod h1:gqJQy2yDOB50R3JUReHSFr+cwJnL8G1dzTA0YLEqAPI= -k8s.io/client-go v0.34.2 h1:Co6XiknN+uUZqiddlfAjT68184/37PS4QAzYvQvDR8M= -k8s.io/client-go v0.34.2/go.mod h1:2VYDl1XXJsdcAxw7BenFslRQX28Dxz91U9MWKjX97fE= +k8s.io/api v0.34.3 h1:D12sTP257/jSH2vHV2EDYrb16bS7ULlHpdNdNhEw2S4= +k8s.io/api v0.34.3/go.mod h1:PyVQBF886Q5RSQZOim7DybQjAbVs8g7gwJNhGtY5MBk= +k8s.io/apiextensions-apiserver v0.34.3 h1:p10fGlkDY09eWKOTeUSioxwLukJnm+KuDZdrW71y40g= +k8s.io/apiextensions-apiserver v0.34.3/go.mod h1:aujxvqGFRdb/cmXYfcRTeppN7S2XV/t7WMEc64zB5A0= +k8s.io/apimachinery v0.34.3 h1:/TB+SFEiQvN9HPldtlWOTp0hWbJ+fjU+wkxysf/aQnE= +k8s.io/apimachinery v0.34.3/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= +k8s.io/apiserver v0.34.3 h1:uGH1qpDvSiYG4HVFqc6A3L4CKiX+aBWDrrsxHYK0Bdo= +k8s.io/apiserver v0.34.3/go.mod h1:QPnnahMO5C2m3lm6fPW3+JmyQbvHZQ8uudAu/493P2w= +k8s.io/client-go v0.34.3 h1:wtYtpzy/OPNYf7WyNBTj3iUA0XaBHVqhv4Iv3tbrF5A= +k8s.io/client-go v0.34.3/go.mod h1:OxxeYagaP9Kdf78UrKLa3YZixMCfP6bgPwPwNBQBzpM= 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= +k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e h1:iW9ChlU0cU16w8MpVYjXk12dqQ4BPFBEgif+ap7/hqQ= +k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e/go.mod h1:kdmbQkyfwUagLfXIad1y2TdrjPFWp2Q89B3qkRwf/pQ= +k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 h1:SjGebBtkBqHFOli+05xYbK8YF1Dzkbzn+gDM4X9T4Ck= +k8s.io/utils v0.0.0-20251002143259-bc988d571ff4/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg= +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/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.1 h1:JrhdFMqOd/+3ByqlP2I45kTOZmTRLBUm5pvRjeheg7E= diff --git a/apps/folder/go.mod b/apps/folder/go.mod index 476c6949c73..9a673364f89 100644 --- a/apps/folder/go.mod +++ b/apps/folder/go.mod @@ -3,10 +3,10 @@ module github.com/grafana/grafana/apps/folder go 1.25.5 require ( - github.com/grafana/grafana-app-sdk v0.48.5 + github.com/grafana/grafana-app-sdk v0.48.7 github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250514132646-acbc7b54ed9e - k8s.io/apimachinery v0.34.2 - k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 + k8s.io/apimachinery v0.34.3 + k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e ) require ( @@ -17,19 +17,29 @@ require ( github.com/fxamacker/cbor/v2 v2.9.0 // indirect github.com/getkin/kin-openapi v0.133.0 // indirect github.com/go-logr/logr v1.4.3 // 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.1 // indirect - github.com/go-openapi/swag/jsonname v0.25.1 // indirect + github.com/go-openapi/jsonpointer v0.22.4 // indirect + github.com/go-openapi/jsonreference v0.21.4 // indirect + github.com/go-openapi/swag v0.25.4 // indirect + github.com/go-openapi/swag/cmdutils v0.25.4 // indirect + github.com/go-openapi/swag/conv v0.25.4 // indirect + github.com/go-openapi/swag/fileutils v0.25.4 // indirect + github.com/go-openapi/swag/jsonname v0.25.4 // indirect + github.com/go-openapi/swag/jsonutils v0.25.4 // indirect + github.com/go-openapi/swag/loading v0.25.4 // indirect + github.com/go-openapi/swag/mangling v0.25.4 // indirect + github.com/go-openapi/swag/netutils v0.25.4 // indirect + github.com/go-openapi/swag/stringutils v0.25.4 // indirect + github.com/go-openapi/swag/typeutils v0.25.4 // indirect + github.com/go-openapi/swag/yamlutils v0.25.4 // 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/grafana/grafana-app-sdk/logging v0.48.3 // indirect + github.com/google/gnostic-models v0.7.1 // indirect + github.com/grafana/grafana-app-sdk/logging v0.48.7 // 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/mailru/easyjson v0.9.1 // 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 @@ -40,29 +50,29 @@ require ( 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.3 // indirect - github.com/prometheus/procfs v0.16.1 // indirect + github.com/prometheus/common v0.67.4 // indirect + github.com/prometheus/procfs v0.19.2 // indirect github.com/stretchr/objx v0.5.2 // indirect github.com/stretchr/testify v1.11.1 // indirect - github.com/woodsbury/decimal128 v1.3.0 // indirect + github.com/woodsbury/decimal128 v1.4.0 // indirect github.com/x448/float16 v0.8.4 // indirect - go.opentelemetry.io/otel v1.38.0 // indirect - go.opentelemetry.io/otel/trace v1.38.0 // indirect + go.opentelemetry.io/otel v1.39.0 // indirect + go.opentelemetry.io/otel/trace v1.39.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.47.0 // indirect - golang.org/x/oauth2 v0.33.0 // indirect - golang.org/x/sys v0.38.0 // indirect - golang.org/x/term v0.37.0 // indirect - golang.org/x/text v0.31.0 // indirect + golang.org/x/net v0.48.0 // indirect + golang.org/x/oauth2 v0.34.0 // indirect + golang.org/x/sys v0.39.0 // indirect + golang.org/x/term v0.38.0 // indirect + golang.org/x/text v0.32.0 // indirect golang.org/x/time v0.14.0 // indirect - google.golang.org/protobuf v1.36.10 // indirect + google.golang.org/protobuf v1.36.11 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/client-go v0.34.2 // indirect + k8s.io/client-go v0.34.3 // 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 + k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 // indirect + sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect sigs.k8s.io/randfill v1.0.0 // indirect sigs.k8s.io/structured-merge-diff/v6 v6.3.1 // indirect sigs.k8s.io/yaml v1.6.0 // indirect diff --git a/apps/folder/go.sum b/apps/folder/go.sum index d8454185267..3b414d3e3fe 100644 --- a/apps/folder/go.sum +++ b/apps/folder/go.sum @@ -14,29 +14,55 @@ github.com/getkin/kin-openapi v0.133.0 h1:pJdmNohVIJ97r4AUFtEXRXwESr8b0bD721u/Tz github.com/getkin/kin-openapi v0.133.0/go.mod h1:boAciF6cXk5FhPqe/NQeBTeenbjqU4LhWBf09ILVvWE= 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-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.1 h1:lpsStH0n2ittzTnbaSloVZLuB5+fvSY/+hnagBjSNZU= -github.com/go-openapi/swag v0.23.1/go.mod h1:STZs8TbRvEQQKUA+JZNAm3EWlgaOBGpyFDqQnDHMef0= -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/jsonpointer v0.22.4 h1:dZtK82WlNpVLDW2jlA1YCiVJFVqkED1MegOUy9kR5T4= +github.com/go-openapi/jsonpointer v0.22.4/go.mod h1:elX9+UgznpFhgBuaMQ7iu4lvvX1nvNsesQ3oxmYTw80= +github.com/go-openapi/jsonreference v0.21.4 h1:24qaE2y9bx/q3uRK/qN+TDwbok1NhbSmGjjySRCHtC8= +github.com/go-openapi/jsonreference v0.21.4/go.mod h1:rIENPTjDbLpzQmQWCj5kKj3ZlmEh+EFVbz3RTUh30/4= +github.com/go-openapi/swag v0.25.4 h1:OyUPUFYDPDBMkqyxOTkqDYFnrhuhi9NR6QVUvIochMU= +github.com/go-openapi/swag v0.25.4/go.mod h1:zNfJ9WZABGHCFg2RnY0S4IOkAcVTzJ6z2Bi+Q4i6qFQ= +github.com/go-openapi/swag/cmdutils v0.25.4 h1:8rYhB5n6WawR192/BfUu2iVlxqVR9aRgGJP6WaBoW+4= +github.com/go-openapi/swag/cmdutils v0.25.4/go.mod h1:pdae/AFo6WxLl5L0rq87eRzVPm/XRHM3MoYgRMvG4A0= +github.com/go-openapi/swag/conv v0.25.4 h1:/Dd7p0LZXczgUcC/Ikm1+YqVzkEeCc9LnOWjfkpkfe4= +github.com/go-openapi/swag/conv v0.25.4/go.mod h1:3LXfie/lwoAv0NHoEuY1hjoFAYkvlqI/Bn5EQDD3PPU= +github.com/go-openapi/swag/fileutils v0.25.4 h1:2oI0XNW5y6UWZTC7vAxC8hmsK/tOkWXHJQH4lKjqw+Y= +github.com/go-openapi/swag/fileutils v0.25.4/go.mod h1:cdOT/PKbwcysVQ9Tpr0q20lQKH7MGhOEb6EwmHOirUk= +github.com/go-openapi/swag/jsonname v0.25.4 h1:bZH0+MsS03MbnwBXYhuTttMOqk+5KcQ9869Vye1bNHI= +github.com/go-openapi/swag/jsonname v0.25.4/go.mod h1:GPVEk9CWVhNvWhZgrnvRA6utbAltopbKwDu8mXNUMag= +github.com/go-openapi/swag/jsonutils v0.25.4 h1:VSchfbGhD4UTf4vCdR2F4TLBdLwHyUDTd1/q4i+jGZA= +github.com/go-openapi/swag/jsonutils v0.25.4/go.mod h1:7OYGXpvVFPn4PpaSdPHJBtF0iGnbEaTk8AvBkoWnaAY= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4 h1:IACsSvBhiNJwlDix7wq39SS2Fh7lUOCJRmx/4SN4sVo= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4/go.mod h1:Mt0Ost9l3cUzVv4OEZG+WSeoHwjWLnarzMePNDAOBiM= +github.com/go-openapi/swag/loading v0.25.4 h1:jN4MvLj0X6yhCDduRsxDDw1aHe+ZWoLjW+9ZQWIKn2s= +github.com/go-openapi/swag/loading v0.25.4/go.mod h1:rpUM1ZiyEP9+mNLIQUdMiD7dCETXvkkC30z53i+ftTE= +github.com/go-openapi/swag/mangling v0.25.4 h1:2b9kBJk9JvPgxr36V23FxJLdwBrpijI26Bx5JH4Hp48= +github.com/go-openapi/swag/mangling v0.25.4/go.mod h1:6dxwu6QyORHpIIApsdZgb6wBk/DPU15MdyYj/ikn0Hg= +github.com/go-openapi/swag/netutils v0.25.4 h1:Gqe6K71bGRb3ZQLusdI8p/y1KLgV4M/k+/HzVSqT8H0= +github.com/go-openapi/swag/netutils v0.25.4/go.mod h1:m2W8dtdaoX7oj9rEttLyTeEFFEBvnAx9qHd5nJEBzYg= +github.com/go-openapi/swag/stringutils v0.25.4 h1:O6dU1Rd8bej4HPA3/CLPciNBBDwZj9HiEpdVsb8B5A8= +github.com/go-openapi/swag/stringutils v0.25.4/go.mod h1:GTsRvhJW5xM5gkgiFe0fV3PUlFm0dr8vki6/VSRaZK0= +github.com/go-openapi/swag/typeutils v0.25.4 h1:1/fbZOUN472NTc39zpa+YGHn3jzHWhv42wAJSN91wRw= +github.com/go-openapi/swag/typeutils v0.25.4/go.mod h1:Ou7g//Wx8tTLS9vG0UmzfCsjZjKhpjxayRKTHXf2pTE= +github.com/go-openapi/swag/yamlutils v0.25.4 h1:6jdaeSItEUb7ioS9lFoCZ65Cne1/RZtPBZ9A56h92Sw= +github.com/go-openapi/swag/yamlutils v0.25.4/go.mod h1:MNzq1ulQu+yd8Kl7wPOut/YHAAU/H6hL91fF+E2RFwc= +github.com/go-openapi/testify/enable/yaml/v2 v2.0.2 h1:0+Y41Pz1NkbTHz8NngxTuAXxEodtNSI1WG1c/m5Akw4= +github.com/go-openapi/testify/enable/yaml/v2 v2.0.2/go.mod h1:kme83333GCtJQHXQ8UKX3IBZu6z8T5Dvy5+CW3NLUUg= +github.com/go-openapi/testify/v2 v2.0.2 h1:X999g3jeLcoY8qctY/c/Z8iBHTbwLz7R2WXd6Ub6wls= +github.com/go-openapi/testify/v2 v2.0.2/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= 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/google/gnostic-models v0.7.0 h1:qwTtogB15McXDaNqTZdzPJRHvaVJlAl+HVQnLmJEJxo= -github.com/google/gnostic-models v0.7.0/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ= +github.com/google/gnostic-models v0.7.1 h1:SisTfuFKJSKM5CPZkffwi6coztzzeYUhc3v4yxLWH8c= +github.com/google/gnostic-models v0.7.1/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/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.48.5 h1:MS8l9fTZz+VbTfgApn09jw27GxhQ6fNOWGhC4ydvZmM= -github.com/grafana/grafana-app-sdk v0.48.5/go.mod h1:HJsMOSBmt/D/Ihs1SvagOwmXKi0coBMVHlfvdd+qe9Y= -github.com/grafana/grafana-app-sdk/logging v0.48.3 h1:72NUpGNiJXCNQz/on++YSsl38xuVYYBKv5kKQaOClX4= -github.com/grafana/grafana-app-sdk/logging v0.48.3/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA= +github.com/grafana/grafana-app-sdk v0.48.7 h1:9mF7nqkqP0QUYYDlznoOt+GIyjzj45wGfUHB32u2ZMo= +github.com/grafana/grafana-app-sdk v0.48.7/go.mod h1:DWsaaH39ZMHwSOSoUBaeW8paMrRaYsjRYlLwCJYd78k= +github.com/grafana/grafana-app-sdk/logging v0.48.7 h1:Oa5qg473gka5+W/WQk61Xbw4YdAv+wV2Z4bJtzeCaQw= +github.com/grafana/grafana-app-sdk/logging v0.48.7/go.mod h1:5u3KalezoBAAo2Y3ytDYDAIIPvEqFLLDSxeiK99QxDU= 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= @@ -58,8 +84,8 @@ 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/mailru/easyjson v0.9.1 h1:LbtsOm5WAswyWbvTEOqhypdPeZzHavpZx96/n553mR8= +github.com/mailru/easyjson v0.9.1/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= @@ -76,8 +102,6 @@ github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 h1:bQx3WeLcUWy+RletI github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90/go.mod h1:y5+oSEHCPT/DGrS++Wc/479ERge0zTFxaF8PbGKcg2o= 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= @@ -85,10 +109,10 @@ github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h 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.3 h1:shd26MlnwTw5jksTDhC7rTQIteBxy+ZZDr3t7F2xN2Q= -github.com/prometheus/common v0.67.3/go.mod h1:gP0fq6YjjNCLssJCQp0yk4M8W6ikLURwkdd/YKtTbyI= -github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= -github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= +github.com/prometheus/common v0.67.4 h1:yR3NqWO1/UyO1w2PhUvXlGQs/PtFmoveVO0KZ4+Lvsc= +github.com/prometheus/common v0.67.4/go.mod h1:gP0fq6YjjNCLssJCQp0yk4M8W6ikLURwkdd/YKtTbyI= +github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws= +github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw= 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= @@ -101,16 +125,16 @@ 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/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/woodsbury/decimal128 v1.4.0 h1:xJATj7lLu4f2oObouMt2tgGiElE5gO6mSWUjQsBgUlc= +github.com/woodsbury/decimal128 v1.4.0/go.mod h1:BP46FUrVjVhdTbKT+XuQh2xfQaGki9LMIRJSFuh6THU= 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/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/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/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48= +go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8= +go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI= +go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA= 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= @@ -126,24 +150,24 @@ 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.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= -golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= -golang.org/x/oauth2 v0.33.0 h1:4Q+qn+E5z8gPRJfmRy7C2gGG3T4jIprK6aSYgTXGRpo= -golang.org/x/oauth2 v0.33.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= +golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= +golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= +golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw= +golang.org/x/oauth2 v0.34.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/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.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= -golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU= -golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254= +golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= +golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q= +golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg= 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.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= -golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= +golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= +golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= 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= @@ -154,31 +178,31 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= -google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/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/evanphx/json-patch.v4 v4.13.0 h1:czT3CmqEaQ1aanPc5SdlgQrrEIb8w/wwCvWWnfEbYzo= +gopkg.in/evanphx/json-patch.v4 v4.13.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.2 h1:fsSUNZhV+bnL6Aqrp6O7lMTy6o5x2C4XLjnh//8SLYY= -k8s.io/api v0.34.2/go.mod h1:MMBPaWlED2a8w4RSeanD76f7opUoypY8TFYkSM+3XHw= -k8s.io/apimachinery v0.34.2 h1:zQ12Uk3eMHPxrsbUJgNF8bTauTVR2WgqJsTmwTE/NW4= -k8s.io/apimachinery v0.34.2/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= -k8s.io/client-go v0.34.2 h1:Co6XiknN+uUZqiddlfAjT68184/37PS4QAzYvQvDR8M= -k8s.io/client-go v0.34.2/go.mod h1:2VYDl1XXJsdcAxw7BenFslRQX28Dxz91U9MWKjX97fE= +k8s.io/api v0.34.3 h1:D12sTP257/jSH2vHV2EDYrb16bS7ULlHpdNdNhEw2S4= +k8s.io/api v0.34.3/go.mod h1:PyVQBF886Q5RSQZOim7DybQjAbVs8g7gwJNhGtY5MBk= +k8s.io/apimachinery v0.34.3 h1:/TB+SFEiQvN9HPldtlWOTp0hWbJ+fjU+wkxysf/aQnE= +k8s.io/apimachinery v0.34.3/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= +k8s.io/client-go v0.34.3 h1:wtYtpzy/OPNYf7WyNBTj3iUA0XaBHVqhv4Iv3tbrF5A= +k8s.io/client-go v0.34.3/go.mod h1:OxxeYagaP9Kdf78UrKLa3YZixMCfP6bgPwPwNBQBzpM= 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= +k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e h1:iW9ChlU0cU16w8MpVYjXk12dqQ4BPFBEgif+ap7/hqQ= +k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e/go.mod h1:kdmbQkyfwUagLfXIad1y2TdrjPFWp2Q89B3qkRwf/pQ= +k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 h1:SjGebBtkBqHFOli+05xYbK8YF1Dzkbzn+gDM4X9T4Ck= +k8s.io/utils v0.0.0-20251002143259-bc988d571ff4/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg= +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/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.1 h1:JrhdFMqOd/+3ByqlP2I45kTOZmTRLBUm5pvRjeheg7E= diff --git a/apps/iam/go.mod b/apps/iam/go.mod index c741eb97423..24769ca825f 100644 --- a/apps/iam/go.mod +++ b/apps/iam/go.mod @@ -52,19 +52,19 @@ 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.48.5 - github.com/grafana/grafana-app-sdk/logging v0.48.3 + github.com/grafana/grafana-app-sdk v0.48.7 + github.com/grafana/grafana-app-sdk/logging v0.48.7 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 - go.opentelemetry.io/otel v1.38.0 - go.opentelemetry.io/otel/trace v1.38.0 - k8s.io/apimachinery v0.34.2 - k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 + go.opentelemetry.io/otel v1.39.0 + go.opentelemetry.io/otel/trace v1.39.0 + k8s.io/apimachinery v0.34.3 + k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e ) require ( - cel.dev/expr v0.24.0 // indirect + cel.dev/expr v0.25.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 @@ -131,7 +131,7 @@ require ( github.com/blang/semver v3.5.1+incompatible // indirect github.com/blang/semver/v4 v4.0.0 // indirect github.com/bluele/gcache v0.0.2 // indirect - github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874 // indirect + github.com/bradfitz/gomemcache v0.0.0-20250403215159-8d39553ac7cf // indirect github.com/bufbuild/protocompile v0.14.1 // indirect github.com/buger/jsonparser v1.1.1 // indirect github.com/bwmarrin/snowflake v0.3.0 // indirect @@ -143,7 +143,7 @@ require ( github.com/cncf/xds/go v0.0.0-20251022180443-0feb69152e9f // indirect github.com/cockroachdb/apd/v3 v3.2.1 // indirect github.com/coreos/go-semver v0.3.1 // indirect - github.com/coreos/go-systemd/v22 v22.5.0 // indirect + github.com/coreos/go-systemd/v22 v22.6.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/dennwc/varint v1.0.0 // indirect github.com/dgraph-io/badger/v4 v4.7.0 // indirect @@ -178,22 +178,24 @@ require ( github.com/go-logr/stdr v1.2.2 // 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/jsonpointer v0.22.4 // indirect + github.com/go-openapi/jsonreference v0.21.4 // 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.22.0 // indirect github.com/go-openapi/strfmt v0.24.0 // indirect - github.com/go-openapi/swag v0.23.1 // 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/swag v0.25.4 // indirect + github.com/go-openapi/swag/cmdutils v0.25.4 // indirect + github.com/go-openapi/swag/conv v0.25.4 // indirect + github.com/go-openapi/swag/fileutils v0.25.4 // indirect + github.com/go-openapi/swag/jsonname v0.25.4 // indirect + github.com/go-openapi/swag/jsonutils v0.25.4 // indirect + github.com/go-openapi/swag/loading v0.25.4 // indirect + github.com/go-openapi/swag/mangling v0.25.4 // indirect + github.com/go-openapi/swag/netutils v0.25.4 // indirect + github.com/go-openapi/swag/stringutils v0.25.4 // indirect + github.com/go-openapi/swag/typeutils v0.25.4 // indirect + github.com/go-openapi/swag/yamlutils v0.25.4 // 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 @@ -212,7 +214,7 @@ require ( github.com/google/btree v1.1.3 // indirect github.com/google/cel-go v0.26.1 // indirect github.com/google/flatbuffers v25.2.10+incompatible // indirect - github.com/google/gnostic-models v0.7.0 // indirect + github.com/google/gnostic-models v0.7.1 // indirect github.com/google/go-cmp v0.7.0 // indirect github.com/google/go-querystring v1.1.0 // indirect github.com/google/s2a-go v0.1.9 // indirect @@ -285,7 +287,7 @@ require ( github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect github.com/lestrrat-go/strftime v1.0.4 // indirect github.com/lib/pq v1.10.9 // indirect - github.com/mailru/easyjson v0.9.0 // indirect + github.com/mailru/easyjson v0.9.1 // indirect github.com/mattbaird/jsonpatch v0.0.0-20240118010651-0ba75a80ca38 // indirect github.com/mattetti/filebuffer v1.0.1 // indirect github.com/mattn/go-colorable v0.1.14 // indirect @@ -339,10 +341,10 @@ require ( github.com/pressly/goose/v3 v3.26.0 // indirect github.com/prometheus/alertmanager v0.28.2 // indirect github.com/prometheus/client_model v0.6.2 // indirect - github.com/prometheus/common v0.67.3 // indirect + github.com/prometheus/common v0.67.4 // 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/prometheus/procfs v0.19.2 // indirect github.com/prometheus/prometheus v0.303.1 // indirect github.com/puzpuzpuz/xsync/v2 v2.5.1 // indirect github.com/redis/go-redis/v9 v9.14.0 // indirect @@ -359,7 +361,7 @@ require ( github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect github.com/spf13/afero v1.15.0 // indirect github.com/spf13/cast v1.10.0 // indirect - github.com/spf13/cobra v1.10.1 // indirect + github.com/spf13/cobra v1.10.2 // indirect github.com/spf13/pflag v1.0.10 // indirect github.com/spf13/viper v1.21.0 // indirect github.com/spiffe/go-spiffe/v2 v2.6.0 // indirect @@ -373,20 +375,20 @@ require ( github.com/uber/jaeger-client-go v2.30.0+incompatible // indirect github.com/uber/jaeger-lib v2.4.1+incompatible // indirect github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect - github.com/woodsbury/decimal128 v1.3.0 // indirect + github.com/woodsbury/decimal128 v1.4.0 // indirect github.com/x448/float16 v0.8.4 // indirect github.com/zeebo/xxh3 v1.0.2 // indirect - go.etcd.io/etcd/api/v3 v3.6.4 // indirect - go.etcd.io/etcd/client/pkg/v3 v3.6.4 // indirect - go.etcd.io/etcd/client/v3 v3.6.4 // indirect + go.etcd.io/etcd/api/v3 v3.6.6 // indirect + go.etcd.io/etcd/client/pkg/v3 v3.6.6 // indirect + go.etcd.io/etcd/client/v3 v3.6.6 // indirect go.mongodb.org/mongo-driver v1.17.4 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/contrib/bridges/prometheus v0.61.0 // indirect go.opentelemetry.io/contrib/detectors/gcp v1.38.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/google.golang.org/grpc/otelgrpc v0.64.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/instrumentation/net/http/otelhttp v0.64.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/exporters/jaeger v1.17.0 // indirect @@ -394,18 +396,18 @@ require ( go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.12.2 // indirect go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp 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/exporters/otlp/otlptrace v1.39.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.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.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 - go.opentelemetry.io/otel/sdk v1.38.0 // indirect + go.opentelemetry.io/otel/metric v1.39.0 // indirect + go.opentelemetry.io/otel/sdk v1.39.0 // indirect go.opentelemetry.io/otel/sdk/log v0.12.2 // indirect - go.opentelemetry.io/otel/sdk/metric v1.38.0 // indirect + go.opentelemetry.io/otel/sdk/metric v1.39.0 // indirect go.opentelemetry.io/proto/otlp v1.9.0 // indirect go.uber.org/atomic v1.11.0 // indirect go.uber.org/mock v0.6.0 // indirect @@ -414,30 +416,30 @@ require ( go.yaml.in/yaml/v2 v2.4.3 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect gocloud.dev v0.43.0 // indirect - golang.org/x/crypto v0.45.0 // indirect - golang.org/x/exp v0.0.0-20251002181428-27f1f14c8bb9 // indirect - golang.org/x/mod v0.30.0 // indirect - golang.org/x/net v0.47.0 // indirect - golang.org/x/oauth2 v0.33.0 // indirect - golang.org/x/sync v0.18.0 // indirect - golang.org/x/sys v0.38.0 // indirect - golang.org/x/telemetry v0.0.0-20251111182119-bc8e575c7b54 // indirect - golang.org/x/term v0.37.0 // indirect - golang.org/x/text v0.31.0 // indirect + golang.org/x/crypto v0.46.0 // indirect + golang.org/x/exp v0.0.0-20251209150349-8475f28825e9 // indirect + golang.org/x/mod v0.31.0 // indirect + golang.org/x/net v0.48.0 // indirect + golang.org/x/oauth2 v0.34.0 // indirect + golang.org/x/sync v0.19.0 // indirect + golang.org/x/sys v0.39.0 // indirect + golang.org/x/telemetry v0.0.0-20251203150158-8fff8a5912fc // indirect + golang.org/x/term v0.38.0 // indirect + golang.org/x/text v0.32.0 // indirect golang.org/x/time v0.14.0 // indirect - golang.org/x/tools v0.39.0 // indirect + golang.org/x/tools v0.40.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 gonum.org/v1/gonum v0.16.0 // 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-20251111163417-95abcf5c77ba // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2 // indirect google.golang.org/grpc v1.77.0 // indirect - google.golang.org/protobuf v1.36.10 // indirect + google.golang.org/protobuf v1.36.11 // indirect gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect - gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect + gopkg.in/evanphx/json-patch.v4 v4.13.0 // 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 @@ -446,20 +448,20 @@ require ( 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.34.2 // indirect - k8s.io/apiextensions-apiserver v0.34.2 // indirect - k8s.io/apiserver v0.34.2 // indirect - k8s.io/client-go v0.34.2 // indirect - k8s.io/component-base v0.34.2 // indirect + k8s.io/api v0.34.3 // indirect + k8s.io/apiextensions-apiserver v0.34.3 // indirect + k8s.io/apiserver v0.34.3 // indirect + k8s.io/client-go v0.34.3 // indirect + k8s.io/component-base v0.34.3 // indirect k8s.io/klog/v2 v2.130.1 // indirect - k8s.io/kms v0.34.2 // indirect - k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 // indirect + k8s.io/kms v0.34.3 // indirect + k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 // indirect modernc.org/libc v1.66.10 // indirect modernc.org/mathutil v1.7.1 // indirect modernc.org/memory v1.11.0 // indirect modernc.org/sqlite v1.40.1 // indirect - sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2 // indirect - sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect + sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.34.0 // indirect + sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect sigs.k8s.io/randfill v1.0.0 // indirect sigs.k8s.io/structured-merge-diff/v6 v6.3.1 // indirect sigs.k8s.io/yaml v1.6.0 // indirect diff --git a/apps/iam/go.sum b/apps/iam/go.sum index cf4535fbe71..4584bbd9cc1 100644 --- a/apps/iam/go.sum +++ b/apps/iam/go.sum @@ -2,8 +2,8 @@ buf.build/gen/go/parca-dev/parca/connectrpc/go v1.18.1-20250703125925-3f0fcf4bff buf.build/gen/go/parca-dev/parca/connectrpc/go v1.18.1-20250703125925-3f0fcf4bff96.1/go.mod h1:pjl83IqpNF7Lm/lOPMLQ5IIfCg+yTu2A9OgYTcEncCs= buf.build/gen/go/parca-dev/parca/protocolbuffers/go v1.36.2-20250703125925-3f0fcf4bff96.1 h1:9nqE/pDc/HXAXiD5pZncPywjAzWgKuBkFFYgdK2lVU8= buf.build/gen/go/parca-dev/parca/protocolbuffers/go v1.36.2-20250703125925-3f0fcf4bff96.1/go.mod h1:1M7nlq2ljfzb95x9LaA2j1gYIvDkVZii58mGvTa9ExM= -cel.dev/expr v0.24.0 h1:56OvJKSH3hDGL0ml5uSxZmz3/3Pq4tJ+fb1unVLAFcY= -cel.dev/expr v0.24.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw= +cel.dev/expr v0.25.1 h1:1KrZg61W6TWSxuNZ37Xy49ps13NUovb66QLprthtwi4= +cel.dev/expr v0.25.1/go.mod h1:hrXvqGP6G6gyx8UAHSHJ5RGk//1Oj5nXQ2NI02Nrsg4= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7hw= @@ -84,8 +84,8 @@ cloud.google.com/go/trace v1.11.6 h1:2O2zjPzqPYAHrn3OKl029qlqG6W8ZdYaOWRyr8NgMT4 cloud.google.com/go/trace v1.11.6/go.mod h1:GA855OeDEBiBMzcckLPE2kDunIpC72N+Pq8WFieFjnI= connectrpc.com/connect v1.18.1 h1:PAg7CjSAGvscaf6YZKUefjoih5Z/qYkyaTrBW8xvYPw= connectrpc.com/connect v1.18.1/go.mod h1:0292hj1rnx8oFrStN7cB4jjVBeqs+Yx5yDIC2prWDO8= -cuelabs.dev/go/oci/ociregistry v0.0.0-20240906074133-82eb438dd565 h1:R5wwEcbEZSBmeyg91MJZTxfd7WpBo2jPof3AYjRbxwY= -cuelabs.dev/go/oci/ociregistry v0.0.0-20240906074133-82eb438dd565/go.mod h1:5A4xfTzHTXfeVJBU6RAUf+QrlfTCW+017q/QiW+sMLg= +cuelabs.dev/go/oci/ociregistry v0.0.0-20251212221603-3adeb8663819 h1:Zh+Ur3OsoWpvALHPLT45nOekHkgOt+IOfutBbPqM17I= +cuelabs.dev/go/oci/ociregistry v0.0.0-20251212221603-3adeb8663819/go.mod h1:WjmQxb+W6nVNCgj8nXrF24lIz95AHwnSl36tpjDZSU8= cuelang.org/go v0.11.1 h1:pV+49MX1mmvDm8Qh3Za3M786cty8VKPWzQ1Ho4gZRP0= cuelang.org/go v0.11.1/go.mod h1:PBY6XvPUswPPJ2inpvUozP9mebDVTXaeehQikhZPBz0= dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8= @@ -150,6 +150,8 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 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/DATA-DOG/go-sqlmock v1.5.2 h1:OcvFkGmslmlZibjAjaHm3L//6LiuBgolP7OputlJIzU= +github.com/DATA-DOG/go-sqlmock v1.5.2/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ+JlNzwDqpNU= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/FZambia/eagle v0.2.0 h1:1kQaZpJvbkvAXFRE/9K2ucBMuVqo+E29EMLYB74hIis= github.com/FZambia/eagle v0.2.0/go.mod h1:LKMYBwGYhao5sJI0TppvQ4SvvldFj9gITxrl8NvGwG0= @@ -356,8 +358,8 @@ github.com/blugelabs/ice v1.0.0/go.mod h1:gNfFPk5zM+yxJROhthxhVQYjpBO9amuxWXJQ2L github.com/blugelabs/ice/v2 v2.0.1 h1:mzHbntLjk2v7eDRgoXCgzOsPKN1Tenu9Svo6l9cTLS4= github.com/blugelabs/ice/v2 v2.0.1/go.mod h1:QxAWSPNwZwsIqS25c3lbIPFQrVvT1sphf5x5DfMLH5M= 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/bradfitz/gomemcache v0.0.0-20250403215159-8d39553ac7cf h1:TqhNAT4zKbTdLa62d2HDBFdvgSbIGB3eJE8HqhgiL9I= +github.com/bradfitz/gomemcache v0.0.0-20250403215159-8d39553ac7cf/go.mod h1:r5xuitiExdLAJ09PR7vBVENGvp4ZuTBeWTGtxuX3K+c= 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= @@ -426,8 +428,8 @@ github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3Ee github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4= github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= -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/coreos/go-systemd/v22 v22.6.0 h1:aGVa/v8B7hpb0TKl0MWoAavPDmHvobFe5R5zn0bCJWo= +github.com/coreos/go-systemd/v22 v22.6.0/go.mod h1:iG+pp635Fo7ZmV/j14KUcmEyWF+0X7Lua8rrTWzYgWU= 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/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= @@ -508,8 +510,8 @@ 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.13.0 h1:C4Bl2xDndpU6nJ4bc1jXd+uTmYPVUwkD6bFY/oTyCes= github.com/emicklei/go-restful/v3 v3.13.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= -github.com/emicklei/proto v1.13.2 h1:z/etSFO3uyXeuEsVPzfl56WNgzcvIr42aQazXaQmFZY= -github.com/emicklei/proto v1.13.2/go.mod h1:rn1FgRS/FANiZdD2djyH7TMA9jdRDcYQ9IEN9yvjX0A= +github.com/emicklei/proto v1.14.2 h1:wJPxPy2Xifja9cEMrcA/g08art5+7CGJNFNk35iXC1I= +github.com/emicklei/proto v1.14.2/go.mod h1:rn1FgRS/FANiZdD2djyH7TMA9jdRDcYQ9IEN9yvjX0A= 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= @@ -595,10 +597,10 @@ github.com/go-openapi/analysis v0.24.0 h1:vE/VFFkICKyYuTWYnplQ+aVr45vlG6NcZKC7Bd 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/jsonpointer v0.22.4 h1:dZtK82WlNpVLDW2jlA1YCiVJFVqkED1MegOUy9kR5T4= +github.com/go-openapi/jsonpointer v0.22.4/go.mod h1:elX9+UgznpFhgBuaMQ7iu4lvvX1nvNsesQ3oxmYTw80= +github.com/go-openapi/jsonreference v0.21.4 h1:24qaE2y9bx/q3uRK/qN+TDwbok1NhbSmGjjySRCHtC8= +github.com/go-openapi/jsonreference v0.21.4/go.mod h1:rIENPTjDbLpzQmQWCj5kKj3ZlmEh+EFVbz3RTUh30/4= 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= @@ -607,28 +609,36 @@ github.com/go-openapi/spec v0.22.0 h1:xT/EsX4frL3U09QviRIZXvkh80yibxQmtoEvyqug0T 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.1 h1:lpsStH0n2ittzTnbaSloVZLuB5+fvSY/+hnagBjSNZU= -github.com/go-openapi/swag v0.23.1/go.mod h1:STZs8TbRvEQQKUA+JZNAm3EWlgaOBGpyFDqQnDHMef0= -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/swag v0.25.4 h1:OyUPUFYDPDBMkqyxOTkqDYFnrhuhi9NR6QVUvIochMU= +github.com/go-openapi/swag v0.25.4/go.mod h1:zNfJ9WZABGHCFg2RnY0S4IOkAcVTzJ6z2Bi+Q4i6qFQ= +github.com/go-openapi/swag/cmdutils v0.25.4 h1:8rYhB5n6WawR192/BfUu2iVlxqVR9aRgGJP6WaBoW+4= +github.com/go-openapi/swag/cmdutils v0.25.4/go.mod h1:pdae/AFo6WxLl5L0rq87eRzVPm/XRHM3MoYgRMvG4A0= +github.com/go-openapi/swag/conv v0.25.4 h1:/Dd7p0LZXczgUcC/Ikm1+YqVzkEeCc9LnOWjfkpkfe4= +github.com/go-openapi/swag/conv v0.25.4/go.mod h1:3LXfie/lwoAv0NHoEuY1hjoFAYkvlqI/Bn5EQDD3PPU= +github.com/go-openapi/swag/fileutils v0.25.4 h1:2oI0XNW5y6UWZTC7vAxC8hmsK/tOkWXHJQH4lKjqw+Y= +github.com/go-openapi/swag/fileutils v0.25.4/go.mod h1:cdOT/PKbwcysVQ9Tpr0q20lQKH7MGhOEb6EwmHOirUk= +github.com/go-openapi/swag/jsonname v0.25.4 h1:bZH0+MsS03MbnwBXYhuTttMOqk+5KcQ9869Vye1bNHI= +github.com/go-openapi/swag/jsonname v0.25.4/go.mod h1:GPVEk9CWVhNvWhZgrnvRA6utbAltopbKwDu8mXNUMag= +github.com/go-openapi/swag/jsonutils v0.25.4 h1:VSchfbGhD4UTf4vCdR2F4TLBdLwHyUDTd1/q4i+jGZA= +github.com/go-openapi/swag/jsonutils v0.25.4/go.mod h1:7OYGXpvVFPn4PpaSdPHJBtF0iGnbEaTk8AvBkoWnaAY= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4 h1:IACsSvBhiNJwlDix7wq39SS2Fh7lUOCJRmx/4SN4sVo= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4/go.mod h1:Mt0Ost9l3cUzVv4OEZG+WSeoHwjWLnarzMePNDAOBiM= +github.com/go-openapi/swag/loading v0.25.4 h1:jN4MvLj0X6yhCDduRsxDDw1aHe+ZWoLjW+9ZQWIKn2s= +github.com/go-openapi/swag/loading v0.25.4/go.mod h1:rpUM1ZiyEP9+mNLIQUdMiD7dCETXvkkC30z53i+ftTE= +github.com/go-openapi/swag/mangling v0.25.4 h1:2b9kBJk9JvPgxr36V23FxJLdwBrpijI26Bx5JH4Hp48= +github.com/go-openapi/swag/mangling v0.25.4/go.mod h1:6dxwu6QyORHpIIApsdZgb6wBk/DPU15MdyYj/ikn0Hg= +github.com/go-openapi/swag/netutils v0.25.4 h1:Gqe6K71bGRb3ZQLusdI8p/y1KLgV4M/k+/HzVSqT8H0= +github.com/go-openapi/swag/netutils v0.25.4/go.mod h1:m2W8dtdaoX7oj9rEttLyTeEFFEBvnAx9qHd5nJEBzYg= +github.com/go-openapi/swag/stringutils v0.25.4 h1:O6dU1Rd8bej4HPA3/CLPciNBBDwZj9HiEpdVsb8B5A8= +github.com/go-openapi/swag/stringutils v0.25.4/go.mod h1:GTsRvhJW5xM5gkgiFe0fV3PUlFm0dr8vki6/VSRaZK0= +github.com/go-openapi/swag/typeutils v0.25.4 h1:1/fbZOUN472NTc39zpa+YGHn3jzHWhv42wAJSN91wRw= +github.com/go-openapi/swag/typeutils v0.25.4/go.mod h1:Ou7g//Wx8tTLS9vG0UmzfCsjZjKhpjxayRKTHXf2pTE= +github.com/go-openapi/swag/yamlutils v0.25.4 h1:6jdaeSItEUb7ioS9lFoCZ65Cne1/RZtPBZ9A56h92Sw= +github.com/go-openapi/swag/yamlutils v0.25.4/go.mod h1:MNzq1ulQu+yd8Kl7wPOut/YHAAU/H6hL91fF+E2RFwc= +github.com/go-openapi/testify/enable/yaml/v2 v2.0.2 h1:0+Y41Pz1NkbTHz8NngxTuAXxEodtNSI1WG1c/m5Akw4= +github.com/go-openapi/testify/enable/yaml/v2 v2.0.2/go.mod h1:kme83333GCtJQHXQ8UKX3IBZu6z8T5Dvy5+CW3NLUUg= +github.com/go-openapi/testify/v2 v2.0.2 h1:X999g3jeLcoY8qctY/c/Z8iBHTbwLz7R2WXd6Ub6wls= +github.com/go-openapi/testify/v2 v2.0.2/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= 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= @@ -735,8 +745,8 @@ 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.7.0 h1:qwTtogB15McXDaNqTZdzPJRHvaVJlAl+HVQnLmJEJxo= -github.com/google/gnostic-models v0.7.0/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ= +github.com/google/gnostic-models v0.7.1 h1:SisTfuFKJSKM5CPZkffwi6coztzzeYUhc3v4yxLWH8c= +github.com/google/gnostic-models v0.7.1/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= @@ -835,10 +845,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.48.5 h1:MS8l9fTZz+VbTfgApn09jw27GxhQ6fNOWGhC4ydvZmM= -github.com/grafana/grafana-app-sdk v0.48.5/go.mod h1:HJsMOSBmt/D/Ihs1SvagOwmXKi0coBMVHlfvdd+qe9Y= -github.com/grafana/grafana-app-sdk/logging v0.48.3 h1:72NUpGNiJXCNQz/on++YSsl38xuVYYBKv5kKQaOClX4= -github.com/grafana/grafana-app-sdk/logging v0.48.3/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA= +github.com/grafana/grafana-app-sdk v0.48.7 h1:9mF7nqkqP0QUYYDlznoOt+GIyjzj45wGfUHB32u2ZMo= +github.com/grafana/grafana-app-sdk v0.48.7/go.mod h1:DWsaaH39ZMHwSOSoUBaeW8paMrRaYsjRYlLwCJYd78k= +github.com/grafana/grafana-app-sdk/logging v0.48.7 h1:Oa5qg473gka5+W/WQk61Xbw4YdAv+wV2Z4bJtzeCaQw= +github.com/grafana/grafana-app-sdk/logging v0.48.7/go.mod h1:5u3KalezoBAAo2Y3ytDYDAIIPvEqFLLDSxeiK99QxDU= github.com/grafana/grafana-aws-sdk v1.3.0 h1:/bfJzP93rCel1GbWoRSq0oUo424MZXt8jAp2BK9w8tM= github.com/grafana/grafana-aws-sdk v1.3.0/go.mod h1:VGycF0JkCGKND2O5je1ucOqPJ0ZNhZYzV3c2bNBAaGk= github.com/grafana/grafana-azure-sdk-go/v2 v2.3.1 h1:FFcEA01tW+SmuJIuDbHOdgUBL+d7DPrZ2N4zwzPhfGk= @@ -1102,8 +1112,8 @@ github.com/madflojo/testcerts v1.4.0/go.mod h1:MW8sh39gLnkKh4K0Nc55AyHEDl9l/FBLD github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE= github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= -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/mailru/easyjson v0.9.1 h1:LbtsOm5WAswyWbvTEOqhypdPeZzHavpZx96/n553mR8= +github.com/mailru/easyjson v0.9.1/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= github.com/mattbaird/jsonpatch v0.0.0-20240118010651-0ba75a80ca38 h1:hQWBtNqRYrI7CWIaUSXXtNKR90KzcUA5uiuxFVWw7sU= github.com/mattbaird/jsonpatch v0.0.0-20240118010651-0ba75a80ca38/go.mod h1:M1qoD/MqPgTZIk0EWKB38wE28ACRfVcn+cU08jyArI0= github.com/mattermost/xml-roundtrip-validator v0.1.0 h1:RXbVD2UAl7A7nOTR4u7E3ILa4IbtvKBHw64LDsmu9hU= @@ -1351,8 +1361,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.67.3 h1:shd26MlnwTw5jksTDhC7rTQIteBxy+ZZDr3t7F2xN2Q= -github.com/prometheus/common v0.67.3/go.mod h1:gP0fq6YjjNCLssJCQp0yk4M8W6ikLURwkdd/YKtTbyI= +github.com/prometheus/common v0.67.4 h1:yR3NqWO1/UyO1w2PhUvXlGQs/PtFmoveVO0KZ4+Lvsc= +github.com/prometheus/common v0.67.4/go.mod h1:gP0fq6YjjNCLssJCQp0yk4M8W6ikLURwkdd/YKtTbyI= 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= @@ -1364,14 +1374,14 @@ github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsT github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= -github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= +github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws= +github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw= github.com/prometheus/prometheus v0.303.1 h1:He/2jRE6sB23Ew38AIoR1WRR3fCMgPlJA2E0obD2WSY= github.com/prometheus/prometheus v0.303.1/go.mod h1:WEq2ogBPZoLjj9x5K67VEk7ECR0nRD9XCjaOt1lsYck= github.com/prometheus/sigv4 v0.1.2 h1:R7570f8AoM5YnTUPFm3mjZH5q2k4D+I/phCWvZ4PXG8= github.com/prometheus/sigv4 v0.1.2/go.mod h1:GF9fwrvLgkQwDdQ5BXeV9XUSCH/IPNqzvAoaohfjqMU= -github.com/protocolbuffers/txtpbfmt v0.0.0-20241112170944-20d2c9ebc01d h1:HWfigq7lB31IeJL8iy7jkUmU/PG1Sr8jVGhS749dbUA= -github.com/protocolbuffers/txtpbfmt v0.0.0-20241112170944-20d2c9ebc01d/go.mod h1:jgxiZysxFPM+iWKwQwPR+y+Jvo54ARd4EisXxKYpB5c= +github.com/protocolbuffers/txtpbfmt v0.0.0-20251124094003-fcb97cc64c7b h1:fPVI9E6QNFYI0Ph3XpKUDrcAvbCifHvqYJcntFLPog8= +github.com/protocolbuffers/txtpbfmt v0.0.0-20251124094003-fcb97cc64c7b/go.mod h1:JSbkp0BviKovYYt9XunS95M3mLPibE9bGg+Y95DsEEY= 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/puzpuzpuz/xsync/v4 v4.2.0 h1:dlxm77dZj2c3rxq0/XNvvUKISAmovoXF4a4qM6Wvkr0= @@ -1448,8 +1458,8 @@ github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8 github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= 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/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU= +github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4= 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.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= @@ -1523,8 +1533,8 @@ github.com/wk8/go-ordered-map v1.0.0 h1:BV7z+2PaK8LTSd/mWgY12HyMAo5CEgkHqbkVq2th github.com/wk8/go-ordered-map v1.0.0/go.mod h1:9ZIbRunKbuvfPKyBP1SIKLcXNlv74YCOZ3t3VTS6gRk= 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/woodsbury/decimal128 v1.4.0 h1:xJATj7lLu4f2oObouMt2tgGiElE5gO6mSWUjQsBgUlc= +github.com/woodsbury/decimal128 v1.4.0/go.mod h1:BP46FUrVjVhdTbKT+XuQh2xfQaGki9LMIRJSFuh6THU= 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= @@ -1555,15 +1565,15 @@ gitlab.com/nyarla/go-crypt v0.0.0-20160106005555-d9a5dc2b789b/go.mod h1:T3BPAOm2 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.6.4 h1:7F6N7toCKcV72QmoUKa23yYLiiljMrT4xCeBL9BmXdo= -go.etcd.io/etcd/api/v3 v3.6.4/go.mod h1:eFhhvfR8Px1P6SEuLT600v+vrhdDTdcfMzmnxVXXSbk= +go.etcd.io/etcd/api/v3 v3.6.6 h1:mcaMp3+7JawWv69p6QShYWS8cIWUOl32bFLb6qf8pOQ= +go.etcd.io/etcd/api/v3 v3.6.6/go.mod h1:f/om26iXl2wSkcTA1zGQv8reJRSLVdoEBsi4JdfMrx4= go.etcd.io/etcd/client/pkg/v3 v3.5.4/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= -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/pkg/v3 v3.6.6 h1:uoqgzSOv2H9KlIF5O1Lsd8sW+eMLuV6wzE3q5GJGQNs= +go.etcd.io/etcd/client/pkg/v3 v3.6.6/go.mod h1:YngfUVmvsvOJ2rRgStIyHsKtOt9SZI2aBJrZiWJhCbI= 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.6.4 h1:YOMrCfMhRzY8NgtzUsHl8hC2EBSnuqbR3dh84Uryl7A= -go.etcd.io/etcd/client/v3 v3.6.4/go.mod h1:jaNNHCyg2FdALyKWnd7hxZXZxZANb0+KGY+YQaEMISo= +go.etcd.io/etcd/client/v3 v3.6.6 h1:G5z1wMf5B9SNexoxOHUGBaULurOZPIgGPsW6CN492ec= +go.etcd.io/etcd/client/v3 v3.6.6/go.mod h1:36Qv6baQ07znPR3+n7t+Rk5VHEzVYPvFfGmfF4wBHV8= go.etcd.io/etcd/pkg/v3 v3.6.4 h1:fy8bmXIec1Q35/jRZ0KOes8vuFxbvdN0aAFqmEfJZWA= go.etcd.io/etcd/pkg/v3 v3.6.4/go.mod h1:kKcYWP8gHuBRcteyv6MXWSN0+bVMnfgqiHueIZnKMtE= go.etcd.io/etcd/server/v3 v3.6.4 h1:LsCA7CzjVt+8WGrdsnh6RhC0XqCsLkBly3ve5rTxMAU= @@ -1595,19 +1605,19 @@ go.opentelemetry.io/contrib/detectors/gcp v1.38.0 h1:ZoYbqX7OaA/TAikspPl3ozPI6iY go.opentelemetry.io/contrib/detectors/gcp v1.38.0/go.mod h1:SU+iU7nu5ud4oCb3LQOhIZ3nRLj6FNVrKgtflbaf2ts= 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= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0/go.mod h1:fvPi2qXDqFs8M4B4fmJhE92TyQs9Ydjlg3RvfUp+NbQ= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.64.0 h1:RN3ifU8y4prNWeEnQp2kRRHz8UwonAEYZl8tUzHEXAk= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.64.0/go.mod h1:habDz3tEWiFANTo6oUE99EmaFUrCNYAAg3wiVmusm70= 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/instrumentation/net/http/otelhttp v0.64.0 h1:ssfIgGNANqpVFCndZvcuyKbl0g+UAVcbBcqGkG28H0Y= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.64.0/go.mod h1:GQ/474YrbE4Jx8gZ4q5I4hrhUzM6UPzyrqJYV2AqPoQ= 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.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= -go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= +go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48= +go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8= 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= @@ -1618,12 +1628,12 @@ go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0 h1:vl9 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/otlp/otlptrace v1.39.0 h1:f0cb2XPmrqn4XMy9PNliTgRKJgS5WcL/u0/WRYGz4t0= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0/go.mod h1:vnakAaFckOMiMtOIhFI2MNH4FYrZzXCYxmb1LlhoGz8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0 h1:in9O8ESIOlwJAEGTkkf34DesGRAc/Pn8qJ7k3r/42LM= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0/go.mod h1:Rp0EXBm5tfnv0WL+ARyO/PHBEaEAT8UUHQ6AGJcSq6c= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0 h1:Ckwye2FpXkYgiHX7fyVrN1uA/UYd9ounqqTuSNAv0k4= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0/go.mod h1:teIFJh5pW2y+AN7riv6IBPX2DuesS3HgP39mwOspKwU= 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= @@ -1635,20 +1645,20 @@ go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0/go.mod h1:mgIOzS7i 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.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= -go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= +go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0= +go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs= go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E= -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 v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18= +go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE= 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/log/logtest v0.0.0-20250521073539-a85ae98dcedc h1:uqxdywfHqqCl6LmZzI3pUnXT1RGFYyUgxj0AkWPFxi0= go.opentelemetry.io/otel/sdk/log/logtest v0.0.0-20250521073539-a85ae98dcedc/go.mod h1:TY/N/FT7dmFrP/r5ym3g0yysP1DefqGpAZr4f82P0dE= -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/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8= +go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew= go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ= -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/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI= +go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.opentelemetry.io/proto/otlp v1.9.0 h1:l706jCMITVouPOqEnii2fIAuO3IVGBRPV5ICjceRb/A= go.opentelemetry.io/proto/otlp v1.9.0/go.mod h1:xE+Cx5E/eEHw+ISFkwPLwCZefwVjY+pqKg1qcK03+/4= @@ -1690,8 +1700,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.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q= -golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4= +golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU= +golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0= 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= @@ -1705,8 +1715,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-20251002181428-27f1f14c8bb9 h1:TQwNpfvNkxAVlItJf6Cr5JTsVZoC/Sj7K3OZv2Pc14A= -golang.org/x/exp v0.0.0-20251002181428-27f1f14c8bb9/go.mod h1:TwQYMMnGpvZyc+JpB/UAuTNIsVJifOlSkrZkhcvpVUk= +golang.org/x/exp v0.0.0-20251209150349-8475f28825e9 h1:MDfG8Cvcqlt9XXrmEiD4epKn7VJHZO84hejP9Jmp0MM= +golang.org/x/exp v0.0.0-20251209150349-8475f28825e9/go.mod h1:EPRbTFwzwjXj9NpYyyrvenVh9Y+GFeEvMNh7Xuz7xgU= golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= 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= @@ -1733,8 +1743,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.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk= -golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc= +golang.org/x/mod v0.31.0 h1:HaW9xtz0+kOcWKwli0ZXy79Ix+UW/vOfmWI5QVd2tgI= +golang.org/x/mod v0.31.0/go.mod h1:43JraMp9cGx1Rx3AqioxrbrhNsLl2l/iNAvuBkrezpg= 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= @@ -1789,8 +1799,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.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= -golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= +golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= +golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= 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= @@ -1813,8 +1823,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.33.0 h1:4Q+qn+E5z8gPRJfmRy7C2gGG3T4jIprK6aSYgTXGRpo= -golang.org/x/oauth2 v0.33.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= +golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw= +golang.org/x/oauth2 v0.34.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= @@ -1827,8 +1837,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.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= -golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.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= @@ -1918,14 +1928,14 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 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.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= -golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/telemetry v0.0.0-20251111182119-bc8e575c7b54 h1:E2/AqCUMZGgd73TQkxUMcMla25GB9i/5HOdLr+uH7Vo= -golang.org/x/telemetry v0.0.0-20251111182119-bc8e575c7b54/go.mod h1:hKdjCMrbv9skySur+Nek8Hd0uJ0GuxJIoIX2payrIdQ= +golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= +golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/telemetry v0.0.0-20251203150158-8fff8a5912fc h1:bH6xUXay0AIFMElXG2rQ4uiE+7ncwtiOdPfYK1NK2XA= +golang.org/x/telemetry v0.0.0-20251203150158-8fff8a5912fc/go.mod h1:hKdjCMrbv9skySur+Nek8Hd0uJ0GuxJIoIX2payrIdQ= 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.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU= -golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254= +golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q= +golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg= 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= @@ -1935,8 +1945,8 @@ 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.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= -golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= +golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= +golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= 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= @@ -2003,8 +2013,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.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ= -golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ= +golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA= +golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc= 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= @@ -2157,10 +2167,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-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-20251111163417-95abcf5c77ba h1:B14OtaXuMaCQsl2deSvNkyPKIzq3BjfxQp8d00QyWx4= -google.golang.org/genproto/googleapis/api v0.0.0-20251111163417-95abcf5c77ba/go.mod h1:G5IanEx8/PgI9w6CFcYQf7jMtHQhZruvfM1i3qOqk5U= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba h1:UKgtfRM7Yh93Sya0Fo8ZzhDP4qBckrrxEr2oF5UIVb8= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= +google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2 h1:7LRqPCEdE4TP4/9psdaB7F2nhZFfBiGJomA5sojLWdU= +google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2/go.mod h1:+rXWjjaukWZun3mLfjmVnQi18E1AsFbDN9QdJ5YXLto= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2 h1:2I6GHUeJ/4shcDpoUlLs/2WPnhg7yJwvXtqcMJt9liA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.18.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= @@ -2211,8 +2221,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.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= -google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/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= @@ -2223,8 +2233,8 @@ gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8 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/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -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/evanphx/json-patch.v4 v4.13.0 h1:czT3CmqEaQ1aanPc5SdlgQrrEIb8w/wwCvWWnfEbYzo= +gopkg.in/evanphx/json-patch.v4 v4.13.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= @@ -2261,28 +2271,28 @@ 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.34.2 h1:fsSUNZhV+bnL6Aqrp6O7lMTy6o5x2C4XLjnh//8SLYY= -k8s.io/api v0.34.2/go.mod h1:MMBPaWlED2a8w4RSeanD76f7opUoypY8TFYkSM+3XHw= -k8s.io/apiextensions-apiserver v0.34.2 h1:WStKftnGeoKP4AZRz/BaAAEJvYp4mlZGN0UCv+uvsqo= -k8s.io/apiextensions-apiserver v0.34.2/go.mod h1:398CJrsgXF1wytdaanynDpJ67zG4Xq7yj91GrmYN2SE= -k8s.io/apimachinery v0.34.2 h1:zQ12Uk3eMHPxrsbUJgNF8bTauTVR2WgqJsTmwTE/NW4= -k8s.io/apimachinery v0.34.2/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= -k8s.io/apiserver v0.34.2 h1:2/yu8suwkmES7IzwlehAovo8dDE07cFRC7KMDb1+MAE= -k8s.io/apiserver v0.34.2/go.mod h1:gqJQy2yDOB50R3JUReHSFr+cwJnL8G1dzTA0YLEqAPI= -k8s.io/client-go v0.34.2 h1:Co6XiknN+uUZqiddlfAjT68184/37PS4QAzYvQvDR8M= -k8s.io/client-go v0.34.2/go.mod h1:2VYDl1XXJsdcAxw7BenFslRQX28Dxz91U9MWKjX97fE= -k8s.io/component-base v0.34.2 h1:HQRqK9x2sSAsd8+R4xxRirlTjowsg6fWCPwWYeSvogQ= -k8s.io/component-base v0.34.2/go.mod h1:9xw2FHJavUHBFpiGkZoKuYZ5pdtLKe97DEByaA+hHbM= +k8s.io/api v0.34.3 h1:D12sTP257/jSH2vHV2EDYrb16bS7ULlHpdNdNhEw2S4= +k8s.io/api v0.34.3/go.mod h1:PyVQBF886Q5RSQZOim7DybQjAbVs8g7gwJNhGtY5MBk= +k8s.io/apiextensions-apiserver v0.34.3 h1:p10fGlkDY09eWKOTeUSioxwLukJnm+KuDZdrW71y40g= +k8s.io/apiextensions-apiserver v0.34.3/go.mod h1:aujxvqGFRdb/cmXYfcRTeppN7S2XV/t7WMEc64zB5A0= +k8s.io/apimachinery v0.34.3 h1:/TB+SFEiQvN9HPldtlWOTp0hWbJ+fjU+wkxysf/aQnE= +k8s.io/apimachinery v0.34.3/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= +k8s.io/apiserver v0.34.3 h1:uGH1qpDvSiYG4HVFqc6A3L4CKiX+aBWDrrsxHYK0Bdo= +k8s.io/apiserver v0.34.3/go.mod h1:QPnnahMO5C2m3lm6fPW3+JmyQbvHZQ8uudAu/493P2w= +k8s.io/client-go v0.34.3 h1:wtYtpzy/OPNYf7WyNBTj3iUA0XaBHVqhv4Iv3tbrF5A= +k8s.io/client-go v0.34.3/go.mod h1:OxxeYagaP9Kdf78UrKLa3YZixMCfP6bgPwPwNBQBzpM= +k8s.io/component-base v0.34.3 h1:zsEgw6ELqK0XncCQomgO9DpUIzlrYuZYA0Cgo+JWpVk= +k8s.io/component-base v0.34.3/go.mod h1:5iIlD8wPfWE/xSHTRfbjuvUul2WZbI2nOUK65XL0E/c= 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.34.2 h1:91rj4MDZLyIT9KxG8J5/CcMH666Z88CF/xJQeuPfJc8= -k8s.io/kms v0.34.2/go.mod h1:s1CFkLG7w9eaTYvctOxosx88fl4spqmixnNpys0JAtM= -k8s.io/kube-aggregator v0.34.2 h1:Nn0Vksj67WHBL2x7bJ6vuxL44RbMTK6uRtXX+3vMVJk= -k8s.io/kube-aggregator v0.34.2/go.mod h1:/tp4cc/1p2AvICsS4mjjSJakdrbhcGbRmj0mdHTdR2Q= -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= +k8s.io/kms v0.34.3 h1:QzBOD0sk1bGQVMcZQAHGjtbP1iKZJUyhC6D0I+BTxIE= +k8s.io/kms v0.34.3/go.mod h1:s1CFkLG7w9eaTYvctOxosx88fl4spqmixnNpys0JAtM= +k8s.io/kube-aggregator v0.34.3 h1:rKsZWTD2As4dKuv+zzdJU0uo5H7bFlAEoSucai4mW6M= +k8s.io/kube-aggregator v0.34.3/go.mod h1:d4D8PV2FK4Qlq6u442FSum1tHPhK9tKdKBfH/A3R0I0= +k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e h1:iW9ChlU0cU16w8MpVYjXk12dqQ4BPFBEgif+ap7/hqQ= +k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e/go.mod h1:kdmbQkyfwUagLfXIad1y2TdrjPFWp2Q89B3qkRwf/pQ= +k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 h1:SjGebBtkBqHFOli+05xYbK8YF1Dzkbzn+gDM4X9T4Ck= +k8s.io/utils v0.0.0-20251002143259-bc988d571ff4/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= @@ -2313,10 +2323,10 @@ rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8 rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= -sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2 h1:jpcvIRr3GLoUoEKRkHKSmGjxb6lWwrBlJsXc+eUYQHM= -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/apiserver-network-proxy/konnectivity-client v0.34.0 h1:hSfpvjjTQXQY2Fol2CS0QHMNs/WI1MOSGzCm1KhM5ec= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.34.0/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw= +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg= +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/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.1 h1:JrhdFMqOd/+3ByqlP2I45kTOZmTRLBUm5pvRjeheg7E= diff --git a/apps/investigations/go.mod b/apps/investigations/go.mod index 3844fec2689..40677b56dab 100644 --- a/apps/investigations/go.mod +++ b/apps/investigations/go.mod @@ -3,15 +3,15 @@ module github.com/grafana/grafana/apps/investigations go 1.25.5 require ( - github.com/grafana/grafana-app-sdk v0.48.5 - k8s.io/apimachinery v0.34.2 + github.com/grafana/grafana-app-sdk v0.48.7 + k8s.io/apimachinery v0.34.3 k8s.io/klog/v2 v2.130.1 - k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 + k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e ) require ( github.com/beorn7/perks v1.0.1 // indirect - github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874 // indirect + github.com/bradfitz/gomemcache v0.0.0-20250403215159-8d39553ac7cf // 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 @@ -21,23 +21,33 @@ require ( github.com/getkin/kin-openapi v0.133.0 // 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.1 // indirect - github.com/go-openapi/swag/jsonname v0.25.1 // indirect + github.com/go-openapi/jsonpointer v0.22.4 // indirect + github.com/go-openapi/jsonreference v0.21.4 // indirect + github.com/go-openapi/swag v0.25.4 // indirect + github.com/go-openapi/swag/cmdutils v0.25.4 // indirect + github.com/go-openapi/swag/conv v0.25.4 // indirect + github.com/go-openapi/swag/fileutils v0.25.4 // indirect + github.com/go-openapi/swag/jsonname v0.25.4 // indirect + github.com/go-openapi/swag/jsonutils v0.25.4 // indirect + github.com/go-openapi/swag/loading v0.25.4 // indirect + github.com/go-openapi/swag/mangling v0.25.4 // indirect + github.com/go-openapi/swag/netutils v0.25.4 // indirect + github.com/go-openapi/swag/stringutils v0.25.4 // indirect + github.com/go-openapi/swag/typeutils v0.25.4 // indirect + github.com/go-openapi/swag/yamlutils v0.25.4 // 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/gnostic-models v0.7.1 // 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/grafana-app-sdk/logging v0.48.3 // indirect + github.com/grafana/grafana-app-sdk/logging v0.48.7 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3 // 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/mailru/easyjson v0.9.1 // 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 @@ -50,42 +60,42 @@ require ( 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.3 // indirect - github.com/prometheus/procfs v0.16.1 // indirect + github.com/prometheus/common v0.67.4 // indirect + github.com/prometheus/procfs v0.19.2 // 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/woodsbury/decimal128 v1.4.0 // indirect github.com/x448/float16 v0.8.4 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // 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/otel v1.39.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0 // indirect + go.opentelemetry.io/otel/metric v1.39.0 // indirect + go.opentelemetry.io/otel/sdk v1.39.0 // indirect + go.opentelemetry.io/otel/trace v1.39.0 // indirect go.opentelemetry.io/proto/otlp v1.9.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.47.0 // indirect - golang.org/x/oauth2 v0.33.0 // indirect - golang.org/x/sync v0.18.0 // indirect - golang.org/x/sys v0.38.0 // indirect - golang.org/x/term v0.37.0 // indirect - golang.org/x/text v0.31.0 // indirect + golang.org/x/net v0.48.0 // indirect + golang.org/x/oauth2 v0.34.0 // indirect + golang.org/x/sync v0.19.0 // indirect + golang.org/x/sys v0.39.0 // indirect + golang.org/x/term v0.38.0 // indirect + golang.org/x/text v0.32.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-20251111163417-95abcf5c77ba // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2 // indirect google.golang.org/grpc v1.77.0 // indirect - google.golang.org/protobuf v1.36.10 // indirect + google.golang.org/protobuf v1.36.11 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/api v0.34.2 // indirect - k8s.io/apiextensions-apiserver v0.34.2 // indirect - k8s.io/client-go v0.34.2 // indirect - k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 // indirect - sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect + k8s.io/api v0.34.3 // indirect + k8s.io/apiextensions-apiserver v0.34.3 // indirect + k8s.io/client-go v0.34.3 // indirect + k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 // indirect + sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect sigs.k8s.io/randfill v1.0.0 // indirect sigs.k8s.io/structured-merge-diff/v6 v6.3.1 // indirect sigs.k8s.io/yaml v1.6.0 // indirect diff --git a/apps/investigations/go.sum b/apps/investigations/go.sum index 3df8e8b5ebe..e5233ba82c9 100644 --- a/apps/investigations/go.sum +++ b/apps/investigations/go.sum @@ -1,7 +1,7 @@ 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/bradfitz/gomemcache v0.0.0-20250403215159-8d39553ac7cf h1:TqhNAT4zKbTdLa62d2HDBFdvgSbIGB3eJE8HqhgiL9I= +github.com/bradfitz/gomemcache v0.0.0-20250403215159-8d39553ac7cf/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= @@ -23,14 +23,40 @@ 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.1 h1:lpsStH0n2ittzTnbaSloVZLuB5+fvSY/+hnagBjSNZU= -github.com/go-openapi/swag v0.23.1/go.mod h1:STZs8TbRvEQQKUA+JZNAm3EWlgaOBGpyFDqQnDHMef0= -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/jsonpointer v0.22.4 h1:dZtK82WlNpVLDW2jlA1YCiVJFVqkED1MegOUy9kR5T4= +github.com/go-openapi/jsonpointer v0.22.4/go.mod h1:elX9+UgznpFhgBuaMQ7iu4lvvX1nvNsesQ3oxmYTw80= +github.com/go-openapi/jsonreference v0.21.4 h1:24qaE2y9bx/q3uRK/qN+TDwbok1NhbSmGjjySRCHtC8= +github.com/go-openapi/jsonreference v0.21.4/go.mod h1:rIENPTjDbLpzQmQWCj5kKj3ZlmEh+EFVbz3RTUh30/4= +github.com/go-openapi/swag v0.25.4 h1:OyUPUFYDPDBMkqyxOTkqDYFnrhuhi9NR6QVUvIochMU= +github.com/go-openapi/swag v0.25.4/go.mod h1:zNfJ9WZABGHCFg2RnY0S4IOkAcVTzJ6z2Bi+Q4i6qFQ= +github.com/go-openapi/swag/cmdutils v0.25.4 h1:8rYhB5n6WawR192/BfUu2iVlxqVR9aRgGJP6WaBoW+4= +github.com/go-openapi/swag/cmdutils v0.25.4/go.mod h1:pdae/AFo6WxLl5L0rq87eRzVPm/XRHM3MoYgRMvG4A0= +github.com/go-openapi/swag/conv v0.25.4 h1:/Dd7p0LZXczgUcC/Ikm1+YqVzkEeCc9LnOWjfkpkfe4= +github.com/go-openapi/swag/conv v0.25.4/go.mod h1:3LXfie/lwoAv0NHoEuY1hjoFAYkvlqI/Bn5EQDD3PPU= +github.com/go-openapi/swag/fileutils v0.25.4 h1:2oI0XNW5y6UWZTC7vAxC8hmsK/tOkWXHJQH4lKjqw+Y= +github.com/go-openapi/swag/fileutils v0.25.4/go.mod h1:cdOT/PKbwcysVQ9Tpr0q20lQKH7MGhOEb6EwmHOirUk= +github.com/go-openapi/swag/jsonname v0.25.4 h1:bZH0+MsS03MbnwBXYhuTttMOqk+5KcQ9869Vye1bNHI= +github.com/go-openapi/swag/jsonname v0.25.4/go.mod h1:GPVEk9CWVhNvWhZgrnvRA6utbAltopbKwDu8mXNUMag= +github.com/go-openapi/swag/jsonutils v0.25.4 h1:VSchfbGhD4UTf4vCdR2F4TLBdLwHyUDTd1/q4i+jGZA= +github.com/go-openapi/swag/jsonutils v0.25.4/go.mod h1:7OYGXpvVFPn4PpaSdPHJBtF0iGnbEaTk8AvBkoWnaAY= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4 h1:IACsSvBhiNJwlDix7wq39SS2Fh7lUOCJRmx/4SN4sVo= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4/go.mod h1:Mt0Ost9l3cUzVv4OEZG+WSeoHwjWLnarzMePNDAOBiM= +github.com/go-openapi/swag/loading v0.25.4 h1:jN4MvLj0X6yhCDduRsxDDw1aHe+ZWoLjW+9ZQWIKn2s= +github.com/go-openapi/swag/loading v0.25.4/go.mod h1:rpUM1ZiyEP9+mNLIQUdMiD7dCETXvkkC30z53i+ftTE= +github.com/go-openapi/swag/mangling v0.25.4 h1:2b9kBJk9JvPgxr36V23FxJLdwBrpijI26Bx5JH4Hp48= +github.com/go-openapi/swag/mangling v0.25.4/go.mod h1:6dxwu6QyORHpIIApsdZgb6wBk/DPU15MdyYj/ikn0Hg= +github.com/go-openapi/swag/netutils v0.25.4 h1:Gqe6K71bGRb3ZQLusdI8p/y1KLgV4M/k+/HzVSqT8H0= +github.com/go-openapi/swag/netutils v0.25.4/go.mod h1:m2W8dtdaoX7oj9rEttLyTeEFFEBvnAx9qHd5nJEBzYg= +github.com/go-openapi/swag/stringutils v0.25.4 h1:O6dU1Rd8bej4HPA3/CLPciNBBDwZj9HiEpdVsb8B5A8= +github.com/go-openapi/swag/stringutils v0.25.4/go.mod h1:GTsRvhJW5xM5gkgiFe0fV3PUlFm0dr8vki6/VSRaZK0= +github.com/go-openapi/swag/typeutils v0.25.4 h1:1/fbZOUN472NTc39zpa+YGHn3jzHWhv42wAJSN91wRw= +github.com/go-openapi/swag/typeutils v0.25.4/go.mod h1:Ou7g//Wx8tTLS9vG0UmzfCsjZjKhpjxayRKTHXf2pTE= +github.com/go-openapi/swag/yamlutils v0.25.4 h1:6jdaeSItEUb7ioS9lFoCZ65Cne1/RZtPBZ9A56h92Sw= +github.com/go-openapi/swag/yamlutils v0.25.4/go.mod h1:MNzq1ulQu+yd8Kl7wPOut/YHAAU/H6hL91fF+E2RFwc= +github.com/go-openapi/testify/enable/yaml/v2 v2.0.2 h1:0+Y41Pz1NkbTHz8NngxTuAXxEodtNSI1WG1c/m5Akw4= +github.com/go-openapi/testify/enable/yaml/v2 v2.0.2/go.mod h1:kme83333GCtJQHXQ8UKX3IBZu6z8T5Dvy5+CW3NLUUg= +github.com/go-openapi/testify/v2 v2.0.2 h1:X999g3jeLcoY8qctY/c/Z8iBHTbwLz7R2WXd6Ub6wls= +github.com/go-openapi/testify/v2 v2.0.2/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= 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= @@ -39,8 +65,8 @@ 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/gnostic-models v0.7.1 h1:SisTfuFKJSKM5CPZkffwi6coztzzeYUhc3v4yxLWH8c= +github.com/google/gnostic-models v0.7.1/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= @@ -48,10 +74,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.48.5 h1:MS8l9fTZz+VbTfgApn09jw27GxhQ6fNOWGhC4ydvZmM= -github.com/grafana/grafana-app-sdk v0.48.5/go.mod h1:HJsMOSBmt/D/Ihs1SvagOwmXKi0coBMVHlfvdd+qe9Y= -github.com/grafana/grafana-app-sdk/logging v0.48.3 h1:72NUpGNiJXCNQz/on++YSsl38xuVYYBKv5kKQaOClX4= -github.com/grafana/grafana-app-sdk/logging v0.48.3/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA= +github.com/grafana/grafana-app-sdk v0.48.7 h1:9mF7nqkqP0QUYYDlznoOt+GIyjzj45wGfUHB32u2ZMo= +github.com/grafana/grafana-app-sdk v0.48.7/go.mod h1:DWsaaH39ZMHwSOSoUBaeW8paMrRaYsjRYlLwCJYd78k= +github.com/grafana/grafana-app-sdk/logging v0.48.7 h1:Oa5qg473gka5+W/WQk61Xbw4YdAv+wV2Z4bJtzeCaQw= +github.com/grafana/grafana-app-sdk/logging v0.48.7/go.mod h1:5u3KalezoBAAo2Y3ytDYDAIIPvEqFLLDSxeiK99QxDU= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3 h1:NmZ1PKzSTQbuGHw9DGPFomqkkLWMC+vZCkfs+FHv1Vg= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3/go.mod h1:zQrxl1YP88HQlA6i9c63DSVPFklWpGX4OWAc9bFuaH4= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -73,8 +99,8 @@ 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/mailru/easyjson v0.9.1 h1:LbtsOm5WAswyWbvTEOqhypdPeZzHavpZx96/n553mR8= +github.com/mailru/easyjson v0.9.1/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= @@ -95,8 +121,6 @@ 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/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= @@ -104,10 +128,10 @@ github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h 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.3 h1:shd26MlnwTw5jksTDhC7rTQIteBxy+ZZDr3t7F2xN2Q= -github.com/prometheus/common v0.67.3/go.mod h1:gP0fq6YjjNCLssJCQp0yk4M8W6ikLURwkdd/YKtTbyI= -github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= -github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= +github.com/prometheus/common v0.67.4 h1:yR3NqWO1/UyO1w2PhUvXlGQs/PtFmoveVO0KZ4+Lvsc= +github.com/prometheus/common v0.67.4/go.mod h1:gP0fq6YjjNCLssJCQp0yk4M8W6ikLURwkdd/YKtTbyI= +github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws= +github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw= 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= @@ -122,30 +146,30 @@ 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/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/woodsbury/decimal128 v1.4.0 h1:xJATj7lLu4f2oObouMt2tgGiElE5gO6mSWUjQsBgUlc= +github.com/woodsbury/decimal128 v1.4.0/go.mod h1:BP46FUrVjVhdTbKT+XuQh2xfQaGki9LMIRJSFuh6THU= 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.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= -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/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48= +go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0 h1:f0cb2XPmrqn4XMy9PNliTgRKJgS5WcL/u0/WRYGz4t0= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0/go.mod h1:vnakAaFckOMiMtOIhFI2MNH4FYrZzXCYxmb1LlhoGz8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0 h1:in9O8ESIOlwJAEGTkkf34DesGRAc/Pn8qJ7k3r/42LM= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0/go.mod h1:Rp0EXBm5tfnv0WL+ARyO/PHBEaEAT8UUHQ6AGJcSq6c= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0 h1:Ckwye2FpXkYgiHX7fyVrN1uA/UYd9ounqqTuSNAv0k4= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0/go.mod h1:teIFJh5pW2y+AN7riv6IBPX2DuesS3HgP39mwOspKwU= +go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0= +go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs= +go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18= +go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE= +go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8= +go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew= +go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI= +go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA= go.opentelemetry.io/proto/otlp v1.9.0 h1:l706jCMITVouPOqEnii2fIAuO3IVGBRPV5ICjceRb/A= go.opentelemetry.io/proto/otlp v1.9.0/go.mod h1:xE+Cx5E/eEHw+ISFkwPLwCZefwVjY+pqKg1qcK03+/4= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= @@ -163,34 +187,34 @@ 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.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= -golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= -golang.org/x/oauth2 v0.33.0 h1:4Q+qn+E5z8gPRJfmRy7C2gGG3T4jIprK6aSYgTXGRpo= -golang.org/x/oauth2 v0.33.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= +golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= +golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= +golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw= +golang.org/x/oauth2 v0.34.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.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= -golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.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.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= -golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU= -golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254= +golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= +golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q= +golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg= 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.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= -golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= +golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= +golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= 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.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ= -golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ= +golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA= +golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc= 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= @@ -199,39 +223,39 @@ 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-20251111163417-95abcf5c77ba h1:B14OtaXuMaCQsl2deSvNkyPKIzq3BjfxQp8d00QyWx4= -google.golang.org/genproto/googleapis/api v0.0.0-20251111163417-95abcf5c77ba/go.mod h1:G5IanEx8/PgI9w6CFcYQf7jMtHQhZruvfM1i3qOqk5U= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba h1:UKgtfRM7Yh93Sya0Fo8ZzhDP4qBckrrxEr2oF5UIVb8= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= +google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2 h1:7LRqPCEdE4TP4/9psdaB7F2nhZFfBiGJomA5sojLWdU= +google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2/go.mod h1:+rXWjjaukWZun3mLfjmVnQi18E1AsFbDN9QdJ5YXLto= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2 h1:2I6GHUeJ/4shcDpoUlLs/2WPnhg7yJwvXtqcMJt9liA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM= google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= -google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= -google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/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/evanphx/json-patch.v4 v4.13.0 h1:czT3CmqEaQ1aanPc5SdlgQrrEIb8w/wwCvWWnfEbYzo= +gopkg.in/evanphx/json-patch.v4 v4.13.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.2 h1:fsSUNZhV+bnL6Aqrp6O7lMTy6o5x2C4XLjnh//8SLYY= -k8s.io/api v0.34.2/go.mod h1:MMBPaWlED2a8w4RSeanD76f7opUoypY8TFYkSM+3XHw= -k8s.io/apiextensions-apiserver v0.34.2 h1:WStKftnGeoKP4AZRz/BaAAEJvYp4mlZGN0UCv+uvsqo= -k8s.io/apiextensions-apiserver v0.34.2/go.mod h1:398CJrsgXF1wytdaanynDpJ67zG4Xq7yj91GrmYN2SE= -k8s.io/apimachinery v0.34.2 h1:zQ12Uk3eMHPxrsbUJgNF8bTauTVR2WgqJsTmwTE/NW4= -k8s.io/apimachinery v0.34.2/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= -k8s.io/client-go v0.34.2 h1:Co6XiknN+uUZqiddlfAjT68184/37PS4QAzYvQvDR8M= -k8s.io/client-go v0.34.2/go.mod h1:2VYDl1XXJsdcAxw7BenFslRQX28Dxz91U9MWKjX97fE= +k8s.io/api v0.34.3 h1:D12sTP257/jSH2vHV2EDYrb16bS7ULlHpdNdNhEw2S4= +k8s.io/api v0.34.3/go.mod h1:PyVQBF886Q5RSQZOim7DybQjAbVs8g7gwJNhGtY5MBk= +k8s.io/apiextensions-apiserver v0.34.3 h1:p10fGlkDY09eWKOTeUSioxwLukJnm+KuDZdrW71y40g= +k8s.io/apiextensions-apiserver v0.34.3/go.mod h1:aujxvqGFRdb/cmXYfcRTeppN7S2XV/t7WMEc64zB5A0= +k8s.io/apimachinery v0.34.3 h1:/TB+SFEiQvN9HPldtlWOTp0hWbJ+fjU+wkxysf/aQnE= +k8s.io/apimachinery v0.34.3/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= +k8s.io/client-go v0.34.3 h1:wtYtpzy/OPNYf7WyNBTj3iUA0XaBHVqhv4Iv3tbrF5A= +k8s.io/client-go v0.34.3/go.mod h1:OxxeYagaP9Kdf78UrKLa3YZixMCfP6bgPwPwNBQBzpM= 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= +k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e h1:iW9ChlU0cU16w8MpVYjXk12dqQ4BPFBEgif+ap7/hqQ= +k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e/go.mod h1:kdmbQkyfwUagLfXIad1y2TdrjPFWp2Q89B3qkRwf/pQ= +k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 h1:SjGebBtkBqHFOli+05xYbK8YF1Dzkbzn+gDM4X9T4Ck= +k8s.io/utils v0.0.0-20251002143259-bc988d571ff4/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg= +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/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.1 h1:JrhdFMqOd/+3ByqlP2I45kTOZmTRLBUm5pvRjeheg7E= diff --git a/apps/logsdrilldown/go.mod b/apps/logsdrilldown/go.mod index 2a35278d19a..e210773eb2e 100644 --- a/apps/logsdrilldown/go.mod +++ b/apps/logsdrilldown/go.mod @@ -3,15 +3,15 @@ module github.com/grafana/grafana/apps/logsdrilldown go 1.25.5 require ( - github.com/grafana/grafana-app-sdk v0.48.5 - github.com/grafana/grafana-app-sdk/logging v0.48.3 - k8s.io/apimachinery v0.34.2 - k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 + github.com/grafana/grafana-app-sdk v0.48.7 + github.com/grafana/grafana-app-sdk/logging v0.48.7 + k8s.io/apimachinery v0.34.3 + k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e ) require ( github.com/beorn7/perks v1.0.1 // indirect - github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874 // indirect + github.com/bradfitz/gomemcache v0.0.0-20250403215159-8d39553ac7cf // 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 @@ -21,13 +21,23 @@ require ( github.com/getkin/kin-openapi v0.133.0 // 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.1 // indirect - github.com/go-openapi/swag/jsonname v0.25.1 // indirect + github.com/go-openapi/jsonpointer v0.22.4 // indirect + github.com/go-openapi/jsonreference v0.21.4 // indirect + github.com/go-openapi/swag v0.25.4 // indirect + github.com/go-openapi/swag/cmdutils v0.25.4 // indirect + github.com/go-openapi/swag/conv v0.25.4 // indirect + github.com/go-openapi/swag/fileutils v0.25.4 // indirect + github.com/go-openapi/swag/jsonname v0.25.4 // indirect + github.com/go-openapi/swag/jsonutils v0.25.4 // indirect + github.com/go-openapi/swag/loading v0.25.4 // indirect + github.com/go-openapi/swag/mangling v0.25.4 // indirect + github.com/go-openapi/swag/netutils v0.25.4 // indirect + github.com/go-openapi/swag/stringutils v0.25.4 // indirect + github.com/go-openapi/swag/typeutils v0.25.4 // indirect + github.com/go-openapi/swag/yamlutils v0.25.4 // 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/gnostic-models v0.7.1 // 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 @@ -36,7 +46,7 @@ require ( 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/mailru/easyjson v0.9.1 // 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 @@ -49,43 +59,43 @@ require ( 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.3 // indirect - github.com/prometheus/procfs v0.16.1 // indirect + github.com/prometheus/common v0.67.4 // indirect + github.com/prometheus/procfs v0.19.2 // 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/woodsbury/decimal128 v1.4.0 // indirect github.com/x448/float16 v0.8.4 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // 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/otel v1.39.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0 // indirect + go.opentelemetry.io/otel/metric v1.39.0 // indirect + go.opentelemetry.io/otel/sdk v1.39.0 // indirect + go.opentelemetry.io/otel/trace v1.39.0 // indirect go.opentelemetry.io/proto/otlp v1.9.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.47.0 // indirect - golang.org/x/oauth2 v0.33.0 // indirect - golang.org/x/sync v0.18.0 // indirect - golang.org/x/sys v0.38.0 // indirect - golang.org/x/term v0.37.0 // indirect - golang.org/x/text v0.31.0 // indirect + golang.org/x/net v0.48.0 // indirect + golang.org/x/oauth2 v0.34.0 // indirect + golang.org/x/sync v0.19.0 // indirect + golang.org/x/sys v0.39.0 // indirect + golang.org/x/term v0.38.0 // indirect + golang.org/x/text v0.32.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-20251111163417-95abcf5c77ba // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2 // indirect google.golang.org/grpc v1.77.0 // indirect - google.golang.org/protobuf v1.36.10 // indirect + google.golang.org/protobuf v1.36.11 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/api v0.34.2 // indirect - k8s.io/apiextensions-apiserver v0.34.2 // indirect - k8s.io/client-go v0.34.2 // indirect + k8s.io/api v0.34.3 // indirect + k8s.io/apiextensions-apiserver v0.34.3 // indirect + k8s.io/client-go v0.34.3 // 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 + k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 // indirect + sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect sigs.k8s.io/randfill v1.0.0 // indirect sigs.k8s.io/structured-merge-diff/v6 v6.3.1 // indirect sigs.k8s.io/yaml v1.6.0 // indirect diff --git a/apps/logsdrilldown/go.sum b/apps/logsdrilldown/go.sum index 3df8e8b5ebe..e5233ba82c9 100644 --- a/apps/logsdrilldown/go.sum +++ b/apps/logsdrilldown/go.sum @@ -1,7 +1,7 @@ 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/bradfitz/gomemcache v0.0.0-20250403215159-8d39553ac7cf h1:TqhNAT4zKbTdLa62d2HDBFdvgSbIGB3eJE8HqhgiL9I= +github.com/bradfitz/gomemcache v0.0.0-20250403215159-8d39553ac7cf/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= @@ -23,14 +23,40 @@ 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.1 h1:lpsStH0n2ittzTnbaSloVZLuB5+fvSY/+hnagBjSNZU= -github.com/go-openapi/swag v0.23.1/go.mod h1:STZs8TbRvEQQKUA+JZNAm3EWlgaOBGpyFDqQnDHMef0= -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/jsonpointer v0.22.4 h1:dZtK82WlNpVLDW2jlA1YCiVJFVqkED1MegOUy9kR5T4= +github.com/go-openapi/jsonpointer v0.22.4/go.mod h1:elX9+UgznpFhgBuaMQ7iu4lvvX1nvNsesQ3oxmYTw80= +github.com/go-openapi/jsonreference v0.21.4 h1:24qaE2y9bx/q3uRK/qN+TDwbok1NhbSmGjjySRCHtC8= +github.com/go-openapi/jsonreference v0.21.4/go.mod h1:rIENPTjDbLpzQmQWCj5kKj3ZlmEh+EFVbz3RTUh30/4= +github.com/go-openapi/swag v0.25.4 h1:OyUPUFYDPDBMkqyxOTkqDYFnrhuhi9NR6QVUvIochMU= +github.com/go-openapi/swag v0.25.4/go.mod h1:zNfJ9WZABGHCFg2RnY0S4IOkAcVTzJ6z2Bi+Q4i6qFQ= +github.com/go-openapi/swag/cmdutils v0.25.4 h1:8rYhB5n6WawR192/BfUu2iVlxqVR9aRgGJP6WaBoW+4= +github.com/go-openapi/swag/cmdutils v0.25.4/go.mod h1:pdae/AFo6WxLl5L0rq87eRzVPm/XRHM3MoYgRMvG4A0= +github.com/go-openapi/swag/conv v0.25.4 h1:/Dd7p0LZXczgUcC/Ikm1+YqVzkEeCc9LnOWjfkpkfe4= +github.com/go-openapi/swag/conv v0.25.4/go.mod h1:3LXfie/lwoAv0NHoEuY1hjoFAYkvlqI/Bn5EQDD3PPU= +github.com/go-openapi/swag/fileutils v0.25.4 h1:2oI0XNW5y6UWZTC7vAxC8hmsK/tOkWXHJQH4lKjqw+Y= +github.com/go-openapi/swag/fileutils v0.25.4/go.mod h1:cdOT/PKbwcysVQ9Tpr0q20lQKH7MGhOEb6EwmHOirUk= +github.com/go-openapi/swag/jsonname v0.25.4 h1:bZH0+MsS03MbnwBXYhuTttMOqk+5KcQ9869Vye1bNHI= +github.com/go-openapi/swag/jsonname v0.25.4/go.mod h1:GPVEk9CWVhNvWhZgrnvRA6utbAltopbKwDu8mXNUMag= +github.com/go-openapi/swag/jsonutils v0.25.4 h1:VSchfbGhD4UTf4vCdR2F4TLBdLwHyUDTd1/q4i+jGZA= +github.com/go-openapi/swag/jsonutils v0.25.4/go.mod h1:7OYGXpvVFPn4PpaSdPHJBtF0iGnbEaTk8AvBkoWnaAY= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4 h1:IACsSvBhiNJwlDix7wq39SS2Fh7lUOCJRmx/4SN4sVo= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4/go.mod h1:Mt0Ost9l3cUzVv4OEZG+WSeoHwjWLnarzMePNDAOBiM= +github.com/go-openapi/swag/loading v0.25.4 h1:jN4MvLj0X6yhCDduRsxDDw1aHe+ZWoLjW+9ZQWIKn2s= +github.com/go-openapi/swag/loading v0.25.4/go.mod h1:rpUM1ZiyEP9+mNLIQUdMiD7dCETXvkkC30z53i+ftTE= +github.com/go-openapi/swag/mangling v0.25.4 h1:2b9kBJk9JvPgxr36V23FxJLdwBrpijI26Bx5JH4Hp48= +github.com/go-openapi/swag/mangling v0.25.4/go.mod h1:6dxwu6QyORHpIIApsdZgb6wBk/DPU15MdyYj/ikn0Hg= +github.com/go-openapi/swag/netutils v0.25.4 h1:Gqe6K71bGRb3ZQLusdI8p/y1KLgV4M/k+/HzVSqT8H0= +github.com/go-openapi/swag/netutils v0.25.4/go.mod h1:m2W8dtdaoX7oj9rEttLyTeEFFEBvnAx9qHd5nJEBzYg= +github.com/go-openapi/swag/stringutils v0.25.4 h1:O6dU1Rd8bej4HPA3/CLPciNBBDwZj9HiEpdVsb8B5A8= +github.com/go-openapi/swag/stringutils v0.25.4/go.mod h1:GTsRvhJW5xM5gkgiFe0fV3PUlFm0dr8vki6/VSRaZK0= +github.com/go-openapi/swag/typeutils v0.25.4 h1:1/fbZOUN472NTc39zpa+YGHn3jzHWhv42wAJSN91wRw= +github.com/go-openapi/swag/typeutils v0.25.4/go.mod h1:Ou7g//Wx8tTLS9vG0UmzfCsjZjKhpjxayRKTHXf2pTE= +github.com/go-openapi/swag/yamlutils v0.25.4 h1:6jdaeSItEUb7ioS9lFoCZ65Cne1/RZtPBZ9A56h92Sw= +github.com/go-openapi/swag/yamlutils v0.25.4/go.mod h1:MNzq1ulQu+yd8Kl7wPOut/YHAAU/H6hL91fF+E2RFwc= +github.com/go-openapi/testify/enable/yaml/v2 v2.0.2 h1:0+Y41Pz1NkbTHz8NngxTuAXxEodtNSI1WG1c/m5Akw4= +github.com/go-openapi/testify/enable/yaml/v2 v2.0.2/go.mod h1:kme83333GCtJQHXQ8UKX3IBZu6z8T5Dvy5+CW3NLUUg= +github.com/go-openapi/testify/v2 v2.0.2 h1:X999g3jeLcoY8qctY/c/Z8iBHTbwLz7R2WXd6Ub6wls= +github.com/go-openapi/testify/v2 v2.0.2/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= 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= @@ -39,8 +65,8 @@ 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/gnostic-models v0.7.1 h1:SisTfuFKJSKM5CPZkffwi6coztzzeYUhc3v4yxLWH8c= +github.com/google/gnostic-models v0.7.1/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= @@ -48,10 +74,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.48.5 h1:MS8l9fTZz+VbTfgApn09jw27GxhQ6fNOWGhC4ydvZmM= -github.com/grafana/grafana-app-sdk v0.48.5/go.mod h1:HJsMOSBmt/D/Ihs1SvagOwmXKi0coBMVHlfvdd+qe9Y= -github.com/grafana/grafana-app-sdk/logging v0.48.3 h1:72NUpGNiJXCNQz/on++YSsl38xuVYYBKv5kKQaOClX4= -github.com/grafana/grafana-app-sdk/logging v0.48.3/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA= +github.com/grafana/grafana-app-sdk v0.48.7 h1:9mF7nqkqP0QUYYDlznoOt+GIyjzj45wGfUHB32u2ZMo= +github.com/grafana/grafana-app-sdk v0.48.7/go.mod h1:DWsaaH39ZMHwSOSoUBaeW8paMrRaYsjRYlLwCJYd78k= +github.com/grafana/grafana-app-sdk/logging v0.48.7 h1:Oa5qg473gka5+W/WQk61Xbw4YdAv+wV2Z4bJtzeCaQw= +github.com/grafana/grafana-app-sdk/logging v0.48.7/go.mod h1:5u3KalezoBAAo2Y3ytDYDAIIPvEqFLLDSxeiK99QxDU= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3 h1:NmZ1PKzSTQbuGHw9DGPFomqkkLWMC+vZCkfs+FHv1Vg= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3/go.mod h1:zQrxl1YP88HQlA6i9c63DSVPFklWpGX4OWAc9bFuaH4= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -73,8 +99,8 @@ 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/mailru/easyjson v0.9.1 h1:LbtsOm5WAswyWbvTEOqhypdPeZzHavpZx96/n553mR8= +github.com/mailru/easyjson v0.9.1/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= @@ -95,8 +121,6 @@ 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/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= @@ -104,10 +128,10 @@ github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h 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.3 h1:shd26MlnwTw5jksTDhC7rTQIteBxy+ZZDr3t7F2xN2Q= -github.com/prometheus/common v0.67.3/go.mod h1:gP0fq6YjjNCLssJCQp0yk4M8W6ikLURwkdd/YKtTbyI= -github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= -github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= +github.com/prometheus/common v0.67.4 h1:yR3NqWO1/UyO1w2PhUvXlGQs/PtFmoveVO0KZ4+Lvsc= +github.com/prometheus/common v0.67.4/go.mod h1:gP0fq6YjjNCLssJCQp0yk4M8W6ikLURwkdd/YKtTbyI= +github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws= +github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw= 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= @@ -122,30 +146,30 @@ 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/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/woodsbury/decimal128 v1.4.0 h1:xJATj7lLu4f2oObouMt2tgGiElE5gO6mSWUjQsBgUlc= +github.com/woodsbury/decimal128 v1.4.0/go.mod h1:BP46FUrVjVhdTbKT+XuQh2xfQaGki9LMIRJSFuh6THU= 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.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= -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/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48= +go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0 h1:f0cb2XPmrqn4XMy9PNliTgRKJgS5WcL/u0/WRYGz4t0= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0/go.mod h1:vnakAaFckOMiMtOIhFI2MNH4FYrZzXCYxmb1LlhoGz8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0 h1:in9O8ESIOlwJAEGTkkf34DesGRAc/Pn8qJ7k3r/42LM= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0/go.mod h1:Rp0EXBm5tfnv0WL+ARyO/PHBEaEAT8UUHQ6AGJcSq6c= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0 h1:Ckwye2FpXkYgiHX7fyVrN1uA/UYd9ounqqTuSNAv0k4= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0/go.mod h1:teIFJh5pW2y+AN7riv6IBPX2DuesS3HgP39mwOspKwU= +go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0= +go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs= +go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18= +go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE= +go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8= +go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew= +go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI= +go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA= go.opentelemetry.io/proto/otlp v1.9.0 h1:l706jCMITVouPOqEnii2fIAuO3IVGBRPV5ICjceRb/A= go.opentelemetry.io/proto/otlp v1.9.0/go.mod h1:xE+Cx5E/eEHw+ISFkwPLwCZefwVjY+pqKg1qcK03+/4= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= @@ -163,34 +187,34 @@ 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.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= -golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= -golang.org/x/oauth2 v0.33.0 h1:4Q+qn+E5z8gPRJfmRy7C2gGG3T4jIprK6aSYgTXGRpo= -golang.org/x/oauth2 v0.33.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= +golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= +golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= +golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw= +golang.org/x/oauth2 v0.34.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.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= -golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.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.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= -golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU= -golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254= +golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= +golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q= +golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg= 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.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= -golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= +golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= +golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= 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.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ= -golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ= +golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA= +golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc= 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= @@ -199,39 +223,39 @@ 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-20251111163417-95abcf5c77ba h1:B14OtaXuMaCQsl2deSvNkyPKIzq3BjfxQp8d00QyWx4= -google.golang.org/genproto/googleapis/api v0.0.0-20251111163417-95abcf5c77ba/go.mod h1:G5IanEx8/PgI9w6CFcYQf7jMtHQhZruvfM1i3qOqk5U= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba h1:UKgtfRM7Yh93Sya0Fo8ZzhDP4qBckrrxEr2oF5UIVb8= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= +google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2 h1:7LRqPCEdE4TP4/9psdaB7F2nhZFfBiGJomA5sojLWdU= +google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2/go.mod h1:+rXWjjaukWZun3mLfjmVnQi18E1AsFbDN9QdJ5YXLto= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2 h1:2I6GHUeJ/4shcDpoUlLs/2WPnhg7yJwvXtqcMJt9liA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM= google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= -google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= -google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/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/evanphx/json-patch.v4 v4.13.0 h1:czT3CmqEaQ1aanPc5SdlgQrrEIb8w/wwCvWWnfEbYzo= +gopkg.in/evanphx/json-patch.v4 v4.13.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.2 h1:fsSUNZhV+bnL6Aqrp6O7lMTy6o5x2C4XLjnh//8SLYY= -k8s.io/api v0.34.2/go.mod h1:MMBPaWlED2a8w4RSeanD76f7opUoypY8TFYkSM+3XHw= -k8s.io/apiextensions-apiserver v0.34.2 h1:WStKftnGeoKP4AZRz/BaAAEJvYp4mlZGN0UCv+uvsqo= -k8s.io/apiextensions-apiserver v0.34.2/go.mod h1:398CJrsgXF1wytdaanynDpJ67zG4Xq7yj91GrmYN2SE= -k8s.io/apimachinery v0.34.2 h1:zQ12Uk3eMHPxrsbUJgNF8bTauTVR2WgqJsTmwTE/NW4= -k8s.io/apimachinery v0.34.2/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= -k8s.io/client-go v0.34.2 h1:Co6XiknN+uUZqiddlfAjT68184/37PS4QAzYvQvDR8M= -k8s.io/client-go v0.34.2/go.mod h1:2VYDl1XXJsdcAxw7BenFslRQX28Dxz91U9MWKjX97fE= +k8s.io/api v0.34.3 h1:D12sTP257/jSH2vHV2EDYrb16bS7ULlHpdNdNhEw2S4= +k8s.io/api v0.34.3/go.mod h1:PyVQBF886Q5RSQZOim7DybQjAbVs8g7gwJNhGtY5MBk= +k8s.io/apiextensions-apiserver v0.34.3 h1:p10fGlkDY09eWKOTeUSioxwLukJnm+KuDZdrW71y40g= +k8s.io/apiextensions-apiserver v0.34.3/go.mod h1:aujxvqGFRdb/cmXYfcRTeppN7S2XV/t7WMEc64zB5A0= +k8s.io/apimachinery v0.34.3 h1:/TB+SFEiQvN9HPldtlWOTp0hWbJ+fjU+wkxysf/aQnE= +k8s.io/apimachinery v0.34.3/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= +k8s.io/client-go v0.34.3 h1:wtYtpzy/OPNYf7WyNBTj3iUA0XaBHVqhv4Iv3tbrF5A= +k8s.io/client-go v0.34.3/go.mod h1:OxxeYagaP9Kdf78UrKLa3YZixMCfP6bgPwPwNBQBzpM= 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= +k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e h1:iW9ChlU0cU16w8MpVYjXk12dqQ4BPFBEgif+ap7/hqQ= +k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e/go.mod h1:kdmbQkyfwUagLfXIad1y2TdrjPFWp2Q89B3qkRwf/pQ= +k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 h1:SjGebBtkBqHFOli+05xYbK8YF1Dzkbzn+gDM4X9T4Ck= +k8s.io/utils v0.0.0-20251002143259-bc988d571ff4/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg= +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/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.1 h1:JrhdFMqOd/+3ByqlP2I45kTOZmTRLBUm5pvRjeheg7E= diff --git a/apps/playlist/go.mod b/apps/playlist/go.mod index ae38e3d0cd3..dd749f9fede 100644 --- a/apps/playlist/go.mod +++ b/apps/playlist/go.mod @@ -3,16 +3,16 @@ module github.com/grafana/grafana/apps/playlist go 1.25.5 require ( - github.com/grafana/grafana-app-sdk v0.48.5 - k8s.io/apimachinery v0.34.2 - k8s.io/client-go v0.34.2 + github.com/grafana/grafana-app-sdk v0.48.7 + k8s.io/apimachinery v0.34.3 + k8s.io/client-go v0.34.3 k8s.io/klog/v2 v2.130.1 - k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 + k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e ) require ( github.com/beorn7/perks v1.0.1 // indirect - github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874 // indirect + github.com/bradfitz/gomemcache v0.0.0-20250403215159-8d39553ac7cf // 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 @@ -22,23 +22,33 @@ require ( github.com/getkin/kin-openapi v0.133.0 // 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.1 // indirect - github.com/go-openapi/swag/jsonname v0.25.1 // indirect + github.com/go-openapi/jsonpointer v0.22.4 // indirect + github.com/go-openapi/jsonreference v0.21.4 // indirect + github.com/go-openapi/swag v0.25.4 // indirect + github.com/go-openapi/swag/cmdutils v0.25.4 // indirect + github.com/go-openapi/swag/conv v0.25.4 // indirect + github.com/go-openapi/swag/fileutils v0.25.4 // indirect + github.com/go-openapi/swag/jsonname v0.25.4 // indirect + github.com/go-openapi/swag/jsonutils v0.25.4 // indirect + github.com/go-openapi/swag/loading v0.25.4 // indirect + github.com/go-openapi/swag/mangling v0.25.4 // indirect + github.com/go-openapi/swag/netutils v0.25.4 // indirect + github.com/go-openapi/swag/stringutils v0.25.4 // indirect + github.com/go-openapi/swag/typeutils v0.25.4 // indirect + github.com/go-openapi/swag/yamlutils v0.25.4 // 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/gnostic-models v0.7.1 // 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/grafana-app-sdk/logging v0.48.3 // indirect + github.com/grafana/grafana-app-sdk/logging v0.48.7 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3 // 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/mailru/easyjson v0.9.1 // 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 @@ -51,41 +61,41 @@ require ( 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.3 // indirect - github.com/prometheus/procfs v0.16.1 // indirect + github.com/prometheus/common v0.67.4 // indirect + github.com/prometheus/procfs v0.19.2 // 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/woodsbury/decimal128 v1.4.0 // indirect github.com/x448/float16 v0.8.4 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // 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/otel v1.39.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0 // indirect + go.opentelemetry.io/otel/metric v1.39.0 // indirect + go.opentelemetry.io/otel/sdk v1.39.0 // indirect + go.opentelemetry.io/otel/trace v1.39.0 // indirect go.opentelemetry.io/proto/otlp v1.9.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.47.0 // indirect - golang.org/x/oauth2 v0.33.0 // indirect - golang.org/x/sync v0.18.0 // indirect - golang.org/x/sys v0.38.0 // indirect - golang.org/x/term v0.37.0 // indirect - golang.org/x/text v0.31.0 // indirect + golang.org/x/net v0.48.0 // indirect + golang.org/x/oauth2 v0.34.0 // indirect + golang.org/x/sync v0.19.0 // indirect + golang.org/x/sys v0.39.0 // indirect + golang.org/x/term v0.38.0 // indirect + golang.org/x/text v0.32.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-20251111163417-95abcf5c77ba // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2 // indirect google.golang.org/grpc v1.77.0 // indirect - google.golang.org/protobuf v1.36.10 // indirect + google.golang.org/protobuf v1.36.11 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/api v0.34.2 // indirect - k8s.io/apiextensions-apiserver v0.34.2 // indirect - k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 // indirect - sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect + k8s.io/api v0.34.3 // indirect + k8s.io/apiextensions-apiserver v0.34.3 // indirect + k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 // indirect + sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect sigs.k8s.io/randfill v1.0.0 // indirect sigs.k8s.io/structured-merge-diff/v6 v6.3.1 // indirect sigs.k8s.io/yaml v1.6.0 // indirect diff --git a/apps/playlist/go.sum b/apps/playlist/go.sum index 3df8e8b5ebe..e5233ba82c9 100644 --- a/apps/playlist/go.sum +++ b/apps/playlist/go.sum @@ -1,7 +1,7 @@ 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/bradfitz/gomemcache v0.0.0-20250403215159-8d39553ac7cf h1:TqhNAT4zKbTdLa62d2HDBFdvgSbIGB3eJE8HqhgiL9I= +github.com/bradfitz/gomemcache v0.0.0-20250403215159-8d39553ac7cf/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= @@ -23,14 +23,40 @@ 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.1 h1:lpsStH0n2ittzTnbaSloVZLuB5+fvSY/+hnagBjSNZU= -github.com/go-openapi/swag v0.23.1/go.mod h1:STZs8TbRvEQQKUA+JZNAm3EWlgaOBGpyFDqQnDHMef0= -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/jsonpointer v0.22.4 h1:dZtK82WlNpVLDW2jlA1YCiVJFVqkED1MegOUy9kR5T4= +github.com/go-openapi/jsonpointer v0.22.4/go.mod h1:elX9+UgznpFhgBuaMQ7iu4lvvX1nvNsesQ3oxmYTw80= +github.com/go-openapi/jsonreference v0.21.4 h1:24qaE2y9bx/q3uRK/qN+TDwbok1NhbSmGjjySRCHtC8= +github.com/go-openapi/jsonreference v0.21.4/go.mod h1:rIENPTjDbLpzQmQWCj5kKj3ZlmEh+EFVbz3RTUh30/4= +github.com/go-openapi/swag v0.25.4 h1:OyUPUFYDPDBMkqyxOTkqDYFnrhuhi9NR6QVUvIochMU= +github.com/go-openapi/swag v0.25.4/go.mod h1:zNfJ9WZABGHCFg2RnY0S4IOkAcVTzJ6z2Bi+Q4i6qFQ= +github.com/go-openapi/swag/cmdutils v0.25.4 h1:8rYhB5n6WawR192/BfUu2iVlxqVR9aRgGJP6WaBoW+4= +github.com/go-openapi/swag/cmdutils v0.25.4/go.mod h1:pdae/AFo6WxLl5L0rq87eRzVPm/XRHM3MoYgRMvG4A0= +github.com/go-openapi/swag/conv v0.25.4 h1:/Dd7p0LZXczgUcC/Ikm1+YqVzkEeCc9LnOWjfkpkfe4= +github.com/go-openapi/swag/conv v0.25.4/go.mod h1:3LXfie/lwoAv0NHoEuY1hjoFAYkvlqI/Bn5EQDD3PPU= +github.com/go-openapi/swag/fileutils v0.25.4 h1:2oI0XNW5y6UWZTC7vAxC8hmsK/tOkWXHJQH4lKjqw+Y= +github.com/go-openapi/swag/fileutils v0.25.4/go.mod h1:cdOT/PKbwcysVQ9Tpr0q20lQKH7MGhOEb6EwmHOirUk= +github.com/go-openapi/swag/jsonname v0.25.4 h1:bZH0+MsS03MbnwBXYhuTttMOqk+5KcQ9869Vye1bNHI= +github.com/go-openapi/swag/jsonname v0.25.4/go.mod h1:GPVEk9CWVhNvWhZgrnvRA6utbAltopbKwDu8mXNUMag= +github.com/go-openapi/swag/jsonutils v0.25.4 h1:VSchfbGhD4UTf4vCdR2F4TLBdLwHyUDTd1/q4i+jGZA= +github.com/go-openapi/swag/jsonutils v0.25.4/go.mod h1:7OYGXpvVFPn4PpaSdPHJBtF0iGnbEaTk8AvBkoWnaAY= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4 h1:IACsSvBhiNJwlDix7wq39SS2Fh7lUOCJRmx/4SN4sVo= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4/go.mod h1:Mt0Ost9l3cUzVv4OEZG+WSeoHwjWLnarzMePNDAOBiM= +github.com/go-openapi/swag/loading v0.25.4 h1:jN4MvLj0X6yhCDduRsxDDw1aHe+ZWoLjW+9ZQWIKn2s= +github.com/go-openapi/swag/loading v0.25.4/go.mod h1:rpUM1ZiyEP9+mNLIQUdMiD7dCETXvkkC30z53i+ftTE= +github.com/go-openapi/swag/mangling v0.25.4 h1:2b9kBJk9JvPgxr36V23FxJLdwBrpijI26Bx5JH4Hp48= +github.com/go-openapi/swag/mangling v0.25.4/go.mod h1:6dxwu6QyORHpIIApsdZgb6wBk/DPU15MdyYj/ikn0Hg= +github.com/go-openapi/swag/netutils v0.25.4 h1:Gqe6K71bGRb3ZQLusdI8p/y1KLgV4M/k+/HzVSqT8H0= +github.com/go-openapi/swag/netutils v0.25.4/go.mod h1:m2W8dtdaoX7oj9rEttLyTeEFFEBvnAx9qHd5nJEBzYg= +github.com/go-openapi/swag/stringutils v0.25.4 h1:O6dU1Rd8bej4HPA3/CLPciNBBDwZj9HiEpdVsb8B5A8= +github.com/go-openapi/swag/stringutils v0.25.4/go.mod h1:GTsRvhJW5xM5gkgiFe0fV3PUlFm0dr8vki6/VSRaZK0= +github.com/go-openapi/swag/typeutils v0.25.4 h1:1/fbZOUN472NTc39zpa+YGHn3jzHWhv42wAJSN91wRw= +github.com/go-openapi/swag/typeutils v0.25.4/go.mod h1:Ou7g//Wx8tTLS9vG0UmzfCsjZjKhpjxayRKTHXf2pTE= +github.com/go-openapi/swag/yamlutils v0.25.4 h1:6jdaeSItEUb7ioS9lFoCZ65Cne1/RZtPBZ9A56h92Sw= +github.com/go-openapi/swag/yamlutils v0.25.4/go.mod h1:MNzq1ulQu+yd8Kl7wPOut/YHAAU/H6hL91fF+E2RFwc= +github.com/go-openapi/testify/enable/yaml/v2 v2.0.2 h1:0+Y41Pz1NkbTHz8NngxTuAXxEodtNSI1WG1c/m5Akw4= +github.com/go-openapi/testify/enable/yaml/v2 v2.0.2/go.mod h1:kme83333GCtJQHXQ8UKX3IBZu6z8T5Dvy5+CW3NLUUg= +github.com/go-openapi/testify/v2 v2.0.2 h1:X999g3jeLcoY8qctY/c/Z8iBHTbwLz7R2WXd6Ub6wls= +github.com/go-openapi/testify/v2 v2.0.2/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= 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= @@ -39,8 +65,8 @@ 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/gnostic-models v0.7.1 h1:SisTfuFKJSKM5CPZkffwi6coztzzeYUhc3v4yxLWH8c= +github.com/google/gnostic-models v0.7.1/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= @@ -48,10 +74,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.48.5 h1:MS8l9fTZz+VbTfgApn09jw27GxhQ6fNOWGhC4ydvZmM= -github.com/grafana/grafana-app-sdk v0.48.5/go.mod h1:HJsMOSBmt/D/Ihs1SvagOwmXKi0coBMVHlfvdd+qe9Y= -github.com/grafana/grafana-app-sdk/logging v0.48.3 h1:72NUpGNiJXCNQz/on++YSsl38xuVYYBKv5kKQaOClX4= -github.com/grafana/grafana-app-sdk/logging v0.48.3/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA= +github.com/grafana/grafana-app-sdk v0.48.7 h1:9mF7nqkqP0QUYYDlznoOt+GIyjzj45wGfUHB32u2ZMo= +github.com/grafana/grafana-app-sdk v0.48.7/go.mod h1:DWsaaH39ZMHwSOSoUBaeW8paMrRaYsjRYlLwCJYd78k= +github.com/grafana/grafana-app-sdk/logging v0.48.7 h1:Oa5qg473gka5+W/WQk61Xbw4YdAv+wV2Z4bJtzeCaQw= +github.com/grafana/grafana-app-sdk/logging v0.48.7/go.mod h1:5u3KalezoBAAo2Y3ytDYDAIIPvEqFLLDSxeiK99QxDU= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3 h1:NmZ1PKzSTQbuGHw9DGPFomqkkLWMC+vZCkfs+FHv1Vg= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3/go.mod h1:zQrxl1YP88HQlA6i9c63DSVPFklWpGX4OWAc9bFuaH4= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -73,8 +99,8 @@ 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/mailru/easyjson v0.9.1 h1:LbtsOm5WAswyWbvTEOqhypdPeZzHavpZx96/n553mR8= +github.com/mailru/easyjson v0.9.1/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= @@ -95,8 +121,6 @@ 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/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= @@ -104,10 +128,10 @@ github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h 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.3 h1:shd26MlnwTw5jksTDhC7rTQIteBxy+ZZDr3t7F2xN2Q= -github.com/prometheus/common v0.67.3/go.mod h1:gP0fq6YjjNCLssJCQp0yk4M8W6ikLURwkdd/YKtTbyI= -github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= -github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= +github.com/prometheus/common v0.67.4 h1:yR3NqWO1/UyO1w2PhUvXlGQs/PtFmoveVO0KZ4+Lvsc= +github.com/prometheus/common v0.67.4/go.mod h1:gP0fq6YjjNCLssJCQp0yk4M8W6ikLURwkdd/YKtTbyI= +github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws= +github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw= 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= @@ -122,30 +146,30 @@ 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/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/woodsbury/decimal128 v1.4.0 h1:xJATj7lLu4f2oObouMt2tgGiElE5gO6mSWUjQsBgUlc= +github.com/woodsbury/decimal128 v1.4.0/go.mod h1:BP46FUrVjVhdTbKT+XuQh2xfQaGki9LMIRJSFuh6THU= 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.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= -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/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48= +go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0 h1:f0cb2XPmrqn4XMy9PNliTgRKJgS5WcL/u0/WRYGz4t0= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0/go.mod h1:vnakAaFckOMiMtOIhFI2MNH4FYrZzXCYxmb1LlhoGz8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0 h1:in9O8ESIOlwJAEGTkkf34DesGRAc/Pn8qJ7k3r/42LM= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0/go.mod h1:Rp0EXBm5tfnv0WL+ARyO/PHBEaEAT8UUHQ6AGJcSq6c= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0 h1:Ckwye2FpXkYgiHX7fyVrN1uA/UYd9ounqqTuSNAv0k4= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0/go.mod h1:teIFJh5pW2y+AN7riv6IBPX2DuesS3HgP39mwOspKwU= +go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0= +go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs= +go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18= +go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE= +go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8= +go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew= +go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI= +go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA= go.opentelemetry.io/proto/otlp v1.9.0 h1:l706jCMITVouPOqEnii2fIAuO3IVGBRPV5ICjceRb/A= go.opentelemetry.io/proto/otlp v1.9.0/go.mod h1:xE+Cx5E/eEHw+ISFkwPLwCZefwVjY+pqKg1qcK03+/4= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= @@ -163,34 +187,34 @@ 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.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= -golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= -golang.org/x/oauth2 v0.33.0 h1:4Q+qn+E5z8gPRJfmRy7C2gGG3T4jIprK6aSYgTXGRpo= -golang.org/x/oauth2 v0.33.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= +golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= +golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= +golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw= +golang.org/x/oauth2 v0.34.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.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= -golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.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.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= -golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU= -golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254= +golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= +golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q= +golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg= 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.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= -golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= +golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= +golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= 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.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ= -golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ= +golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA= +golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc= 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= @@ -199,39 +223,39 @@ 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-20251111163417-95abcf5c77ba h1:B14OtaXuMaCQsl2deSvNkyPKIzq3BjfxQp8d00QyWx4= -google.golang.org/genproto/googleapis/api v0.0.0-20251111163417-95abcf5c77ba/go.mod h1:G5IanEx8/PgI9w6CFcYQf7jMtHQhZruvfM1i3qOqk5U= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba h1:UKgtfRM7Yh93Sya0Fo8ZzhDP4qBckrrxEr2oF5UIVb8= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= +google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2 h1:7LRqPCEdE4TP4/9psdaB7F2nhZFfBiGJomA5sojLWdU= +google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2/go.mod h1:+rXWjjaukWZun3mLfjmVnQi18E1AsFbDN9QdJ5YXLto= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2 h1:2I6GHUeJ/4shcDpoUlLs/2WPnhg7yJwvXtqcMJt9liA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM= google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= -google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= -google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/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/evanphx/json-patch.v4 v4.13.0 h1:czT3CmqEaQ1aanPc5SdlgQrrEIb8w/wwCvWWnfEbYzo= +gopkg.in/evanphx/json-patch.v4 v4.13.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.2 h1:fsSUNZhV+bnL6Aqrp6O7lMTy6o5x2C4XLjnh//8SLYY= -k8s.io/api v0.34.2/go.mod h1:MMBPaWlED2a8w4RSeanD76f7opUoypY8TFYkSM+3XHw= -k8s.io/apiextensions-apiserver v0.34.2 h1:WStKftnGeoKP4AZRz/BaAAEJvYp4mlZGN0UCv+uvsqo= -k8s.io/apiextensions-apiserver v0.34.2/go.mod h1:398CJrsgXF1wytdaanynDpJ67zG4Xq7yj91GrmYN2SE= -k8s.io/apimachinery v0.34.2 h1:zQ12Uk3eMHPxrsbUJgNF8bTauTVR2WgqJsTmwTE/NW4= -k8s.io/apimachinery v0.34.2/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= -k8s.io/client-go v0.34.2 h1:Co6XiknN+uUZqiddlfAjT68184/37PS4QAzYvQvDR8M= -k8s.io/client-go v0.34.2/go.mod h1:2VYDl1XXJsdcAxw7BenFslRQX28Dxz91U9MWKjX97fE= +k8s.io/api v0.34.3 h1:D12sTP257/jSH2vHV2EDYrb16bS7ULlHpdNdNhEw2S4= +k8s.io/api v0.34.3/go.mod h1:PyVQBF886Q5RSQZOim7DybQjAbVs8g7gwJNhGtY5MBk= +k8s.io/apiextensions-apiserver v0.34.3 h1:p10fGlkDY09eWKOTeUSioxwLukJnm+KuDZdrW71y40g= +k8s.io/apiextensions-apiserver v0.34.3/go.mod h1:aujxvqGFRdb/cmXYfcRTeppN7S2XV/t7WMEc64zB5A0= +k8s.io/apimachinery v0.34.3 h1:/TB+SFEiQvN9HPldtlWOTp0hWbJ+fjU+wkxysf/aQnE= +k8s.io/apimachinery v0.34.3/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= +k8s.io/client-go v0.34.3 h1:wtYtpzy/OPNYf7WyNBTj3iUA0XaBHVqhv4Iv3tbrF5A= +k8s.io/client-go v0.34.3/go.mod h1:OxxeYagaP9Kdf78UrKLa3YZixMCfP6bgPwPwNBQBzpM= 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= +k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e h1:iW9ChlU0cU16w8MpVYjXk12dqQ4BPFBEgif+ap7/hqQ= +k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e/go.mod h1:kdmbQkyfwUagLfXIad1y2TdrjPFWp2Q89B3qkRwf/pQ= +k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 h1:SjGebBtkBqHFOli+05xYbK8YF1Dzkbzn+gDM4X9T4Ck= +k8s.io/utils v0.0.0-20251002143259-bc988d571ff4/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg= +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/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.1 h1:JrhdFMqOd/+3ByqlP2I45kTOZmTRLBUm5pvRjeheg7E= diff --git a/apps/plugins/go.mod b/apps/plugins/go.mod index 5341081d027..edcf18ea3e3 100644 --- a/apps/plugins/go.mod +++ b/apps/plugins/go.mod @@ -11,19 +11,20 @@ replace github.com/grafana/grafana/pkg/apiserver => ../../pkg/apiserver require ( github.com/emicklei/go-restful/v3 v3.13.0 github.com/grafana/grafana v0.0.0-00010101000000-000000000000 - github.com/grafana/grafana-app-sdk v0.48.5 - github.com/grafana/grafana-app-sdk/logging v0.48.3 + github.com/grafana/grafana-app-sdk v0.48.7 + github.com/grafana/grafana-app-sdk/logging v0.48.7 github.com/stretchr/testify v1.11.1 - k8s.io/apimachinery v0.34.2 - k8s.io/apiserver v0.34.2 - k8s.io/client-go v0.34.2 + k8s.io/apimachinery v0.34.3 + k8s.io/apiserver v0.34.3 + k8s.io/client-go v0.34.3 k8s.io/klog/v2 v2.130.1 - k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 + k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e ) require ( - cel.dev/expr v0.24.0 // indirect + cel.dev/expr v0.25.1 // indirect github.com/NYTimes/gziphandler v1.1.1 // indirect + github.com/ProtonMail/go-crypto v1.1.6 // indirect github.com/antlr4-go/antlr/v4 v4.13.1 // indirect github.com/apache/arrow-go/v18 v18.4.1 // indirect github.com/armon/go-metrics v0.4.1 // indirect @@ -35,16 +36,21 @@ require ( github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.8 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.38.5 // indirect github.com/aws/smithy-go v1.23.1 // indirect + github.com/barkimedes/go-deepcopy v0.0.0-20220514131651-17c30cfc62df // indirect github.com/beorn7/perks v1.0.1 // indirect + github.com/blang/semver v3.5.1+incompatible // indirect github.com/blang/semver/v4 v4.0.0 // indirect - github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874 // indirect + github.com/bluele/gcache v0.0.2 // indirect + github.com/bradfitz/gomemcache v0.0.0-20250403215159-8d39553ac7cf // indirect github.com/bwmarrin/snowflake v0.3.0 // 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/cloudflare/circl v1.6.1 // indirect github.com/coreos/go-semver v0.3.1 // indirect - github.com/coreos/go-systemd/v22 v22.5.0 // indirect + github.com/coreos/go-systemd/v22 v22.6.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/diegoholiveira/jsonlogic/v3 v3.7.4 // indirect github.com/evanphx/json-patch v5.9.11+incompatible // indirect github.com/fatih/color v1.18.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect @@ -56,10 +62,20 @@ require ( github.com/go-logfmt/logfmt v0.6.1 // 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.1 // indirect - github.com/go-openapi/swag/jsonname v0.25.1 // indirect + github.com/go-openapi/jsonpointer v0.22.4 // indirect + github.com/go-openapi/jsonreference v0.21.4 // indirect + github.com/go-openapi/swag v0.25.4 // indirect + github.com/go-openapi/swag/cmdutils v0.25.4 // indirect + github.com/go-openapi/swag/conv v0.25.4 // indirect + github.com/go-openapi/swag/fileutils v0.25.4 // indirect + github.com/go-openapi/swag/jsonname v0.25.4 // indirect + github.com/go-openapi/swag/jsonutils v0.25.4 // indirect + github.com/go-openapi/swag/loading v0.25.4 // indirect + github.com/go-openapi/swag/mangling v0.25.4 // indirect + github.com/go-openapi/swag/netutils v0.25.4 // indirect + github.com/go-openapi/swag/stringutils v0.25.4 // indirect + github.com/go-openapi/swag/typeutils v0.25.4 // indirect + github.com/go-openapi/swag/yamlutils v0.25.4 // indirect github.com/go-stack/stack v1.8.1 // indirect github.com/go-test/deep v1.1.1 // indirect github.com/gobwas/glob v0.2.3 // indirect @@ -71,7 +87,7 @@ require ( github.com/google/btree v1.1.3 // indirect github.com/google/cel-go v0.26.1 // indirect github.com/google/flatbuffers v25.2.10+incompatible // indirect - github.com/google/gnostic-models v0.7.0 // indirect + github.com/google/gnostic-models v0.7.1 // indirect github.com/google/go-cmp v0.7.0 // indirect github.com/google/uuid v1.6.0 // indirect github.com/grafana/alerting v0.0.0-20251212143239-491433b332b7 // indirect @@ -84,6 +100,7 @@ require ( github.com/grafana/grafana-plugin-sdk-go v0.284.0 // indirect github.com/grafana/grafana/pkg/apimachinery v0.0.0 // indirect github.com/grafana/grafana/pkg/apiserver v0.0.0 // indirect + github.com/grafana/grafana/pkg/semconv v0.0.0-20250804150913-990f1c69ecc2 // indirect github.com/grafana/otel-profiling-go v0.5.1 // indirect github.com/grafana/pyroscope-go/godeltaprof v0.1.9 // indirect github.com/grafana/sqlds/v4 v4.2.7 // indirect @@ -113,7 +130,7 @@ require ( github.com/klauspost/compress v1.18.0 // indirect github.com/klauspost/cpuid/v2 v2.3.0 // indirect github.com/kylelemons/godebug v1.1.0 // indirect - github.com/mailru/easyjson v0.9.0 // indirect + github.com/mailru/easyjson v0.9.1 // indirect github.com/mattetti/filebuffer v1.0.1 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect @@ -132,11 +149,15 @@ require ( 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 + github.com/nikunjy/rules v1.5.0 // indirect github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 // indirect github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 // indirect 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.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 @@ -145,72 +166,76 @@ require ( github.com/prometheus/alertmanager v0.28.2 // 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.3 // indirect + github.com/prometheus/common v0.67.4 // indirect github.com/prometheus/exporter-toolkit v0.14.0 // indirect - github.com/prometheus/procfs v0.16.1 // indirect + github.com/prometheus/procfs v0.19.2 // indirect github.com/puzpuzpuz/xsync/v2 v2.5.1 // indirect github.com/rivo/uniseg v0.4.7 // indirect github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 // indirect - github.com/spf13/cobra v1.10.1 // indirect + github.com/spf13/cobra v1.10.2 // indirect github.com/spf13/pflag v1.0.10 // indirect github.com/stoewer/go-strcase v1.3.1 // indirect github.com/stretchr/objx v0.5.2 // indirect + github.com/thomaspoignant/go-feature-flag v1.42.0 // indirect github.com/tjhop/slog-gokit v0.1.5 // indirect - github.com/woodsbury/decimal128 v1.3.0 // indirect + github.com/woodsbury/decimal128 v1.4.0 // indirect github.com/x448/float16 v0.8.4 // indirect github.com/zeebo/xxh3 v1.0.2 // indirect - go.etcd.io/etcd/api/v3 v3.6.4 // indirect - go.etcd.io/etcd/client/pkg/v3 v3.6.4 // indirect - go.etcd.io/etcd/client/v3 v3.6.4 // indirect + go.etcd.io/etcd/api/v3 v3.6.6 // indirect + go.etcd.io/etcd/client/pkg/v3 v3.6.6 // indirect + go.etcd.io/etcd/client/v3 v3.6.6 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.64.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/instrumentation/net/http/otelhttp v0.64.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/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/otel v1.39.0 // indirect + go.opentelemetry.io/otel/exporters/jaeger v1.17.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0 // indirect + go.opentelemetry.io/otel/metric v1.39.0 // indirect + go.opentelemetry.io/otel/sdk v1.39.0 // indirect + go.opentelemetry.io/otel/trace v1.39.0 // indirect go.opentelemetry.io/proto/otlp v1.9.0 // indirect + go.uber.org/atomic v1.11.0 // indirect + go.uber.org/mock v0.6.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.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.45.0 // indirect - golang.org/x/exp v0.0.0-20251002181428-27f1f14c8bb9 // indirect - golang.org/x/mod v0.30.0 // indirect - golang.org/x/net v0.47.0 // indirect - golang.org/x/oauth2 v0.33.0 // indirect - golang.org/x/sync v0.18.0 // indirect - golang.org/x/sys v0.38.0 // indirect - golang.org/x/telemetry v0.0.0-20251111182119-bc8e575c7b54 // indirect - golang.org/x/term v0.37.0 // indirect - golang.org/x/text v0.31.0 // indirect + golang.org/x/crypto v0.46.0 // indirect + golang.org/x/exp v0.0.0-20251209150349-8475f28825e9 // indirect + golang.org/x/mod v0.31.0 // indirect + golang.org/x/net v0.48.0 // indirect + golang.org/x/oauth2 v0.34.0 // indirect + golang.org/x/sync v0.19.0 // indirect + golang.org/x/sys v0.39.0 // indirect + golang.org/x/telemetry v0.0.0-20251203150158-8fff8a5912fc // indirect + golang.org/x/term v0.38.0 // indirect + golang.org/x/text v0.32.0 // indirect golang.org/x/time v0.14.0 // indirect - golang.org/x/tools v0.39.0 // indirect + golang.org/x/tools v0.40.0 // indirect golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20251111163417-95abcf5c77ba // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2 // indirect google.golang.org/grpc v1.77.0 // indirect - google.golang.org/protobuf v1.36.10 // indirect - gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect + google.golang.org/protobuf v1.36.11 // indirect + gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/api v0.34.2 // indirect - k8s.io/apiextensions-apiserver v0.34.2 // indirect - k8s.io/component-base v0.34.2 // indirect - k8s.io/kms v0.34.2 // indirect - k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 // indirect - sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2 // indirect - sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect + k8s.io/api v0.34.3 // indirect + k8s.io/apiextensions-apiserver v0.34.3 // indirect + k8s.io/component-base v0.34.3 // indirect + k8s.io/kms v0.34.3 // indirect + k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 // indirect + sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.34.0 // indirect + sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect sigs.k8s.io/randfill v1.0.0 // indirect sigs.k8s.io/structured-merge-diff/v6 v6.3.1 // indirect sigs.k8s.io/yaml v1.6.0 // indirect diff --git a/apps/plugins/go.sum b/apps/plugins/go.sum index 7d58d87be04..c5fbc7a39a5 100644 --- a/apps/plugins/go.sum +++ b/apps/plugins/go.sum @@ -1,12 +1,16 @@ -cel.dev/expr v0.24.0 h1:56OvJKSH3hDGL0ml5uSxZmz3/3Pq4tJ+fb1unVLAFcY= -cel.dev/expr v0.24.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw= +cel.dev/expr v0.25.1 h1:1KrZg61W6TWSxuNZ37Xy49ps13NUovb66QLprthtwi4= +cel.dev/expr v0.25.1/go.mod h1:hrXvqGP6G6gyx8UAHSHJ5RGk//1Oj5nXQ2NI02Nrsg4= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +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/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I= github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= +github.com/ProtonMail/go-crypto v1.1.6 h1:ZcV+Ropw6Qn0AX9brlQLAUXfqLBc7Bl+f/DmNxpLfdw= +github.com/ProtonMail/go-crypto v1.1.6/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE= 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= @@ -38,14 +42,20 @@ github.com/aws/aws-sdk-go-v2/service/sts v1.38.5 h1:+LVB0xBqEgjQoqr9bGZbRzvg212B github.com/aws/aws-sdk-go-v2/service/sts v1.38.5/go.mod h1:xoaxeqnnUaZjPjaICgIy5B+MHCSb/ZSOn4MvkFNOUA0= 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/barkimedes/go-deepcopy v0.0.0-20220514131651-17c30cfc62df h1:GSoSVRLoBaFpOOds6QyY1L8AX7uoY+Ln3BHc22W40X0= +github.com/barkimedes/go-deepcopy v0.0.0-20220514131651-17c30cfc62df/go.mod h1:hiVxq5OP2bUGBRNS3Z/bt/reCLFNbdcST6gISi1fiOM= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= 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 v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ= +github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= 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/bluele/gcache v0.0.2 h1:WcbfdXICg7G/DGBh1PFfcirkWOQV+v077yF1pSy3DGw= +github.com/bluele/gcache v0.0.2/go.mod h1:m15KV+ECjptwSPxKhOhQoAFQVtUFjTVkc3H8o0t/fp0= +github.com/bradfitz/gomemcache v0.0.0-20250403215159-8d39553ac7cf h1:TqhNAT4zKbTdLa62d2HDBFdvgSbIGB3eJE8HqhgiL9I= +github.com/bradfitz/gomemcache v0.0.0-20250403215159-8d39553ac7cf/go.mod h1:r5xuitiExdLAJ09PR7vBVENGvp4ZuTBeWTGtxuX3K+c= 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/bwmarrin/snowflake v0.3.0 h1:xm67bEhkKh6ij1790JB83OujPR5CzNe8QuQqAgISZN0= @@ -60,15 +70,19 @@ github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wX github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0= +github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs= github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4= github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec= -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/coreos/go-systemd/v22 v22.6.0 h1:aGVa/v8B7hpb0TKl0MWoAavPDmHvobFe5R5zn0bCJWo= +github.com/coreos/go-systemd/v22 v22.6.0/go.mod h1:iG+pp635Fo7ZmV/j14KUcmEyWF+0X7Lua8rrTWzYgWU= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= 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/diegoholiveira/jsonlogic/v3 v3.7.4 h1:92HSmB9bwM/o0ZvrCpcvTP2EsPXSkKtAniIr2W/dcIM= +github.com/diegoholiveira/jsonlogic/v3 v3.7.4/go.mod h1:OYRb6FSTVmMM+MNQ7ElmMsczyNSepw+OU4Z8emDSi4w= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/emicklei/go-restful/v3 v3.13.0 h1:C4Bl2xDndpU6nJ4bc1jXd+uTmYPVUwkD6bFY/oTyCes= @@ -106,14 +120,40 @@ 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-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg= -github.com/go-openapi/jsonpointer v0.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.1 h1:lpsStH0n2ittzTnbaSloVZLuB5+fvSY/+hnagBjSNZU= -github.com/go-openapi/swag v0.23.1/go.mod h1:STZs8TbRvEQQKUA+JZNAm3EWlgaOBGpyFDqQnDHMef0= -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/jsonpointer v0.22.4 h1:dZtK82WlNpVLDW2jlA1YCiVJFVqkED1MegOUy9kR5T4= +github.com/go-openapi/jsonpointer v0.22.4/go.mod h1:elX9+UgznpFhgBuaMQ7iu4lvvX1nvNsesQ3oxmYTw80= +github.com/go-openapi/jsonreference v0.21.4 h1:24qaE2y9bx/q3uRK/qN+TDwbok1NhbSmGjjySRCHtC8= +github.com/go-openapi/jsonreference v0.21.4/go.mod h1:rIENPTjDbLpzQmQWCj5kKj3ZlmEh+EFVbz3RTUh30/4= +github.com/go-openapi/swag v0.25.4 h1:OyUPUFYDPDBMkqyxOTkqDYFnrhuhi9NR6QVUvIochMU= +github.com/go-openapi/swag v0.25.4/go.mod h1:zNfJ9WZABGHCFg2RnY0S4IOkAcVTzJ6z2Bi+Q4i6qFQ= +github.com/go-openapi/swag/cmdutils v0.25.4 h1:8rYhB5n6WawR192/BfUu2iVlxqVR9aRgGJP6WaBoW+4= +github.com/go-openapi/swag/cmdutils v0.25.4/go.mod h1:pdae/AFo6WxLl5L0rq87eRzVPm/XRHM3MoYgRMvG4A0= +github.com/go-openapi/swag/conv v0.25.4 h1:/Dd7p0LZXczgUcC/Ikm1+YqVzkEeCc9LnOWjfkpkfe4= +github.com/go-openapi/swag/conv v0.25.4/go.mod h1:3LXfie/lwoAv0NHoEuY1hjoFAYkvlqI/Bn5EQDD3PPU= +github.com/go-openapi/swag/fileutils v0.25.4 h1:2oI0XNW5y6UWZTC7vAxC8hmsK/tOkWXHJQH4lKjqw+Y= +github.com/go-openapi/swag/fileutils v0.25.4/go.mod h1:cdOT/PKbwcysVQ9Tpr0q20lQKH7MGhOEb6EwmHOirUk= +github.com/go-openapi/swag/jsonname v0.25.4 h1:bZH0+MsS03MbnwBXYhuTttMOqk+5KcQ9869Vye1bNHI= +github.com/go-openapi/swag/jsonname v0.25.4/go.mod h1:GPVEk9CWVhNvWhZgrnvRA6utbAltopbKwDu8mXNUMag= +github.com/go-openapi/swag/jsonutils v0.25.4 h1:VSchfbGhD4UTf4vCdR2F4TLBdLwHyUDTd1/q4i+jGZA= +github.com/go-openapi/swag/jsonutils v0.25.4/go.mod h1:7OYGXpvVFPn4PpaSdPHJBtF0iGnbEaTk8AvBkoWnaAY= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4 h1:IACsSvBhiNJwlDix7wq39SS2Fh7lUOCJRmx/4SN4sVo= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4/go.mod h1:Mt0Ost9l3cUzVv4OEZG+WSeoHwjWLnarzMePNDAOBiM= +github.com/go-openapi/swag/loading v0.25.4 h1:jN4MvLj0X6yhCDduRsxDDw1aHe+ZWoLjW+9ZQWIKn2s= +github.com/go-openapi/swag/loading v0.25.4/go.mod h1:rpUM1ZiyEP9+mNLIQUdMiD7dCETXvkkC30z53i+ftTE= +github.com/go-openapi/swag/mangling v0.25.4 h1:2b9kBJk9JvPgxr36V23FxJLdwBrpijI26Bx5JH4Hp48= +github.com/go-openapi/swag/mangling v0.25.4/go.mod h1:6dxwu6QyORHpIIApsdZgb6wBk/DPU15MdyYj/ikn0Hg= +github.com/go-openapi/swag/netutils v0.25.4 h1:Gqe6K71bGRb3ZQLusdI8p/y1KLgV4M/k+/HzVSqT8H0= +github.com/go-openapi/swag/netutils v0.25.4/go.mod h1:m2W8dtdaoX7oj9rEttLyTeEFFEBvnAx9qHd5nJEBzYg= +github.com/go-openapi/swag/stringutils v0.25.4 h1:O6dU1Rd8bej4HPA3/CLPciNBBDwZj9HiEpdVsb8B5A8= +github.com/go-openapi/swag/stringutils v0.25.4/go.mod h1:GTsRvhJW5xM5gkgiFe0fV3PUlFm0dr8vki6/VSRaZK0= +github.com/go-openapi/swag/typeutils v0.25.4 h1:1/fbZOUN472NTc39zpa+YGHn3jzHWhv42wAJSN91wRw= +github.com/go-openapi/swag/typeutils v0.25.4/go.mod h1:Ou7g//Wx8tTLS9vG0UmzfCsjZjKhpjxayRKTHXf2pTE= +github.com/go-openapi/swag/yamlutils v0.25.4 h1:6jdaeSItEUb7ioS9lFoCZ65Cne1/RZtPBZ9A56h92Sw= +github.com/go-openapi/swag/yamlutils v0.25.4/go.mod h1:MNzq1ulQu+yd8Kl7wPOut/YHAAU/H6hL91fF+E2RFwc= +github.com/go-openapi/testify/enable/yaml/v2 v2.0.2 h1:0+Y41Pz1NkbTHz8NngxTuAXxEodtNSI1WG1c/m5Akw4= +github.com/go-openapi/testify/enable/yaml/v2 v2.0.2/go.mod h1:kme83333GCtJQHXQ8UKX3IBZu6z8T5Dvy5+CW3NLUUg= +github.com/go-openapi/testify/v2 v2.0.2 h1:X999g3jeLcoY8qctY/c/Z8iBHTbwLz7R2WXd6Ub6wls= +github.com/go-openapi/testify/v2 v2.0.2/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= 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= @@ -127,7 +167,6 @@ 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= github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= -github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/googleapis v1.4.1 h1:1Yx4Myt7BxzvUr5ldGSbwYiZG6t9wGBZ+8/fX3Wvtq0= github.com/gogo/googleapis v1.4.1/go.mod h1:2lpHqI5OcWCtVElxXnPt+s8oJvMpySlOyM6xDCrzib4= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= @@ -157,8 +196,8 @@ 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.7.0 h1:qwTtogB15McXDaNqTZdzPJRHvaVJlAl+HVQnLmJEJxo= -github.com/google/gnostic-models v0.7.0/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ= +github.com/google/gnostic-models v0.7.1 h1:SisTfuFKJSKM5CPZkffwi6coztzzeYUhc3v4yxLWH8c= +github.com/google/gnostic-models v0.7.1/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ= 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= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= @@ -184,16 +223,18 @@ github.com/grafana/dataplane/sdata v0.0.9 h1:AGL1LZnCUG4MnQtnWpBPbQ8ZpptaZs14w6k github.com/grafana/dataplane/sdata v0.0.9/go.mod h1:Jvs5ddpGmn6vcxT7tCTWAZ1mgi4sbcdFt9utQx5uMAU= 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.5 h1:MS8l9fTZz+VbTfgApn09jw27GxhQ6fNOWGhC4ydvZmM= -github.com/grafana/grafana-app-sdk v0.48.5/go.mod h1:HJsMOSBmt/D/Ihs1SvagOwmXKi0coBMVHlfvdd+qe9Y= -github.com/grafana/grafana-app-sdk/logging v0.48.3 h1:72NUpGNiJXCNQz/on++YSsl38xuVYYBKv5kKQaOClX4= -github.com/grafana/grafana-app-sdk/logging v0.48.3/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA= +github.com/grafana/grafana-app-sdk v0.48.7 h1:9mF7nqkqP0QUYYDlznoOt+GIyjzj45wGfUHB32u2ZMo= +github.com/grafana/grafana-app-sdk v0.48.7/go.mod h1:DWsaaH39ZMHwSOSoUBaeW8paMrRaYsjRYlLwCJYd78k= +github.com/grafana/grafana-app-sdk/logging v0.48.7 h1:Oa5qg473gka5+W/WQk61Xbw4YdAv+wV2Z4bJtzeCaQw= +github.com/grafana/grafana-app-sdk/logging v0.48.7/go.mod h1:5u3KalezoBAAo2Y3ytDYDAIIPvEqFLLDSxeiK99QxDU= github.com/grafana/grafana-aws-sdk v1.3.0 h1:/bfJzP93rCel1GbWoRSq0oUo424MZXt8jAp2BK9w8tM= github.com/grafana/grafana-aws-sdk v1.3.0/go.mod h1:VGycF0JkCGKND2O5je1ucOqPJ0ZNhZYzV3c2bNBAaGk= 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.284.0 h1:1bK7eWsnPBLUWDcWJWe218Ik5ad0a5JpEL4mH9ry7Ws= github.com/grafana/grafana-plugin-sdk-go v0.284.0/go.mod h1:lHPniaSxq3SL5MxDIPy04TYB1jnTp/ivkYO+xn5Rz3E= +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.20250911094103-5456b6e45604 h1:aXfUhVN/Ewfpbko2CCtL65cIiGgwStOo4lWH2b6gw2U= @@ -286,8 +327,8 @@ 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/mailru/easyjson v0.9.1 h1:LbtsOm5WAswyWbvTEOqhypdPeZzHavpZx96/n553mR8= +github.com/mailru/easyjson v0.9.1/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= github.com/mattetti/filebuffer v1.0.1 h1:gG7pyfnSIZCxdoKq+cPa8T0hhYtD9NxCdI4D7PTjRLM= github.com/mattetti/filebuffer v1.0.1/go.mod h1:YdMURNDOttIiruleeVr6f56OrMc+MydEnTcXwtkxNVs= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= @@ -341,6 +382,8 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8m github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= 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/nikunjy/rules v1.5.0 h1:KJDSLOsFhwt7kcXUyZqwkgrQg5YoUwj+TVu6ItCQShw= +github.com/nikunjy/rules v1.5.0/go.mod h1:TlZtZdBChrkqi8Lr2AXocme8Z7EsbxtFdDoKeI6neBQ= 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= @@ -355,6 +398,12 @@ 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/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/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= @@ -388,8 +437,8 @@ github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8 github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= 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.67.3 h1:shd26MlnwTw5jksTDhC7rTQIteBxy+ZZDr3t7F2xN2Q= -github.com/prometheus/common v0.67.3/go.mod h1:gP0fq6YjjNCLssJCQp0yk4M8W6ikLURwkdd/YKtTbyI= +github.com/prometheus/common v0.67.4 h1:yR3NqWO1/UyO1w2PhUvXlGQs/PtFmoveVO0KZ4+Lvsc= +github.com/prometheus/common v0.67.4/go.mod h1:gP0fq6YjjNCLssJCQp0yk4M8W6ikLURwkdd/YKtTbyI= github.com/prometheus/exporter-toolkit v0.14.0 h1:NMlswfibpcZZ+H0sZBiTjrA3/aBFHkNZqE+iCj5EmRg= github.com/prometheus/exporter-toolkit v0.14.0/go.mod h1:Gu5LnVvt7Nr/oqTBUC23WILZepW0nffNo10XdhQcwWA= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= @@ -398,8 +447,8 @@ github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsT github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= -github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= +github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws= +github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw= 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/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= @@ -417,8 +466,8 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js= github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= -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/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU= +github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4= github.com/spf13/pflag v1.0.9/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= @@ -440,6 +489,10 @@ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= 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/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= +github.com/thomaspoignant/go-feature-flag v1.42.0/go.mod h1:y0QiWH7chHWhGATb/+XqwAwErORmPSH2MUsQlCmmWlM= github.com/tjhop/slog-gokit v0.1.5 h1:ayloIUi5EK2QYB8eY4DOPO95/mRtMW42lUkp3quJohc= github.com/tjhop/slog-gokit v0.1.5/go.mod h1:yA48zAHvV+Sg4z4VRyeFyFUNNXd3JY5Zg84u3USICq0= github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75 h1:6fotK7otjonDflCTK0BCfls4SPy3NcCVb5dqqmbRknE= @@ -447,8 +500,8 @@ github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75/go.mod h1 github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= 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/woodsbury/decimal128 v1.4.0 h1:xJATj7lLu4f2oObouMt2tgGiElE5gO6mSWUjQsBgUlc= +github.com/woodsbury/decimal128 v1.4.0/go.mod h1:BP46FUrVjVhdTbKT+XuQh2xfQaGki9LMIRJSFuh6THU= 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/xiang90/probing v0.0.0-20221125231312-a49e3df8f510 h1:S2dVYn90KE98chqDkyE9Z4N61UnQd+KOfgp5Iu53llk= @@ -461,12 +514,12 @@ github.com/zeebo/xxh3 v1.0.2 h1:xZmwmqxHZA8AI603jOQ0tMqmBr9lPeFwGg6d+xy9DC0= github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA= go.etcd.io/bbolt v1.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.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.6.4 h1:9HBYrjppeOfFjBjaMTRxT3R7xT0GLK8EJMVC4xg6ok0= -go.etcd.io/etcd/client/pkg/v3 v3.6.4/go.mod h1:sbdzr2cl3HzVmxNw//PH7aLGVtY4QySjQFuaCgcRFAI= -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.etcd.io/etcd/api/v3 v3.6.6 h1:mcaMp3+7JawWv69p6QShYWS8cIWUOl32bFLb6qf8pOQ= +go.etcd.io/etcd/api/v3 v3.6.6/go.mod h1:f/om26iXl2wSkcTA1zGQv8reJRSLVdoEBsi4JdfMrx4= +go.etcd.io/etcd/client/pkg/v3 v3.6.6 h1:uoqgzSOv2H9KlIF5O1Lsd8sW+eMLuV6wzE3q5GJGQNs= +go.etcd.io/etcd/client/pkg/v3 v3.6.6/go.mod h1:YngfUVmvsvOJ2rRgStIyHsKtOt9SZI2aBJrZiWJhCbI= +go.etcd.io/etcd/client/v3 v3.6.6 h1:G5z1wMf5B9SNexoxOHUGBaULurOZPIgGPsW6CN492ec= +go.etcd.io/etcd/client/v3 v3.6.6/go.mod h1:36Qv6baQ07znPR3+n7t+Rk5VHEzVYPvFfGmfF4wBHV8= go.etcd.io/etcd/pkg/v3 v3.6.4 h1:fy8bmXIec1Q35/jRZ0KOes8vuFxbvdN0aAFqmEfJZWA= go.etcd.io/etcd/pkg/v3 v3.6.4/go.mod h1:kKcYWP8gHuBRcteyv6MXWSN0+bVMnfgqiHueIZnKMtE= go.etcd.io/etcd/server/v3 v3.6.4 h1:LsCA7CzjVt+8WGrdsnh6RhC0XqCsLkBly3ve5rTxMAU= @@ -475,40 +528,46 @@ go.etcd.io/raft/v3 v3.6.0 h1:5NtvbDVYpnfZWcIHgGRk9DyzkBIXOi8j+DDp1IcnUWQ= go.etcd.io/raft/v3 v3.6.0/go.mod h1:nLvLevg6+xrVtHUmVaTcTz603gQPHfh7kUAwV6YpfGo= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= -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/google.golang.org/grpc/otelgrpc v0.64.0 h1:RN3ifU8y4prNWeEnQp2kRRHz8UwonAEYZl8tUzHEXAk= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.64.0/go.mod h1:habDz3tEWiFANTo6oUE99EmaFUrCNYAAg3wiVmusm70= 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/instrumentation/net/http/otelhttp v0.64.0 h1:ssfIgGNANqpVFCndZvcuyKbl0g+UAVcbBcqGkG28H0Y= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.64.0/go.mod h1:GQ/474YrbE4Jx8gZ4q5I4hrhUzM6UPzyrqJYV2AqPoQ= 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.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 v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48= +go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8= +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/otlptrace v1.39.0 h1:f0cb2XPmrqn4XMy9PNliTgRKJgS5WcL/u0/WRYGz4t0= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0/go.mod h1:vnakAaFckOMiMtOIhFI2MNH4FYrZzXCYxmb1LlhoGz8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0 h1:in9O8ESIOlwJAEGTkkf34DesGRAc/Pn8qJ7k3r/42LM= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0/go.mod h1:Rp0EXBm5tfnv0WL+ARyO/PHBEaEAT8UUHQ6AGJcSq6c= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0 h1:Ckwye2FpXkYgiHX7fyVrN1uA/UYd9ounqqTuSNAv0k4= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0/go.mod h1:teIFJh5pW2y+AN7riv6IBPX2DuesS3HgP39mwOspKwU= go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM= -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/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0= +go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs= go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E= -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/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18= +go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE= +go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8= +go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew= go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ= -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/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI= +go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA= go.opentelemetry.io/proto/otlp v1.9.0 h1:l706jCMITVouPOqEnii2fIAuO3IVGBRPV5ICjceRb/A= go.opentelemetry.io/proto/otlp v1.9.0/go.mod h1:xE+Cx5E/eEHw+ISFkwPLwCZefwVjY+pqKg1qcK03+/4= +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.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= @@ -521,15 +580,15 @@ golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnf 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.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q= -golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4= -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/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU= +golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0= +golang.org/x/exp v0.0.0-20251209150349-8475f28825e9 h1:MDfG8Cvcqlt9XXrmEiD4epKn7VJHZO84hejP9Jmp0MM= +golang.org/x/exp v0.0.0-20251209150349-8475f28825e9/go.mod h1:EPRbTFwzwjXj9NpYyyrvenVh9Y+GFeEvMNh7Xuz7xgU= 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.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk= -golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc= +golang.org/x/mod v0.31.0 h1:HaW9xtz0+kOcWKwli0ZXy79Ix+UW/vOfmWI5QVd2tgI= +golang.org/x/mod v0.31.0/go.mod h1:43JraMp9cGx1Rx3AqioxrbrhNsLl2l/iNAvuBkrezpg= 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-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -542,12 +601,12 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= -golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= +golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= +golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.33.0 h1:4Q+qn+E5z8gPRJfmRy7C2gGG3T4jIprK6aSYgTXGRpo= -golang.org/x/oauth2 v0.33.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= +golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw= +golang.org/x/oauth2 v0.34.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= @@ -555,8 +614,8 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ 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.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= -golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= 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= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -578,17 +637,17 @@ golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 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.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= -golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/telemetry v0.0.0-20251111182119-bc8e575c7b54 h1:E2/AqCUMZGgd73TQkxUMcMla25GB9i/5HOdLr+uH7Vo= -golang.org/x/telemetry v0.0.0-20251111182119-bc8e575c7b54/go.mod h1:hKdjCMrbv9skySur+Nek8Hd0uJ0GuxJIoIX2payrIdQ= -golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU= -golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254= +golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= +golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/telemetry v0.0.0-20251203150158-8fff8a5912fc h1:bH6xUXay0AIFMElXG2rQ4uiE+7ncwtiOdPfYK1NK2XA= +golang.org/x/telemetry v0.0.0-20251203150158-8fff8a5912fc/go.mod h1:hKdjCMrbv9skySur+Nek8Hd0uJ0GuxJIoIX2payrIdQ= +golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q= +golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= -golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= +golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= +golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= 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= @@ -596,8 +655,8 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm 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.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ= -golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ= +golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA= +golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc= 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= @@ -611,10 +670,10 @@ gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto/googleapis/api v0.0.0-20251111163417-95abcf5c77ba h1:B14OtaXuMaCQsl2deSvNkyPKIzq3BjfxQp8d00QyWx4= -google.golang.org/genproto/googleapis/api v0.0.0-20251111163417-95abcf5c77ba/go.mod h1:G5IanEx8/PgI9w6CFcYQf7jMtHQhZruvfM1i3qOqk5U= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba h1:UKgtfRM7Yh93Sya0Fo8ZzhDP4qBckrrxEr2oF5UIVb8= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= +google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2 h1:7LRqPCEdE4TP4/9psdaB7F2nhZFfBiGJomA5sojLWdU= +google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2/go.mod h1:+rXWjjaukWZun3mLfjmVnQi18E1AsFbDN9QdJ5YXLto= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2 h1:2I6GHUeJ/4shcDpoUlLs/2WPnhg7yJwvXtqcMJt9liA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/grpc v1.18.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM= google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= @@ -625,15 +684,15 @@ google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miE google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= -google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= 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= 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/evanphx/json-patch.v4 v4.13.0 h1:czT3CmqEaQ1aanPc5SdlgQrrEIb8w/wwCvWWnfEbYzo= +gopkg.in/evanphx/json-patch.v4 v4.13.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/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= @@ -651,30 +710,30 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -k8s.io/api v0.34.2 h1:fsSUNZhV+bnL6Aqrp6O7lMTy6o5x2C4XLjnh//8SLYY= -k8s.io/api v0.34.2/go.mod h1:MMBPaWlED2a8w4RSeanD76f7opUoypY8TFYkSM+3XHw= -k8s.io/apiextensions-apiserver v0.34.2 h1:WStKftnGeoKP4AZRz/BaAAEJvYp4mlZGN0UCv+uvsqo= -k8s.io/apiextensions-apiserver v0.34.2/go.mod h1:398CJrsgXF1wytdaanynDpJ67zG4Xq7yj91GrmYN2SE= -k8s.io/apimachinery v0.34.2 h1:zQ12Uk3eMHPxrsbUJgNF8bTauTVR2WgqJsTmwTE/NW4= -k8s.io/apimachinery v0.34.2/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= -k8s.io/apiserver v0.34.2 h1:2/yu8suwkmES7IzwlehAovo8dDE07cFRC7KMDb1+MAE= -k8s.io/apiserver v0.34.2/go.mod h1:gqJQy2yDOB50R3JUReHSFr+cwJnL8G1dzTA0YLEqAPI= -k8s.io/client-go v0.34.2 h1:Co6XiknN+uUZqiddlfAjT68184/37PS4QAzYvQvDR8M= -k8s.io/client-go v0.34.2/go.mod h1:2VYDl1XXJsdcAxw7BenFslRQX28Dxz91U9MWKjX97fE= -k8s.io/component-base v0.34.2 h1:HQRqK9x2sSAsd8+R4xxRirlTjowsg6fWCPwWYeSvogQ= -k8s.io/component-base v0.34.2/go.mod h1:9xw2FHJavUHBFpiGkZoKuYZ5pdtLKe97DEByaA+hHbM= +k8s.io/api v0.34.3 h1:D12sTP257/jSH2vHV2EDYrb16bS7ULlHpdNdNhEw2S4= +k8s.io/api v0.34.3/go.mod h1:PyVQBF886Q5RSQZOim7DybQjAbVs8g7gwJNhGtY5MBk= +k8s.io/apiextensions-apiserver v0.34.3 h1:p10fGlkDY09eWKOTeUSioxwLukJnm+KuDZdrW71y40g= +k8s.io/apiextensions-apiserver v0.34.3/go.mod h1:aujxvqGFRdb/cmXYfcRTeppN7S2XV/t7WMEc64zB5A0= +k8s.io/apimachinery v0.34.3 h1:/TB+SFEiQvN9HPldtlWOTp0hWbJ+fjU+wkxysf/aQnE= +k8s.io/apimachinery v0.34.3/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= +k8s.io/apiserver v0.34.3 h1:uGH1qpDvSiYG4HVFqc6A3L4CKiX+aBWDrrsxHYK0Bdo= +k8s.io/apiserver v0.34.3/go.mod h1:QPnnahMO5C2m3lm6fPW3+JmyQbvHZQ8uudAu/493P2w= +k8s.io/client-go v0.34.3 h1:wtYtpzy/OPNYf7WyNBTj3iUA0XaBHVqhv4Iv3tbrF5A= +k8s.io/client-go v0.34.3/go.mod h1:OxxeYagaP9Kdf78UrKLa3YZixMCfP6bgPwPwNBQBzpM= +k8s.io/component-base v0.34.3 h1:zsEgw6ELqK0XncCQomgO9DpUIzlrYuZYA0Cgo+JWpVk= +k8s.io/component-base v0.34.3/go.mod h1:5iIlD8wPfWE/xSHTRfbjuvUul2WZbI2nOUK65XL0E/c= 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.34.2 h1:91rj4MDZLyIT9KxG8J5/CcMH666Z88CF/xJQeuPfJc8= -k8s.io/kms v0.34.2/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= -sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2 h1:jpcvIRr3GLoUoEKRkHKSmGjxb6lWwrBlJsXc+eUYQHM= -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= +k8s.io/kms v0.34.3 h1:QzBOD0sk1bGQVMcZQAHGjtbP1iKZJUyhC6D0I+BTxIE= +k8s.io/kms v0.34.3/go.mod h1:s1CFkLG7w9eaTYvctOxosx88fl4spqmixnNpys0JAtM= +k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e h1:iW9ChlU0cU16w8MpVYjXk12dqQ4BPFBEgif+ap7/hqQ= +k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e/go.mod h1:kdmbQkyfwUagLfXIad1y2TdrjPFWp2Q89B3qkRwf/pQ= +k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 h1:SjGebBtkBqHFOli+05xYbK8YF1Dzkbzn+gDM4X9T4Ck= +k8s.io/utils v0.0.0-20251002143259-bc988d571ff4/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.34.0 h1:hSfpvjjTQXQY2Fol2CS0QHMNs/WI1MOSGzCm1KhM5ec= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.34.0/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw= +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg= +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/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.1 h1:JrhdFMqOd/+3ByqlP2I45kTOZmTRLBUm5pvRjeheg7E= diff --git a/apps/plugins/kinds/meta.cue b/apps/plugins/kinds/meta.cue index 34a7b9aaf12..d29308e2ca2 100644 --- a/apps/plugins/kinds/meta.cue +++ b/apps/plugins/kinds/meta.cue @@ -5,7 +5,25 @@ metaV0Alpha1: { scope: "Namespaced" schema: { spec: { - pluginJSON: #JSONData, + pluginJson: #JSONData + class: "core" | "external" + module?: { + path: string + hash?: string + loadingStrategy?: "fetch" | "script" + } + baseURL?: string + signature?: { + status: "internal" | "valid" | "invalid" | "modified" | "unsigned" + type?: "grafana" | "commercial" | "community" | "private" | "private-glob" + org?: string + } + angular?: { + detected: bool + } + translations?: [string]: string + // +listType=atomic + children?: [...string] } } } diff --git a/apps/plugins/kinds/plugin.cue b/apps/plugins/kinds/plugin.cue index dc16a3f6de4..854448a5b72 100644 --- a/apps/plugins/kinds/plugin.cue +++ b/apps/plugins/kinds/plugin.cue @@ -9,7 +9,6 @@ pluginV0Alpha1: { id: string version: string url?: string - class: "core" | "external" } } } diff --git a/apps/plugins/pkg/apis/plugins/v0alpha1/meta_spec_gen.go b/apps/plugins/pkg/apis/plugins/v0alpha1/meta_spec_gen.go index 9598da22ef7..f3671a040db 100644 --- a/apps/plugins/pkg/apis/plugins/v0alpha1/meta_spec_gen.go +++ b/apps/plugins/pkg/apis/plugins/v0alpha1/meta_spec_gen.go @@ -208,13 +208,21 @@ func NewMetaExtensions() *MetaExtensions { // +k8s:openapi-gen=true type MetaSpec struct { - PluginJSON MetaJSONData `json:"pluginJSON"` + PluginJson MetaJSONData `json:"pluginJson"` + Class MetaSpecClass `json:"class"` + Module *MetaV0alpha1SpecModule `json:"module,omitempty"` + BaseURL *string `json:"baseURL,omitempty"` + Signature *MetaV0alpha1SpecSignature `json:"signature,omitempty"` + Angular *MetaV0alpha1SpecAngular `json:"angular,omitempty"` + Translations map[string]string `json:"translations,omitempty"` + // +listType=atomic + Children []string `json:"children,omitempty"` } // NewMetaSpec creates a new MetaSpec object. func NewMetaSpec() *MetaSpec { return &MetaSpec{ - PluginJSON: *NewMetaJSONData(), + PluginJson: *NewMetaJSONData(), } } @@ -412,6 +420,40 @@ func NewMetaV0alpha1ExtensionsExtensionPoints() *MetaV0alpha1ExtensionsExtension return &MetaV0alpha1ExtensionsExtensionPoints{} } +// +k8s:openapi-gen=true +type MetaV0alpha1SpecModule struct { + Path string `json:"path"` + Hash *string `json:"hash,omitempty"` + LoadingStrategy *MetaV0alpha1SpecModuleLoadingStrategy `json:"loadingStrategy,omitempty"` +} + +// NewMetaV0alpha1SpecModule creates a new MetaV0alpha1SpecModule object. +func NewMetaV0alpha1SpecModule() *MetaV0alpha1SpecModule { + return &MetaV0alpha1SpecModule{} +} + +// +k8s:openapi-gen=true +type MetaV0alpha1SpecSignature struct { + Status MetaV0alpha1SpecSignatureStatus `json:"status"` + Type *MetaV0alpha1SpecSignatureType `json:"type,omitempty"` + Org *string `json:"org,omitempty"` +} + +// NewMetaV0alpha1SpecSignature creates a new MetaV0alpha1SpecSignature object. +func NewMetaV0alpha1SpecSignature() *MetaV0alpha1SpecSignature { + return &MetaV0alpha1SpecSignature{} +} + +// +k8s:openapi-gen=true +type MetaV0alpha1SpecAngular struct { + Detected bool `json:"detected"` +} + +// NewMetaV0alpha1SpecAngular creates a new MetaV0alpha1SpecAngular object. +func NewMetaV0alpha1SpecAngular() *MetaV0alpha1SpecAngular { + return &MetaV0alpha1SpecAngular{} +} + // +k8s:openapi-gen=true type MetaJSONDataType string @@ -464,6 +506,14 @@ const ( MetaIncludeRoleViewer MetaIncludeRole = "Viewer" ) +// +k8s:openapi-gen=true +type MetaSpecClass string + +const ( + MetaSpecClassCore MetaSpecClass = "core" + MetaSpecClassExternal MetaSpecClass = "external" +) + // +k8s:openapi-gen=true type MetaV0alpha1DependenciesPluginsType string @@ -472,3 +522,33 @@ const ( MetaV0alpha1DependenciesPluginsTypeDatasource MetaV0alpha1DependenciesPluginsType = "datasource" MetaV0alpha1DependenciesPluginsTypePanel MetaV0alpha1DependenciesPluginsType = "panel" ) + +// +k8s:openapi-gen=true +type MetaV0alpha1SpecModuleLoadingStrategy string + +const ( + MetaV0alpha1SpecModuleLoadingStrategyFetch MetaV0alpha1SpecModuleLoadingStrategy = "fetch" + MetaV0alpha1SpecModuleLoadingStrategyScript MetaV0alpha1SpecModuleLoadingStrategy = "script" +) + +// +k8s:openapi-gen=true +type MetaV0alpha1SpecSignatureStatus string + +const ( + MetaV0alpha1SpecSignatureStatusInternal MetaV0alpha1SpecSignatureStatus = "internal" + MetaV0alpha1SpecSignatureStatusValid MetaV0alpha1SpecSignatureStatus = "valid" + MetaV0alpha1SpecSignatureStatusInvalid MetaV0alpha1SpecSignatureStatus = "invalid" + MetaV0alpha1SpecSignatureStatusModified MetaV0alpha1SpecSignatureStatus = "modified" + MetaV0alpha1SpecSignatureStatusUnsigned MetaV0alpha1SpecSignatureStatus = "unsigned" +) + +// +k8s:openapi-gen=true +type MetaV0alpha1SpecSignatureType string + +const ( + MetaV0alpha1SpecSignatureTypeGrafana MetaV0alpha1SpecSignatureType = "grafana" + MetaV0alpha1SpecSignatureTypeCommercial MetaV0alpha1SpecSignatureType = "commercial" + MetaV0alpha1SpecSignatureTypeCommunity MetaV0alpha1SpecSignatureType = "community" + MetaV0alpha1SpecSignatureTypePrivate MetaV0alpha1SpecSignatureType = "private" + MetaV0alpha1SpecSignatureTypePrivateGlob MetaV0alpha1SpecSignatureType = "private-glob" +) diff --git a/apps/plugins/pkg/apis/plugins/v0alpha1/plugin_spec_gen.go b/apps/plugins/pkg/apis/plugins/v0alpha1/plugin_spec_gen.go index 9ae14bcbdc5..51f5440eb92 100644 --- a/apps/plugins/pkg/apis/plugins/v0alpha1/plugin_spec_gen.go +++ b/apps/plugins/pkg/apis/plugins/v0alpha1/plugin_spec_gen.go @@ -4,21 +4,12 @@ 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"` + Id string `json:"id"` + Version string `json:"version"` + Url *string `json:"url,omitempty"` } // 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" -) diff --git a/apps/plugins/pkg/apis/plugins_manifest.go b/apps/plugins/pkg/apis/plugins_manifest.go index 1a351eb2baf..7b87dcf0ea7 100644 --- a/apps/plugins/pkg/apis/plugins_manifest.go +++ b/apps/plugins/pkg/apis/plugins_manifest.go @@ -20,10 +20,10 @@ import ( ) var ( - 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"]},"spec":{"additionalProperties":false,"properties":{"class":{"enum":["core","external"],"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"}}`) + 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"]},"spec":{"additionalProperties":false,"properties":{"id":{"type":"string"},"url":{"type":"string"},"version":{"type":"string"}},"required":["id","version"],"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) - rawSchemaMetav0alpha1 = []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":{"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"},"suggestions":{"type":"boolean"},"tracing":{"type":"boolean"},"type":{"description":"Plugin type","enum":["app","datasource","panel","renderer"],"type":"string"}},"required":["id","type","name","info","dependencies"],"type":"object"},"Meta":{"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"},"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"}}`) + rawSchemaMetav0alpha1 = []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":{"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"},"suggestions":{"type":"boolean"},"tracing":{"type":"boolean"},"type":{"description":"Plugin type","enum":["app","datasource","panel","renderer"],"type":"string"}},"required":["id","type","name","info","dependencies"],"type":"object"},"Meta":{"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"},"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":{"angular":{"additionalProperties":false,"properties":{"detected":{"type":"boolean"}},"required":["detected"],"type":"object"},"baseURL":{"type":"string"},"children":{"description":"+listType=atomic","items":{"type":"string"},"type":"array"},"class":{"enum":["core","external"],"type":"string"},"module":{"additionalProperties":false,"properties":{"hash":{"type":"string"},"loadingStrategy":{"enum":["fetch","script"],"type":"string"},"path":{"type":"string"}},"required":["path"],"type":"object"},"pluginJson":{"$ref":"#/components/schemas/JSONData"},"signature":{"additionalProperties":false,"properties":{"org":{"type":"string"},"status":{"enum":["internal","valid","invalid","modified","unsigned"],"type":"string"},"type":{"enum":["grafana","commercial","community","private","private-glob"],"type":"string"}},"required":["status"],"type":"object"},"translations":{"additionalProperties":{"type":"string"},"type":"object"}},"required":["pluginJson","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"}}`) versionSchemaMetav0alpha1 app.VersionSchema _ = json.Unmarshal(rawSchemaMetav0alpha1, &versionSchemaMetav0alpha1) ) diff --git a/apps/plugins/pkg/app/install/registrar.go b/apps/plugins/pkg/app/install/registrar.go index 3977fd88cf0..a900db1a68d 100644 --- a/apps/plugins/pkg/app/install/registrar.go +++ b/apps/plugins/pkg/app/install/registrar.go @@ -15,16 +15,6 @@ const ( PluginInstallSourceAnnotation = "plugins.grafana.app/install-source" ) -// Class represents the plugin class type in an unversioned internal format. -// This intentionally duplicates the versioned API type (PluginInstallSpecClass) to decouple -// internal code from API version changes, making it easier to support multiple API versions. -type Class = string - -const ( - ClassCore Class = "core" - ClassExternal Class = "external" -) - type Source = string const ( @@ -36,7 +26,6 @@ type PluginInstall struct { ID string Version string URL string - Class Class Source Source } @@ -57,7 +46,6 @@ func (p *PluginInstall) ToPluginInstallV0Alpha1(namespace string) *pluginsv0alph Id: p.ID, Version: p.Version, Url: url, - Class: pluginsv0alpha1.PluginSpecClass(p.Class), }, } } @@ -70,9 +58,6 @@ func (p *PluginInstall) ShouldUpdate(existing *pluginsv0alpha1.Plugin) bool { if existing.Spec.Version != update.Spec.Version { return true } - if existing.Spec.Class != update.Spec.Class { - return true // this should never really happen - } if !equalStringPointers(existing.Spec.Url, update.Spec.Url) { return true } diff --git a/apps/plugins/pkg/app/install/registrar_test.go b/apps/plugins/pkg/app/install/registrar_test.go index f1e0adbc508..6961acb98f8 100644 --- a/apps/plugins/pkg/app/install/registrar_test.go +++ b/apps/plugins/pkg/app/install/registrar_test.go @@ -26,14 +26,12 @@ func TestPluginInstall_ShouldUpdate(t *testing.T) { Spec: pluginsv0alpha1.PluginSpec{ Id: "plugin-1", Version: "1.0.0", - Class: pluginsv0alpha1.PluginSpecClass(ClassExternal), }, } baseInstall := PluginInstall{ ID: "plugin-1", Version: "1.0.0", - Class: ClassExternal, Source: SourcePluginStore, } @@ -54,13 +52,6 @@ func TestPluginInstall_ShouldUpdate(t *testing.T) { }, expectUpdate: true, }, - { - name: "class differs", - modifyInstall: func(pi *PluginInstall) { - pi.Class = ClassCore - }, - expectUpdate: true, - }, { name: "url differs", modifyInstall: func(pi *PluginInstall) { @@ -109,7 +100,6 @@ func TestInstallRegistrar_Register(t *testing.T) { install: &PluginInstall{ ID: "plugin-1", Version: "1.0.0", - Class: ClassExternal, Source: SourcePluginStore, }, existingErr: errorsK8s.NewNotFound(pluginGroupResource(), "plugin-1"), @@ -120,7 +110,6 @@ func TestInstallRegistrar_Register(t *testing.T) { install: &PluginInstall{ ID: "plugin-1", Version: "2.0.0", - Class: ClassExternal, Source: SourcePluginStore, }, existing: &pluginsv0alpha1.Plugin{ @@ -135,7 +124,6 @@ func TestInstallRegistrar_Register(t *testing.T) { Spec: pluginsv0alpha1.PluginSpec{ Id: "plugin-1", Version: "1.0.0", - Class: pluginsv0alpha1.PluginSpecClass(ClassExternal), }, }, expectedUpdates: 1, @@ -145,7 +133,6 @@ func TestInstallRegistrar_Register(t *testing.T) { install: &PluginInstall{ ID: "plugin-1", Version: "1.0.0", - Class: ClassExternal, Source: SourcePluginStore, }, existing: &pluginsv0alpha1.Plugin{ @@ -160,7 +147,6 @@ func TestInstallRegistrar_Register(t *testing.T) { Spec: pluginsv0alpha1.PluginSpec{ Id: "plugin-1", Version: "1.0.0", - Class: pluginsv0alpha1.PluginSpecClass(ClassExternal), }, }, }, @@ -169,7 +155,6 @@ func TestInstallRegistrar_Register(t *testing.T) { install: &PluginInstall{ ID: "plugin-err", Version: "1.0.0", - Class: ClassExternal, Source: SourcePluginStore, }, existingErr: errorsK8s.NewInternalError(errors.New("boom")), @@ -410,7 +395,6 @@ func TestPluginInstall_ToPluginInstallV0Alpha1(t *testing.T) { install: PluginInstall{ ID: "plugin-1", Version: "1.0.0", - Class: ClassExternal, Source: SourcePluginStore, }, namespace: "org-1", @@ -424,7 +408,6 @@ func TestPluginInstall_ToPluginInstallV0Alpha1(t *testing.T) { ID: "plugin-1", Version: "1.0.0", URL: "https://example.com/plugin.zip", - Class: ClassExternal, Source: SourcePluginStore, }, namespace: "org-1", @@ -433,25 +416,11 @@ func TestPluginInstall_ToPluginInstallV0Alpha1(t *testing.T) { require.Equal(t, "https://example.com/plugin.zip", *p.Spec.Url) }, }, - { - name: "core class is mapped correctly", - install: PluginInstall{ - ID: "plugin-core", - Version: "2.0.0", - Class: ClassCore, - Source: SourcePluginStore, - }, - namespace: "org-2", - validate: func(t *testing.T, p *pluginsv0alpha1.Plugin) { - require.Equal(t, pluginsv0alpha1.PluginSpecClass(ClassCore), p.Spec.Class) - }, - }, { name: "source annotation is set correctly", install: PluginInstall{ ID: "plugin-1", Version: "1.0.0", - Class: ClassExternal, Source: SourceUnknown, }, namespace: "org-1", @@ -464,7 +433,6 @@ func TestPluginInstall_ToPluginInstallV0Alpha1(t *testing.T) { install: PluginInstall{ ID: "my-plugin", Version: "1.0.0", - Class: ClassExternal, Source: SourcePluginStore, }, namespace: "my-namespace", @@ -556,7 +524,6 @@ func TestPluginInstall_ShouldUpdate_URLTransitions(t *testing.T) { ID: "plugin-1", Version: "1.0.0", URL: newURL, - Class: ClassExternal, Source: SourcePluginStore, }, existingURL: nil, @@ -568,7 +535,6 @@ func TestPluginInstall_ShouldUpdate_URLTransitions(t *testing.T) { ID: "plugin-1", Version: "1.0.0", URL: "", - Class: ClassExternal, Source: SourcePluginStore, }, existingURL: &existingURL, @@ -580,7 +546,6 @@ func TestPluginInstall_ShouldUpdate_URLTransitions(t *testing.T) { ID: "plugin-1", Version: "1.0.0", URL: "", - Class: ClassExternal, Source: SourcePluginStore, }, existingURL: nil, @@ -592,7 +557,6 @@ func TestPluginInstall_ShouldUpdate_URLTransitions(t *testing.T) { ID: "plugin-1", Version: "1.0.0", URL: existingURL, - Class: ClassExternal, Source: SourcePluginStore, }, existingURL: &existingURL, @@ -614,7 +578,6 @@ func TestPluginInstall_ShouldUpdate_URLTransitions(t *testing.T) { Id: "plugin-1", Version: "1.0.0", Url: tt.existingURL, - Class: pluginsv0alpha1.PluginSpecClass(ClassExternal), }, } @@ -670,7 +633,6 @@ func TestInstallRegistrar_Register_ErrorCases(t *testing.T) { install: &PluginInstall{ ID: "plugin-1", Version: "1.0.0", - Class: ClassExternal, Source: SourcePluginStore, }, setupClient: func(fc *fakePluginInstallClient) { @@ -688,7 +650,6 @@ func TestInstallRegistrar_Register_ErrorCases(t *testing.T) { install: &PluginInstall{ ID: "plugin-1", Version: "2.0.0", - Class: ClassExternal, Source: SourcePluginStore, }, setupClient: func(fc *fakePluginInstallClient) { @@ -705,7 +666,6 @@ func TestInstallRegistrar_Register_ErrorCases(t *testing.T) { Spec: pluginsv0alpha1.PluginSpec{ Id: "plugin-1", Version: "1.0.0", - Class: pluginsv0alpha1.PluginSpecClass(ClassExternal), }, }, nil } @@ -876,7 +836,6 @@ func TestInstallRegistrar_GetClientError(t *testing.T) { install := &PluginInstall{ ID: "plugin-1", Version: "1.0.0", - Class: ClassExternal, Source: SourcePluginStore, } diff --git a/apps/plugins/pkg/app/meta/catalog.go b/apps/plugins/pkg/app/meta/catalog.go index 6e6a47fa0bd..481db9b5947 100644 --- a/apps/plugins/pkg/app/meta/catalog.go +++ b/apps/plugins/pkg/app/meta/catalog.go @@ -10,8 +10,6 @@ import ( "time" "github.com/grafana/grafana-app-sdk/logging" - - pluginsv0alpha1 "github.com/grafana/grafana/apps/plugins/pkg/apis/plugins/v0alpha1" ) const ( @@ -87,45 +85,9 @@ func (p *CatalogProvider) GetMeta(ctx context.Context, pluginID, version string) return nil, fmt.Errorf("failed to decode response: %w", err) } + metaSpec := grafanaComPluginVersionMetaToMetaSpec(gcomMeta) return &Result{ - Meta: gcomMeta.JSON, + Meta: metaSpec, TTL: p.ttl, }, nil } - -// grafanaComPluginVersionMeta represents the response from grafana.com API -// GET /api/plugins/{pluginId}/versions/{version} -type grafanaComPluginVersionMeta struct { - PluginID string `json:"pluginSlug"` - Version string `json:"version"` - URL string `json:"url"` - Commit string `json:"commit"` - Description string `json:"description"` - Keywords []string `json:"keywords"` - CreatedAt time.Time `json:"createdAt"` - UpdatedAt time.Time `json:"updatedAt"` - JSON pluginsv0alpha1.MetaJSONData `json:"json"` - Readme string `json:"readme"` - Downloads int `json:"downloads"` - Verified bool `json:"verified"` - Status string `json:"status"` - StatusContext string `json:"statusContext"` - DownloadSlug string `json:"downloadSlug"` - SignatureType string `json:"signatureType"` - SignedByOrg string `json:"signedByOrg"` - SignedByOrgName string `json:"signedByOrgName"` - Packages struct { - Any struct { - Md5 string `json:"md5"` - Sha256 string `json:"sha256"` - PackageName string `json:"packageName"` - DownloadURL string `json:"downloadUrl"` - } `json:"any"` - } `json:"packages"` - Links []struct { - Rel string `json:"rel"` - Href string `json:"href"` - } `json:"links"` - AngularDetected bool `json:"angularDetected"` - Scopes []string `json:"scopes"` -} diff --git a/apps/plugins/pkg/app/meta/catalog_test.go b/apps/plugins/pkg/app/meta/catalog_test.go index 845afc7cd54..1dea816e002 100644 --- a/apps/plugins/pkg/app/meta/catalog_test.go +++ b/apps/plugins/pkg/app/meta/catalog_test.go @@ -49,7 +49,7 @@ func TestCatalogProvider_GetMeta(t *testing.T) { require.NoError(t, err) require.NotNil(t, result) - assert.Equal(t, expectedMeta, result.Meta) + assert.Equal(t, expectedMeta, result.Meta.PluginJson) assert.Equal(t, defaultCatalogTTL, result.TTL) }) diff --git a/apps/plugins/pkg/app/meta/converter.go b/apps/plugins/pkg/app/meta/converter.go new file mode 100644 index 00000000000..28180a263bd --- /dev/null +++ b/apps/plugins/pkg/app/meta/converter.go @@ -0,0 +1,744 @@ +package meta + +import ( + "encoding/json" + "time" + + pluginsv0alpha1 "github.com/grafana/grafana/apps/plugins/pkg/apis/plugins/v0alpha1" + "github.com/grafana/grafana/pkg/plugins" + "github.com/grafana/grafana/pkg/services/pluginsintegration/pluginstore" +) + +// jsonDataToMetaJSONData converts a plugins.JSONData to a pluginsv0alpha1.MetaJSONData. +// nolint:gocyclo +func jsonDataToMetaJSONData(jsonData plugins.JSONData) pluginsv0alpha1.MetaJSONData { + meta := pluginsv0alpha1.MetaJSONData{ + Id: jsonData.ID, + Name: jsonData.Name, + } + + // Map plugin type + switch jsonData.Type { + case plugins.TypeApp: + meta.Type = pluginsv0alpha1.MetaJSONDataTypeApp + case plugins.TypeDataSource: + meta.Type = pluginsv0alpha1.MetaJSONDataTypeDatasource + case plugins.TypePanel: + meta.Type = pluginsv0alpha1.MetaJSONDataTypePanel + case plugins.TypeRenderer: + meta.Type = pluginsv0alpha1.MetaJSONDataTypeRenderer + } + + // Map Info + meta.Info = pluginsv0alpha1.MetaInfo{ + Keywords: jsonData.Info.Keywords, + Logos: pluginsv0alpha1.MetaV0alpha1InfoLogos{ + Small: jsonData.Info.Logos.Small, + Large: jsonData.Info.Logos.Large, + }, + Updated: jsonData.Info.Updated, + Version: jsonData.Info.Version, + } + + if jsonData.Info.Description != "" { + meta.Info.Description = &jsonData.Info.Description + } + + if jsonData.Info.Author.Name != "" || jsonData.Info.Author.URL != "" { + author := &pluginsv0alpha1.MetaV0alpha1InfoAuthor{} + if jsonData.Info.Author.Name != "" { + author.Name = &jsonData.Info.Author.Name + } + if jsonData.Info.Author.URL != "" { + author.Url = &jsonData.Info.Author.URL + } + meta.Info.Author = author + } + + if len(jsonData.Info.Links) > 0 { + meta.Info.Links = make([]pluginsv0alpha1.MetaV0alpha1InfoLinks, 0, len(jsonData.Info.Links)) + for _, link := range jsonData.Info.Links { + v0Link := pluginsv0alpha1.MetaV0alpha1InfoLinks{} + if link.Name != "" { + v0Link.Name = &link.Name + } + if link.URL != "" { + v0Link.Url = &link.URL + } + meta.Info.Links = append(meta.Info.Links, v0Link) + } + } + + if len(jsonData.Info.Screenshots) > 0 { + meta.Info.Screenshots = make([]pluginsv0alpha1.MetaV0alpha1InfoScreenshots, 0, len(jsonData.Info.Screenshots)) + for _, screenshot := range jsonData.Info.Screenshots { + v0Screenshot := pluginsv0alpha1.MetaV0alpha1InfoScreenshots{} + if screenshot.Name != "" { + v0Screenshot.Name = &screenshot.Name + } + if screenshot.Path != "" { + v0Screenshot.Path = &screenshot.Path + } + meta.Info.Screenshots = append(meta.Info.Screenshots, v0Screenshot) + } + } + + // Map Dependencies + meta.Dependencies = pluginsv0alpha1.MetaDependencies{ + GrafanaDependency: jsonData.Dependencies.GrafanaDependency, + } + + if jsonData.Dependencies.GrafanaVersion != "" { + meta.Dependencies.GrafanaVersion = &jsonData.Dependencies.GrafanaVersion + } + + if len(jsonData.Dependencies.Plugins) > 0 { + meta.Dependencies.Plugins = make([]pluginsv0alpha1.MetaV0alpha1DependenciesPlugins, 0, len(jsonData.Dependencies.Plugins)) + for _, dep := range jsonData.Dependencies.Plugins { + var depType pluginsv0alpha1.MetaV0alpha1DependenciesPluginsType + switch dep.Type { + case "app": + depType = pluginsv0alpha1.MetaV0alpha1DependenciesPluginsTypeApp + case "datasource": + depType = pluginsv0alpha1.MetaV0alpha1DependenciesPluginsTypeDatasource + case "panel": + depType = pluginsv0alpha1.MetaV0alpha1DependenciesPluginsTypePanel + } + meta.Dependencies.Plugins = append(meta.Dependencies.Plugins, pluginsv0alpha1.MetaV0alpha1DependenciesPlugins{ + Id: dep.ID, + Type: depType, + Name: dep.Name, + }) + } + } + + if len(jsonData.Dependencies.Extensions.ExposedComponents) > 0 { + meta.Dependencies.Extensions = &pluginsv0alpha1.MetaV0alpha1DependenciesExtensions{ + ExposedComponents: jsonData.Dependencies.Extensions.ExposedComponents, + } + } + + // Map optional boolean fields + if jsonData.Alerting { + meta.Alerting = &jsonData.Alerting + } + if jsonData.Annotations { + meta.Annotations = &jsonData.Annotations + } + if jsonData.AutoEnabled { + meta.AutoEnabled = &jsonData.AutoEnabled + } + if jsonData.Backend { + meta.Backend = &jsonData.Backend + } + if jsonData.BuiltIn { + meta.BuiltIn = &jsonData.BuiltIn + } + if jsonData.HideFromList { + meta.HideFromList = &jsonData.HideFromList + } + if jsonData.Logs { + meta.Logs = &jsonData.Logs + } + if jsonData.Metrics { + meta.Metrics = &jsonData.Metrics + } + if jsonData.MultiValueFilterOperators { + meta.MultiValueFilterOperators = &jsonData.MultiValueFilterOperators + } + if jsonData.Preload { + meta.Preload = &jsonData.Preload + } + if jsonData.SkipDataQuery { + meta.SkipDataQuery = &jsonData.SkipDataQuery + } + if jsonData.Streaming { + meta.Streaming = &jsonData.Streaming + } + if jsonData.Tracing { + meta.Tracing = &jsonData.Tracing + } + + // Map category + if jsonData.Category != "" { + var category pluginsv0alpha1.MetaJSONDataCategory + switch jsonData.Category { + case "tsdb": + category = pluginsv0alpha1.MetaJSONDataCategoryTsdb + case "logging": + category = pluginsv0alpha1.MetaJSONDataCategoryLogging + case "cloud": + category = pluginsv0alpha1.MetaJSONDataCategoryCloud + case "tracing": + category = pluginsv0alpha1.MetaJSONDataCategoryTracing + case "profiling": + category = pluginsv0alpha1.MetaJSONDataCategoryProfiling + case "sql": + category = pluginsv0alpha1.MetaJSONDataCategorySql + case "enterprise": + category = pluginsv0alpha1.MetaJSONDataCategoryEnterprise + case "iot": + category = pluginsv0alpha1.MetaJSONDataCategoryIot + case "other": + category = pluginsv0alpha1.MetaJSONDataCategoryOther + default: + category = pluginsv0alpha1.MetaJSONDataCategoryOther + } + meta.Category = &category + } + + // Map state + if jsonData.State != "" { + var state pluginsv0alpha1.MetaJSONDataState + switch jsonData.State { + case plugins.ReleaseStateAlpha: + state = pluginsv0alpha1.MetaJSONDataStateAlpha + case plugins.ReleaseStateBeta: + state = pluginsv0alpha1.MetaJSONDataStateBeta + default: + } + if state != "" { + meta.State = &state + } + } + + // Map executable + if jsonData.Executable != "" { + meta.Executable = &jsonData.Executable + } + + // Map QueryOptions + if len(jsonData.QueryOptions) > 0 { + queryOptions := &pluginsv0alpha1.MetaQueryOptions{} + if val, ok := jsonData.QueryOptions["maxDataPoints"]; ok { + queryOptions.MaxDataPoints = &val + } + if val, ok := jsonData.QueryOptions["minInterval"]; ok { + queryOptions.MinInterval = &val + } + if val, ok := jsonData.QueryOptions["cacheTimeout"]; ok { + queryOptions.CacheTimeout = &val + } + meta.QueryOptions = queryOptions + } + + // Map Includes + if len(jsonData.Includes) > 0 { + meta.Includes = make([]pluginsv0alpha1.MetaInclude, 0, len(jsonData.Includes)) + for _, include := range jsonData.Includes { + v0Include := pluginsv0alpha1.MetaInclude{} + if include.UID != "" { + v0Include.Uid = &include.UID + } + if include.Type != "" { + var includeType pluginsv0alpha1.MetaIncludeType + switch include.Type { + case "dashboard": + includeType = pluginsv0alpha1.MetaIncludeTypeDashboard + case "page": + includeType = pluginsv0alpha1.MetaIncludeTypePage + case "panel": + includeType = pluginsv0alpha1.MetaIncludeTypePanel + case "datasource": + includeType = pluginsv0alpha1.MetaIncludeTypeDatasource + } + v0Include.Type = &includeType + } + if include.Name != "" { + v0Include.Name = &include.Name + } + if include.Component != "" { + v0Include.Component = &include.Component + } + if include.Role != "" { + var role pluginsv0alpha1.MetaIncludeRole + switch include.Role { + case "Admin": + role = pluginsv0alpha1.MetaIncludeRoleAdmin + case "Editor": + role = pluginsv0alpha1.MetaIncludeRoleEditor + case "Viewer": + role = pluginsv0alpha1.MetaIncludeRoleViewer + } + v0Include.Role = &role + } + if include.Action != "" { + v0Include.Action = &include.Action + } + if include.Path != "" { + v0Include.Path = &include.Path + } + if include.AddToNav { + v0Include.AddToNav = &include.AddToNav + } + if include.DefaultNav { + v0Include.DefaultNav = &include.DefaultNav + } + if include.Icon != "" { + v0Include.Icon = &include.Icon + } + meta.Includes = append(meta.Includes, v0Include) + } + } + + // Map Routes + if len(jsonData.Routes) > 0 { + meta.Routes = make([]pluginsv0alpha1.MetaRoute, 0, len(jsonData.Routes)) + for _, route := range jsonData.Routes { + v0Route := pluginsv0alpha1.MetaRoute{} + if route.Path != "" { + v0Route.Path = &route.Path + } + if route.Method != "" { + v0Route.Method = &route.Method + } + if route.URL != "" { + v0Route.Url = &route.URL + } + if route.ReqRole != "" { + reqRole := string(route.ReqRole) + v0Route.ReqRole = &reqRole + } + if route.ReqAction != "" { + v0Route.ReqAction = &route.ReqAction + } + if len(route.Headers) > 0 { + headers := make([]string, 0, len(route.Headers)) + for _, header := range route.Headers { + headers = append(headers, header.Name+": "+header.Content) + } + v0Route.Headers = headers + } + if len(route.URLParams) > 0 { + v0Route.UrlParams = make([]pluginsv0alpha1.MetaV0alpha1RouteUrlParams, 0, len(route.URLParams)) + for _, param := range route.URLParams { + v0Param := pluginsv0alpha1.MetaV0alpha1RouteUrlParams{} + if param.Name != "" { + v0Param.Name = ¶m.Name + } + if param.Content != "" { + v0Param.Content = ¶m.Content + } + v0Route.UrlParams = append(v0Route.UrlParams, v0Param) + } + } + if route.TokenAuth != nil { + v0Route.TokenAuth = &pluginsv0alpha1.MetaV0alpha1RouteTokenAuth{} + if route.TokenAuth.Url != "" { + v0Route.TokenAuth.Url = &route.TokenAuth.Url + } + if len(route.TokenAuth.Scopes) > 0 { + v0Route.TokenAuth.Scopes = route.TokenAuth.Scopes + } + if len(route.TokenAuth.Params) > 0 { + v0Route.TokenAuth.Params = make(map[string]interface{}) + for k, v := range route.TokenAuth.Params { + v0Route.TokenAuth.Params[k] = v + } + } + } + if route.JwtTokenAuth != nil { + v0Route.JwtTokenAuth = &pluginsv0alpha1.MetaV0alpha1RouteJwtTokenAuth{} + if route.JwtTokenAuth.Url != "" { + v0Route.JwtTokenAuth.Url = &route.JwtTokenAuth.Url + } + if len(route.JwtTokenAuth.Scopes) > 0 { + v0Route.JwtTokenAuth.Scopes = route.JwtTokenAuth.Scopes + } + if len(route.JwtTokenAuth.Params) > 0 { + v0Route.JwtTokenAuth.Params = make(map[string]interface{}) + for k, v := range route.JwtTokenAuth.Params { + v0Route.JwtTokenAuth.Params[k] = v + } + } + } + if len(route.Body) > 0 { + var bodyMap map[string]interface{} + if err := json.Unmarshal(route.Body, &bodyMap); err == nil { + v0Route.Body = bodyMap + } + } + meta.Routes = append(meta.Routes, v0Route) + } + } + + // Map Extensions + if len(jsonData.Extensions.AddedLinks) > 0 || len(jsonData.Extensions.AddedComponents) > 0 || + len(jsonData.Extensions.ExposedComponents) > 0 || len(jsonData.Extensions.ExtensionPoints) > 0 { + extensions := &pluginsv0alpha1.MetaExtensions{} + + if len(jsonData.Extensions.AddedLinks) > 0 { + extensions.AddedLinks = make([]pluginsv0alpha1.MetaV0alpha1ExtensionsAddedLinks, 0, len(jsonData.Extensions.AddedLinks)) + for _, link := range jsonData.Extensions.AddedLinks { + v0Link := pluginsv0alpha1.MetaV0alpha1ExtensionsAddedLinks{ + Targets: link.Targets, + Title: link.Title, + } + if link.Description != "" { + v0Link.Description = &link.Description + } + extensions.AddedLinks = append(extensions.AddedLinks, v0Link) + } + } + + if len(jsonData.Extensions.AddedComponents) > 0 { + extensions.AddedComponents = make([]pluginsv0alpha1.MetaV0alpha1ExtensionsAddedComponents, 0, len(jsonData.Extensions.AddedComponents)) + for _, comp := range jsonData.Extensions.AddedComponents { + v0Comp := pluginsv0alpha1.MetaV0alpha1ExtensionsAddedComponents{ + Targets: comp.Targets, + Title: comp.Title, + } + if comp.Description != "" { + v0Comp.Description = &comp.Description + } + extensions.AddedComponents = append(extensions.AddedComponents, v0Comp) + } + } + + if len(jsonData.Extensions.ExposedComponents) > 0 { + extensions.ExposedComponents = make([]pluginsv0alpha1.MetaV0alpha1ExtensionsExposedComponents, 0, len(jsonData.Extensions.ExposedComponents)) + for _, comp := range jsonData.Extensions.ExposedComponents { + v0Comp := pluginsv0alpha1.MetaV0alpha1ExtensionsExposedComponents{ + Id: comp.Id, + } + if comp.Title != "" { + v0Comp.Title = &comp.Title + } + if comp.Description != "" { + v0Comp.Description = &comp.Description + } + extensions.ExposedComponents = append(extensions.ExposedComponents, v0Comp) + } + } + + if len(jsonData.Extensions.ExtensionPoints) > 0 { + extensions.ExtensionPoints = make([]pluginsv0alpha1.MetaV0alpha1ExtensionsExtensionPoints, 0, len(jsonData.Extensions.ExtensionPoints)) + for _, point := range jsonData.Extensions.ExtensionPoints { + v0Point := pluginsv0alpha1.MetaV0alpha1ExtensionsExtensionPoints{ + Id: point.Id, + } + if point.Title != "" { + v0Point.Title = &point.Title + } + if point.Description != "" { + v0Point.Description = &point.Description + } + extensions.ExtensionPoints = append(extensions.ExtensionPoints, v0Point) + } + } + + meta.Extensions = extensions + } + + // Map Roles + if len(jsonData.Roles) > 0 { + meta.Roles = make([]pluginsv0alpha1.MetaRole, 0, len(jsonData.Roles)) + for _, role := range jsonData.Roles { + v0Role := pluginsv0alpha1.MetaRole{ + Grants: role.Grants, + } + if role.Role.Name != "" || role.Role.Description != "" || len(role.Role.Permissions) > 0 { + v0RoleRole := &pluginsv0alpha1.MetaV0alpha1RoleRole{} + if role.Role.Name != "" { + v0RoleRole.Name = &role.Role.Name + } + if role.Role.Description != "" { + v0RoleRole.Description = &role.Role.Description + } + if len(role.Role.Permissions) > 0 { + v0RoleRole.Permissions = make([]pluginsv0alpha1.MetaV0alpha1RoleRolePermissions, 0, len(role.Role.Permissions)) + for _, perm := range role.Role.Permissions { + v0Perm := pluginsv0alpha1.MetaV0alpha1RoleRolePermissions{} + if perm.Action != "" { + v0Perm.Action = &perm.Action + } + if perm.Scope != "" { + v0Perm.Scope = &perm.Scope + } + v0RoleRole.Permissions = append(v0RoleRole.Permissions, v0Perm) + } + } + v0Role.Role = v0RoleRole + } + meta.Roles = append(meta.Roles, v0Role) + } + } + + // Map IAM + if jsonData.IAM != nil && len(jsonData.IAM.Permissions) > 0 { + iam := &pluginsv0alpha1.MetaIAM{ + Permissions: make([]pluginsv0alpha1.MetaV0alpha1IAMPermissions, 0, len(jsonData.IAM.Permissions)), + } + for _, perm := range jsonData.IAM.Permissions { + v0Perm := pluginsv0alpha1.MetaV0alpha1IAMPermissions{} + if perm.Action != "" { + v0Perm.Action = &perm.Action + } + if perm.Scope != "" { + v0Perm.Scope = &perm.Scope + } + iam.Permissions = append(iam.Permissions, v0Perm) + } + meta.Iam = iam + } + + return meta +} + +// pluginStorePluginToMeta converts a pluginstore.Plugin to a pluginsv0alpha1.MetaSpec. +// This is similar to pluginToPluginMetaSpec but works with the plugin store DTO. +// loadingStrategy and moduleHash are optional calculated values that can be provided. +func pluginStorePluginToMeta(plugin pluginstore.Plugin, loadingStrategy plugins.LoadingStrategy, moduleHash string) pluginsv0alpha1.MetaSpec { + metaSpec := pluginsv0alpha1.MetaSpec{ + PluginJson: jsonDataToMetaJSONData(plugin.JSONData), + } + + // Set Class - default to External if not specified + var c pluginsv0alpha1.MetaSpecClass + if plugin.Class == plugins.ClassCore { + c = pluginsv0alpha1.MetaSpecClassCore + } else { + c = pluginsv0alpha1.MetaSpecClassExternal + } + metaSpec.Class = c + + if plugin.Module != "" { + module := &pluginsv0alpha1.MetaV0alpha1SpecModule{ + Path: plugin.Module, + } + if moduleHash != "" { + module.Hash = &moduleHash + } + if loadingStrategy != "" { + var ls pluginsv0alpha1.MetaV0alpha1SpecModuleLoadingStrategy + switch loadingStrategy { + case plugins.LoadingStrategyFetch: + ls = pluginsv0alpha1.MetaV0alpha1SpecModuleLoadingStrategyFetch + case plugins.LoadingStrategyScript: + ls = pluginsv0alpha1.MetaV0alpha1SpecModuleLoadingStrategyScript + } + module.LoadingStrategy = &ls + } + metaSpec.Module = module + } + + if plugin.BaseURL != "" { + metaSpec.BaseURL = &plugin.BaseURL + } + + if plugin.Signature != "" { + signature := &pluginsv0alpha1.MetaV0alpha1SpecSignature{ + Status: convertSignatureStatus(plugin.Signature), + } + + if plugin.SignatureType != "" { + sigType := convertSignatureType(plugin.SignatureType) + signature.Type = &sigType + } + + if plugin.SignatureOrg != "" { + signature.Org = &plugin.SignatureOrg + } + + metaSpec.Signature = signature + } + + if len(plugin.Children) > 0 { + metaSpec.Children = plugin.Children + } + + metaSpec.Angular = &pluginsv0alpha1.MetaV0alpha1SpecAngular{ + Detected: plugin.Angular.Detected, + } + + if len(plugin.Translations) > 0 { + metaSpec.Translations = plugin.Translations + } + + return metaSpec +} + +// convertSignatureStatus converts plugins.SignatureStatus to pluginsv0alpha1.MetaV0alpha1SpecSignatureStatus. +func convertSignatureStatus(status plugins.SignatureStatus) pluginsv0alpha1.MetaV0alpha1SpecSignatureStatus { + switch status { + case plugins.SignatureStatusInternal: + return pluginsv0alpha1.MetaV0alpha1SpecSignatureStatusInternal + case plugins.SignatureStatusValid: + return pluginsv0alpha1.MetaV0alpha1SpecSignatureStatusValid + case plugins.SignatureStatusInvalid: + return pluginsv0alpha1.MetaV0alpha1SpecSignatureStatusInvalid + case plugins.SignatureStatusModified: + return pluginsv0alpha1.MetaV0alpha1SpecSignatureStatusModified + case plugins.SignatureStatusUnsigned: + return pluginsv0alpha1.MetaV0alpha1SpecSignatureStatusUnsigned + default: + return pluginsv0alpha1.MetaV0alpha1SpecSignatureStatusUnsigned + } +} + +// convertSignatureType converts plugins.SignatureType to pluginsv0alpha1.MetaV0alpha1SpecSignatureType. +func convertSignatureType(sigType plugins.SignatureType) pluginsv0alpha1.MetaV0alpha1SpecSignatureType { + switch sigType { + case plugins.SignatureTypeGrafana: + return pluginsv0alpha1.MetaV0alpha1SpecSignatureTypeGrafana + case plugins.SignatureTypeCommercial: + return pluginsv0alpha1.MetaV0alpha1SpecSignatureTypeCommercial + case plugins.SignatureTypeCommunity: + return pluginsv0alpha1.MetaV0alpha1SpecSignatureTypeCommunity + case plugins.SignatureTypePrivate: + return pluginsv0alpha1.MetaV0alpha1SpecSignatureTypePrivate + case plugins.SignatureTypePrivateGlob: + return pluginsv0alpha1.MetaV0alpha1SpecSignatureTypePrivateGlob + default: + return pluginsv0alpha1.MetaV0alpha1SpecSignatureTypeGrafana + } +} + +// pluginToMetaSpec converts a fully loaded *plugins.Plugin to a pluginsv0alpha1.MetaSpec. +func pluginToMetaSpec(plugin *plugins.Plugin) pluginsv0alpha1.MetaSpec { + metaSpec := pluginsv0alpha1.MetaSpec{ + PluginJson: jsonDataToMetaJSONData(plugin.JSONData), + } + + // Set Class - default to External if not specified + var c pluginsv0alpha1.MetaSpecClass + if plugin.Class == plugins.ClassCore { + c = pluginsv0alpha1.MetaSpecClassCore + } else { + c = pluginsv0alpha1.MetaSpecClassExternal + } + metaSpec.Class = c + + // Set module information + if plugin.Module != "" { + module := &pluginsv0alpha1.MetaV0alpha1SpecModule{ + Path: plugin.Module, + } + + loadingStrategy := pluginsv0alpha1.MetaV0alpha1SpecModuleLoadingStrategyScript + module.LoadingStrategy = &loadingStrategy + + metaSpec.Module = module + } + + // Set BaseURL + if plugin.BaseURL != "" { + metaSpec.BaseURL = &plugin.BaseURL + } + + // Set signature information + signature := &pluginsv0alpha1.MetaV0alpha1SpecSignature{ + Status: convertSignatureStatus(plugin.Signature), + } + + if plugin.SignatureType != "" { + sigType := convertSignatureType(plugin.SignatureType) + signature.Type = &sigType + } + + if plugin.SignatureOrg != "" { + signature.Org = &plugin.SignatureOrg + } + + metaSpec.Signature = signature + + if len(plugin.Children) > 0 { + children := make([]string, 0, len(plugin.Children)) + for _, child := range plugin.Children { + children = append(children, child.ID) + } + metaSpec.Children = children + } + + metaSpec.Angular = &pluginsv0alpha1.MetaV0alpha1SpecAngular{ + Detected: plugin.Angular.Detected, + } + + if len(plugin.Translations) > 0 { + metaSpec.Translations = plugin.Translations + } + + return metaSpec +} + +// grafanaComPluginVersionMeta represents the response from grafana.com API +// GET /api/plugins/{pluginId}/versions/{version} +type grafanaComPluginVersionMeta struct { + PluginID string `json:"pluginSlug"` + Version string `json:"version"` + URL string `json:"url"` + Commit string `json:"commit"` + Description string `json:"description"` + Keywords []string `json:"keywords"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` + JSON pluginsv0alpha1.MetaJSONData `json:"json"` + Readme string `json:"readme"` + Downloads int `json:"downloads"` + Verified bool `json:"verified"` + Status string `json:"status"` + StatusContext string `json:"statusContext"` + DownloadSlug string `json:"downloadSlug"` + SignatureType string `json:"signatureType"` + SignedByOrg string `json:"signedByOrg"` + SignedByOrgName string `json:"signedByOrgName"` + Packages struct { + Any struct { + Md5 string `json:"md5"` + Sha256 string `json:"sha256"` + PackageName string `json:"packageName"` + DownloadURL string `json:"downloadUrl"` + } `json:"any"` + } `json:"packages"` + Links []struct { + Rel string `json:"rel"` + Href string `json:"href"` + } `json:"links"` + AngularDetected bool `json:"angularDetected"` + Scopes []string `json:"scopes"` +} + +// grafanaComPluginVersionMetaToMetaSpec converts a grafanaComPluginVersionMeta to a pluginsv0alpha1.MetaSpec. +func grafanaComPluginVersionMetaToMetaSpec(gcomMeta grafanaComPluginVersionMeta) pluginsv0alpha1.MetaSpec { + metaSpec := pluginsv0alpha1.MetaSpec{ + PluginJson: gcomMeta.JSON, + Class: pluginsv0alpha1.MetaSpecClassExternal, + } + + if gcomMeta.SignatureType != "" { + signature := &pluginsv0alpha1.MetaV0alpha1SpecSignature{ + Status: pluginsv0alpha1.MetaV0alpha1SpecSignatureStatusValid, + } + + switch gcomMeta.SignatureType { + case "grafana": + sigType := pluginsv0alpha1.MetaV0alpha1SpecSignatureTypeGrafana + signature.Type = &sigType + case "commercial": + sigType := pluginsv0alpha1.MetaV0alpha1SpecSignatureTypeCommercial + signature.Type = &sigType + case "community": + sigType := pluginsv0alpha1.MetaV0alpha1SpecSignatureTypeCommunity + signature.Type = &sigType + case "private": + sigType := pluginsv0alpha1.MetaV0alpha1SpecSignatureTypePrivate + signature.Type = &sigType + case "private-glob": + sigType := pluginsv0alpha1.MetaV0alpha1SpecSignatureTypePrivateGlob + signature.Type = &sigType + } + + if gcomMeta.SignedByOrg != "" { + signature.Org = &gcomMeta.SignedByOrg + } + + metaSpec.Signature = signature + } + + // Set angular info + metaSpec.Angular = &pluginsv0alpha1.MetaV0alpha1SpecAngular{ + Detected: gcomMeta.AngularDetected, + } + + return metaSpec +} diff --git a/apps/plugins/pkg/app/meta/core.go b/apps/plugins/pkg/app/meta/core.go index e16f7a23db5..9fb167d5578 100644 --- a/apps/plugins/pkg/app/meta/core.go +++ b/apps/plugins/pkg/app/meta/core.go @@ -2,7 +2,6 @@ package meta import ( "context" - "encoding/json" "errors" "os" "path/filepath" @@ -13,7 +12,15 @@ import ( pluginsv0alpha1 "github.com/grafana/grafana/apps/plugins/pkg/apis/plugins/v0alpha1" "github.com/grafana/grafana/pkg/plugins" + "github.com/grafana/grafana/pkg/plugins/config" + pluginsLoader "github.com/grafana/grafana/pkg/plugins/manager/loader" + "github.com/grafana/grafana/pkg/plugins/manager/pipeline/bootstrap" + "github.com/grafana/grafana/pkg/plugins/manager/pipeline/discovery" + "github.com/grafana/grafana/pkg/plugins/manager/pipeline/initialization" + "github.com/grafana/grafana/pkg/plugins/manager/pipeline/termination" + "github.com/grafana/grafana/pkg/plugins/manager/pipeline/validation" "github.com/grafana/grafana/pkg/plugins/manager/sources" + "github.com/grafana/grafana/pkg/services/pluginsintegration/pluginerrs" ) const ( @@ -23,9 +30,10 @@ const ( // CoreProvider retrieves plugin metadata for core plugins. type CoreProvider struct { mu sync.RWMutex - loadedPlugins map[string]pluginsv0alpha1.MetaJSONData + loadedPlugins map[string]pluginsv0alpha1.MetaSpec initialized bool ttl time.Duration + loader pluginsLoader.Service } // NewCoreProvider creates a new CoreProvider for core plugins. @@ -35,9 +43,13 @@ func NewCoreProvider() *CoreProvider { // NewCoreProviderWithTTL creates a new CoreProvider with a custom TTL. func NewCoreProviderWithTTL(ttl time.Duration) *CoreProvider { + cfg := &config.PluginManagementCfg{ + Features: config.Features{}, + } return &CoreProvider{ - loadedPlugins: make(map[string]pluginsv0alpha1.MetaJSONData), + loadedPlugins: make(map[string]pluginsv0alpha1.MetaSpec), ttl: ttl, + loader: createLoader(cfg), } } @@ -76,9 +88,9 @@ func (p *CoreProvider) GetMeta(ctx context.Context, pluginID, _ string) (*Result p.initialized = true } - if meta, found := p.loadedPlugins[pluginID]; found { + if spec, found := p.loadedPlugins[pluginID]; found { return &Result{ - Meta: meta, + Meta: spec, TTL: p.ttl, }, nil } @@ -86,8 +98,8 @@ func (p *CoreProvider) GetMeta(ctx context.Context, pluginID, _ string) (*Result return nil, ErrMetaNotFound } -// loadPlugins discovers and caches all core plugins. -// Returns an error if the static root path cannot be found or if plugin discovery fails. +// loadPlugins discovers and caches all core plugins by fully loading them. +// Returns an error if the static root path cannot be found or if plugin loading fails. // This error will be handled gracefully by GetMeta, which will return ErrMetaNotFound // to allow other providers to handle the request. func (p *CoreProvider) loadPlugins(ctx context.Context) error { @@ -108,496 +120,51 @@ func (p *CoreProvider) loadPlugins(ctx context.Context) error { panelPath := filepath.Join(staticRootPath, "app", "plugins", "panel") src := sources.NewLocalSource(plugins.ClassCore, []string{datasourcePath, panelPath}) - ps, err := src.Discover(ctx) + loadedPlugins, err := p.loader.Load(ctx, src) if err != nil { return err } - if len(ps) == 0 { - logging.DefaultLogger.Warn("CoreProvider: no core plugins found during discovery") + if len(loadedPlugins) == 0 { + logging.DefaultLogger.Warn("CoreProvider: no core plugins found during loading") return nil } - for _, bundle := range ps { - meta := jsonDataToMetaJSONData(bundle.Primary.JSONData) - p.loadedPlugins[bundle.Primary.JSONData.ID] = meta + for _, plugin := range loadedPlugins { + metaSpec := pluginToMetaSpec(plugin) + p.loadedPlugins[plugin.ID] = metaSpec } return nil } -// jsonDataToMetaJSONData converts a plugins.JSONData to a pluginsv0alpha1.MetaJSONData. -// nolint:gocyclo -func jsonDataToMetaJSONData(jsonData plugins.JSONData) pluginsv0alpha1.MetaJSONData { - meta := pluginsv0alpha1.MetaJSONData{ - Id: jsonData.ID, - Name: jsonData.Name, - } - - // Map plugin type - switch jsonData.Type { - case plugins.TypeApp: - meta.Type = pluginsv0alpha1.MetaJSONDataTypeApp - case plugins.TypeDataSource: - meta.Type = pluginsv0alpha1.MetaJSONDataTypeDatasource - case plugins.TypePanel: - meta.Type = pluginsv0alpha1.MetaJSONDataTypePanel - case plugins.TypeRenderer: - meta.Type = pluginsv0alpha1.MetaJSONDataTypeRenderer - } - - // Map Info - meta.Info = pluginsv0alpha1.MetaInfo{ - Keywords: jsonData.Info.Keywords, - Logos: pluginsv0alpha1.MetaV0alpha1InfoLogos{ - Small: jsonData.Info.Logos.Small, - Large: jsonData.Info.Logos.Large, +// createLoader creates a loader service configured for core plugins. +func createLoader(cfg *config.PluginManagementCfg) pluginsLoader.Service { + d := discovery.New(cfg, discovery.Opts{ + FilterFuncs: []discovery.FilterFunc{ + // Allow all plugin types for core plugins }, - Updated: jsonData.Info.Updated, - Version: jsonData.Info.Version, - } + }) + b := bootstrap.New(cfg, bootstrap.Opts{ + DecorateFuncs: []bootstrap.DecorateFunc{}, // no decoration required for metadata + }) + v := validation.New(cfg, validation.Opts{ + ValidateFuncs: []validation.ValidateFunc{ + // Skip validation for core plugins - they're trusted + }, + }) + i := initialization.New(cfg, initialization.Opts{ + InitializeFuncs: []initialization.InitializeFunc{ + // Skip initialization - we only need metadata, not running plugins + }, + }) + t, _ := termination.New(cfg, termination.Opts{ + TerminateFuncs: []termination.TerminateFunc{ + // No termination needed for metadata-only loading + }, + }) - if jsonData.Info.Description != "" { - meta.Info.Description = &jsonData.Info.Description - } + et := pluginerrs.ProvideErrorTracker() - if jsonData.Info.Author.Name != "" || jsonData.Info.Author.URL != "" { - author := &pluginsv0alpha1.MetaV0alpha1InfoAuthor{} - if jsonData.Info.Author.Name != "" { - author.Name = &jsonData.Info.Author.Name - } - if jsonData.Info.Author.URL != "" { - author.Url = &jsonData.Info.Author.URL - } - meta.Info.Author = author - } - - if len(jsonData.Info.Links) > 0 { - meta.Info.Links = make([]pluginsv0alpha1.MetaV0alpha1InfoLinks, 0, len(jsonData.Info.Links)) - for _, link := range jsonData.Info.Links { - v0Link := pluginsv0alpha1.MetaV0alpha1InfoLinks{} - if link.Name != "" { - v0Link.Name = &link.Name - } - if link.URL != "" { - v0Link.Url = &link.URL - } - meta.Info.Links = append(meta.Info.Links, v0Link) - } - } - - if len(jsonData.Info.Screenshots) > 0 { - meta.Info.Screenshots = make([]pluginsv0alpha1.MetaV0alpha1InfoScreenshots, 0, len(jsonData.Info.Screenshots)) - for _, screenshot := range jsonData.Info.Screenshots { - v0Screenshot := pluginsv0alpha1.MetaV0alpha1InfoScreenshots{} - if screenshot.Name != "" { - v0Screenshot.Name = &screenshot.Name - } - if screenshot.Path != "" { - v0Screenshot.Path = &screenshot.Path - } - meta.Info.Screenshots = append(meta.Info.Screenshots, v0Screenshot) - } - } - - // Map Dependencies - meta.Dependencies = pluginsv0alpha1.MetaDependencies{ - GrafanaDependency: jsonData.Dependencies.GrafanaDependency, - } - - if jsonData.Dependencies.GrafanaVersion != "" { - meta.Dependencies.GrafanaVersion = &jsonData.Dependencies.GrafanaVersion - } - - if len(jsonData.Dependencies.Plugins) > 0 { - meta.Dependencies.Plugins = make([]pluginsv0alpha1.MetaV0alpha1DependenciesPlugins, 0, len(jsonData.Dependencies.Plugins)) - for _, dep := range jsonData.Dependencies.Plugins { - var depType pluginsv0alpha1.MetaV0alpha1DependenciesPluginsType - switch dep.Type { - case "app": - depType = pluginsv0alpha1.MetaV0alpha1DependenciesPluginsTypeApp - case "datasource": - depType = pluginsv0alpha1.MetaV0alpha1DependenciesPluginsTypeDatasource - case "panel": - depType = pluginsv0alpha1.MetaV0alpha1DependenciesPluginsTypePanel - } - meta.Dependencies.Plugins = append(meta.Dependencies.Plugins, pluginsv0alpha1.MetaV0alpha1DependenciesPlugins{ - Id: dep.ID, - Type: depType, - Name: dep.Name, - }) - } - } - - if len(jsonData.Dependencies.Extensions.ExposedComponents) > 0 { - meta.Dependencies.Extensions = &pluginsv0alpha1.MetaV0alpha1DependenciesExtensions{ - ExposedComponents: jsonData.Dependencies.Extensions.ExposedComponents, - } - } - - // Map optional boolean fields - if jsonData.Alerting { - meta.Alerting = &jsonData.Alerting - } - if jsonData.Annotations { - meta.Annotations = &jsonData.Annotations - } - if jsonData.AutoEnabled { - meta.AutoEnabled = &jsonData.AutoEnabled - } - if jsonData.Backend { - meta.Backend = &jsonData.Backend - } - if jsonData.BuiltIn { - meta.BuiltIn = &jsonData.BuiltIn - } - if jsonData.HideFromList { - meta.HideFromList = &jsonData.HideFromList - } - if jsonData.Logs { - meta.Logs = &jsonData.Logs - } - if jsonData.Metrics { - meta.Metrics = &jsonData.Metrics - } - if jsonData.MultiValueFilterOperators { - meta.MultiValueFilterOperators = &jsonData.MultiValueFilterOperators - } - if jsonData.Preload { - meta.Preload = &jsonData.Preload - } - if jsonData.SkipDataQuery { - meta.SkipDataQuery = &jsonData.SkipDataQuery - } - if jsonData.Streaming { - meta.Streaming = &jsonData.Streaming - } - if jsonData.Tracing { - meta.Tracing = &jsonData.Tracing - } - - // Map category - if jsonData.Category != "" { - var category pluginsv0alpha1.MetaJSONDataCategory - switch jsonData.Category { - case "tsdb": - category = pluginsv0alpha1.MetaJSONDataCategoryTsdb - case "logging": - category = pluginsv0alpha1.MetaJSONDataCategoryLogging - case "cloud": - category = pluginsv0alpha1.MetaJSONDataCategoryCloud - case "tracing": - category = pluginsv0alpha1.MetaJSONDataCategoryTracing - case "profiling": - category = pluginsv0alpha1.MetaJSONDataCategoryProfiling - case "sql": - category = pluginsv0alpha1.MetaJSONDataCategorySql - case "enterprise": - category = pluginsv0alpha1.MetaJSONDataCategoryEnterprise - case "iot": - category = pluginsv0alpha1.MetaJSONDataCategoryIot - case "other": - category = pluginsv0alpha1.MetaJSONDataCategoryOther - default: - category = pluginsv0alpha1.MetaJSONDataCategoryOther - } - meta.Category = &category - } - - // Map state - if jsonData.State != "" { - var state pluginsv0alpha1.MetaJSONDataState - switch jsonData.State { - case plugins.ReleaseStateAlpha: - state = pluginsv0alpha1.MetaJSONDataStateAlpha - case plugins.ReleaseStateBeta: - state = pluginsv0alpha1.MetaJSONDataStateBeta - default: - } - if state != "" { - meta.State = &state - } - } - - // Map executable - if jsonData.Executable != "" { - meta.Executable = &jsonData.Executable - } - - // Map QueryOptions - if len(jsonData.QueryOptions) > 0 { - queryOptions := &pluginsv0alpha1.MetaQueryOptions{} - if val, ok := jsonData.QueryOptions["maxDataPoints"]; ok { - queryOptions.MaxDataPoints = &val - } - if val, ok := jsonData.QueryOptions["minInterval"]; ok { - queryOptions.MinInterval = &val - } - if val, ok := jsonData.QueryOptions["cacheTimeout"]; ok { - queryOptions.CacheTimeout = &val - } - meta.QueryOptions = queryOptions - } - - // Map Includes - if len(jsonData.Includes) > 0 { - meta.Includes = make([]pluginsv0alpha1.MetaInclude, 0, len(jsonData.Includes)) - for _, include := range jsonData.Includes { - v0Include := pluginsv0alpha1.MetaInclude{} - if include.UID != "" { - v0Include.Uid = &include.UID - } - if include.Type != "" { - var includeType pluginsv0alpha1.MetaIncludeType - switch include.Type { - case "dashboard": - includeType = pluginsv0alpha1.MetaIncludeTypeDashboard - case "page": - includeType = pluginsv0alpha1.MetaIncludeTypePage - case "panel": - includeType = pluginsv0alpha1.MetaIncludeTypePanel - case "datasource": - includeType = pluginsv0alpha1.MetaIncludeTypeDatasource - } - v0Include.Type = &includeType - } - if include.Name != "" { - v0Include.Name = &include.Name - } - if include.Component != "" { - v0Include.Component = &include.Component - } - if include.Role != "" { - var role pluginsv0alpha1.MetaIncludeRole - switch include.Role { - case "Admin": - role = pluginsv0alpha1.MetaIncludeRoleAdmin - case "Editor": - role = pluginsv0alpha1.MetaIncludeRoleEditor - case "Viewer": - role = pluginsv0alpha1.MetaIncludeRoleViewer - } - v0Include.Role = &role - } - if include.Action != "" { - v0Include.Action = &include.Action - } - if include.Path != "" { - v0Include.Path = &include.Path - } - if include.AddToNav { - v0Include.AddToNav = &include.AddToNav - } - if include.DefaultNav { - v0Include.DefaultNav = &include.DefaultNav - } - if include.Icon != "" { - v0Include.Icon = &include.Icon - } - meta.Includes = append(meta.Includes, v0Include) - } - } - - // Map Routes - if len(jsonData.Routes) > 0 { - meta.Routes = make([]pluginsv0alpha1.MetaRoute, 0, len(jsonData.Routes)) - for _, route := range jsonData.Routes { - v0Route := pluginsv0alpha1.MetaRoute{} - if route.Path != "" { - v0Route.Path = &route.Path - } - if route.Method != "" { - v0Route.Method = &route.Method - } - if route.URL != "" { - v0Route.Url = &route.URL - } - if route.ReqRole != "" { - reqRole := string(route.ReqRole) - v0Route.ReqRole = &reqRole - } - if route.ReqAction != "" { - v0Route.ReqAction = &route.ReqAction - } - if len(route.Headers) > 0 { - headers := make([]string, 0, len(route.Headers)) - for _, header := range route.Headers { - headers = append(headers, header.Name+": "+header.Content) - } - v0Route.Headers = headers - } - if len(route.URLParams) > 0 { - v0Route.UrlParams = make([]pluginsv0alpha1.MetaV0alpha1RouteUrlParams, 0, len(route.URLParams)) - for _, param := range route.URLParams { - v0Param := pluginsv0alpha1.MetaV0alpha1RouteUrlParams{} - if param.Name != "" { - v0Param.Name = ¶m.Name - } - if param.Content != "" { - v0Param.Content = ¶m.Content - } - v0Route.UrlParams = append(v0Route.UrlParams, v0Param) - } - } - if route.TokenAuth != nil { - v0Route.TokenAuth = &pluginsv0alpha1.MetaV0alpha1RouteTokenAuth{} - if route.TokenAuth.Url != "" { - v0Route.TokenAuth.Url = &route.TokenAuth.Url - } - if len(route.TokenAuth.Scopes) > 0 { - v0Route.TokenAuth.Scopes = route.TokenAuth.Scopes - } - if len(route.TokenAuth.Params) > 0 { - v0Route.TokenAuth.Params = make(map[string]interface{}) - for k, v := range route.TokenAuth.Params { - v0Route.TokenAuth.Params[k] = v - } - } - } - if route.JwtTokenAuth != nil { - v0Route.JwtTokenAuth = &pluginsv0alpha1.MetaV0alpha1RouteJwtTokenAuth{} - if route.JwtTokenAuth.Url != "" { - v0Route.JwtTokenAuth.Url = &route.JwtTokenAuth.Url - } - if len(route.JwtTokenAuth.Scopes) > 0 { - v0Route.JwtTokenAuth.Scopes = route.JwtTokenAuth.Scopes - } - if len(route.JwtTokenAuth.Params) > 0 { - v0Route.JwtTokenAuth.Params = make(map[string]interface{}) - for k, v := range route.JwtTokenAuth.Params { - v0Route.JwtTokenAuth.Params[k] = v - } - } - } - if len(route.Body) > 0 { - var bodyMap map[string]interface{} - if err := json.Unmarshal(route.Body, &bodyMap); err == nil { - v0Route.Body = bodyMap - } - } - meta.Routes = append(meta.Routes, v0Route) - } - } - - // Map Extensions - if len(jsonData.Extensions.AddedLinks) > 0 || len(jsonData.Extensions.AddedComponents) > 0 || - len(jsonData.Extensions.ExposedComponents) > 0 || len(jsonData.Extensions.ExtensionPoints) > 0 { - extensions := &pluginsv0alpha1.MetaExtensions{} - - if len(jsonData.Extensions.AddedLinks) > 0 { - extensions.AddedLinks = make([]pluginsv0alpha1.MetaV0alpha1ExtensionsAddedLinks, 0, len(jsonData.Extensions.AddedLinks)) - for _, link := range jsonData.Extensions.AddedLinks { - v0Link := pluginsv0alpha1.MetaV0alpha1ExtensionsAddedLinks{ - Targets: link.Targets, - Title: link.Title, - } - if link.Description != "" { - v0Link.Description = &link.Description - } - extensions.AddedLinks = append(extensions.AddedLinks, v0Link) - } - } - - if len(jsonData.Extensions.AddedComponents) > 0 { - extensions.AddedComponents = make([]pluginsv0alpha1.MetaV0alpha1ExtensionsAddedComponents, 0, len(jsonData.Extensions.AddedComponents)) - for _, comp := range jsonData.Extensions.AddedComponents { - v0Comp := pluginsv0alpha1.MetaV0alpha1ExtensionsAddedComponents{ - Targets: comp.Targets, - Title: comp.Title, - } - if comp.Description != "" { - v0Comp.Description = &comp.Description - } - extensions.AddedComponents = append(extensions.AddedComponents, v0Comp) - } - } - - if len(jsonData.Extensions.ExposedComponents) > 0 { - extensions.ExposedComponents = make([]pluginsv0alpha1.MetaV0alpha1ExtensionsExposedComponents, 0, len(jsonData.Extensions.ExposedComponents)) - for _, comp := range jsonData.Extensions.ExposedComponents { - v0Comp := pluginsv0alpha1.MetaV0alpha1ExtensionsExposedComponents{ - Id: comp.Id, - } - if comp.Title != "" { - v0Comp.Title = &comp.Title - } - if comp.Description != "" { - v0Comp.Description = &comp.Description - } - extensions.ExposedComponents = append(extensions.ExposedComponents, v0Comp) - } - } - - if len(jsonData.Extensions.ExtensionPoints) > 0 { - extensions.ExtensionPoints = make([]pluginsv0alpha1.MetaV0alpha1ExtensionsExtensionPoints, 0, len(jsonData.Extensions.ExtensionPoints)) - for _, point := range jsonData.Extensions.ExtensionPoints { - v0Point := pluginsv0alpha1.MetaV0alpha1ExtensionsExtensionPoints{ - Id: point.Id, - } - if point.Title != "" { - v0Point.Title = &point.Title - } - if point.Description != "" { - v0Point.Description = &point.Description - } - extensions.ExtensionPoints = append(extensions.ExtensionPoints, v0Point) - } - } - - meta.Extensions = extensions - } - - // Map Roles - if len(jsonData.Roles) > 0 { - meta.Roles = make([]pluginsv0alpha1.MetaRole, 0, len(jsonData.Roles)) - for _, role := range jsonData.Roles { - v0Role := pluginsv0alpha1.MetaRole{ - Grants: role.Grants, - } - if role.Role.Name != "" || role.Role.Description != "" || len(role.Role.Permissions) > 0 { - v0RoleRole := &pluginsv0alpha1.MetaV0alpha1RoleRole{} - if role.Role.Name != "" { - v0RoleRole.Name = &role.Role.Name - } - if role.Role.Description != "" { - v0RoleRole.Description = &role.Role.Description - } - if len(role.Role.Permissions) > 0 { - v0RoleRole.Permissions = make([]pluginsv0alpha1.MetaV0alpha1RoleRolePermissions, 0, len(role.Role.Permissions)) - for _, perm := range role.Role.Permissions { - v0Perm := pluginsv0alpha1.MetaV0alpha1RoleRolePermissions{} - if perm.Action != "" { - v0Perm.Action = &perm.Action - } - if perm.Scope != "" { - v0Perm.Scope = &perm.Scope - } - v0RoleRole.Permissions = append(v0RoleRole.Permissions, v0Perm) - } - } - v0Role.Role = v0RoleRole - } - meta.Roles = append(meta.Roles, v0Role) - } - } - - // Map IAM - if jsonData.IAM != nil && len(jsonData.IAM.Permissions) > 0 { - iam := &pluginsv0alpha1.MetaIAM{ - Permissions: make([]pluginsv0alpha1.MetaV0alpha1IAMPermissions, 0, len(jsonData.IAM.Permissions)), - } - for _, perm := range jsonData.IAM.Permissions { - v0Perm := pluginsv0alpha1.MetaV0alpha1IAMPermissions{} - if perm.Action != "" { - v0Perm.Action = &perm.Action - } - if perm.Scope != "" { - v0Perm.Scope = &perm.Scope - } - iam.Permissions = append(iam.Permissions, v0Perm) - } - meta.Iam = iam - } - - return meta + return pluginsLoader.New(cfg, d, b, v, i, t, et) } diff --git a/apps/plugins/pkg/app/meta/core_test.go b/apps/plugins/pkg/app/meta/core_test.go index d5235c9d120..d6f51057fab 100644 --- a/apps/plugins/pkg/app/meta/core_test.go +++ b/apps/plugins/pkg/app/meta/core_test.go @@ -22,10 +22,12 @@ func TestCoreProvider_GetMeta(t *testing.T) { t.Run("returns cached plugin when available", func(t *testing.T) { provider := NewCoreProvider() - expectedMeta := pluginsv0alpha1.MetaJSONData{ - Id: "test-plugin", - Name: "Test Plugin", - Type: pluginsv0alpha1.MetaJSONDataTypeDatasource, + expectedMeta := pluginsv0alpha1.MetaSpec{ + PluginJson: pluginsv0alpha1.MetaJSONData{ + Id: "test-plugin", + Name: "Test Plugin", + Type: pluginsv0alpha1.MetaJSONDataTypeDatasource, + }, } provider.mu.Lock() @@ -58,10 +60,12 @@ func TestCoreProvider_GetMeta(t *testing.T) { t.Run("ignores version parameter", func(t *testing.T) { provider := NewCoreProvider() - expectedMeta := pluginsv0alpha1.MetaJSONData{ - Id: "test-plugin", - Name: "Test Plugin", - Type: pluginsv0alpha1.MetaJSONDataTypeDatasource, + expectedMeta := pluginsv0alpha1.MetaSpec{ + PluginJson: pluginsv0alpha1.MetaJSONData{ + Id: "test-plugin", + Name: "Test Plugin", + Type: pluginsv0alpha1.MetaJSONDataTypeDatasource, + }, } provider.mu.Lock() @@ -81,10 +85,12 @@ func TestCoreProvider_GetMeta(t *testing.T) { customTTL := 2 * time.Hour provider := NewCoreProviderWithTTL(customTTL) - expectedMeta := pluginsv0alpha1.MetaJSONData{ - Id: "test-plugin", - Name: "Test Plugin", - Type: pluginsv0alpha1.MetaJSONDataTypeDatasource, + expectedMeta := pluginsv0alpha1.MetaSpec{ + PluginJson: pluginsv0alpha1.MetaJSONData{ + Id: "test-plugin", + Name: "Test Plugin", + Type: pluginsv0alpha1.MetaJSONDataTypeDatasource, + }, } provider.mu.Lock() @@ -226,8 +232,8 @@ func TestCoreProvider_loadPlugins(t *testing.T) { if loaded { result, err := provider.GetMeta(ctx, "test-datasource", "1.0.0") require.NoError(t, err) - assert.Equal(t, "test-datasource", result.Meta.Id) - assert.Equal(t, "Test Datasource", result.Meta.Name) + assert.Equal(t, "test-datasource", result.Meta.PluginJson.Id) + assert.Equal(t, "Test Datasource", result.Meta.PluginJson.Name) } }) } diff --git a/apps/plugins/pkg/app/meta/local.go b/apps/plugins/pkg/app/meta/local.go new file mode 100644 index 00000000000..2c699520cfc --- /dev/null +++ b/apps/plugins/pkg/app/meta/local.go @@ -0,0 +1,53 @@ +package meta + +import ( + "context" + "time" + + "github.com/grafana/grafana/pkg/plugins" + "github.com/grafana/grafana/pkg/services/pluginsintegration/pluginstore" +) + +const ( + defaultLocalTTL = 1 * time.Hour +) + +// PluginAssetsCalculator is an interface for calculating plugin asset information. +// LocalProvider requires this to calculate loading strategy and module hash. +type PluginAssetsCalculator interface { + LoadingStrategy(ctx context.Context, p pluginstore.Plugin) plugins.LoadingStrategy + ModuleHash(ctx context.Context, p pluginstore.Plugin) string +} + +// LocalProvider retrieves plugin metadata for locally installed plugins. +// It uses the plugin store to access plugins that have already been loaded. +type LocalProvider struct { + store pluginstore.Store + pluginAssets PluginAssetsCalculator +} + +// NewLocalProvider creates a new LocalProvider for locally installed plugins. +// pluginAssets is required for calculating loading strategy and module hash. +func NewLocalProvider(pluginStore pluginstore.Store, pluginAssets PluginAssetsCalculator) *LocalProvider { + return &LocalProvider{ + store: pluginStore, + pluginAssets: pluginAssets, + } +} + +// GetMeta retrieves plugin metadata for locally installed plugins. +func (p *LocalProvider) GetMeta(ctx context.Context, pluginID, version string) (*Result, error) { + plugin, exists := p.store.Plugin(ctx, pluginID) + if !exists { + return nil, ErrMetaNotFound + } + + loadingStrategy := p.pluginAssets.LoadingStrategy(ctx, plugin) + moduleHash := p.pluginAssets.ModuleHash(ctx, plugin) + + spec := pluginStorePluginToMeta(plugin, loadingStrategy, moduleHash) + return &Result{ + Meta: spec, + TTL: defaultLocalTTL, + }, nil +} diff --git a/apps/plugins/pkg/app/meta/manager.go b/apps/plugins/pkg/app/meta/manager.go index 7e99d0cc197..d8cd1f554c2 100644 --- a/apps/plugins/pkg/app/meta/manager.go +++ b/apps/plugins/pkg/app/meta/manager.go @@ -16,7 +16,7 @@ const ( // cachedMeta represents a cached metadata entry with expiration time type cachedMeta struct { - meta pluginsv0alpha1.MetaJSONData + meta pluginsv0alpha1.MetaSpec ttl time.Duration expiresAt time.Time } @@ -84,7 +84,7 @@ func (pm *ProviderManager) GetMeta(ctx context.Context, pluginID, version string if err == nil { // Don't cache results with a zero TTL if result.TTL == 0 { - continue + return result, nil } pm.cacheMu.Lock() diff --git a/apps/plugins/pkg/app/meta/manager_test.go b/apps/plugins/pkg/app/meta/manager_test.go index 31a75424a23..c9a8a9f3a5f 100644 --- a/apps/plugins/pkg/app/meta/manager_test.go +++ b/apps/plugins/pkg/app/meta/manager_test.go @@ -35,10 +35,12 @@ func TestProviderManager_GetMeta(t *testing.T) { ctx := context.Background() t.Run("returns cached result when available and not expired", func(t *testing.T) { - cachedMeta := pluginsv0alpha1.MetaJSONData{ - Id: "test-plugin", - Name: "Test Plugin", - Type: pluginsv0alpha1.MetaJSONDataTypeDatasource, + cachedMeta := pluginsv0alpha1.MetaSpec{ + PluginJson: pluginsv0alpha1.MetaJSONData{ + Id: "test-plugin", + Name: "Test Plugin", + Type: pluginsv0alpha1.MetaJSONDataTypeDatasource, + }, } provider := &mockProvider{ @@ -60,8 +62,10 @@ func TestProviderManager_GetMeta(t *testing.T) { provider.getMetaFunc = func(ctx context.Context, pluginID, version string) (*Result, error) { return &Result{ - Meta: pluginsv0alpha1.MetaJSONData{Id: "different"}, - TTL: time.Hour, + Meta: pluginsv0alpha1.MetaSpec{ + PluginJson: pluginsv0alpha1.MetaJSONData{Id: "different"}, + }, + TTL: time.Hour, }, nil } @@ -73,10 +77,12 @@ func TestProviderManager_GetMeta(t *testing.T) { }) t.Run("fetches from provider when not cached", func(t *testing.T) { - expectedMeta := pluginsv0alpha1.MetaJSONData{ - Id: "test-plugin", - Name: "Test Plugin", - Type: pluginsv0alpha1.MetaJSONDataTypeDatasource, + expectedMeta := pluginsv0alpha1.MetaSpec{ + PluginJson: pluginsv0alpha1.MetaJSONData{ + Id: "test-plugin", + Name: "Test Plugin", + Type: pluginsv0alpha1.MetaJSONDataTypeDatasource, + }, } expectedTTL := 2 * time.Hour @@ -107,19 +113,16 @@ func TestProviderManager_GetMeta(t *testing.T) { assert.Equal(t, expectedTTL, cached.ttl) }) - t.Run("does not cache result with zero TTL and tries next provider", func(t *testing.T) { - zeroTTLMeta := pluginsv0alpha1.MetaJSONData{ - Id: "test-plugin", - Name: "Zero TTL Plugin", - Type: pluginsv0alpha1.MetaJSONDataTypeDatasource, - } - expectedMeta := pluginsv0alpha1.MetaJSONData{ - Id: "test-plugin", - Name: "Test Plugin", - Type: pluginsv0alpha1.MetaJSONDataTypeDatasource, + t.Run("does not cache result with zero TTL", func(t *testing.T) { + zeroTTLMeta := pluginsv0alpha1.MetaSpec{ + PluginJson: pluginsv0alpha1.MetaJSONData{ + Id: "test-plugin", + Name: "Zero TTL Plugin", + Type: pluginsv0alpha1.MetaJSONDataTypeDatasource, + }, } - provider1 := &mockProvider{ + provider := &mockProvider{ getMetaFunc: func(ctx context.Context, pluginID, version string) (*Result, error) { return &Result{ Meta: zeroTTLMeta, @@ -127,37 +130,30 @@ func TestProviderManager_GetMeta(t *testing.T) { }, nil }, } - provider2 := &mockProvider{ - getMetaFunc: func(ctx context.Context, pluginID, version string) (*Result, error) { - return &Result{ - Meta: expectedMeta, - TTL: time.Hour, - }, nil - }, - } - pm := NewProviderManager(provider1, provider2) + pm := NewProviderManager(provider) result, err := pm.GetMeta(ctx, "test-plugin", "1.0.0") require.NoError(t, err) require.NotNil(t, result) - assert.Equal(t, expectedMeta, result.Meta) + assert.Equal(t, zeroTTLMeta, result.Meta) + assert.Equal(t, time.Duration(0), result.TTL) pm.cacheMu.RLock() - cached, exists := pm.cache["test-plugin:1.0.0"] + _, exists := pm.cache["test-plugin:1.0.0"] pm.cacheMu.RUnlock() - assert.True(t, exists) - assert.Equal(t, expectedMeta, cached.meta) - assert.Equal(t, time.Hour, cached.ttl) + assert.False(t, exists, "zero TTL results should not be cached") }) t.Run("tries next provider when first returns ErrMetaNotFound", func(t *testing.T) { - expectedMeta := pluginsv0alpha1.MetaJSONData{ - Id: "test-plugin", - Name: "Test Plugin", - Type: pluginsv0alpha1.MetaJSONDataTypeDatasource, + expectedMeta := pluginsv0alpha1.MetaSpec{ + PluginJson: pluginsv0alpha1.MetaJSONData{ + Id: "test-plugin", + Name: "Test Plugin", + Type: pluginsv0alpha1.MetaJSONDataTypeDatasource, + }, } provider1 := &mockProvider{ @@ -229,15 +225,19 @@ func TestProviderManager_GetMeta(t *testing.T) { }) t.Run("skips expired cache entries", func(t *testing.T) { - expiredMeta := pluginsv0alpha1.MetaJSONData{ - Id: "test-plugin", - Name: "Expired Plugin", - Type: pluginsv0alpha1.MetaJSONDataTypeDatasource, + expiredMeta := pluginsv0alpha1.MetaSpec{ + PluginJson: pluginsv0alpha1.MetaJSONData{ + Id: "test-plugin", + Name: "Expired Plugin", + Type: pluginsv0alpha1.MetaJSONDataTypeDatasource, + }, } - expectedMeta := pluginsv0alpha1.MetaJSONData{ - Id: "test-plugin", - Name: "Test Plugin", - Type: pluginsv0alpha1.MetaJSONDataTypeDatasource, + expectedMeta := pluginsv0alpha1.MetaSpec{ + PluginJson: pluginsv0alpha1.MetaJSONData{ + Id: "test-plugin", + Name: "Test Plugin", + Type: pluginsv0alpha1.MetaJSONDataTypeDatasource, + }, } callCount := 0 @@ -272,15 +272,19 @@ func TestProviderManager_GetMeta(t *testing.T) { }) t.Run("uses first successful provider", func(t *testing.T) { - expectedMeta1 := pluginsv0alpha1.MetaJSONData{ - Id: "test-plugin", - Name: "Provider 1 Plugin", - Type: pluginsv0alpha1.MetaJSONDataTypeDatasource, + expectedMeta1 := pluginsv0alpha1.MetaSpec{ + PluginJson: pluginsv0alpha1.MetaJSONData{ + Id: "test-plugin", + Name: "Provider 1 Plugin", + Type: pluginsv0alpha1.MetaJSONDataTypeDatasource, + }, } - expectedMeta2 := pluginsv0alpha1.MetaJSONData{ - Id: "test-plugin", - Name: "Provider 2 Plugin", - Type: pluginsv0alpha1.MetaJSONDataTypeDatasource, + expectedMeta2 := pluginsv0alpha1.MetaSpec{ + PluginJson: pluginsv0alpha1.MetaJSONData{ + Id: "test-plugin", + Name: "Provider 2 Plugin", + Type: pluginsv0alpha1.MetaJSONDataTypeDatasource, + }, } provider1 := &mockProvider{ @@ -331,9 +335,9 @@ func TestProviderManager_Run(t *testing.T) { func TestProviderManager_cleanupExpired(t *testing.T) { t.Run("removes expired entries", func(t *testing.T) { - validMeta := pluginsv0alpha1.MetaJSONData{Id: "valid"} - expiredMeta1 := pluginsv0alpha1.MetaJSONData{Id: "expired1"} - expiredMeta2 := pluginsv0alpha1.MetaJSONData{Id: "expired2"} + validMeta := pluginsv0alpha1.MetaSpec{PluginJson: pluginsv0alpha1.MetaJSONData{Id: "valid"}} + expiredMeta1 := pluginsv0alpha1.MetaSpec{PluginJson: pluginsv0alpha1.MetaJSONData{Id: "expired1"}} + expiredMeta2 := pluginsv0alpha1.MetaSpec{PluginJson: pluginsv0alpha1.MetaJSONData{Id: "expired2"}} provider := &mockProvider{ getMetaFunc: func(ctx context.Context, pluginID, version string) (*Result, error) { diff --git a/apps/plugins/pkg/app/meta/provider.go b/apps/plugins/pkg/app/meta/provider.go index 818c0da9dc5..3c01361d656 100644 --- a/apps/plugins/pkg/app/meta/provider.go +++ b/apps/plugins/pkg/app/meta/provider.go @@ -14,7 +14,7 @@ var ( // Result contains plugin metadata along with its recommended TTL. type Result struct { - Meta pluginsv0alpha1.MetaJSONData + Meta pluginsv0alpha1.MetaSpec TTL time.Duration } diff --git a/apps/plugins/pkg/app/storage.go b/apps/plugins/pkg/app/storage.go index f2dd2ac98d5..01e62b9c4ec 100644 --- a/apps/plugins/pkg/app/storage.go +++ b/apps/plugins/pkg/app/storage.go @@ -121,8 +121,19 @@ func (s *MetaStorage) List(ctx context.Context, options *internalversion.ListOpt continue } - pluginMeta := createMetaFromMetaJSONData(result.Meta, plugin.Name, plugin.Namespace) - metaItems = append(metaItems, *pluginMeta) + pluginMeta := pluginsv0alpha1.Meta{ + ObjectMeta: metav1.ObjectMeta{ + Name: plugin.Name, + Namespace: plugin.Namespace, + }, + Spec: result.Meta, + } + pluginMeta.SetGroupVersionKind(schema.GroupVersionKind{ + Group: pluginsv0alpha1.APIGroup, + Version: pluginsv0alpha1.APIVersion, + Kind: pluginsv0alpha1.MetaKind().Kind(), + }) + metaItems = append(metaItems, pluginMeta) } list := &pluginsv0alpha1.MetaList{ @@ -169,27 +180,18 @@ func (s *MetaStorage) Get(ctx context.Context, name string, options *metav1.GetO return nil, apierrors.NewInternalError(fmt.Errorf("failed to fetch plugin metadata: %w", err)) } - return createMetaFromMetaJSONData(result.Meta, name, ns.Value), nil -} - -// createMetaFromMetaJSONData creates a Meta k8s object from MetaJSONData and plugin metadata. -func createMetaFromMetaJSONData(pluginJSON pluginsv0alpha1.MetaJSONData, name, namespace string) *pluginsv0alpha1.Meta { pluginMeta := &pluginsv0alpha1.Meta{ ObjectMeta: metav1.ObjectMeta{ - Name: name, - Namespace: namespace, - }, - Spec: pluginsv0alpha1.MetaSpec{ - PluginJSON: pluginJSON, + Name: plugin.Name, + Namespace: plugin.Namespace, }, + Spec: result.Meta, } - - // Set the GroupVersionKind pluginMeta.SetGroupVersionKind(schema.GroupVersionKind{ Group: pluginsv0alpha1.APIGroup, Version: pluginsv0alpha1.APIVersion, Kind: pluginsv0alpha1.MetaKind().Kind(), }) - return pluginMeta + return pluginMeta, nil } diff --git a/apps/preferences/go.mod b/apps/preferences/go.mod index 661002a3b59..520609347ae 100644 --- a/apps/preferences/go.mod +++ b/apps/preferences/go.mod @@ -3,10 +3,10 @@ module github.com/grafana/grafana/apps/preferences go 1.25.5 require ( - github.com/grafana/grafana-app-sdk v0.48.5 + github.com/grafana/grafana-app-sdk v0.48.7 github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250804150913-990f1c69ecc2 - k8s.io/apimachinery v0.34.2 - k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 + k8s.io/apimachinery v0.34.3 + k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e ) require ( @@ -17,19 +17,29 @@ require ( github.com/fxamacker/cbor/v2 v2.9.0 // indirect github.com/getkin/kin-openapi v0.133.0 // indirect github.com/go-logr/logr v1.4.3 // 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.1 // indirect - github.com/go-openapi/swag/jsonname v0.25.1 // indirect + github.com/go-openapi/jsonpointer v0.22.4 // indirect + github.com/go-openapi/jsonreference v0.21.4 // indirect + github.com/go-openapi/swag v0.25.4 // indirect + github.com/go-openapi/swag/cmdutils v0.25.4 // indirect + github.com/go-openapi/swag/conv v0.25.4 // indirect + github.com/go-openapi/swag/fileutils v0.25.4 // indirect + github.com/go-openapi/swag/jsonname v0.25.4 // indirect + github.com/go-openapi/swag/jsonutils v0.25.4 // indirect + github.com/go-openapi/swag/loading v0.25.4 // indirect + github.com/go-openapi/swag/mangling v0.25.4 // indirect + github.com/go-openapi/swag/netutils v0.25.4 // indirect + github.com/go-openapi/swag/stringutils v0.25.4 // indirect + github.com/go-openapi/swag/typeutils v0.25.4 // indirect + github.com/go-openapi/swag/yamlutils v0.25.4 // 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/grafana/grafana-app-sdk/logging v0.48.3 // indirect + github.com/google/gnostic-models v0.7.1 // indirect + github.com/grafana/grafana-app-sdk/logging v0.48.7 // 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/mailru/easyjson v0.9.1 // 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 @@ -40,29 +50,29 @@ require ( 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.3 // indirect - github.com/prometheus/procfs v0.16.1 // indirect + github.com/prometheus/common v0.67.4 // indirect + github.com/prometheus/procfs v0.19.2 // indirect github.com/stretchr/objx v0.5.2 // indirect github.com/stretchr/testify v1.11.1 // indirect - github.com/woodsbury/decimal128 v1.3.0 // indirect + github.com/woodsbury/decimal128 v1.4.0 // indirect github.com/x448/float16 v0.8.4 // indirect - go.opentelemetry.io/otel v1.38.0 // indirect - go.opentelemetry.io/otel/trace v1.38.0 // indirect + go.opentelemetry.io/otel v1.39.0 // indirect + go.opentelemetry.io/otel/trace v1.39.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.47.0 // indirect - golang.org/x/oauth2 v0.33.0 // indirect - golang.org/x/sys v0.38.0 // indirect - golang.org/x/term v0.37.0 // indirect - golang.org/x/text v0.31.0 // indirect + golang.org/x/net v0.48.0 // indirect + golang.org/x/oauth2 v0.34.0 // indirect + golang.org/x/sys v0.39.0 // indirect + golang.org/x/term v0.38.0 // indirect + golang.org/x/text v0.32.0 // indirect golang.org/x/time v0.14.0 // indirect - google.golang.org/protobuf v1.36.10 // indirect + google.golang.org/protobuf v1.36.11 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/client-go v0.34.2 // indirect + k8s.io/client-go v0.34.3 // 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 + k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 // indirect + sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect sigs.k8s.io/randfill v1.0.0 // indirect sigs.k8s.io/structured-merge-diff/v6 v6.3.1 // indirect sigs.k8s.io/yaml v1.6.0 // indirect diff --git a/apps/preferences/go.sum b/apps/preferences/go.sum index 75a19848d73..aa5de8cbe99 100644 --- a/apps/preferences/go.sum +++ b/apps/preferences/go.sum @@ -14,29 +14,55 @@ github.com/getkin/kin-openapi v0.133.0 h1:pJdmNohVIJ97r4AUFtEXRXwESr8b0bD721u/Tz github.com/getkin/kin-openapi v0.133.0/go.mod h1:boAciF6cXk5FhPqe/NQeBTeenbjqU4LhWBf09ILVvWE= 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-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.1 h1:lpsStH0n2ittzTnbaSloVZLuB5+fvSY/+hnagBjSNZU= -github.com/go-openapi/swag v0.23.1/go.mod h1:STZs8TbRvEQQKUA+JZNAm3EWlgaOBGpyFDqQnDHMef0= -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/jsonpointer v0.22.4 h1:dZtK82WlNpVLDW2jlA1YCiVJFVqkED1MegOUy9kR5T4= +github.com/go-openapi/jsonpointer v0.22.4/go.mod h1:elX9+UgznpFhgBuaMQ7iu4lvvX1nvNsesQ3oxmYTw80= +github.com/go-openapi/jsonreference v0.21.4 h1:24qaE2y9bx/q3uRK/qN+TDwbok1NhbSmGjjySRCHtC8= +github.com/go-openapi/jsonreference v0.21.4/go.mod h1:rIENPTjDbLpzQmQWCj5kKj3ZlmEh+EFVbz3RTUh30/4= +github.com/go-openapi/swag v0.25.4 h1:OyUPUFYDPDBMkqyxOTkqDYFnrhuhi9NR6QVUvIochMU= +github.com/go-openapi/swag v0.25.4/go.mod h1:zNfJ9WZABGHCFg2RnY0S4IOkAcVTzJ6z2Bi+Q4i6qFQ= +github.com/go-openapi/swag/cmdutils v0.25.4 h1:8rYhB5n6WawR192/BfUu2iVlxqVR9aRgGJP6WaBoW+4= +github.com/go-openapi/swag/cmdutils v0.25.4/go.mod h1:pdae/AFo6WxLl5L0rq87eRzVPm/XRHM3MoYgRMvG4A0= +github.com/go-openapi/swag/conv v0.25.4 h1:/Dd7p0LZXczgUcC/Ikm1+YqVzkEeCc9LnOWjfkpkfe4= +github.com/go-openapi/swag/conv v0.25.4/go.mod h1:3LXfie/lwoAv0NHoEuY1hjoFAYkvlqI/Bn5EQDD3PPU= +github.com/go-openapi/swag/fileutils v0.25.4 h1:2oI0XNW5y6UWZTC7vAxC8hmsK/tOkWXHJQH4lKjqw+Y= +github.com/go-openapi/swag/fileutils v0.25.4/go.mod h1:cdOT/PKbwcysVQ9Tpr0q20lQKH7MGhOEb6EwmHOirUk= +github.com/go-openapi/swag/jsonname v0.25.4 h1:bZH0+MsS03MbnwBXYhuTttMOqk+5KcQ9869Vye1bNHI= +github.com/go-openapi/swag/jsonname v0.25.4/go.mod h1:GPVEk9CWVhNvWhZgrnvRA6utbAltopbKwDu8mXNUMag= +github.com/go-openapi/swag/jsonutils v0.25.4 h1:VSchfbGhD4UTf4vCdR2F4TLBdLwHyUDTd1/q4i+jGZA= +github.com/go-openapi/swag/jsonutils v0.25.4/go.mod h1:7OYGXpvVFPn4PpaSdPHJBtF0iGnbEaTk8AvBkoWnaAY= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4 h1:IACsSvBhiNJwlDix7wq39SS2Fh7lUOCJRmx/4SN4sVo= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4/go.mod h1:Mt0Ost9l3cUzVv4OEZG+WSeoHwjWLnarzMePNDAOBiM= +github.com/go-openapi/swag/loading v0.25.4 h1:jN4MvLj0X6yhCDduRsxDDw1aHe+ZWoLjW+9ZQWIKn2s= +github.com/go-openapi/swag/loading v0.25.4/go.mod h1:rpUM1ZiyEP9+mNLIQUdMiD7dCETXvkkC30z53i+ftTE= +github.com/go-openapi/swag/mangling v0.25.4 h1:2b9kBJk9JvPgxr36V23FxJLdwBrpijI26Bx5JH4Hp48= +github.com/go-openapi/swag/mangling v0.25.4/go.mod h1:6dxwu6QyORHpIIApsdZgb6wBk/DPU15MdyYj/ikn0Hg= +github.com/go-openapi/swag/netutils v0.25.4 h1:Gqe6K71bGRb3ZQLusdI8p/y1KLgV4M/k+/HzVSqT8H0= +github.com/go-openapi/swag/netutils v0.25.4/go.mod h1:m2W8dtdaoX7oj9rEttLyTeEFFEBvnAx9qHd5nJEBzYg= +github.com/go-openapi/swag/stringutils v0.25.4 h1:O6dU1Rd8bej4HPA3/CLPciNBBDwZj9HiEpdVsb8B5A8= +github.com/go-openapi/swag/stringutils v0.25.4/go.mod h1:GTsRvhJW5xM5gkgiFe0fV3PUlFm0dr8vki6/VSRaZK0= +github.com/go-openapi/swag/typeutils v0.25.4 h1:1/fbZOUN472NTc39zpa+YGHn3jzHWhv42wAJSN91wRw= +github.com/go-openapi/swag/typeutils v0.25.4/go.mod h1:Ou7g//Wx8tTLS9vG0UmzfCsjZjKhpjxayRKTHXf2pTE= +github.com/go-openapi/swag/yamlutils v0.25.4 h1:6jdaeSItEUb7ioS9lFoCZ65Cne1/RZtPBZ9A56h92Sw= +github.com/go-openapi/swag/yamlutils v0.25.4/go.mod h1:MNzq1ulQu+yd8Kl7wPOut/YHAAU/H6hL91fF+E2RFwc= +github.com/go-openapi/testify/enable/yaml/v2 v2.0.2 h1:0+Y41Pz1NkbTHz8NngxTuAXxEodtNSI1WG1c/m5Akw4= +github.com/go-openapi/testify/enable/yaml/v2 v2.0.2/go.mod h1:kme83333GCtJQHXQ8UKX3IBZu6z8T5Dvy5+CW3NLUUg= +github.com/go-openapi/testify/v2 v2.0.2 h1:X999g3jeLcoY8qctY/c/Z8iBHTbwLz7R2WXd6Ub6wls= +github.com/go-openapi/testify/v2 v2.0.2/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= 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/google/gnostic-models v0.7.0 h1:qwTtogB15McXDaNqTZdzPJRHvaVJlAl+HVQnLmJEJxo= -github.com/google/gnostic-models v0.7.0/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ= +github.com/google/gnostic-models v0.7.1 h1:SisTfuFKJSKM5CPZkffwi6coztzzeYUhc3v4yxLWH8c= +github.com/google/gnostic-models v0.7.1/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/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.48.5 h1:MS8l9fTZz+VbTfgApn09jw27GxhQ6fNOWGhC4ydvZmM= -github.com/grafana/grafana-app-sdk v0.48.5/go.mod h1:HJsMOSBmt/D/Ihs1SvagOwmXKi0coBMVHlfvdd+qe9Y= -github.com/grafana/grafana-app-sdk/logging v0.48.3 h1:72NUpGNiJXCNQz/on++YSsl38xuVYYBKv5kKQaOClX4= -github.com/grafana/grafana-app-sdk/logging v0.48.3/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA= +github.com/grafana/grafana-app-sdk v0.48.7 h1:9mF7nqkqP0QUYYDlznoOt+GIyjzj45wGfUHB32u2ZMo= +github.com/grafana/grafana-app-sdk v0.48.7/go.mod h1:DWsaaH39ZMHwSOSoUBaeW8paMrRaYsjRYlLwCJYd78k= +github.com/grafana/grafana-app-sdk/logging v0.48.7 h1:Oa5qg473gka5+W/WQk61Xbw4YdAv+wV2Z4bJtzeCaQw= +github.com/grafana/grafana-app-sdk/logging v0.48.7/go.mod h1:5u3KalezoBAAo2Y3ytDYDAIIPvEqFLLDSxeiK99QxDU= 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= @@ -58,8 +84,8 @@ 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/mailru/easyjson v0.9.1 h1:LbtsOm5WAswyWbvTEOqhypdPeZzHavpZx96/n553mR8= +github.com/mailru/easyjson v0.9.1/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= @@ -76,8 +102,6 @@ github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 h1:bQx3WeLcUWy+RletI github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90/go.mod h1:y5+oSEHCPT/DGrS++Wc/479ERge0zTFxaF8PbGKcg2o= 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= @@ -85,10 +109,10 @@ github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h 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.3 h1:shd26MlnwTw5jksTDhC7rTQIteBxy+ZZDr3t7F2xN2Q= -github.com/prometheus/common v0.67.3/go.mod h1:gP0fq6YjjNCLssJCQp0yk4M8W6ikLURwkdd/YKtTbyI= -github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= -github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= +github.com/prometheus/common v0.67.4 h1:yR3NqWO1/UyO1w2PhUvXlGQs/PtFmoveVO0KZ4+Lvsc= +github.com/prometheus/common v0.67.4/go.mod h1:gP0fq6YjjNCLssJCQp0yk4M8W6ikLURwkdd/YKtTbyI= +github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws= +github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw= 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= @@ -101,16 +125,16 @@ 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/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/woodsbury/decimal128 v1.4.0 h1:xJATj7lLu4f2oObouMt2tgGiElE5gO6mSWUjQsBgUlc= +github.com/woodsbury/decimal128 v1.4.0/go.mod h1:BP46FUrVjVhdTbKT+XuQh2xfQaGki9LMIRJSFuh6THU= 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/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/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/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48= +go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8= +go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI= +go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA= 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= @@ -126,24 +150,24 @@ 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.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= -golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= -golang.org/x/oauth2 v0.33.0 h1:4Q+qn+E5z8gPRJfmRy7C2gGG3T4jIprK6aSYgTXGRpo= -golang.org/x/oauth2 v0.33.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= +golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= +golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= +golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw= +golang.org/x/oauth2 v0.34.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/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.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= -golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU= -golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254= +golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= +golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q= +golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg= 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.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= -golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= +golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= +golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= 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= @@ -154,31 +178,31 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= -google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/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/evanphx/json-patch.v4 v4.13.0 h1:czT3CmqEaQ1aanPc5SdlgQrrEIb8w/wwCvWWnfEbYzo= +gopkg.in/evanphx/json-patch.v4 v4.13.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.2 h1:fsSUNZhV+bnL6Aqrp6O7lMTy6o5x2C4XLjnh//8SLYY= -k8s.io/api v0.34.2/go.mod h1:MMBPaWlED2a8w4RSeanD76f7opUoypY8TFYkSM+3XHw= -k8s.io/apimachinery v0.34.2 h1:zQ12Uk3eMHPxrsbUJgNF8bTauTVR2WgqJsTmwTE/NW4= -k8s.io/apimachinery v0.34.2/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= -k8s.io/client-go v0.34.2 h1:Co6XiknN+uUZqiddlfAjT68184/37PS4QAzYvQvDR8M= -k8s.io/client-go v0.34.2/go.mod h1:2VYDl1XXJsdcAxw7BenFslRQX28Dxz91U9MWKjX97fE= +k8s.io/api v0.34.3 h1:D12sTP257/jSH2vHV2EDYrb16bS7ULlHpdNdNhEw2S4= +k8s.io/api v0.34.3/go.mod h1:PyVQBF886Q5RSQZOim7DybQjAbVs8g7gwJNhGtY5MBk= +k8s.io/apimachinery v0.34.3 h1:/TB+SFEiQvN9HPldtlWOTp0hWbJ+fjU+wkxysf/aQnE= +k8s.io/apimachinery v0.34.3/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= +k8s.io/client-go v0.34.3 h1:wtYtpzy/OPNYf7WyNBTj3iUA0XaBHVqhv4Iv3tbrF5A= +k8s.io/client-go v0.34.3/go.mod h1:OxxeYagaP9Kdf78UrKLa3YZixMCfP6bgPwPwNBQBzpM= 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= +k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e h1:iW9ChlU0cU16w8MpVYjXk12dqQ4BPFBEgif+ap7/hqQ= +k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e/go.mod h1:kdmbQkyfwUagLfXIad1y2TdrjPFWp2Q89B3qkRwf/pQ= +k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 h1:SjGebBtkBqHFOli+05xYbK8YF1Dzkbzn+gDM4X9T4Ck= +k8s.io/utils v0.0.0-20251002143259-bc988d571ff4/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg= +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/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.1 h1:JrhdFMqOd/+3ByqlP2I45kTOZmTRLBUm5pvRjeheg7E= diff --git a/apps/provisioning/go.mod b/apps/provisioning/go.mod index 3cccd7dd8be..62f3f1bf49c 100644 --- a/apps/provisioning/go.mod +++ b/apps/provisioning/go.mod @@ -7,17 +7,18 @@ 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.48.3 + github.com/grafana/grafana-app-sdk v0.48.7 + github.com/grafana/grafana-app-sdk/logging v0.48.7 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.3.0 github.com/migueleliasweb/go-github-mock v1.1.0 github.com/stretchr/testify v1.11.1 - golang.org/x/oauth2 v0.33.0 - k8s.io/apimachinery v0.34.2 - k8s.io/apiserver v0.34.2 - k8s.io/client-go v0.34.2 - k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 + golang.org/x/oauth2 v0.34.0 + k8s.io/apimachinery v0.34.3 + k8s.io/apiserver v0.34.3 + k8s.io/client-go v0.34.3 + k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e sigs.k8s.io/structured-merge-diff/v6 v6.3.1 ) @@ -28,64 +29,81 @@ require ( github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/emicklei/go-restful/v3 v3.13.0 // 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/v3 v3.0.4 // indirect github.com/go-jose/go-jose/v4 v4.1.3 // 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.1 // indirect - github.com/go-openapi/swag/jsonname v0.25.1 // indirect + github.com/go-openapi/jsonpointer v0.22.4 // indirect + github.com/go-openapi/jsonreference v0.21.4 // indirect + github.com/go-openapi/swag v0.25.4 // indirect + github.com/go-openapi/swag/cmdutils v0.25.4 // indirect + github.com/go-openapi/swag/conv v0.25.4 // indirect + github.com/go-openapi/swag/fileutils v0.25.4 // indirect + github.com/go-openapi/swag/jsonname v0.25.4 // indirect + github.com/go-openapi/swag/jsonutils v0.25.4 // indirect + github.com/go-openapi/swag/loading v0.25.4 // indirect + github.com/go-openapi/swag/mangling v0.25.4 // indirect + github.com/go-openapi/swag/netutils v0.25.4 // indirect + github.com/go-openapi/swag/stringutils v0.25.4 // indirect + github.com/go-openapi/swag/typeutils v0.25.4 // indirect + github.com/go-openapi/swag/yamlutils v0.25.4 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/google/gnostic-models v0.7.0 // indirect + github.com/google/gnostic-models v0.7.1 // indirect github.com/google/go-cmp v0.7.0 // indirect github.com/google/go-github/v64 v64.0.0 // indirect github.com/google/go-querystring v1.1.0 // indirect github.com/gorilla/mux v1.8.1 // indirect github.com/grafana/authlib/types v0.0.0-20251119142549-be091cf2f4d4 // indirect github.com/grafana/dskit v0.0.0-20250908063411-6b6da59b5cc4 // indirect - github.com/grafana/grafana-app-sdk v0.48.5 // 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/klauspost/compress v1.18.0 // indirect - github.com/mailru/easyjson v0.9.0 // indirect + github.com/mailru/easyjson v0.9.1 // 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/patrickmn/go-cache v2.1.0+incompatible // indirect - github.com/pkg/errors v0.9.1 // 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.3 // indirect - github.com/prometheus/procfs v0.16.1 // indirect + github.com/prometheus/common v0.67.4 // indirect + github.com/prometheus/procfs v0.19.2 // indirect github.com/spf13/pflag v1.0.10 // indirect github.com/stretchr/objx v0.5.2 // indirect + github.com/woodsbury/decimal128 v1.4.0 // indirect github.com/x448/float16 v0.8.4 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect - go.opentelemetry.io/otel v1.38.0 // indirect - go.opentelemetry.io/otel/metric v1.38.0 // indirect - go.opentelemetry.io/otel/trace v1.38.0 // indirect + go.opentelemetry.io/otel v1.39.0 // indirect + go.opentelemetry.io/otel/metric v1.39.0 // indirect + go.opentelemetry.io/otel/sdk/metric v1.39.0 // indirect + go.opentelemetry.io/otel/trace v1.39.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.45.0 // indirect - golang.org/x/net v0.47.0 // indirect - golang.org/x/sync v0.18.0 // indirect - golang.org/x/sys v0.38.0 // indirect - golang.org/x/term v0.37.0 // indirect - golang.org/x/text v0.31.0 // indirect + golang.org/x/crypto v0.46.0 // indirect + golang.org/x/net v0.48.0 // indirect + golang.org/x/sync v0.19.0 // indirect + golang.org/x/sys v0.39.0 // indirect + golang.org/x/term v0.38.0 // indirect + golang.org/x/text v0.32.0 // indirect golang.org/x/time v0.14.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2 // indirect google.golang.org/grpc v1.77.0 // indirect - google.golang.org/protobuf v1.36.10 // indirect - gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect + google.golang.org/protobuf v1.36.11 // indirect + gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/api v0.34.2 // indirect - k8s.io/component-base v0.34.2 // indirect + k8s.io/api v0.34.3 // indirect + k8s.io/component-base v0.34.3 // 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 + k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 // indirect + sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect sigs.k8s.io/randfill v1.0.0 // indirect sigs.k8s.io/yaml v1.6.0 // indirect ) diff --git a/apps/provisioning/go.sum b/apps/provisioning/go.sum index 0e1ba180fad..8b5733639be 100644 --- a/apps/provisioning/go.sum +++ b/apps/provisioning/go.sum @@ -14,6 +14,8 @@ github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= 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/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.3 h1:CVLmWDhDVRa6Mi/IgCgaopNosCaHz7zrMeF9MlZRkrs= @@ -23,22 +25,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/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.1 h1:lpsStH0n2ittzTnbaSloVZLuB5+fvSY/+hnagBjSNZU= -github.com/go-openapi/swag v0.23.1/go.mod h1:STZs8TbRvEQQKUA+JZNAm3EWlgaOBGpyFDqQnDHMef0= -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/jsonpointer v0.22.4 h1:dZtK82WlNpVLDW2jlA1YCiVJFVqkED1MegOUy9kR5T4= +github.com/go-openapi/jsonpointer v0.22.4/go.mod h1:elX9+UgznpFhgBuaMQ7iu4lvvX1nvNsesQ3oxmYTw80= +github.com/go-openapi/jsonreference v0.21.4 h1:24qaE2y9bx/q3uRK/qN+TDwbok1NhbSmGjjySRCHtC8= +github.com/go-openapi/jsonreference v0.21.4/go.mod h1:rIENPTjDbLpzQmQWCj5kKj3ZlmEh+EFVbz3RTUh30/4= +github.com/go-openapi/swag v0.25.4 h1:OyUPUFYDPDBMkqyxOTkqDYFnrhuhi9NR6QVUvIochMU= +github.com/go-openapi/swag v0.25.4/go.mod h1:zNfJ9WZABGHCFg2RnY0S4IOkAcVTzJ6z2Bi+Q4i6qFQ= +github.com/go-openapi/swag/cmdutils v0.25.4 h1:8rYhB5n6WawR192/BfUu2iVlxqVR9aRgGJP6WaBoW+4= +github.com/go-openapi/swag/cmdutils v0.25.4/go.mod h1:pdae/AFo6WxLl5L0rq87eRzVPm/XRHM3MoYgRMvG4A0= +github.com/go-openapi/swag/conv v0.25.4 h1:/Dd7p0LZXczgUcC/Ikm1+YqVzkEeCc9LnOWjfkpkfe4= +github.com/go-openapi/swag/conv v0.25.4/go.mod h1:3LXfie/lwoAv0NHoEuY1hjoFAYkvlqI/Bn5EQDD3PPU= +github.com/go-openapi/swag/fileutils v0.25.4 h1:2oI0XNW5y6UWZTC7vAxC8hmsK/tOkWXHJQH4lKjqw+Y= +github.com/go-openapi/swag/fileutils v0.25.4/go.mod h1:cdOT/PKbwcysVQ9Tpr0q20lQKH7MGhOEb6EwmHOirUk= +github.com/go-openapi/swag/jsonname v0.25.4 h1:bZH0+MsS03MbnwBXYhuTttMOqk+5KcQ9869Vye1bNHI= +github.com/go-openapi/swag/jsonname v0.25.4/go.mod h1:GPVEk9CWVhNvWhZgrnvRA6utbAltopbKwDu8mXNUMag= +github.com/go-openapi/swag/jsonutils v0.25.4 h1:VSchfbGhD4UTf4vCdR2F4TLBdLwHyUDTd1/q4i+jGZA= +github.com/go-openapi/swag/jsonutils v0.25.4/go.mod h1:7OYGXpvVFPn4PpaSdPHJBtF0iGnbEaTk8AvBkoWnaAY= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4 h1:IACsSvBhiNJwlDix7wq39SS2Fh7lUOCJRmx/4SN4sVo= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4/go.mod h1:Mt0Ost9l3cUzVv4OEZG+WSeoHwjWLnarzMePNDAOBiM= +github.com/go-openapi/swag/loading v0.25.4 h1:jN4MvLj0X6yhCDduRsxDDw1aHe+ZWoLjW+9ZQWIKn2s= +github.com/go-openapi/swag/loading v0.25.4/go.mod h1:rpUM1ZiyEP9+mNLIQUdMiD7dCETXvkkC30z53i+ftTE= +github.com/go-openapi/swag/mangling v0.25.4 h1:2b9kBJk9JvPgxr36V23FxJLdwBrpijI26Bx5JH4Hp48= +github.com/go-openapi/swag/mangling v0.25.4/go.mod h1:6dxwu6QyORHpIIApsdZgb6wBk/DPU15MdyYj/ikn0Hg= +github.com/go-openapi/swag/netutils v0.25.4 h1:Gqe6K71bGRb3ZQLusdI8p/y1KLgV4M/k+/HzVSqT8H0= +github.com/go-openapi/swag/netutils v0.25.4/go.mod h1:m2W8dtdaoX7oj9rEttLyTeEFFEBvnAx9qHd5nJEBzYg= +github.com/go-openapi/swag/stringutils v0.25.4 h1:O6dU1Rd8bej4HPA3/CLPciNBBDwZj9HiEpdVsb8B5A8= +github.com/go-openapi/swag/stringutils v0.25.4/go.mod h1:GTsRvhJW5xM5gkgiFe0fV3PUlFm0dr8vki6/VSRaZK0= +github.com/go-openapi/swag/typeutils v0.25.4 h1:1/fbZOUN472NTc39zpa+YGHn3jzHWhv42wAJSN91wRw= +github.com/go-openapi/swag/typeutils v0.25.4/go.mod h1:Ou7g//Wx8tTLS9vG0UmzfCsjZjKhpjxayRKTHXf2pTE= +github.com/go-openapi/swag/yamlutils v0.25.4 h1:6jdaeSItEUb7ioS9lFoCZ65Cne1/RZtPBZ9A56h92Sw= +github.com/go-openapi/swag/yamlutils v0.25.4/go.mod h1:MNzq1ulQu+yd8Kl7wPOut/YHAAU/H6hL91fF+E2RFwc= +github.com/go-openapi/testify/enable/yaml/v2 v2.0.2 h1:0+Y41Pz1NkbTHz8NngxTuAXxEodtNSI1WG1c/m5Akw4= +github.com/go-openapi/testify/enable/yaml/v2 v2.0.2/go.mod h1:kme83333GCtJQHXQ8UKX3IBZu6z8T5Dvy5+CW3NLUUg= +github.com/go-openapi/testify/v2 v2.0.2 h1:X999g3jeLcoY8qctY/c/Z8iBHTbwLz7R2WXd6Ub6wls= +github.com/go-openapi/testify/v2 v2.0.2/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= 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/gnostic-models v0.7.1 h1:SisTfuFKJSKM5CPZkffwi6coztzzeYUhc3v4yxLWH8c= +github.com/google/gnostic-models v0.7.1/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= @@ -62,16 +92,21 @@ github.com/grafana/authlib/types v0.0.0-20251119142549-be091cf2f4d4 h1:Muoy+FMGr github.com/grafana/authlib/types v0.0.0-20251119142549-be091cf2f4d4/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.5 h1:MS8l9fTZz+VbTfgApn09jw27GxhQ6fNOWGhC4ydvZmM= -github.com/grafana/grafana-app-sdk v0.48.5/go.mod h1:HJsMOSBmt/D/Ihs1SvagOwmXKi0coBMVHlfvdd+qe9Y= -github.com/grafana/grafana-app-sdk/logging v0.48.3 h1:72NUpGNiJXCNQz/on++YSsl38xuVYYBKv5kKQaOClX4= -github.com/grafana/grafana-app-sdk/logging v0.48.3/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA= +github.com/grafana/grafana-app-sdk v0.48.7 h1:9mF7nqkqP0QUYYDlznoOt+GIyjzj45wGfUHB32u2ZMo= +github.com/grafana/grafana-app-sdk v0.48.7/go.mod h1:DWsaaH39ZMHwSOSoUBaeW8paMrRaYsjRYlLwCJYd78k= +github.com/grafana/grafana-app-sdk/logging v0.48.7 h1:Oa5qg473gka5+W/WQk61Xbw4YdAv+wV2Z4bJtzeCaQw= +github.com/grafana/grafana-app-sdk/logging v0.48.7/go.mod h1:5u3KalezoBAAo2Y3ytDYDAIIPvEqFLLDSxeiK99QxDU= 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= github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250804150913-990f1c69ecc2/go.mod h1:RRvSjHH12/PnQaXraMO65jUhVu8n59mzvhfIMBETnV4= github.com/grafana/nanogit v0.3.0 h1:XNEef+4Vi+465ZITJs/g/xgnDRJbWhhJ7iQrAnWZ0oQ= github.com/grafana/nanogit v0.3.0/go.mod h1:6s6CCTpyMOHPpcUZaLGI+rgBEKdmxVbhqSGgCK13j7Y= +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= @@ -86,8 +121,8 @@ 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/mailru/easyjson v0.9.1 h1:LbtsOm5WAswyWbvTEOqhypdPeZzHavpZx96/n553mR8= +github.com/mailru/easyjson v0.9.1/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= github.com/migueleliasweb/go-github-mock v1.1.0 h1:GKaOBPsrPGkAKgtfuWY8MclS1xR6MInkx1SexJucMwE= github.com/migueleliasweb/go-github-mock v1.1.0/go.mod h1:pYe/XlGs4BGMfRY4vmeixVsODHnVDDhJ9zoi0qzSMHc= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -96,14 +131,22 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ 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= @@ -113,10 +156,10 @@ github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h 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.3 h1:shd26MlnwTw5jksTDhC7rTQIteBxy+ZZDr3t7F2xN2Q= -github.com/prometheus/common v0.67.3/go.mod h1:gP0fq6YjjNCLssJCQp0yk4M8W6ikLURwkdd/YKtTbyI= -github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= -github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= +github.com/prometheus/common v0.67.4 h1:yR3NqWO1/UyO1w2PhUvXlGQs/PtFmoveVO0KZ4+Lvsc= +github.com/prometheus/common v0.67.4/go.mod h1:gP0fq6YjjNCLssJCQp0yk4M8W6ikLURwkdd/YKtTbyI= +github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws= +github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw= 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= @@ -128,6 +171,10 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 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.4.0 h1:xJATj7lLu4f2oObouMt2tgGiElE5gO6mSWUjQsBgUlc= +github.com/woodsbury/decimal128 v1.4.0/go.mod h1:BP46FUrVjVhdTbKT+XuQh2xfQaGki9LMIRJSFuh6THU= 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= @@ -135,16 +182,16 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= -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/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/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48= +go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8= +go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0= +go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs= +go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18= +go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE= +go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8= +go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew= +go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI= +go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA= 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= @@ -156,8 +203,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.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q= -golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4= +golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU= +golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0= 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,17 +217,17 @@ 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.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= -golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= -golang.org/x/oauth2 v0.33.0 h1:4Q+qn+E5z8gPRJfmRy7C2gGG3T4jIprK6aSYgTXGRpo= -golang.org/x/oauth2 v0.33.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= +golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= +golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= +golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw= +golang.org/x/oauth2 v0.34.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.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.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= -golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.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= @@ -191,23 +238,23 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= -golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= +golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= 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.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= -golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU= -golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254= +golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q= +golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg= 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= 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.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= -golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= +golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= +golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= 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= @@ -216,48 +263,48 @@ golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ= -golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ= +golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA= +golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc= 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= 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/rpc v0.0.0-20251111163417-95abcf5c77ba h1:UKgtfRM7Yh93Sya0Fo8ZzhDP4qBckrrxEr2oF5UIVb8= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2 h1:2I6GHUeJ/4shcDpoUlLs/2WPnhg7yJwvXtqcMJt9liA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM= google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= -google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= -google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/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/evanphx/json-patch.v4 v4.13.0 h1:czT3CmqEaQ1aanPc5SdlgQrrEIb8w/wwCvWWnfEbYzo= +gopkg.in/evanphx/json-patch.v4 v4.13.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.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 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.2 h1:fsSUNZhV+bnL6Aqrp6O7lMTy6o5x2C4XLjnh//8SLYY= -k8s.io/api v0.34.2/go.mod h1:MMBPaWlED2a8w4RSeanD76f7opUoypY8TFYkSM+3XHw= -k8s.io/apimachinery v0.34.2 h1:zQ12Uk3eMHPxrsbUJgNF8bTauTVR2WgqJsTmwTE/NW4= -k8s.io/apimachinery v0.34.2/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= -k8s.io/apiserver v0.34.2 h1:2/yu8suwkmES7IzwlehAovo8dDE07cFRC7KMDb1+MAE= -k8s.io/apiserver v0.34.2/go.mod h1:gqJQy2yDOB50R3JUReHSFr+cwJnL8G1dzTA0YLEqAPI= -k8s.io/client-go v0.34.2 h1:Co6XiknN+uUZqiddlfAjT68184/37PS4QAzYvQvDR8M= -k8s.io/client-go v0.34.2/go.mod h1:2VYDl1XXJsdcAxw7BenFslRQX28Dxz91U9MWKjX97fE= -k8s.io/component-base v0.34.2 h1:HQRqK9x2sSAsd8+R4xxRirlTjowsg6fWCPwWYeSvogQ= -k8s.io/component-base v0.34.2/go.mod h1:9xw2FHJavUHBFpiGkZoKuYZ5pdtLKe97DEByaA+hHbM= +k8s.io/api v0.34.3 h1:D12sTP257/jSH2vHV2EDYrb16bS7ULlHpdNdNhEw2S4= +k8s.io/api v0.34.3/go.mod h1:PyVQBF886Q5RSQZOim7DybQjAbVs8g7gwJNhGtY5MBk= +k8s.io/apimachinery v0.34.3 h1:/TB+SFEiQvN9HPldtlWOTp0hWbJ+fjU+wkxysf/aQnE= +k8s.io/apimachinery v0.34.3/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= +k8s.io/apiserver v0.34.3 h1:uGH1qpDvSiYG4HVFqc6A3L4CKiX+aBWDrrsxHYK0Bdo= +k8s.io/apiserver v0.34.3/go.mod h1:QPnnahMO5C2m3lm6fPW3+JmyQbvHZQ8uudAu/493P2w= +k8s.io/client-go v0.34.3 h1:wtYtpzy/OPNYf7WyNBTj3iUA0XaBHVqhv4Iv3tbrF5A= +k8s.io/client-go v0.34.3/go.mod h1:OxxeYagaP9Kdf78UrKLa3YZixMCfP6bgPwPwNBQBzpM= +k8s.io/component-base v0.34.3 h1:zsEgw6ELqK0XncCQomgO9DpUIzlrYuZYA0Cgo+JWpVk= +k8s.io/component-base v0.34.3/go.mod h1:5iIlD8wPfWE/xSHTRfbjuvUul2WZbI2nOUK65XL0E/c= 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= +k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e h1:iW9ChlU0cU16w8MpVYjXk12dqQ4BPFBEgif+ap7/hqQ= +k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e/go.mod h1:kdmbQkyfwUagLfXIad1y2TdrjPFWp2Q89B3qkRwf/pQ= +k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 h1:SjGebBtkBqHFOli+05xYbK8YF1Dzkbzn+gDM4X9T4Ck= +k8s.io/utils v0.0.0-20251002143259-bc988d571ff4/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg= +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/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.1 h1:JrhdFMqOd/+3ByqlP2I45kTOZmTRLBUm5pvRjeheg7E= diff --git a/apps/provisioning/kinds/manifest.cue b/apps/provisioning/kinds/manifest.cue index d0d751dd62b..b0202cb47ce 100644 --- a/apps/provisioning/kinds/manifest.cue +++ b/apps/provisioning/kinds/manifest.cue @@ -1,9 +1,10 @@ package repository manifest: { - appName: "provisioning" - groupOverride: "provisioning.grafana.app" - kinds: [ + appName: "provisioning" + groupOverride: "provisioning.grafana.app" + preferredVersion: "v0alpha1" + kinds: [ repository, connection ] diff --git a/apps/provisioning/kinds/repository.cue b/apps/provisioning/kinds/repository.cue index ba36b4b962f..629d7a62885 100644 --- a/apps/provisioning/kinds/repository.cue +++ b/apps/provisioning/kinds/repository.cue @@ -80,10 +80,13 @@ repository: { // Enabled must be saved as true before any sync job will run enabled: bool // Where values should be saved - target: "unified" | "legacy" + target: "instance" | "folder" // When non-zero, the sync will run periodically intervalSeconds?: int } + #ConnectionInfo: { + name: string + } #HealthStatus: { // When not healthy, requests will not be executed healthy: bool @@ -152,6 +155,9 @@ repository: { // The repository on GitLab. // Mutually exclusive with local | github | git. gitlab?: #GitLabRepositoryConfig + // The connection the repository references. + // This means the Repository is interacting with git via a Connection. + connection?: #ConnectionInfo } status: { // The generation of the spec last time reconciliation ran @@ -168,4 +174,4 @@ repository: { } } } -} \ No newline at end of file +} diff --git a/apps/provisioning/pkg/apis/manifestdata/provisioning_manifest.go b/apps/provisioning/pkg/apis/manifestdata/provisioning_manifest.go new file mode 100644 index 00000000000..c13e0389c11 --- /dev/null +++ b/apps/provisioning/pkg/apis/manifestdata/provisioning_manifest.go @@ -0,0 +1,92 @@ +// +// This file is generated by grafana-app-sdk +// DO NOT EDIT +// + +package manifestdata + +import ( + "fmt" + "strings" + + "github.com/grafana/grafana-app-sdk/app" + "github.com/grafana/grafana-app-sdk/resource" + "k8s.io/apimachinery/pkg/runtime" +) + +var appManifestData = app.ManifestData{ + AppName: "provisioning", + Group: "provisioning.grafana.app", + PreferredVersion: "v0alpha1", + Versions: []app.ManifestVersion{}, +} + +func LocalManifest() app.Manifest { + return app.NewEmbeddedManifest(appManifestData) +} + +func RemoteManifest() app.Manifest { + return app.NewAPIServerManifest("provisioning") +} + +var kindVersionToGoType = map[string]resource.Kind{} + +// 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{} + +// 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{} + +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/provisioning/pkg/apis/provisioning/v0alpha1/jobs.go b/apps/provisioning/pkg/apis/provisioning/v0alpha1/jobs.go index 2e7700ac4a2..100c75b080b 100644 --- a/apps/provisioning/pkg/apis/provisioning/v0alpha1/jobs.go +++ b/apps/provisioning/pkg/apis/provisioning/v0alpha1/jobs.go @@ -136,9 +136,6 @@ type ExportJobOptions struct { } type MigrateJobOptions struct { - // Preserve history (if possible) - History bool `json:"history,omitempty"` - // Message to use when committing the changes in a single commit Message string `json:"message,omitempty"` } diff --git a/apps/provisioning/pkg/apis/provisioning/v0alpha1/settings.go b/apps/provisioning/pkg/apis/provisioning/v0alpha1/settings.go index 3031bde77cb..1aab919c9f6 100644 --- a/apps/provisioning/pkg/apis/provisioning/v0alpha1/settings.go +++ b/apps/provisioning/pkg/apis/provisioning/v0alpha1/settings.go @@ -9,11 +9,6 @@ import ( type RepositoryViewList struct { metav1.TypeMeta `json:",inline"` - // The backend is using legacy storage - // FIXME: Not sure where this should be exposed... but we need it somewhere - // The UI should force the onboarding workflow when this is true - LegacyStorage bool `json:"legacyStorage,omitempty"` - // The valid targets (can disable instance or folder types) AllowedTargets []SyncTargetType `json:"allowedTargets,omitempty"` diff --git a/apps/provisioning/pkg/apis/provisioning/v0alpha1/types.go b/apps/provisioning/pkg/apis/provisioning/v0alpha1/types.go index a4c4f0ef643..c2247e21809 100644 --- a/apps/provisioning/pkg/apis/provisioning/v0alpha1/types.go +++ b/apps/provisioning/pkg/apis/provisioning/v0alpha1/types.go @@ -219,6 +219,10 @@ func (r *Repository) Path() string { return "" } +type ConnectionInfo struct { + Name string `json:"name"` +} + type RepositorySpec struct { // The repository display name (shown in the UI) Title string `json:"title"` @@ -256,6 +260,10 @@ type RepositorySpec struct { // The repository on GitLab. // Mutually exclusive with local | github | git. GitLab *GitLabRepositoryConfig `json:"gitlab,omitempty"` + + // The connection the repository references. + // This means the Repository is interacting with git via a Connection. + Connection *ConnectionInfo `json:"connection,omitempty"` } // SyncTargetType defines where we want all values to resolve diff --git a/apps/provisioning/pkg/apis/provisioning/v0alpha1/zz_generated.deepcopy.go b/apps/provisioning/pkg/apis/provisioning/v0alpha1/zz_generated.deepcopy.go index 6ca50fdd277..48d03d23f99 100644 --- a/apps/provisioning/pkg/apis/provisioning/v0alpha1/zz_generated.deepcopy.go +++ b/apps/provisioning/pkg/apis/provisioning/v0alpha1/zz_generated.deepcopy.go @@ -88,6 +88,22 @@ func (in *Connection) DeepCopyObject() runtime.Object { return nil } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ConnectionInfo) DeepCopyInto(out *ConnectionInfo) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConnectionInfo. +func (in *ConnectionInfo) DeepCopy() *ConnectionInfo { + if in == nil { + return nil + } + out := new(ConnectionInfo) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ConnectionList) DeepCopyInto(out *ConnectionList) { *out = *in @@ -922,6 +938,11 @@ func (in *RepositorySpec) DeepCopyInto(out *RepositorySpec) { *out = new(GitLabRepositoryConfig) **out = **in } + if in.Connection != nil { + in, out := &in.Connection, &out.Connection + *out = new(ConnectionInfo) + **out = **in + } return } diff --git a/apps/provisioning/pkg/apis/provisioning/v0alpha1/zz_generated.openapi.go b/apps/provisioning/pkg/apis/provisioning/v0alpha1/zz_generated.openapi.go index 0e1a224d457..a96fa2d8a6b 100644 --- a/apps/provisioning/pkg/apis/provisioning/v0alpha1/zz_generated.openapi.go +++ b/apps/provisioning/pkg/apis/provisioning/v0alpha1/zz_generated.openapi.go @@ -18,6 +18,7 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1.BitbucketConnectionConfig": schema_pkg_apis_provisioning_v0alpha1_BitbucketConnectionConfig(ref), "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1.BitbucketRepositoryConfig": schema_pkg_apis_provisioning_v0alpha1_BitbucketRepositoryConfig(ref), "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1.Connection": schema_pkg_apis_provisioning_v0alpha1_Connection(ref), + "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1.ConnectionInfo": schema_pkg_apis_provisioning_v0alpha1_ConnectionInfo(ref), "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1.ConnectionList": schema_pkg_apis_provisioning_v0alpha1_ConnectionList(ref), "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1.ConnectionSecure": schema_pkg_apis_provisioning_v0alpha1_ConnectionSecure(ref), "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1.ConnectionSpec": schema_pkg_apis_provisioning_v0alpha1_ConnectionSpec(ref), @@ -224,6 +225,26 @@ func schema_pkg_apis_provisioning_v0alpha1_Connection(ref common.ReferenceCallba } } +func schema_pkg_apis_provisioning_v0alpha1_ConnectionInfo(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "name": { + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + Required: []string{"name"}, + }, + }, + } +} + func schema_pkg_apis_provisioning_v0alpha1_ConnectionList(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ @@ -1474,13 +1495,6 @@ func schema_pkg_apis_provisioning_v0alpha1_MigrateJobOptions(ref common.Referenc SchemaProps: spec.SchemaProps{ Type: []string{"object"}, Properties: map[string]spec.Schema{ - "history": { - SchemaProps: spec.SchemaProps{ - Description: "Preserve history (if possible)", - Type: []string{"boolean"}, - Format: "", - }, - }, "message": { SchemaProps: spec.SchemaProps{ Description: "Message to use when committing the changes in a single commit", @@ -1868,12 +1882,18 @@ func schema_pkg_apis_provisioning_v0alpha1_RepositorySpec(ref common.ReferenceCa Ref: ref("github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1.GitLabRepositoryConfig"), }, }, + "connection": { + SchemaProps: spec.SchemaProps{ + Description: "The connection the repository references. This means the Repository is interacting with git via a Connection.", + Ref: ref("github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1.ConnectionInfo"), + }, + }, }, Required: []string{"title", "workflows", "sync", "type"}, }, }, Dependencies: []string{ - "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1.BitbucketRepositoryConfig", "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1.GitHubRepositoryConfig", "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1.GitLabRepositoryConfig", "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1.GitRepositoryConfig", "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1.LocalRepositoryConfig", "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1.SyncOptions"}, + "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1.BitbucketRepositoryConfig", "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1.ConnectionInfo", "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1.GitHubRepositoryConfig", "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1.GitLabRepositoryConfig", "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1.GitRepositoryConfig", "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1.LocalRepositoryConfig", "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1.SyncOptions"}, } } @@ -2092,13 +2112,6 @@ func schema_pkg_apis_provisioning_v0alpha1_RepositoryViewList(ref common.Referen Format: "", }, }, - "legacyStorage": { - SchemaProps: spec.SchemaProps{ - Description: "The backend is using legacy storage FIXME: Not sure where this should be exposed... but we need it somewhere The UI should force the onboarding workflow when this is true", - Type: []string{"boolean"}, - Format: "", - }, - }, "allowedTargets": { SchemaProps: spec.SchemaProps{ Description: "The valid targets (can disable instance or folder types)", diff --git a/apps/provisioning/pkg/auth/access_checker.go b/apps/provisioning/pkg/auth/access_checker.go new file mode 100644 index 00000000000..841c5421f2a --- /dev/null +++ b/apps/provisioning/pkg/auth/access_checker.go @@ -0,0 +1,22 @@ +package auth + +import ( + "context" + + authlib "github.com/grafana/authlib/types" + "github.com/grafana/grafana/pkg/apimachinery/identity" +) + +//go:generate mockery --name AccessChecker --structname MockAccessChecker --inpackage --filename access_checker_mock.go --with-expecter + +// AccessChecker provides access control checks with optional role-based fallback. +type AccessChecker interface { + // Check performs an access check and returns nil if allowed, or an appropriate + // API error if denied. If req.Namespace is empty, it will be filled from the + // identity's namespace. + Check(ctx context.Context, req authlib.CheckRequest, folder string) error + + // WithFallbackRole returns an AccessChecker configured with the specified fallback role. + // Whether the fallback is actually applied depends on the implementation. + WithFallbackRole(role identity.RoleType) AccessChecker +} diff --git a/apps/provisioning/pkg/auth/access_checker_mock.go b/apps/provisioning/pkg/auth/access_checker_mock.go new file mode 100644 index 00000000000..d0f1cddd7fc --- /dev/null +++ b/apps/provisioning/pkg/auth/access_checker_mock.go @@ -0,0 +1,135 @@ +// Code generated by mockery v2.53.4. DO NOT EDIT. + +package auth + +import ( + context "context" + + identity "github.com/grafana/grafana/pkg/apimachinery/identity" + mock "github.com/stretchr/testify/mock" + + types "github.com/grafana/authlib/types" +) + +// MockAccessChecker is an autogenerated mock type for the AccessChecker type +type MockAccessChecker struct { + mock.Mock +} + +type MockAccessChecker_Expecter struct { + mock *mock.Mock +} + +func (_m *MockAccessChecker) EXPECT() *MockAccessChecker_Expecter { + return &MockAccessChecker_Expecter{mock: &_m.Mock} +} + +// Check provides a mock function with given fields: ctx, req, folder +func (_m *MockAccessChecker) Check(ctx context.Context, req types.CheckRequest, folder string) error { + ret := _m.Called(ctx, req, folder) + + if len(ret) == 0 { + panic("no return value specified for Check") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, types.CheckRequest, string) error); ok { + r0 = rf(ctx, req, folder) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockAccessChecker_Check_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Check' +type MockAccessChecker_Check_Call struct { + *mock.Call +} + +// Check is a helper method to define mock.On call +// - ctx context.Context +// - req types.CheckRequest +// - folder string +func (_e *MockAccessChecker_Expecter) Check(ctx interface{}, req interface{}, folder interface{}) *MockAccessChecker_Check_Call { + return &MockAccessChecker_Check_Call{Call: _e.mock.On("Check", ctx, req, folder)} +} + +func (_c *MockAccessChecker_Check_Call) Run(run func(ctx context.Context, req types.CheckRequest, folder string)) *MockAccessChecker_Check_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(types.CheckRequest), args[2].(string)) + }) + return _c +} + +func (_c *MockAccessChecker_Check_Call) Return(_a0 error) *MockAccessChecker_Check_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockAccessChecker_Check_Call) RunAndReturn(run func(context.Context, types.CheckRequest, string) error) *MockAccessChecker_Check_Call { + _c.Call.Return(run) + return _c +} + +// WithFallbackRole provides a mock function with given fields: role +func (_m *MockAccessChecker) WithFallbackRole(role identity.RoleType) AccessChecker { + ret := _m.Called(role) + + if len(ret) == 0 { + panic("no return value specified for WithFallbackRole") + } + + var r0 AccessChecker + if rf, ok := ret.Get(0).(func(identity.RoleType) AccessChecker); ok { + r0 = rf(role) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(AccessChecker) + } + } + + return r0 +} + +// MockAccessChecker_WithFallbackRole_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WithFallbackRole' +type MockAccessChecker_WithFallbackRole_Call struct { + *mock.Call +} + +// WithFallbackRole is a helper method to define mock.On call +// - role identity.RoleType +func (_e *MockAccessChecker_Expecter) WithFallbackRole(role interface{}) *MockAccessChecker_WithFallbackRole_Call { + return &MockAccessChecker_WithFallbackRole_Call{Call: _e.mock.On("WithFallbackRole", role)} +} + +func (_c *MockAccessChecker_WithFallbackRole_Call) Run(run func(role identity.RoleType)) *MockAccessChecker_WithFallbackRole_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(identity.RoleType)) + }) + return _c +} + +func (_c *MockAccessChecker_WithFallbackRole_Call) Return(_a0 AccessChecker) *MockAccessChecker_WithFallbackRole_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockAccessChecker_WithFallbackRole_Call) RunAndReturn(run func(identity.RoleType) AccessChecker) *MockAccessChecker_WithFallbackRole_Call { + _c.Call.Return(run) + return _c +} + +// NewMockAccessChecker creates a new instance of MockAccessChecker. 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 NewMockAccessChecker(t interface { + mock.TestingT + Cleanup(func()) +}) *MockAccessChecker { + mock := &MockAccessChecker{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/apps/provisioning/pkg/auth/round_tripper.go b/apps/provisioning/pkg/auth/round_tripper.go index 0d2f1cb4ac4..f5da0d778f0 100644 --- a/apps/provisioning/pkg/auth/round_tripper.go +++ b/apps/provisioning/pkg/auth/round_tripper.go @@ -1,3 +1,4 @@ +// Package auth provides authentication utilities for the provisioning API. package auth import ( @@ -6,7 +7,6 @@ import ( "net/http" "github.com/grafana/authlib/authn" - "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1" utilnet "k8s.io/apimachinery/pkg/util/net" ) @@ -15,29 +15,61 @@ type tokenExchanger interface { Exchange(ctx context.Context, req authn.TokenExchangeRequest) (*authn.TokenExchangeResponse, error) } -// RoundTripper injects an exchanged access token for the provisioning API into outgoing requests. -type RoundTripper struct { - client tokenExchanger - transport http.RoundTripper - audience string +// RoundTripperOption configures optional behavior for the RoundTripper. +type RoundTripperOption func(*RoundTripper) + +// ExtraAudience appends an additional audience to the token exchange request. +// +// This is primarily used by operators connecting to the multitenant aggregator, +// where the token must include both the target API server's audience (e.g., dashboards, +// folders) and the provisioning group audience. The provisioning group audience is +// required so that the token passes the enforceManagerProperties check, which prevents +// unauthorized updates to provisioned resources. +// +// Example: +// +// authrt.NewRoundTripper(client, rt, "dashboards.grafana.app", authrt.ExtraAudience("provisioning.grafana.app")) +func ExtraAudience(audience string) RoundTripperOption { + return func(rt *RoundTripper) { + rt.extraAudience = audience + } } -// NewRoundTripper constructs a RoundTripper that exchanges the provided token per request -// and forwards the request to the provided base transport. -func NewRoundTripper(tokenExchangeClient tokenExchanger, base http.RoundTripper, audience string) *RoundTripper { - return &RoundTripper{ +// RoundTripper is an http.RoundTripper that performs token exchange before each request. +// It exchanges the service's credentials for an access token scoped to the configured +// audience(s), then injects that token into the outgoing request's X-Access-Token header. +type RoundTripper struct { + client tokenExchanger + transport http.RoundTripper + audience string + extraAudience string +} + +// NewRoundTripper creates a RoundTripper that exchanges tokens for each outgoing request. +// +// Parameters: +// - tokenExchangeClient: the client used to exchange credentials for access tokens +// - base: the underlying transport to delegate requests to after token injection +// - audience: the primary audience for the token (typically the target API server's group) +// - opts: optional configuration (e.g., ExtraAudience to include additional audiences) +func NewRoundTripper(tokenExchangeClient tokenExchanger, base http.RoundTripper, audience string, opts ...RoundTripperOption) *RoundTripper { + rt := &RoundTripper{ client: tokenExchangeClient, transport: base, audience: audience, } + for _, opt := range opts { + opt(rt) + } + return rt } +// RoundTrip exchanges credentials for an access token and injects it into the request. +// The token is scoped to all configured audiences and the wildcard namespace ("*"). func (t *RoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { - // when we want to write resources with the provisioning API, the audience needs to include provisioning - // so that it passes the check in enforceManagerProperties, which prevents others from updating provisioned resources audiences := []string{t.audience} - if t.audience != v0alpha1.GROUP { - audiences = append(audiences, v0alpha1.GROUP) + if t.extraAudience != "" && t.extraAudience != t.audience { + audiences = append(audiences, t.extraAudience) } tokenResponse, err := t.client.Exchange(req.Context(), authn.TokenExchangeRequest{ diff --git a/apps/provisioning/pkg/auth/round_tripper_test.go b/apps/provisioning/pkg/auth/round_tripper_test.go index e3ae4b7b3d4..c1b2b81e17f 100644 --- a/apps/provisioning/pkg/auth/round_tripper_test.go +++ b/apps/provisioning/pkg/auth/round_tripper_test.go @@ -71,16 +71,29 @@ func TestRoundTripper_AudiencesAndNamespace(t *testing.T) { tests := []struct { name string audience string + extraAudience string wantAudiences []string }{ { - name: "adds group when custom audience", + name: "uses only provided audience by default", audience: "example-audience", + wantAudiences: []string{"example-audience"}, + }, + { + name: "uses only group audience by default", + audience: v0alpha1.GROUP, + wantAudiences: []string{v0alpha1.GROUP}, + }, + { + name: "extra audience adds provisioning group", + audience: "example-audience", + extraAudience: v0alpha1.GROUP, wantAudiences: []string{"example-audience", v0alpha1.GROUP}, }, { - name: "no duplicate when group audience", + name: "extra audience no duplicate when same as primary", audience: v0alpha1.GROUP, + extraAudience: v0alpha1.GROUP, wantAudiences: []string{v0alpha1.GROUP}, }, } @@ -88,11 +101,15 @@ func TestRoundTripper_AudiencesAndNamespace(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { fx := &fakeExchanger{resp: &authn.TokenExchangeResponse{Token: "abc123"}} + var opts []RoundTripperOption + if tt.extraAudience != "" { + opts = append(opts, ExtraAudience(tt.extraAudience)) + } tr := NewRoundTripper(fx, roundTripperFunc(func(_ *http.Request) (*http.Response, error) { rr := httptest.NewRecorder() rr.WriteHeader(http.StatusOK) return rr.Result(), nil - }), tt.audience) + }), tt.audience, opts...) req, _ := http.NewRequestWithContext(context.Background(), http.MethodGet, "http://example", nil) resp, err := tr.RoundTrip(req) diff --git a/apps/provisioning/pkg/auth/session_access_checker.go b/apps/provisioning/pkg/auth/session_access_checker.go new file mode 100644 index 00000000000..1bc6a1b7218 --- /dev/null +++ b/apps/provisioning/pkg/auth/session_access_checker.go @@ -0,0 +1,153 @@ +package auth + +import ( + "context" + "fmt" + "strings" + + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/runtime/schema" + + authlib "github.com/grafana/authlib/types" + "github.com/grafana/grafana-app-sdk/logging" + "github.com/grafana/grafana/pkg/apimachinery/identity" +) + +// sessionAccessChecker implements AccessChecker using Grafana session identity. +type sessionAccessChecker struct { + inner authlib.AccessChecker + fallbackRole identity.RoleType +} + +// NewSessionAccessChecker creates an AccessChecker that gets identity from Grafana +// sessions via GetRequester(ctx). Supports optional role-based fallback via +// WithFallbackRole for backwards compatibility. +func NewSessionAccessChecker(inner authlib.AccessChecker) AccessChecker { + return &sessionAccessChecker{ + inner: inner, + fallbackRole: "", + } +} + +// WithFallbackRole returns a new AccessChecker with the specified fallback role. +func (c *sessionAccessChecker) WithFallbackRole(role identity.RoleType) AccessChecker { + return &sessionAccessChecker{ + inner: c.inner, + fallbackRole: role, + } +} + +// Check performs an access check with optional role-based fallback. +// Returns nil if access is allowed, or an appropriate API error if denied. +func (c *sessionAccessChecker) Check(ctx context.Context, req authlib.CheckRequest, folder string) error { + logger := logging.FromContext(ctx).With("logger", "sessionAccessChecker") + + // Get identity from Grafana session + requester, err := identity.GetRequester(ctx) + if err != nil { + logger.Debug("failed to get requester", + "resource", req.Resource, + "verb", req.Verb, + "error", err.Error(), + ) + return apierrors.NewUnauthorized(fmt.Sprintf("failed to get requester: %v", err)) + } + + logger.Debug("checking access", + "identityType", requester.GetIdentityType(), + "orgRole", requester.GetOrgRole(), + "namespace", requester.GetNamespace(), + "resource", req.Resource, + "verb", req.Verb, + "group", req.Group, + "name", req.Name, + "folder", folder, + "fallbackRole", c.fallbackRole, + ) + + // Fill in namespace from identity if not provided + if req.Namespace == "" { + req.Namespace = requester.GetNamespace() + } + + // Perform the access check + rsp, err := c.inner.Check(ctx, requester, req, folder) + + // Build the GroupResource for error messages + gr := schema.GroupResource{Group: req.Group, Resource: req.Resource} + + // No fallback configured, return result directly + if c.fallbackRole == "" { + if err != nil { + logger.Debug("access check error (no fallback)", + "resource", req.Resource, + "verb", req.Verb, + "error", err.Error(), + ) + return apierrors.NewForbidden(gr, req.Name, fmt.Errorf("%s.%s is forbidden: %w", req.Resource, req.Group, err)) + } + if !rsp.Allowed { + logger.Debug("access check denied (no fallback)", + "resource", req.Resource, + "verb", req.Verb, + "group", req.Group, + "allowed", rsp.Allowed, + ) + return apierrors.NewForbidden(gr, req.Name, fmt.Errorf("permission denied")) + } + logger.Debug("access allowed", + "resource", req.Resource, + "verb", req.Verb, + ) + return nil + } + + // Fallback is configured - apply fallback logic + if err != nil { + if requester.GetOrgRole().Includes(c.fallbackRole) { + logger.Debug("access allowed via role fallback (after error)", + "resource", req.Resource, + "verb", req.Verb, + "fallbackRole", c.fallbackRole, + "orgRole", requester.GetOrgRole(), + ) + return nil // Fallback succeeded + } + logger.Debug("access check error (fallback failed)", + "resource", req.Resource, + "verb", req.Verb, + "error", err.Error(), + "fallbackRole", c.fallbackRole, + "orgRole", requester.GetOrgRole(), + ) + return apierrors.NewForbidden(gr, req.Name, fmt.Errorf("%s.%s is forbidden: %w", req.Resource, req.Group, err)) + } + + if rsp.Allowed { + logger.Debug("access allowed", + "resource", req.Resource, + "verb", req.Verb, + ) + return nil + } + + // Fall back to role for backwards compatibility + if requester.GetOrgRole().Includes(c.fallbackRole) { + logger.Debug("access allowed via role fallback", + "resource", req.Resource, + "verb", req.Verb, + "fallbackRole", c.fallbackRole, + "orgRole", requester.GetOrgRole(), + ) + return nil // Fallback succeeded + } + + logger.Debug("access denied (fallback role not met)", + "resource", req.Resource, + "verb", req.Verb, + "group", req.Group, + "fallbackRole", c.fallbackRole, + "orgRole", requester.GetOrgRole(), + ) + return apierrors.NewForbidden(gr, req.Name, fmt.Errorf("%s role is required", strings.ToLower(string(c.fallbackRole)))) +} diff --git a/apps/provisioning/pkg/auth/session_access_checker_test.go b/apps/provisioning/pkg/auth/session_access_checker_test.go new file mode 100644 index 00000000000..1e99a6e46db --- /dev/null +++ b/apps/provisioning/pkg/auth/session_access_checker_test.go @@ -0,0 +1,244 @@ +package auth + +import ( + "context" + "errors" + "testing" + + apierrors "k8s.io/apimachinery/pkg/api/errors" + + authlib "github.com/grafana/authlib/types" + "github.com/grafana/grafana/pkg/apimachinery/identity" + "github.com/grafana/grafana/pkg/services/user" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// mockRequester implements identity.Requester for testing. +type mockRequester struct { + identity.Requester + orgRole identity.RoleType + identityType authlib.IdentityType + namespace string +} + +func (m *mockRequester) GetOrgRole() identity.RoleType { + return m.orgRole +} + +func (m *mockRequester) GetIdentityType() authlib.IdentityType { + return m.identityType +} + +func (m *mockRequester) GetNamespace() string { + return m.namespace +} + +func TestSessionAccessChecker_Check(t *testing.T) { + ctx := context.Background() + req := authlib.CheckRequest{ + Verb: "get", + Group: "provisioning.grafana.app", + Resource: "repositories", + Name: "test-repo", + Namespace: "default", + } + + tests := []struct { + name string + fallbackRole identity.RoleType + innerResponse authlib.CheckResponse + innerErr error + requester *mockRequester + expectAllow bool + }{ + { + name: "allowed by checker", + fallbackRole: identity.RoleAdmin, + innerResponse: authlib.CheckResponse{Allowed: true}, + requester: &mockRequester{orgRole: identity.RoleViewer, identityType: authlib.TypeUser}, + expectAllow: true, + }, + { + name: "denied by checker, fallback to admin role succeeds", + fallbackRole: identity.RoleAdmin, + innerResponse: authlib.CheckResponse{Allowed: false}, + requester: &mockRequester{orgRole: identity.RoleAdmin, identityType: authlib.TypeUser}, + expectAllow: true, + }, + { + name: "denied by checker, fallback to admin role fails for viewer", + fallbackRole: identity.RoleAdmin, + innerResponse: authlib.CheckResponse{Allowed: false}, + requester: &mockRequester{orgRole: identity.RoleViewer, identityType: authlib.TypeUser}, + expectAllow: false, + }, + { + name: "error from checker, fallback to admin role succeeds", + fallbackRole: identity.RoleAdmin, + innerErr: errors.New("access check failed"), + requester: &mockRequester{orgRole: identity.RoleAdmin, identityType: authlib.TypeUser}, + expectAllow: true, + }, + { + name: "error from checker, fallback fails for viewer", + fallbackRole: identity.RoleAdmin, + innerErr: errors.New("access check failed"), + requester: &mockRequester{orgRole: identity.RoleViewer, identityType: authlib.TypeUser}, + expectAllow: false, + }, + { + name: "denied, editor fallback succeeds for editor", + fallbackRole: identity.RoleEditor, + innerResponse: authlib.CheckResponse{Allowed: false}, + requester: &mockRequester{orgRole: identity.RoleEditor, identityType: authlib.TypeUser}, + expectAllow: true, + }, + { + name: "denied, editor fallback fails for viewer", + fallbackRole: identity.RoleEditor, + innerResponse: authlib.CheckResponse{Allowed: false}, + requester: &mockRequester{orgRole: identity.RoleViewer, identityType: authlib.TypeUser}, + expectAllow: false, + }, + { + name: "no fallback configured, denied stays denied", + fallbackRole: "", // no fallback + innerResponse: authlib.CheckResponse{Allowed: false}, + requester: &mockRequester{orgRole: identity.RoleAdmin, identityType: authlib.TypeUser}, + expectAllow: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + mock := &mockInnerAccessChecker{ + response: tt.innerResponse, + err: tt.innerErr, + } + + checker := NewSessionAccessChecker(mock) + if tt.fallbackRole != "" { + checker = checker.WithFallbackRole(tt.fallbackRole) + } + + // Add requester to context + testCtx := identity.WithRequester(ctx, tt.requester) + + err := checker.Check(testCtx, req, "") + + if tt.expectAllow { + require.NoError(t, err) + } else { + require.Error(t, err) + assert.True(t, apierrors.IsForbidden(err), "expected Forbidden error, got: %v", err) + } + }) + } +} + +func TestSessionAccessChecker_NoRequester(t *testing.T) { + mock := &mockInnerAccessChecker{ + response: authlib.CheckResponse{Allowed: true}, + } + + checker := NewSessionAccessChecker(mock) + err := checker.Check(context.Background(), authlib.CheckRequest{}, "") + + require.Error(t, err) + assert.True(t, apierrors.IsUnauthorized(err), "expected Unauthorized error") +} + +func TestSessionAccessChecker_WithFallbackRole_ImmutableOriginal(t *testing.T) { + mock := &mockInnerAccessChecker{ + response: authlib.CheckResponse{Allowed: false}, + } + + original := NewSessionAccessChecker(mock) + withAdmin := original.WithFallbackRole(identity.RoleAdmin) + withEditor := original.WithFallbackRole(identity.RoleEditor) + + ctx := identity.WithRequester(context.Background(), &mockRequester{ + orgRole: identity.RoleEditor, + identityType: authlib.TypeUser, + }) + + req := authlib.CheckRequest{} + + // Original should deny (no fallback) + err := original.Check(ctx, req, "") + require.Error(t, err, "original should deny without fallback") + + // WithAdmin should deny for editor + err = withAdmin.Check(ctx, req, "") + require.Error(t, err, "admin fallback should deny for editor") + + // WithEditor should allow for editor + err = withEditor.Check(ctx, req, "") + require.NoError(t, err, "editor fallback should allow for editor") +} + +func TestSessionAccessChecker_WithFallbackRole_ChainedCalls(t *testing.T) { + mock := &mockInnerAccessChecker{ + response: authlib.CheckResponse{Allowed: false}, + } + + // Ensure chained WithFallbackRole calls work correctly + checker := NewSessionAccessChecker(mock). + WithFallbackRole(identity.RoleAdmin). + WithFallbackRole(identity.RoleEditor) // This should override admin + + ctx := identity.WithRequester(context.Background(), &mockRequester{ + orgRole: identity.RoleEditor, + identityType: authlib.TypeUser, + }) + + err := checker.Check(ctx, authlib.CheckRequest{}, "") + require.NoError(t, err, "last fallback (editor) should be used") +} + +func TestSessionAccessChecker_RealSignedInUser(t *testing.T) { + mock := &mockInnerAccessChecker{ + response: authlib.CheckResponse{Allowed: false}, + } + + checker := NewSessionAccessChecker(mock).WithFallbackRole(identity.RoleAdmin) + + // Use a real SignedInUser + signedInUser := &user.SignedInUser{ + UserID: 1, + OrgID: 1, + OrgRole: identity.RoleAdmin, + } + + ctx := identity.WithRequester(context.Background(), signedInUser) + + err := checker.Check(ctx, authlib.CheckRequest{}, "") + require.NoError(t, err, "admin user should be allowed via fallback") +} + +func TestSessionAccessChecker_FillsNamespace(t *testing.T) { + mock := &mockInnerAccessChecker{ + response: authlib.CheckResponse{Allowed: true}, + } + + checker := NewSessionAccessChecker(mock) + + ctx := identity.WithRequester(context.Background(), &mockRequester{ + orgRole: identity.RoleAdmin, + identityType: authlib.TypeUser, + namespace: "org-123", + }) + + // Request without namespace + req := authlib.CheckRequest{ + Verb: "get", + Group: "provisioning.grafana.app", + Resource: "repositories", + Name: "test-repo", + // Namespace intentionally empty + } + + err := checker.Check(ctx, req, "") + require.NoError(t, err) +} diff --git a/apps/provisioning/pkg/auth/token_access_checker.go b/apps/provisioning/pkg/auth/token_access_checker.go new file mode 100644 index 00000000000..8df833d7a34 --- /dev/null +++ b/apps/provisioning/pkg/auth/token_access_checker.go @@ -0,0 +1,92 @@ +package auth + +import ( + "context" + "fmt" + + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/runtime/schema" + + authlib "github.com/grafana/authlib/types" + "github.com/grafana/grafana-app-sdk/logging" + "github.com/grafana/grafana/pkg/apimachinery/identity" +) + +// tokenAccessChecker implements AccessChecker using access tokens from context. +type tokenAccessChecker struct { + inner authlib.AccessChecker +} + +// NewTokenAccessChecker creates an AccessChecker that gets identity from access tokens +// via AuthInfoFrom(ctx). Role-based fallback is not supported. +func NewTokenAccessChecker(inner authlib.AccessChecker) AccessChecker { + return &tokenAccessChecker{inner: inner} +} + +// WithFallbackRole returns the same checker since fallback is not supported. +func (c *tokenAccessChecker) WithFallbackRole(_ identity.RoleType) AccessChecker { + return c +} + +// Check performs an access check using AuthInfo from context. +// Returns nil if access is allowed, or an appropriate API error if denied. +func (c *tokenAccessChecker) Check(ctx context.Context, req authlib.CheckRequest, folder string) error { + logger := logging.FromContext(ctx).With("logger", "tokenAccessChecker") + + // Get identity from access token in context + id, ok := authlib.AuthInfoFrom(ctx) + if !ok { + logger.Debug("no auth info in context", + "resource", req.Resource, + "verb", req.Verb, + "namespace", req.Namespace, + ) + return apierrors.NewUnauthorized("no auth info in context") + } + + logger.Debug("checking access", + "identityType", id.GetIdentityType(), + "namespace", id.GetNamespace(), + "resource", req.Resource, + "verb", req.Verb, + "group", req.Group, + "name", req.Name, + "folder", folder, + ) + + // Fill in namespace from identity if not provided + if req.Namespace == "" { + req.Namespace = id.GetNamespace() + } + + // Perform the access check + rsp, err := c.inner.Check(ctx, id, req, folder) + + // Build the GroupResource for error messages + gr := schema.GroupResource{Group: req.Group, Resource: req.Resource} + + if err != nil { + logger.Debug("access check error", + "resource", req.Resource, + "verb", req.Verb, + "error", err.Error(), + ) + return apierrors.NewForbidden(gr, req.Name, fmt.Errorf("%s.%s is forbidden: %w", req.Resource, req.Group, err)) + } + if !rsp.Allowed { + logger.Debug("access check denied", + "resource", req.Resource, + "verb", req.Verb, + "group", req.Group, + "identityType", id.GetIdentityType(), + "allowed", rsp.Allowed, + ) + return apierrors.NewForbidden(gr, req.Name, fmt.Errorf("permission denied")) + } + + logger.Debug("access allowed", + "resource", req.Resource, + "verb", req.Verb, + ) + return nil +} diff --git a/apps/provisioning/pkg/auth/token_access_checker_test.go b/apps/provisioning/pkg/auth/token_access_checker_test.go new file mode 100644 index 00000000000..bce0d3a77a0 --- /dev/null +++ b/apps/provisioning/pkg/auth/token_access_checker_test.go @@ -0,0 +1,137 @@ +package auth + +import ( + "context" + "errors" + "testing" + + apierrors "k8s.io/apimachinery/pkg/api/errors" + + authlib "github.com/grafana/authlib/types" + "github.com/grafana/grafana/pkg/apimachinery/identity" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestTokenAccessChecker_Check(t *testing.T) { + req := authlib.CheckRequest{ + Verb: "get", + Group: "provisioning.grafana.app", + Resource: "repositories", + Name: "test-repo", + Namespace: "default", + } + + tests := []struct { + name string + innerResponse authlib.CheckResponse + innerErr error + authInfo *identity.StaticRequester + expectAllow bool + }{ + { + name: "allowed by checker", + innerResponse: authlib.CheckResponse{Allowed: true}, + authInfo: &identity.StaticRequester{Type: authlib.TypeUser}, + expectAllow: true, + }, + { + name: "denied by checker", + innerResponse: authlib.CheckResponse{Allowed: false}, + authInfo: &identity.StaticRequester{Type: authlib.TypeUser}, + expectAllow: false, + }, + { + name: "error from checker", + innerErr: errors.New("access check failed"), + authInfo: &identity.StaticRequester{Type: authlib.TypeUser}, + expectAllow: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + mock := &mockInnerAccessChecker{ + response: tt.innerResponse, + err: tt.innerErr, + } + + checker := NewTokenAccessChecker(mock) + + // Add auth info to context + testCtx := authlib.WithAuthInfo(context.Background(), tt.authInfo) + + err := checker.Check(testCtx, req, "") + + if tt.expectAllow { + require.NoError(t, err) + } else { + require.Error(t, err) + assert.True(t, apierrors.IsForbidden(err), "expected Forbidden error, got: %v", err) + } + }) + } +} + +func TestTokenAccessChecker_NoAuthInfo(t *testing.T) { + mock := &mockInnerAccessChecker{ + response: authlib.CheckResponse{Allowed: true}, + } + + checker := NewTokenAccessChecker(mock) + err := checker.Check(context.Background(), authlib.CheckRequest{}, "") + + require.Error(t, err) + assert.True(t, apierrors.IsUnauthorized(err), "expected Unauthorized error") +} + +func TestTokenAccessChecker_WithFallbackRole_IsNoOp(t *testing.T) { + mock := &mockInnerAccessChecker{ + response: authlib.CheckResponse{Allowed: false}, + } + + checker := NewTokenAccessChecker(mock) + checkerWithFallback := checker.WithFallbackRole(identity.RoleAdmin) + + // They should be the same instance + assert.Same(t, checker, checkerWithFallback, "WithFallbackRole should return same instance") +} + +func TestTokenAccessChecker_FillsNamespace(t *testing.T) { + mock := &mockInnerAccessChecker{ + response: authlib.CheckResponse{Allowed: true}, + } + + checker := NewTokenAccessChecker(mock) + + ctx := authlib.WithAuthInfo(context.Background(), &identity.StaticRequester{ + Type: authlib.TypeUser, + Namespace: "org-123", + }) + + // Request without namespace + req := authlib.CheckRequest{ + Verb: "get", + Group: "provisioning.grafana.app", + Resource: "repositories", + Name: "test-repo", + // Namespace intentionally empty + } + + err := checker.Check(ctx, req, "") + require.NoError(t, err) +} + +// mockInnerAccessChecker implements authlib.AccessChecker for testing. +type mockInnerAccessChecker struct { + response authlib.CheckResponse + err error +} + +func (m *mockInnerAccessChecker) Check(_ context.Context, _ authlib.AuthInfo, _ authlib.CheckRequest, _ string) (authlib.CheckResponse, error) { + return m.response, m.err +} + +func (m *mockInnerAccessChecker) Compile(_ context.Context, _ authlib.AuthInfo, _ authlib.ListRequest) (authlib.ItemChecker, authlib.Zookie, error) { + return nil, nil, nil +} diff --git a/apps/provisioning/pkg/generated/applyconfiguration/provisioning/v0alpha1/connectioninfo.go b/apps/provisioning/pkg/generated/applyconfiguration/provisioning/v0alpha1/connectioninfo.go new file mode 100644 index 00000000000..87e4aa7e180 --- /dev/null +++ b/apps/provisioning/pkg/generated/applyconfiguration/provisioning/v0alpha1/connectioninfo.go @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: AGPL-3.0-only + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v0alpha1 + +// ConnectionInfoApplyConfiguration represents a declarative configuration of the ConnectionInfo type for use +// with apply. +type ConnectionInfoApplyConfiguration struct { + Name *string `json:"name,omitempty"` +} + +// ConnectionInfoApplyConfiguration constructs a declarative configuration of the ConnectionInfo type for use with +// apply. +func ConnectionInfo() *ConnectionInfoApplyConfiguration { + return &ConnectionInfoApplyConfiguration{} +} + +// WithName sets the Name field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Name field is set to the value of the last call. +func (b *ConnectionInfoApplyConfiguration) WithName(value string) *ConnectionInfoApplyConfiguration { + b.Name = &value + return b +} diff --git a/apps/provisioning/pkg/generated/applyconfiguration/provisioning/v0alpha1/migratejoboptions.go b/apps/provisioning/pkg/generated/applyconfiguration/provisioning/v0alpha1/migratejoboptions.go index aee0b05fa3a..7f689c19585 100644 --- a/apps/provisioning/pkg/generated/applyconfiguration/provisioning/v0alpha1/migratejoboptions.go +++ b/apps/provisioning/pkg/generated/applyconfiguration/provisioning/v0alpha1/migratejoboptions.go @@ -7,7 +7,6 @@ package v0alpha1 // MigrateJobOptionsApplyConfiguration represents a declarative configuration of the MigrateJobOptions type for use // with apply. type MigrateJobOptionsApplyConfiguration struct { - History *bool `json:"history,omitempty"` Message *string `json:"message,omitempty"` } @@ -17,14 +16,6 @@ func MigrateJobOptions() *MigrateJobOptionsApplyConfiguration { return &MigrateJobOptionsApplyConfiguration{} } -// WithHistory sets the History field in the declarative configuration to the given value -// and returns the receiver, so that objects can be built by chaining "With" function invocations. -// If called multiple times, the History field is set to the value of the last call. -func (b *MigrateJobOptionsApplyConfiguration) WithHistory(value bool) *MigrateJobOptionsApplyConfiguration { - b.History = &value - return b -} - // WithMessage sets the Message field in the declarative configuration to the given value // and returns the receiver, so that objects can be built by chaining "With" function invocations. // If called multiple times, the Message field is set to the value of the last call. diff --git a/apps/provisioning/pkg/generated/applyconfiguration/provisioning/v0alpha1/repositoryspec.go b/apps/provisioning/pkg/generated/applyconfiguration/provisioning/v0alpha1/repositoryspec.go index 6fff6f2de42..5caf805702b 100644 --- a/apps/provisioning/pkg/generated/applyconfiguration/provisioning/v0alpha1/repositoryspec.go +++ b/apps/provisioning/pkg/generated/applyconfiguration/provisioning/v0alpha1/repositoryspec.go @@ -21,6 +21,7 @@ type RepositorySpecApplyConfiguration struct { Git *GitRepositoryConfigApplyConfiguration `json:"git,omitempty"` Bitbucket *BitbucketRepositoryConfigApplyConfiguration `json:"bitbucket,omitempty"` GitLab *GitLabRepositoryConfigApplyConfiguration `json:"gitlab,omitempty"` + Connection *ConnectionInfoApplyConfiguration `json:"connection,omitempty"` } // RepositorySpecApplyConfiguration constructs a declarative configuration of the RepositorySpec type for use with @@ -110,3 +111,11 @@ func (b *RepositorySpecApplyConfiguration) WithGitLab(value *GitLabRepositoryCon b.GitLab = value return b } + +// WithConnection sets the Connection field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Connection field is set to the value of the last call. +func (b *RepositorySpecApplyConfiguration) WithConnection(value *ConnectionInfoApplyConfiguration) *RepositorySpecApplyConfiguration { + b.Connection = value + return b +} diff --git a/apps/provisioning/pkg/generated/applyconfiguration/utils.go b/apps/provisioning/pkg/generated/applyconfiguration/utils.go index 52c3faee58c..7168418b82d 100644 --- a/apps/provisioning/pkg/generated/applyconfiguration/utils.go +++ b/apps/provisioning/pkg/generated/applyconfiguration/utils.go @@ -24,6 +24,8 @@ func ForKind(kind schema.GroupVersionKind) interface{} { return &provisioningv0alpha1.BitbucketRepositoryConfigApplyConfiguration{} case v0alpha1.SchemeGroupVersion.WithKind("Connection"): return &provisioningv0alpha1.ConnectionApplyConfiguration{} + case v0alpha1.SchemeGroupVersion.WithKind("ConnectionInfo"): + return &provisioningv0alpha1.ConnectionInfoApplyConfiguration{} case v0alpha1.SchemeGroupVersion.WithKind("ConnectionSecure"): return &provisioningv0alpha1.ConnectionSecureApplyConfiguration{} case v0alpha1.SchemeGroupVersion.WithKind("ConnectionSpec"): diff --git a/apps/provisioning/pkg/jobs/validator_test.go b/apps/provisioning/pkg/jobs/validator_test.go index fdd29598ebc..172e1929e1e 100644 --- a/apps/provisioning/pkg/jobs/validator_test.go +++ b/apps/provisioning/pkg/jobs/validator_test.go @@ -384,8 +384,7 @@ func TestValidateJob(t *testing.T) { Action: provisioning.JobActionMigrate, Repository: "test-repo", Migrate: &provisioning.MigrateJobOptions{ - History: true, - Message: "Migrate from legacy", + Message: "Migrate from unified", }, }, }, diff --git a/apps/provisioning/pkg/repository/git/repository.go b/apps/provisioning/pkg/repository/git/repository.go index 82d5ca6bd1d..bac3bd6d0a6 100644 --- a/apps/provisioning/pkg/repository/git/repository.go +++ b/apps/provisioning/pkg/repository/git/repository.go @@ -238,6 +238,8 @@ func (r *gitRepository) Read(ctx context.Context, filePath, ref string) (*reposi // Check if the path represents a directory if safepath.IsDir(filePath) { + // Strip trailing slash for git tree lookup to avoid empty path components + finalPath = strings.TrimSuffix(finalPath, "/") tree, err := r.client.GetTreeByPath(ctx, commit.Tree, finalPath) if err != nil { if errors.Is(err, nanogit.ErrObjectNotFound) { diff --git a/apps/provisioning/pkg/repository/tester.go b/apps/provisioning/pkg/repository/tester.go index 6bd65443d92..14290d0514b 100644 --- a/apps/provisioning/pkg/repository/tester.go +++ b/apps/provisioning/pkg/repository/tester.go @@ -23,7 +23,13 @@ func NewSimpleRepositoryTester(validator RepositoryValidator) SimpleRepositoryTe // TestRepository validates the repository and then runs a health check func (t *SimpleRepositoryTester) TestRepository(ctx context.Context, repo Repository) (*provisioning.TestResults, error) { - errors := t.validator.ValidateRepository(repo) + // Determine if this is a CREATE or UPDATE operation + // If the repository has been observed by the controller (ObservedGeneration > 0), + // it's an existing repository and we should treat it as UPDATE + cfg := repo.Config() + isCreate := cfg.Status.ObservedGeneration == 0 + + errors := t.validator.ValidateRepository(repo, isCreate) if len(errors) > 0 { rsp := &provisioning.TestResults{ Code: http.StatusUnprocessableEntity, // Invalid diff --git a/apps/provisioning/pkg/repository/validator.go b/apps/provisioning/pkg/repository/validator.go index 73198f0d7ee..46ba81f8cbd 100644 --- a/apps/provisioning/pkg/repository/validator.go +++ b/apps/provisioning/pkg/repository/validator.go @@ -32,7 +32,9 @@ func NewValidator(minSyncInterval time.Duration, allowedTargets []provisioning.S } // ValidateRepository solely does configuration checks on the repository object. It does not run a health check or compare against existing repositories. -func (v *RepositoryValidator) ValidateRepository(repo Repository) field.ErrorList { +// isCreate indicates whether this is a CREATE operation (true) or UPDATE operation (false). +// When isCreate is false, allowedTargets validation is skipped to allow existing repositories to continue working. +func (v *RepositoryValidator) ValidateRepository(repo Repository, isCreate bool) field.ErrorList { list := repo.Validate() cfg := repo.Config() @@ -44,7 +46,7 @@ func (v *RepositoryValidator) ValidateRepository(repo Repository) field.ErrorLis if cfg.Spec.Sync.Target == "" { list = append(list, field.Required(field.NewPath("spec", "sync", "target"), "The target type is required when sync is enabled")) - } else if !slices.Contains(v.allowedTargets, cfg.Spec.Sync.Target) { + } else if isCreate && !slices.Contains(v.allowedTargets, cfg.Spec.Sync.Target) { list = append(list, field.Invalid( field.NewPath("spec", "target"), diff --git a/apps/provisioning/pkg/repository/validator_test.go b/apps/provisioning/pkg/repository/validator_test.go index cb8b726a9bf..75980733e17 100644 --- a/apps/provisioning/pkg/repository/validator_test.go +++ b/apps/provisioning/pkg/repository/validator_test.go @@ -303,7 +303,8 @@ func TestValidateRepository(t *testing.T) { validator := NewValidator(10*time.Second, []provisioning.SyncTargetType{provisioning.SyncTargetTypeFolder}, false) for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - errors := validator.ValidateRepository(tt.repository) + // Tests validate new configurations, so always pass isCreate=true + errors := validator.ValidateRepository(tt.repository, true) require.Len(t, errors, tt.expectedErrs) if tt.validateError != nil { tt.validateError(t, errors) diff --git a/apps/quotas/go.mod b/apps/quotas/go.mod index 1ab18fe8876..857521f2c57 100644 --- a/apps/quotas/go.mod +++ b/apps/quotas/go.mod @@ -3,15 +3,15 @@ module github.com/grafana/grafana/apps/quotas go 1.25.3 require ( - github.com/grafana/grafana-app-sdk v0.48.5 - github.com/grafana/grafana-app-sdk/logging v0.48.3 - k8s.io/apimachinery v0.34.2 - k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 + github.com/grafana/grafana-app-sdk v0.48.7 + github.com/grafana/grafana-app-sdk/logging v0.48.7 + k8s.io/apimachinery v0.34.3 + k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e ) require ( github.com/beorn7/perks v1.0.1 // indirect - github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874 // indirect + github.com/bradfitz/gomemcache v0.0.0-20250403215159-8d39553ac7cf // 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 @@ -21,22 +21,22 @@ require ( github.com/getkin/kin-openapi v0.133.0 // 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-openapi/jsonpointer v0.22.4 // indirect + github.com/go-openapi/jsonreference v0.21.4 // indirect + github.com/go-openapi/swag v0.25.4 // indirect + github.com/go-openapi/swag/jsonname v0.25.4 // 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/gnostic-models v0.7.1 // 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/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3 // 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/mailru/easyjson v0.9.1 // 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 @@ -49,43 +49,43 @@ require ( 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.3 // indirect - github.com/prometheus/procfs v0.16.1 // indirect + github.com/prometheus/common v0.67.4 // indirect + github.com/prometheus/procfs v0.19.2 // 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/woodsbury/decimal128 v1.4.0 // indirect github.com/x448/float16 v0.8.4 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // 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.opentelemetry.io/otel v1.39.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0 // indirect + go.opentelemetry.io/otel/metric v1.39.0 // indirect + go.opentelemetry.io/otel/sdk v1.39.0 // indirect + go.opentelemetry.io/otel/trace v1.39.0 // indirect + go.opentelemetry.io/proto/otlp v1.9.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.47.0 // indirect - golang.org/x/oauth2 v0.33.0 // indirect - golang.org/x/sync v0.18.0 // indirect - golang.org/x/sys v0.38.0 // indirect - golang.org/x/term v0.37.0 // indirect - golang.org/x/text v0.31.0 // indirect + golang.org/x/net v0.48.0 // indirect + golang.org/x/oauth2 v0.34.0 // indirect + golang.org/x/sync v0.19.0 // indirect + golang.org/x/sys v0.39.0 // indirect + golang.org/x/term v0.38.0 // indirect + golang.org/x/text v0.32.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-20251022142026-3a174f9686a8 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2 // indirect google.golang.org/grpc v1.77.0 // indirect - google.golang.org/protobuf v1.36.10 // indirect + google.golang.org/protobuf v1.36.11 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/api v0.34.2 // indirect - k8s.io/apiextensions-apiserver v0.34.2 // indirect - k8s.io/client-go v0.34.2 // indirect + k8s.io/api v0.34.3 // indirect + k8s.io/apiextensions-apiserver v0.34.3 // indirect + k8s.io/client-go v0.34.3 // 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 + k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 // indirect + sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect sigs.k8s.io/randfill v1.0.0 // indirect sigs.k8s.io/structured-merge-diff/v6 v6.3.1 // indirect sigs.k8s.io/yaml v1.6.0 // indirect diff --git a/apps/quotas/go.sum b/apps/quotas/go.sum index 5787fa55023..6bbf64cb454 100644 --- a/apps/quotas/go.sum +++ b/apps/quotas/go.sum @@ -2,6 +2,7 @@ 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/bradfitz/gomemcache v0.0.0-20250403215159-8d39553ac7cf/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= @@ -25,12 +26,16 @@ 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/jsonpointer v0.22.4/go.mod h1:elX9+UgznpFhgBuaMQ7iu4lvvX1nvNsesQ3oxmYTw80= 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/jsonreference v0.21.4/go.mod h1:rIENPTjDbLpzQmQWCj5kKj3ZlmEh+EFVbz3RTUh30/4= 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 v0.25.4/go.mod h1:zNfJ9WZABGHCFg2RnY0S4IOkAcVTzJ6z2Bi+Q4i6qFQ= 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/jsonname v0.25.4/go.mod h1:GPVEk9CWVhNvWhZgrnvRA6utbAltopbKwDu8mXNUMag= 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= @@ -41,6 +46,7 @@ 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/gnostic-models v0.7.1/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= @@ -54,11 +60,16 @@ github.com/grafana/grafana-app-sdk v0.48.4 h1:t9r+Y6E7D832ZxQ2c1n0lp6cvsYKhhrAod github.com/grafana/grafana-app-sdk v0.48.4/go.mod h1:HJsMOSBmt/D/Ihs1SvagOwmXKi0coBMVHlfvdd+qe9Y= github.com/grafana/grafana-app-sdk v0.48.5 h1:MS8l9fTZz+VbTfgApn09jw27GxhQ6fNOWGhC4ydvZmM= github.com/grafana/grafana-app-sdk v0.48.5/go.mod h1:HJsMOSBmt/D/Ihs1SvagOwmXKi0coBMVHlfvdd+qe9Y= +github.com/grafana/grafana-app-sdk v0.48.7 h1:9mF7nqkqP0QUYYDlznoOt+GIyjzj45wGfUHB32u2ZMo= +github.com/grafana/grafana-app-sdk v0.48.7/go.mod h1:DWsaaH39ZMHwSOSoUBaeW8paMrRaYsjRYlLwCJYd78k= 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-app-sdk/logging v0.48.3/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA= +github.com/grafana/grafana-app-sdk/logging v0.48.7 h1:Oa5qg473gka5+W/WQk61Xbw4YdAv+wV2Z4bJtzeCaQw= +github.com/grafana/grafana-app-sdk/logging v0.48.7/go.mod h1:5u3KalezoBAAo2Y3ytDYDAIIPvEqFLLDSxeiK99QxDU= 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/grpc-ecosystem/grpc-gateway/v2 v2.27.3/go.mod h1:zQrxl1YP88HQlA6i9c63DSVPFklWpGX4OWAc9bFuaH4= 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= @@ -80,6 +91,7 @@ github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0 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/mailru/easyjson v0.9.1/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= @@ -111,8 +123,10 @@ github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNw github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= github.com/prometheus/common v0.67.3 h1:shd26MlnwTw5jksTDhC7rTQIteBxy+ZZDr3t7F2xN2Q= github.com/prometheus/common v0.67.3/go.mod h1:gP0fq6YjjNCLssJCQp0yk4M8W6ikLURwkdd/YKtTbyI= +github.com/prometheus/common v0.67.4/go.mod h1:gP0fq6YjjNCLssJCQp0yk4M8W6ikLURwkdd/YKtTbyI= github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= +github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw= 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.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= @@ -129,6 +143,7 @@ github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4d 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/woodsbury/decimal128 v1.4.0/go.mod h1:BP46FUrVjVhdTbKT+XuQh2xfQaGki9LMIRJSFuh6THU= 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= @@ -138,22 +153,32 @@ go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= 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 v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48= +go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8= 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 v1.39.0/go.mod h1:vnakAaFckOMiMtOIhFI2MNH4FYrZzXCYxmb1LlhoGz8= 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/otlptracegrpc v1.39.0/go.mod h1:Rp0EXBm5tfnv0WL+ARyO/PHBEaEAT8UUHQ6AGJcSq6c= 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/otlp/otlptrace/otlptracehttp v1.39.0/go.mod h1:teIFJh5pW2y+AN7riv6IBPX2DuesS3HgP39mwOspKwU= 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/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs= 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 v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE= 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/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI= +go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA= 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.opentelemetry.io/proto/otlp v1.9.0/go.mod h1:xE+Cx5E/eEHw+ISFkwPLwCZefwVjY+pqKg1qcK03+/4= 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= @@ -171,24 +196,30 @@ golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= +golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= golang.org/x/oauth2 v0.33.0 h1:4Q+qn+E5z8gPRJfmRy7C2gGG3T4jIprK6aSYgTXGRpo= golang.org/x/oauth2 v0.33.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= +golang.org/x/oauth2 v0.34.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.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sync v0.19.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.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU= golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254= +golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg= 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.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= +golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= 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= @@ -209,15 +240,18 @@ google.golang.org/genproto/googleapis/api v0.0.0-20250908214217-97024824d090 h1: google.golang.org/genproto/googleapis/api v0.0.0-20250908214217-97024824d090/go.mod h1:U8EXRNSd8sUYyDfs/It7KVWodQr+Hf9xtxyxWudSwEw= google.golang.org/genproto/googleapis/api v0.0.0-20251022142026-3a174f9686a8 h1:mepRgnBZa07I4TRuomDE4sTIYieg/osKmzIf4USdWS4= google.golang.org/genproto/googleapis/api v0.0.0-20251022142026-3a174f9686a8/go.mod h1:fDMmzKV90WSg1NbozdqrE64fkuTv6mlq2zxo9ad+3yo= +google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2/go.mod h1:+rXWjjaukWZun3mLfjmVnQi18E1AsFbDN9QdJ5YXLto= 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/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 h1:M1rk8KBnUsBDg1oPGHNCxG4vc1f49epmTO7xscSajMk= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= 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 v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +google.golang.org/protobuf v1.36.11/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= @@ -227,22 +261,18 @@ 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.2 h1:fsSUNZhV+bnL6Aqrp6O7lMTy6o5x2C4XLjnh//8SLYY= -k8s.io/api v0.34.2/go.mod h1:MMBPaWlED2a8w4RSeanD76f7opUoypY8TFYkSM+3XHw= -k8s.io/apiextensions-apiserver v0.34.2 h1:WStKftnGeoKP4AZRz/BaAAEJvYp4mlZGN0UCv+uvsqo= -k8s.io/apiextensions-apiserver v0.34.2/go.mod h1:398CJrsgXF1wytdaanynDpJ67zG4Xq7yj91GrmYN2SE= -k8s.io/apimachinery v0.34.2 h1:zQ12Uk3eMHPxrsbUJgNF8bTauTVR2WgqJsTmwTE/NW4= -k8s.io/apimachinery v0.34.2/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= -k8s.io/client-go v0.34.2 h1:Co6XiknN+uUZqiddlfAjT68184/37PS4QAzYvQvDR8M= -k8s.io/client-go v0.34.2/go.mod h1:2VYDl1XXJsdcAxw7BenFslRQX28Dxz91U9MWKjX97fE= +k8s.io/api v0.34.3/go.mod h1:PyVQBF886Q5RSQZOim7DybQjAbVs8g7gwJNhGtY5MBk= 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/kube-openapi v0.0.0-20251125145642-4e65d59e963e/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= +k8s.io/utils v0.0.0-20251002143259-bc988d571ff4/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/json v0.0.0-20250730193827-2d320260d730/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= diff --git a/apps/scope/go.mod b/apps/scope/go.mod index c54a582379f..ed380519e75 100644 --- a/apps/scope/go.mod +++ b/apps/scope/go.mod @@ -4,8 +4,8 @@ go 1.25.5 require ( github.com/grafana/grafana/pkg/apimachinery v0.0.0-20251007081214-26e147d01f0a - k8s.io/apimachinery v0.34.2 - k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 + k8s.io/apimachinery v0.34.3 + k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e ) require ( @@ -13,15 +13,24 @@ require ( github.com/emicklei/go-restful/v3 v3.13.0 // indirect github.com/fxamacker/cbor/v2 v2.9.0 // indirect github.com/go-logr/logr v1.4.3 // 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.1 // indirect - github.com/go-openapi/swag/jsonname v0.25.1 // indirect + github.com/go-openapi/jsonpointer v0.22.4 // indirect + github.com/go-openapi/jsonreference v0.21.4 // indirect + github.com/go-openapi/swag v0.25.4 // indirect + github.com/go-openapi/swag/cmdutils v0.25.4 // indirect + github.com/go-openapi/swag/conv v0.25.4 // indirect + github.com/go-openapi/swag/fileutils v0.25.4 // indirect + github.com/go-openapi/swag/jsonname v0.25.4 // indirect + github.com/go-openapi/swag/jsonutils v0.25.4 // indirect + github.com/go-openapi/swag/loading v0.25.4 // indirect + github.com/go-openapi/swag/mangling v0.25.4 // indirect + github.com/go-openapi/swag/netutils v0.25.4 // indirect + github.com/go-openapi/swag/stringutils v0.25.4 // indirect + github.com/go-openapi/swag/typeutils v0.25.4 // indirect + github.com/go-openapi/swag/yamlutils v0.25.4 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/google/gnostic-models v0.7.0 // indirect - github.com/josharian/intern v1.0.0 // indirect + github.com/google/gnostic-models v0.7.1 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/mailru/easyjson v0.9.0 // indirect + github.com/kr/pretty v0.3.1 // 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/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect @@ -30,14 +39,15 @@ 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.47.0 // indirect - golang.org/x/text v0.31.0 // indirect - google.golang.org/protobuf v1.36.10 // indirect + golang.org/x/net v0.48.0 // indirect + golang.org/x/text v0.32.0 // indirect + google.golang.org/protobuf v1.36.11 // indirect + gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v3 v3.0.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 + k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 // indirect + sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect sigs.k8s.io/randfill v1.0.0 // indirect sigs.k8s.io/structured-merge-diff/v6 v6.3.1 // indirect ) diff --git a/apps/scope/go.sum b/apps/scope/go.sum index 5df9519a7e2..19f7f445bc6 100644 --- a/apps/scope/go.sum +++ b/apps/scope/go.sum @@ -1,3 +1,4 @@ +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= @@ -8,44 +9,71 @@ github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sa github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= 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-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.1 h1:lpsStH0n2ittzTnbaSloVZLuB5+fvSY/+hnagBjSNZU= -github.com/go-openapi/swag v0.23.1/go.mod h1:STZs8TbRvEQQKUA+JZNAm3EWlgaOBGpyFDqQnDHMef0= -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/jsonpointer v0.22.4 h1:dZtK82WlNpVLDW2jlA1YCiVJFVqkED1MegOUy9kR5T4= +github.com/go-openapi/jsonpointer v0.22.4/go.mod h1:elX9+UgznpFhgBuaMQ7iu4lvvX1nvNsesQ3oxmYTw80= +github.com/go-openapi/jsonreference v0.21.4 h1:24qaE2y9bx/q3uRK/qN+TDwbok1NhbSmGjjySRCHtC8= +github.com/go-openapi/jsonreference v0.21.4/go.mod h1:rIENPTjDbLpzQmQWCj5kKj3ZlmEh+EFVbz3RTUh30/4= +github.com/go-openapi/swag v0.25.4 h1:OyUPUFYDPDBMkqyxOTkqDYFnrhuhi9NR6QVUvIochMU= +github.com/go-openapi/swag v0.25.4/go.mod h1:zNfJ9WZABGHCFg2RnY0S4IOkAcVTzJ6z2Bi+Q4i6qFQ= +github.com/go-openapi/swag/cmdutils v0.25.4 h1:8rYhB5n6WawR192/BfUu2iVlxqVR9aRgGJP6WaBoW+4= +github.com/go-openapi/swag/cmdutils v0.25.4/go.mod h1:pdae/AFo6WxLl5L0rq87eRzVPm/XRHM3MoYgRMvG4A0= +github.com/go-openapi/swag/conv v0.25.4 h1:/Dd7p0LZXczgUcC/Ikm1+YqVzkEeCc9LnOWjfkpkfe4= +github.com/go-openapi/swag/conv v0.25.4/go.mod h1:3LXfie/lwoAv0NHoEuY1hjoFAYkvlqI/Bn5EQDD3PPU= +github.com/go-openapi/swag/fileutils v0.25.4 h1:2oI0XNW5y6UWZTC7vAxC8hmsK/tOkWXHJQH4lKjqw+Y= +github.com/go-openapi/swag/fileutils v0.25.4/go.mod h1:cdOT/PKbwcysVQ9Tpr0q20lQKH7MGhOEb6EwmHOirUk= +github.com/go-openapi/swag/jsonname v0.25.4 h1:bZH0+MsS03MbnwBXYhuTttMOqk+5KcQ9869Vye1bNHI= +github.com/go-openapi/swag/jsonname v0.25.4/go.mod h1:GPVEk9CWVhNvWhZgrnvRA6utbAltopbKwDu8mXNUMag= +github.com/go-openapi/swag/jsonutils v0.25.4 h1:VSchfbGhD4UTf4vCdR2F4TLBdLwHyUDTd1/q4i+jGZA= +github.com/go-openapi/swag/jsonutils v0.25.4/go.mod h1:7OYGXpvVFPn4PpaSdPHJBtF0iGnbEaTk8AvBkoWnaAY= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4 h1:IACsSvBhiNJwlDix7wq39SS2Fh7lUOCJRmx/4SN4sVo= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4/go.mod h1:Mt0Ost9l3cUzVv4OEZG+WSeoHwjWLnarzMePNDAOBiM= +github.com/go-openapi/swag/loading v0.25.4 h1:jN4MvLj0X6yhCDduRsxDDw1aHe+ZWoLjW+9ZQWIKn2s= +github.com/go-openapi/swag/loading v0.25.4/go.mod h1:rpUM1ZiyEP9+mNLIQUdMiD7dCETXvkkC30z53i+ftTE= +github.com/go-openapi/swag/mangling v0.25.4 h1:2b9kBJk9JvPgxr36V23FxJLdwBrpijI26Bx5JH4Hp48= +github.com/go-openapi/swag/mangling v0.25.4/go.mod h1:6dxwu6QyORHpIIApsdZgb6wBk/DPU15MdyYj/ikn0Hg= +github.com/go-openapi/swag/netutils v0.25.4 h1:Gqe6K71bGRb3ZQLusdI8p/y1KLgV4M/k+/HzVSqT8H0= +github.com/go-openapi/swag/netutils v0.25.4/go.mod h1:m2W8dtdaoX7oj9rEttLyTeEFFEBvnAx9qHd5nJEBzYg= +github.com/go-openapi/swag/stringutils v0.25.4 h1:O6dU1Rd8bej4HPA3/CLPciNBBDwZj9HiEpdVsb8B5A8= +github.com/go-openapi/swag/stringutils v0.25.4/go.mod h1:GTsRvhJW5xM5gkgiFe0fV3PUlFm0dr8vki6/VSRaZK0= +github.com/go-openapi/swag/typeutils v0.25.4 h1:1/fbZOUN472NTc39zpa+YGHn3jzHWhv42wAJSN91wRw= +github.com/go-openapi/swag/typeutils v0.25.4/go.mod h1:Ou7g//Wx8tTLS9vG0UmzfCsjZjKhpjxayRKTHXf2pTE= +github.com/go-openapi/swag/yamlutils v0.25.4 h1:6jdaeSItEUb7ioS9lFoCZ65Cne1/RZtPBZ9A56h92Sw= +github.com/go-openapi/swag/yamlutils v0.25.4/go.mod h1:MNzq1ulQu+yd8Kl7wPOut/YHAAU/H6hL91fF+E2RFwc= +github.com/go-openapi/testify/enable/yaml/v2 v2.0.2 h1:0+Y41Pz1NkbTHz8NngxTuAXxEodtNSI1WG1c/m5Akw4= +github.com/go-openapi/testify/enable/yaml/v2 v2.0.2/go.mod h1:kme83333GCtJQHXQ8UKX3IBZu6z8T5Dvy5+CW3NLUUg= +github.com/go-openapi/testify/v2 v2.0.2 h1:X999g3jeLcoY8qctY/c/Z8iBHTbwLz7R2WXd6Ub6wls= +github.com/go-openapi/testify/v2 v2.0.2/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -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/gnostic-models v0.7.1 h1:SisTfuFKJSKM5CPZkffwi6coztzzeYUhc3v4yxLWH8c= +github.com/google/gnostic-models v0.7.1/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/grafana/grafana/pkg/apimachinery v0.0.0-20251007081214-26e147d01f0a h1:L7xgV9mP6MRF3L2/vDOjNR7heaBPbXPMGTDN9/jXSFQ= github.com/grafana/grafana/pkg/apimachinery v0.0.0-20251007081214-26e147d01f0a/go.mod h1:OK8NwS87D5YphchOcAsiIWk/feMZ0EzfAGME1Kff860= -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/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -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/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= 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/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= 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= @@ -73,8 +101,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.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= -golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= +golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= +golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= 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= @@ -83,8 +111,8 @@ 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/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.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= -golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= +golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= +golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= 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= @@ -93,8 +121,8 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= -google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/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= @@ -102,16 +130,16 @@ 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/apimachinery v0.34.2 h1:zQ12Uk3eMHPxrsbUJgNF8bTauTVR2WgqJsTmwTE/NW4= -k8s.io/apimachinery v0.34.2/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= +k8s.io/apimachinery v0.34.3 h1:/TB+SFEiQvN9HPldtlWOTp0hWbJ+fjU+wkxysf/aQnE= +k8s.io/apimachinery v0.34.3/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= 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= +k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e h1:iW9ChlU0cU16w8MpVYjXk12dqQ4BPFBEgif+ap7/hqQ= +k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e/go.mod h1:kdmbQkyfwUagLfXIad1y2TdrjPFWp2Q89B3qkRwf/pQ= +k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 h1:SjGebBtkBqHFOli+05xYbK8YF1Dzkbzn+gDM4X9T4Ck= +k8s.io/utils v0.0.0-20251002143259-bc988d571ff4/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg= +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/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.1 h1:JrhdFMqOd/+3ByqlP2I45kTOZmTRLBUm5pvRjeheg7E= diff --git a/apps/sdk.mk b/apps/sdk.mk index 68cf4c1c9c9..45580f59037 100644 --- a/apps/sdk.mk +++ b/apps/sdk.mk @@ -1,4 +1,4 @@ -APP_SDK_VERSION = v0.48.5 +APP_SDK_VERSION = v0.48.7 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 a1ed48be6e7..d0da36e2e83 100644 --- a/apps/secret/go.mod +++ b/apps/secret/go.mod @@ -3,15 +3,15 @@ module github.com/grafana/grafana/apps/secret go 1.25.5 require ( - github.com/grafana/grafana-app-sdk v0.48.5 + github.com/grafana/grafana-app-sdk v0.48.7 github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250710134100-1f3dc0533caf github.com/stretchr/testify v1.11.1 go.yaml.in/yaml/v3 v3.0.4 google.golang.org/grpc v1.77.0 - google.golang.org/protobuf v1.36.10 - k8s.io/apimachinery v0.34.2 - k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 - k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 + google.golang.org/protobuf v1.36.11 + k8s.io/apimachinery v0.34.3 + k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e + k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 ) require ( @@ -22,19 +22,29 @@ require ( github.com/fxamacker/cbor/v2 v2.9.0 // indirect github.com/getkin/kin-openapi v0.133.0 // indirect github.com/go-logr/logr v1.4.3 // 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.1 // indirect - github.com/go-openapi/swag/jsonname v0.25.1 // indirect + github.com/go-openapi/jsonpointer v0.22.4 // indirect + github.com/go-openapi/jsonreference v0.21.4 // indirect + github.com/go-openapi/swag v0.25.4 // indirect + github.com/go-openapi/swag/cmdutils v0.25.4 // indirect + github.com/go-openapi/swag/conv v0.25.4 // indirect + github.com/go-openapi/swag/fileutils v0.25.4 // indirect + github.com/go-openapi/swag/jsonname v0.25.4 // indirect + github.com/go-openapi/swag/jsonutils v0.25.4 // indirect + github.com/go-openapi/swag/loading v0.25.4 // indirect + github.com/go-openapi/swag/mangling v0.25.4 // indirect + github.com/go-openapi/swag/netutils v0.25.4 // indirect + github.com/go-openapi/swag/stringutils v0.25.4 // indirect + github.com/go-openapi/swag/typeutils v0.25.4 // indirect + github.com/go-openapi/swag/yamlutils v0.25.4 // 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/grafana/grafana-app-sdk/logging v0.48.3 // indirect + github.com/google/gnostic-models v0.7.1 // indirect + github.com/grafana/grafana-app-sdk/logging v0.48.7 // 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/mailru/easyjson v0.9.1 // 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 @@ -45,26 +55,27 @@ require ( 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.3 // indirect - github.com/prometheus/procfs v0.16.1 // indirect + github.com/prometheus/common v0.67.4 // indirect + github.com/prometheus/procfs v0.19.2 // indirect github.com/stretchr/objx v0.5.2 // indirect - github.com/woodsbury/decimal128 v1.3.0 // indirect + github.com/woodsbury/decimal128 v1.4.0 // indirect github.com/x448/float16 v0.8.4 // indirect - go.opentelemetry.io/otel v1.38.0 // indirect - go.opentelemetry.io/otel/trace v1.38.0 // indirect + go.opentelemetry.io/otel v1.39.0 // indirect + go.opentelemetry.io/otel/sdk/metric v1.39.0 // indirect + go.opentelemetry.io/otel/trace v1.39.0 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect - golang.org/x/net v0.47.0 // indirect - golang.org/x/oauth2 v0.33.0 // indirect - golang.org/x/sys v0.38.0 // indirect - golang.org/x/term v0.37.0 // indirect - golang.org/x/text v0.31.0 // indirect + golang.org/x/net v0.48.0 // indirect + golang.org/x/oauth2 v0.34.0 // indirect + golang.org/x/sys v0.39.0 // indirect + golang.org/x/term v0.38.0 // indirect + golang.org/x/text v0.32.0 // indirect golang.org/x/time v0.14.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/client-go v0.34.2 // indirect + k8s.io/client-go v0.34.3 // indirect k8s.io/klog/v2 v2.130.1 // indirect - sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect + sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect sigs.k8s.io/randfill v1.0.0 // indirect sigs.k8s.io/structured-merge-diff/v6 v6.3.1 // indirect sigs.k8s.io/yaml v1.6.0 // indirect diff --git a/apps/secret/go.sum b/apps/secret/go.sum index 166e281f5af..6ea5dd8dfd3 100644 --- a/apps/secret/go.sum +++ b/apps/secret/go.sum @@ -16,31 +16,57 @@ 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.1 h1:lpsStH0n2ittzTnbaSloVZLuB5+fvSY/+hnagBjSNZU= -github.com/go-openapi/swag v0.23.1/go.mod h1:STZs8TbRvEQQKUA+JZNAm3EWlgaOBGpyFDqQnDHMef0= -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/jsonpointer v0.22.4 h1:dZtK82WlNpVLDW2jlA1YCiVJFVqkED1MegOUy9kR5T4= +github.com/go-openapi/jsonpointer v0.22.4/go.mod h1:elX9+UgznpFhgBuaMQ7iu4lvvX1nvNsesQ3oxmYTw80= +github.com/go-openapi/jsonreference v0.21.4 h1:24qaE2y9bx/q3uRK/qN+TDwbok1NhbSmGjjySRCHtC8= +github.com/go-openapi/jsonreference v0.21.4/go.mod h1:rIENPTjDbLpzQmQWCj5kKj3ZlmEh+EFVbz3RTUh30/4= +github.com/go-openapi/swag v0.25.4 h1:OyUPUFYDPDBMkqyxOTkqDYFnrhuhi9NR6QVUvIochMU= +github.com/go-openapi/swag v0.25.4/go.mod h1:zNfJ9WZABGHCFg2RnY0S4IOkAcVTzJ6z2Bi+Q4i6qFQ= +github.com/go-openapi/swag/cmdutils v0.25.4 h1:8rYhB5n6WawR192/BfUu2iVlxqVR9aRgGJP6WaBoW+4= +github.com/go-openapi/swag/cmdutils v0.25.4/go.mod h1:pdae/AFo6WxLl5L0rq87eRzVPm/XRHM3MoYgRMvG4A0= +github.com/go-openapi/swag/conv v0.25.4 h1:/Dd7p0LZXczgUcC/Ikm1+YqVzkEeCc9LnOWjfkpkfe4= +github.com/go-openapi/swag/conv v0.25.4/go.mod h1:3LXfie/lwoAv0NHoEuY1hjoFAYkvlqI/Bn5EQDD3PPU= +github.com/go-openapi/swag/fileutils v0.25.4 h1:2oI0XNW5y6UWZTC7vAxC8hmsK/tOkWXHJQH4lKjqw+Y= +github.com/go-openapi/swag/fileutils v0.25.4/go.mod h1:cdOT/PKbwcysVQ9Tpr0q20lQKH7MGhOEb6EwmHOirUk= +github.com/go-openapi/swag/jsonname v0.25.4 h1:bZH0+MsS03MbnwBXYhuTttMOqk+5KcQ9869Vye1bNHI= +github.com/go-openapi/swag/jsonname v0.25.4/go.mod h1:GPVEk9CWVhNvWhZgrnvRA6utbAltopbKwDu8mXNUMag= +github.com/go-openapi/swag/jsonutils v0.25.4 h1:VSchfbGhD4UTf4vCdR2F4TLBdLwHyUDTd1/q4i+jGZA= +github.com/go-openapi/swag/jsonutils v0.25.4/go.mod h1:7OYGXpvVFPn4PpaSdPHJBtF0iGnbEaTk8AvBkoWnaAY= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4 h1:IACsSvBhiNJwlDix7wq39SS2Fh7lUOCJRmx/4SN4sVo= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4/go.mod h1:Mt0Ost9l3cUzVv4OEZG+WSeoHwjWLnarzMePNDAOBiM= +github.com/go-openapi/swag/loading v0.25.4 h1:jN4MvLj0X6yhCDduRsxDDw1aHe+ZWoLjW+9ZQWIKn2s= +github.com/go-openapi/swag/loading v0.25.4/go.mod h1:rpUM1ZiyEP9+mNLIQUdMiD7dCETXvkkC30z53i+ftTE= +github.com/go-openapi/swag/mangling v0.25.4 h1:2b9kBJk9JvPgxr36V23FxJLdwBrpijI26Bx5JH4Hp48= +github.com/go-openapi/swag/mangling v0.25.4/go.mod h1:6dxwu6QyORHpIIApsdZgb6wBk/DPU15MdyYj/ikn0Hg= +github.com/go-openapi/swag/netutils v0.25.4 h1:Gqe6K71bGRb3ZQLusdI8p/y1KLgV4M/k+/HzVSqT8H0= +github.com/go-openapi/swag/netutils v0.25.4/go.mod h1:m2W8dtdaoX7oj9rEttLyTeEFFEBvnAx9qHd5nJEBzYg= +github.com/go-openapi/swag/stringutils v0.25.4 h1:O6dU1Rd8bej4HPA3/CLPciNBBDwZj9HiEpdVsb8B5A8= +github.com/go-openapi/swag/stringutils v0.25.4/go.mod h1:GTsRvhJW5xM5gkgiFe0fV3PUlFm0dr8vki6/VSRaZK0= +github.com/go-openapi/swag/typeutils v0.25.4 h1:1/fbZOUN472NTc39zpa+YGHn3jzHWhv42wAJSN91wRw= +github.com/go-openapi/swag/typeutils v0.25.4/go.mod h1:Ou7g//Wx8tTLS9vG0UmzfCsjZjKhpjxayRKTHXf2pTE= +github.com/go-openapi/swag/yamlutils v0.25.4 h1:6jdaeSItEUb7ioS9lFoCZ65Cne1/RZtPBZ9A56h92Sw= +github.com/go-openapi/swag/yamlutils v0.25.4/go.mod h1:MNzq1ulQu+yd8Kl7wPOut/YHAAU/H6hL91fF+E2RFwc= +github.com/go-openapi/testify/enable/yaml/v2 v2.0.2 h1:0+Y41Pz1NkbTHz8NngxTuAXxEodtNSI1WG1c/m5Akw4= +github.com/go-openapi/testify/enable/yaml/v2 v2.0.2/go.mod h1:kme83333GCtJQHXQ8UKX3IBZu6z8T5Dvy5+CW3NLUUg= +github.com/go-openapi/testify/v2 v2.0.2 h1:X999g3jeLcoY8qctY/c/Z8iBHTbwLz7R2WXd6Ub6wls= +github.com/go-openapi/testify/v2 v2.0.2/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= 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/gnostic-models v0.7.1 h1:SisTfuFKJSKM5CPZkffwi6coztzzeYUhc3v4yxLWH8c= +github.com/google/gnostic-models v0.7.1/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/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.48.5 h1:MS8l9fTZz+VbTfgApn09jw27GxhQ6fNOWGhC4ydvZmM= -github.com/grafana/grafana-app-sdk v0.48.5/go.mod h1:HJsMOSBmt/D/Ihs1SvagOwmXKi0coBMVHlfvdd+qe9Y= -github.com/grafana/grafana-app-sdk/logging v0.48.3 h1:72NUpGNiJXCNQz/on++YSsl38xuVYYBKv5kKQaOClX4= -github.com/grafana/grafana-app-sdk/logging v0.48.3/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA= +github.com/grafana/grafana-app-sdk v0.48.7 h1:9mF7nqkqP0QUYYDlznoOt+GIyjzj45wGfUHB32u2ZMo= +github.com/grafana/grafana-app-sdk v0.48.7/go.mod h1:DWsaaH39ZMHwSOSoUBaeW8paMrRaYsjRYlLwCJYd78k= +github.com/grafana/grafana-app-sdk/logging v0.48.7 h1:Oa5qg473gka5+W/WQk61Xbw4YdAv+wV2Z4bJtzeCaQw= +github.com/grafana/grafana-app-sdk/logging v0.48.7/go.mod h1:5u3KalezoBAAo2Y3ytDYDAIIPvEqFLLDSxeiK99QxDU= 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= @@ -62,8 +88,8 @@ 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/mailru/easyjson v0.9.1 h1:LbtsOm5WAswyWbvTEOqhypdPeZzHavpZx96/n553mR8= +github.com/mailru/easyjson v0.9.1/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= @@ -80,8 +106,6 @@ github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 h1:bQx3WeLcUWy+RletI github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90/go.mod h1:y5+oSEHCPT/DGrS++Wc/479ERge0zTFxaF8PbGKcg2o= 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= @@ -89,10 +113,10 @@ github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h 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.3 h1:shd26MlnwTw5jksTDhC7rTQIteBxy+ZZDr3t7F2xN2Q= -github.com/prometheus/common v0.67.3/go.mod h1:gP0fq6YjjNCLssJCQp0yk4M8W6ikLURwkdd/YKtTbyI= -github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= -github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= +github.com/prometheus/common v0.67.4 h1:yR3NqWO1/UyO1w2PhUvXlGQs/PtFmoveVO0KZ4+Lvsc= +github.com/prometheus/common v0.67.4/go.mod h1:gP0fq6YjjNCLssJCQp0yk4M8W6ikLURwkdd/YKtTbyI= +github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws= +github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw= 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= @@ -105,24 +129,24 @@ 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/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/woodsbury/decimal128 v1.4.0 h1:xJATj7lLu4f2oObouMt2tgGiElE5gO6mSWUjQsBgUlc= +github.com/woodsbury/decimal128 v1.4.0/go.mod h1:BP46FUrVjVhdTbKT+XuQh2xfQaGki9LMIRJSFuh6THU= 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.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= -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/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/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48= +go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8= +go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0= +go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs= +go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18= +go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE= +go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8= +go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew= +go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI= +go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA= 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= @@ -138,24 +162,24 @@ 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.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= -golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= -golang.org/x/oauth2 v0.33.0 h1:4Q+qn+E5z8gPRJfmRy7C2gGG3T4jIprK6aSYgTXGRpo= -golang.org/x/oauth2 v0.33.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= +golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= +golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= +golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw= +golang.org/x/oauth2 v0.34.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/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.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= -golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU= -golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254= +golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= +golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q= +golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg= 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.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= -golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= +golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= +golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= 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= @@ -168,35 +192,35 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 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/rpc v0.0.0-20251111163417-95abcf5c77ba h1:UKgtfRM7Yh93Sya0Fo8ZzhDP4qBckrrxEr2oF5UIVb8= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2 h1:2I6GHUeJ/4shcDpoUlLs/2WPnhg7yJwvXtqcMJt9liA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM= google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= -google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= -google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/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/evanphx/json-patch.v4 v4.13.0 h1:czT3CmqEaQ1aanPc5SdlgQrrEIb8w/wwCvWWnfEbYzo= +gopkg.in/evanphx/json-patch.v4 v4.13.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.2 h1:fsSUNZhV+bnL6Aqrp6O7lMTy6o5x2C4XLjnh//8SLYY= -k8s.io/api v0.34.2/go.mod h1:MMBPaWlED2a8w4RSeanD76f7opUoypY8TFYkSM+3XHw= -k8s.io/apimachinery v0.34.2 h1:zQ12Uk3eMHPxrsbUJgNF8bTauTVR2WgqJsTmwTE/NW4= -k8s.io/apimachinery v0.34.2/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= -k8s.io/client-go v0.34.2 h1:Co6XiknN+uUZqiddlfAjT68184/37PS4QAzYvQvDR8M= -k8s.io/client-go v0.34.2/go.mod h1:2VYDl1XXJsdcAxw7BenFslRQX28Dxz91U9MWKjX97fE= +k8s.io/api v0.34.3 h1:D12sTP257/jSH2vHV2EDYrb16bS7ULlHpdNdNhEw2S4= +k8s.io/api v0.34.3/go.mod h1:PyVQBF886Q5RSQZOim7DybQjAbVs8g7gwJNhGtY5MBk= +k8s.io/apimachinery v0.34.3 h1:/TB+SFEiQvN9HPldtlWOTp0hWbJ+fjU+wkxysf/aQnE= +k8s.io/apimachinery v0.34.3/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= +k8s.io/client-go v0.34.3 h1:wtYtpzy/OPNYf7WyNBTj3iUA0XaBHVqhv4Iv3tbrF5A= +k8s.io/client-go v0.34.3/go.mod h1:OxxeYagaP9Kdf78UrKLa3YZixMCfP6bgPwPwNBQBzpM= 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= +k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e h1:iW9ChlU0cU16w8MpVYjXk12dqQ4BPFBEgif+ap7/hqQ= +k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e/go.mod h1:kdmbQkyfwUagLfXIad1y2TdrjPFWp2Q89B3qkRwf/pQ= +k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 h1:SjGebBtkBqHFOli+05xYbK8YF1Dzkbzn+gDM4X9T4Ck= +k8s.io/utils v0.0.0-20251002143259-bc988d571ff4/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg= +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/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.1 h1:JrhdFMqOd/+3ByqlP2I45kTOZmTRLBUm5pvRjeheg7E= diff --git a/apps/shorturl/go.mod b/apps/shorturl/go.mod index 4a414de5b4e..c75106d2822 100644 --- a/apps/shorturl/go.mod +++ b/apps/shorturl/go.mod @@ -3,18 +3,18 @@ module github.com/grafana/grafana/apps/shorturl go 1.25.5 require ( - github.com/grafana/grafana-app-sdk v0.48.5 - github.com/grafana/grafana-app-sdk/logging v0.48.3 + github.com/grafana/grafana-app-sdk v0.48.7 + github.com/grafana/grafana-app-sdk/logging v0.48.7 github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250915132226-585b53bc7dba - k8s.io/apimachinery v0.34.2 - k8s.io/apiserver v0.34.2 + k8s.io/apimachinery v0.34.3 + k8s.io/apiserver v0.34.3 k8s.io/klog/v2 v2.130.1 - k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 + k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e ) require ( github.com/beorn7/perks v1.0.1 // indirect - github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874 // indirect + github.com/bradfitz/gomemcache v0.0.0-20250403215159-8d39553ac7cf // 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 @@ -25,13 +25,23 @@ require ( github.com/go-jose/go-jose/v4 v4.1.3 // 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.1 // indirect - github.com/go-openapi/swag/jsonname v0.25.1 // indirect + github.com/go-openapi/jsonpointer v0.22.4 // indirect + github.com/go-openapi/jsonreference v0.21.4 // indirect + github.com/go-openapi/swag v0.25.4 // indirect + github.com/go-openapi/swag/cmdutils v0.25.4 // indirect + github.com/go-openapi/swag/conv v0.25.4 // indirect + github.com/go-openapi/swag/fileutils v0.25.4 // indirect + github.com/go-openapi/swag/jsonname v0.25.4 // indirect + github.com/go-openapi/swag/jsonutils v0.25.4 // indirect + github.com/go-openapi/swag/loading v0.25.4 // indirect + github.com/go-openapi/swag/mangling v0.25.4 // indirect + github.com/go-openapi/swag/netutils v0.25.4 // indirect + github.com/go-openapi/swag/stringutils v0.25.4 // indirect + github.com/go-openapi/swag/typeutils v0.25.4 // indirect + github.com/go-openapi/swag/yamlutils v0.25.4 // 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/gnostic-models v0.7.1 // 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 @@ -43,7 +53,7 @@ require ( 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/mailru/easyjson v0.9.1 // 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 @@ -57,42 +67,42 @@ require ( 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.3 // indirect - github.com/prometheus/procfs v0.16.1 // indirect + github.com/prometheus/common v0.67.4 // indirect + github.com/prometheus/procfs v0.19.2 // 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/woodsbury/decimal128 v1.4.0 // indirect github.com/x448/float16 v0.8.4 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // 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/otel v1.39.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0 // indirect + go.opentelemetry.io/otel/metric v1.39.0 // indirect + go.opentelemetry.io/otel/sdk v1.39.0 // indirect + go.opentelemetry.io/otel/trace v1.39.0 // indirect go.opentelemetry.io/proto/otlp v1.9.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.47.0 // indirect - golang.org/x/oauth2 v0.33.0 // indirect - golang.org/x/sync v0.18.0 // indirect - golang.org/x/sys v0.38.0 // indirect - golang.org/x/term v0.37.0 // indirect - golang.org/x/text v0.31.0 // indirect + golang.org/x/net v0.48.0 // indirect + golang.org/x/oauth2 v0.34.0 // indirect + golang.org/x/sync v0.19.0 // indirect + golang.org/x/sys v0.39.0 // indirect + golang.org/x/term v0.38.0 // indirect + golang.org/x/text v0.32.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-20251111163417-95abcf5c77ba // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2 // indirect google.golang.org/grpc v1.77.0 // indirect - google.golang.org/protobuf v1.36.10 // indirect + google.golang.org/protobuf v1.36.11 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/api v0.34.2 // indirect - k8s.io/apiextensions-apiserver v0.34.2 // indirect - k8s.io/client-go v0.34.2 // indirect - k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 // indirect - sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect + k8s.io/api v0.34.3 // indirect + k8s.io/apiextensions-apiserver v0.34.3 // indirect + k8s.io/client-go v0.34.3 // indirect + k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 // indirect + sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect sigs.k8s.io/randfill v1.0.0 // indirect sigs.k8s.io/structured-merge-diff/v6 v6.3.1 // indirect sigs.k8s.io/yaml v1.6.0 // indirect diff --git a/apps/shorturl/go.sum b/apps/shorturl/go.sum index 58ecc31fd82..36b5842b179 100644 --- a/apps/shorturl/go.sum +++ b/apps/shorturl/go.sum @@ -1,7 +1,7 @@ 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/bradfitz/gomemcache v0.0.0-20250403215159-8d39553ac7cf h1:TqhNAT4zKbTdLa62d2HDBFdvgSbIGB3eJE8HqhgiL9I= +github.com/bradfitz/gomemcache v0.0.0-20250403215159-8d39553ac7cf/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= @@ -25,14 +25,40 @@ 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.1 h1:lpsStH0n2ittzTnbaSloVZLuB5+fvSY/+hnagBjSNZU= -github.com/go-openapi/swag v0.23.1/go.mod h1:STZs8TbRvEQQKUA+JZNAm3EWlgaOBGpyFDqQnDHMef0= -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/jsonpointer v0.22.4 h1:dZtK82WlNpVLDW2jlA1YCiVJFVqkED1MegOUy9kR5T4= +github.com/go-openapi/jsonpointer v0.22.4/go.mod h1:elX9+UgznpFhgBuaMQ7iu4lvvX1nvNsesQ3oxmYTw80= +github.com/go-openapi/jsonreference v0.21.4 h1:24qaE2y9bx/q3uRK/qN+TDwbok1NhbSmGjjySRCHtC8= +github.com/go-openapi/jsonreference v0.21.4/go.mod h1:rIENPTjDbLpzQmQWCj5kKj3ZlmEh+EFVbz3RTUh30/4= +github.com/go-openapi/swag v0.25.4 h1:OyUPUFYDPDBMkqyxOTkqDYFnrhuhi9NR6QVUvIochMU= +github.com/go-openapi/swag v0.25.4/go.mod h1:zNfJ9WZABGHCFg2RnY0S4IOkAcVTzJ6z2Bi+Q4i6qFQ= +github.com/go-openapi/swag/cmdutils v0.25.4 h1:8rYhB5n6WawR192/BfUu2iVlxqVR9aRgGJP6WaBoW+4= +github.com/go-openapi/swag/cmdutils v0.25.4/go.mod h1:pdae/AFo6WxLl5L0rq87eRzVPm/XRHM3MoYgRMvG4A0= +github.com/go-openapi/swag/conv v0.25.4 h1:/Dd7p0LZXczgUcC/Ikm1+YqVzkEeCc9LnOWjfkpkfe4= +github.com/go-openapi/swag/conv v0.25.4/go.mod h1:3LXfie/lwoAv0NHoEuY1hjoFAYkvlqI/Bn5EQDD3PPU= +github.com/go-openapi/swag/fileutils v0.25.4 h1:2oI0XNW5y6UWZTC7vAxC8hmsK/tOkWXHJQH4lKjqw+Y= +github.com/go-openapi/swag/fileutils v0.25.4/go.mod h1:cdOT/PKbwcysVQ9Tpr0q20lQKH7MGhOEb6EwmHOirUk= +github.com/go-openapi/swag/jsonname v0.25.4 h1:bZH0+MsS03MbnwBXYhuTttMOqk+5KcQ9869Vye1bNHI= +github.com/go-openapi/swag/jsonname v0.25.4/go.mod h1:GPVEk9CWVhNvWhZgrnvRA6utbAltopbKwDu8mXNUMag= +github.com/go-openapi/swag/jsonutils v0.25.4 h1:VSchfbGhD4UTf4vCdR2F4TLBdLwHyUDTd1/q4i+jGZA= +github.com/go-openapi/swag/jsonutils v0.25.4/go.mod h1:7OYGXpvVFPn4PpaSdPHJBtF0iGnbEaTk8AvBkoWnaAY= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4 h1:IACsSvBhiNJwlDix7wq39SS2Fh7lUOCJRmx/4SN4sVo= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4/go.mod h1:Mt0Ost9l3cUzVv4OEZG+WSeoHwjWLnarzMePNDAOBiM= +github.com/go-openapi/swag/loading v0.25.4 h1:jN4MvLj0X6yhCDduRsxDDw1aHe+ZWoLjW+9ZQWIKn2s= +github.com/go-openapi/swag/loading v0.25.4/go.mod h1:rpUM1ZiyEP9+mNLIQUdMiD7dCETXvkkC30z53i+ftTE= +github.com/go-openapi/swag/mangling v0.25.4 h1:2b9kBJk9JvPgxr36V23FxJLdwBrpijI26Bx5JH4Hp48= +github.com/go-openapi/swag/mangling v0.25.4/go.mod h1:6dxwu6QyORHpIIApsdZgb6wBk/DPU15MdyYj/ikn0Hg= +github.com/go-openapi/swag/netutils v0.25.4 h1:Gqe6K71bGRb3ZQLusdI8p/y1KLgV4M/k+/HzVSqT8H0= +github.com/go-openapi/swag/netutils v0.25.4/go.mod h1:m2W8dtdaoX7oj9rEttLyTeEFFEBvnAx9qHd5nJEBzYg= +github.com/go-openapi/swag/stringutils v0.25.4 h1:O6dU1Rd8bej4HPA3/CLPciNBBDwZj9HiEpdVsb8B5A8= +github.com/go-openapi/swag/stringutils v0.25.4/go.mod h1:GTsRvhJW5xM5gkgiFe0fV3PUlFm0dr8vki6/VSRaZK0= +github.com/go-openapi/swag/typeutils v0.25.4 h1:1/fbZOUN472NTc39zpa+YGHn3jzHWhv42wAJSN91wRw= +github.com/go-openapi/swag/typeutils v0.25.4/go.mod h1:Ou7g//Wx8tTLS9vG0UmzfCsjZjKhpjxayRKTHXf2pTE= +github.com/go-openapi/swag/yamlutils v0.25.4 h1:6jdaeSItEUb7ioS9lFoCZ65Cne1/RZtPBZ9A56h92Sw= +github.com/go-openapi/swag/yamlutils v0.25.4/go.mod h1:MNzq1ulQu+yd8Kl7wPOut/YHAAU/H6hL91fF+E2RFwc= +github.com/go-openapi/testify/enable/yaml/v2 v2.0.2 h1:0+Y41Pz1NkbTHz8NngxTuAXxEodtNSI1WG1c/m5Akw4= +github.com/go-openapi/testify/enable/yaml/v2 v2.0.2/go.mod h1:kme83333GCtJQHXQ8UKX3IBZu6z8T5Dvy5+CW3NLUUg= +github.com/go-openapi/testify/v2 v2.0.2 h1:X999g3jeLcoY8qctY/c/Z8iBHTbwLz7R2WXd6Ub6wls= +github.com/go-openapi/testify/v2 v2.0.2/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= 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= @@ -41,8 +67,8 @@ 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/gnostic-models v0.7.1 h1:SisTfuFKJSKM5CPZkffwi6coztzzeYUhc3v4yxLWH8c= +github.com/google/gnostic-models v0.7.1/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= @@ -56,10 +82,10 @@ github.com/grafana/authlib/types v0.0.0-20251119142549-be091cf2f4d4 h1:Muoy+FMGr github.com/grafana/authlib/types v0.0.0-20251119142549-be091cf2f4d4/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.5 h1:MS8l9fTZz+VbTfgApn09jw27GxhQ6fNOWGhC4ydvZmM= -github.com/grafana/grafana-app-sdk v0.48.5/go.mod h1:HJsMOSBmt/D/Ihs1SvagOwmXKi0coBMVHlfvdd+qe9Y= -github.com/grafana/grafana-app-sdk/logging v0.48.3 h1:72NUpGNiJXCNQz/on++YSsl38xuVYYBKv5kKQaOClX4= -github.com/grafana/grafana-app-sdk/logging v0.48.3/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA= +github.com/grafana/grafana-app-sdk v0.48.7 h1:9mF7nqkqP0QUYYDlznoOt+GIyjzj45wGfUHB32u2ZMo= +github.com/grafana/grafana-app-sdk v0.48.7/go.mod h1:DWsaaH39ZMHwSOSoUBaeW8paMrRaYsjRYlLwCJYd78k= +github.com/grafana/grafana-app-sdk/logging v0.48.7 h1:Oa5qg473gka5+W/WQk61Xbw4YdAv+wV2Z4bJtzeCaQw= +github.com/grafana/grafana-app-sdk/logging v0.48.7/go.mod h1:5u3KalezoBAAo2Y3ytDYDAIIPvEqFLLDSxeiK99QxDU= 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.3 h1:NmZ1PKzSTQbuGHw9DGPFomqkkLWMC+vZCkfs+FHv1Vg= @@ -83,8 +109,8 @@ 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/mailru/easyjson v0.9.1 h1:LbtsOm5WAswyWbvTEOqhypdPeZzHavpZx96/n553mR8= +github.com/mailru/easyjson v0.9.1/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= @@ -116,10 +142,10 @@ github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h 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.3 h1:shd26MlnwTw5jksTDhC7rTQIteBxy+ZZDr3t7F2xN2Q= -github.com/prometheus/common v0.67.3/go.mod h1:gP0fq6YjjNCLssJCQp0yk4M8W6ikLURwkdd/YKtTbyI= -github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= -github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= +github.com/prometheus/common v0.67.4 h1:yR3NqWO1/UyO1w2PhUvXlGQs/PtFmoveVO0KZ4+Lvsc= +github.com/prometheus/common v0.67.4/go.mod h1:gP0fq6YjjNCLssJCQp0yk4M8W6ikLURwkdd/YKtTbyI= +github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws= +github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw= 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= @@ -134,30 +160,30 @@ 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/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/woodsbury/decimal128 v1.4.0 h1:xJATj7lLu4f2oObouMt2tgGiElE5gO6mSWUjQsBgUlc= +github.com/woodsbury/decimal128 v1.4.0/go.mod h1:BP46FUrVjVhdTbKT+XuQh2xfQaGki9LMIRJSFuh6THU= 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.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= -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/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48= +go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0 h1:f0cb2XPmrqn4XMy9PNliTgRKJgS5WcL/u0/WRYGz4t0= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0/go.mod h1:vnakAaFckOMiMtOIhFI2MNH4FYrZzXCYxmb1LlhoGz8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0 h1:in9O8ESIOlwJAEGTkkf34DesGRAc/Pn8qJ7k3r/42LM= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0/go.mod h1:Rp0EXBm5tfnv0WL+ARyO/PHBEaEAT8UUHQ6AGJcSq6c= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0 h1:Ckwye2FpXkYgiHX7fyVrN1uA/UYd9ounqqTuSNAv0k4= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0/go.mod h1:teIFJh5pW2y+AN7riv6IBPX2DuesS3HgP39mwOspKwU= +go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0= +go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs= +go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18= +go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE= +go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8= +go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew= +go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI= +go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA= go.opentelemetry.io/proto/otlp v1.9.0 h1:l706jCMITVouPOqEnii2fIAuO3IVGBRPV5ICjceRb/A= go.opentelemetry.io/proto/otlp v1.9.0/go.mod h1:xE+Cx5E/eEHw+ISFkwPLwCZefwVjY+pqKg1qcK03+/4= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= @@ -175,34 +201,34 @@ 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.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= -golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= -golang.org/x/oauth2 v0.33.0 h1:4Q+qn+E5z8gPRJfmRy7C2gGG3T4jIprK6aSYgTXGRpo= -golang.org/x/oauth2 v0.33.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= +golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= +golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= +golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw= +golang.org/x/oauth2 v0.34.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.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= -golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.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.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= -golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU= -golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254= +golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= +golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q= +golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg= 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.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= -golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= +golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= +golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= 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.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ= -golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ= +golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA= +golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc= 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= @@ -211,41 +237,41 @@ 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-20251111163417-95abcf5c77ba h1:B14OtaXuMaCQsl2deSvNkyPKIzq3BjfxQp8d00QyWx4= -google.golang.org/genproto/googleapis/api v0.0.0-20251111163417-95abcf5c77ba/go.mod h1:G5IanEx8/PgI9w6CFcYQf7jMtHQhZruvfM1i3qOqk5U= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba h1:UKgtfRM7Yh93Sya0Fo8ZzhDP4qBckrrxEr2oF5UIVb8= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= +google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2 h1:7LRqPCEdE4TP4/9psdaB7F2nhZFfBiGJomA5sojLWdU= +google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2/go.mod h1:+rXWjjaukWZun3mLfjmVnQi18E1AsFbDN9QdJ5YXLto= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2 h1:2I6GHUeJ/4shcDpoUlLs/2WPnhg7yJwvXtqcMJt9liA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM= google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= -google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= -google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/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/evanphx/json-patch.v4 v4.13.0 h1:czT3CmqEaQ1aanPc5SdlgQrrEIb8w/wwCvWWnfEbYzo= +gopkg.in/evanphx/json-patch.v4 v4.13.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.2 h1:fsSUNZhV+bnL6Aqrp6O7lMTy6o5x2C4XLjnh//8SLYY= -k8s.io/api v0.34.2/go.mod h1:MMBPaWlED2a8w4RSeanD76f7opUoypY8TFYkSM+3XHw= -k8s.io/apiextensions-apiserver v0.34.2 h1:WStKftnGeoKP4AZRz/BaAAEJvYp4mlZGN0UCv+uvsqo= -k8s.io/apiextensions-apiserver v0.34.2/go.mod h1:398CJrsgXF1wytdaanynDpJ67zG4Xq7yj91GrmYN2SE= -k8s.io/apimachinery v0.34.2 h1:zQ12Uk3eMHPxrsbUJgNF8bTauTVR2WgqJsTmwTE/NW4= -k8s.io/apimachinery v0.34.2/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= -k8s.io/apiserver v0.34.2 h1:2/yu8suwkmES7IzwlehAovo8dDE07cFRC7KMDb1+MAE= -k8s.io/apiserver v0.34.2/go.mod h1:gqJQy2yDOB50R3JUReHSFr+cwJnL8G1dzTA0YLEqAPI= -k8s.io/client-go v0.34.2 h1:Co6XiknN+uUZqiddlfAjT68184/37PS4QAzYvQvDR8M= -k8s.io/client-go v0.34.2/go.mod h1:2VYDl1XXJsdcAxw7BenFslRQX28Dxz91U9MWKjX97fE= +k8s.io/api v0.34.3 h1:D12sTP257/jSH2vHV2EDYrb16bS7ULlHpdNdNhEw2S4= +k8s.io/api v0.34.3/go.mod h1:PyVQBF886Q5RSQZOim7DybQjAbVs8g7gwJNhGtY5MBk= +k8s.io/apiextensions-apiserver v0.34.3 h1:p10fGlkDY09eWKOTeUSioxwLukJnm+KuDZdrW71y40g= +k8s.io/apiextensions-apiserver v0.34.3/go.mod h1:aujxvqGFRdb/cmXYfcRTeppN7S2XV/t7WMEc64zB5A0= +k8s.io/apimachinery v0.34.3 h1:/TB+SFEiQvN9HPldtlWOTp0hWbJ+fjU+wkxysf/aQnE= +k8s.io/apimachinery v0.34.3/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= +k8s.io/apiserver v0.34.3 h1:uGH1qpDvSiYG4HVFqc6A3L4CKiX+aBWDrrsxHYK0Bdo= +k8s.io/apiserver v0.34.3/go.mod h1:QPnnahMO5C2m3lm6fPW3+JmyQbvHZQ8uudAu/493P2w= +k8s.io/client-go v0.34.3 h1:wtYtpzy/OPNYf7WyNBTj3iUA0XaBHVqhv4Iv3tbrF5A= +k8s.io/client-go v0.34.3/go.mod h1:OxxeYagaP9Kdf78UrKLa3YZixMCfP6bgPwPwNBQBzpM= 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= +k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e h1:iW9ChlU0cU16w8MpVYjXk12dqQ4BPFBEgif+ap7/hqQ= +k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e/go.mod h1:kdmbQkyfwUagLfXIad1y2TdrjPFWp2Q89B3qkRwf/pQ= +k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 h1:SjGebBtkBqHFOli+05xYbK8YF1Dzkbzn+gDM4X9T4Ck= +k8s.io/utils v0.0.0-20251002143259-bc988d571ff4/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg= +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/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.1 h1:JrhdFMqOd/+3ByqlP2I45kTOZmTRLBUm5pvRjeheg7E= diff --git a/conf/defaults.ini b/conf/defaults.ini index de83393e43d..28cd0420eb2 100644 --- a/conf/defaults.ini +++ b/conf/defaults.ini @@ -335,6 +335,9 @@ rudderstack_data_plane_url = # Rudderstack SDK url, optional, only valid if rudderstack_write_key and rudderstack_data_plane_url is also set rudderstack_sdk_url = +# Rudderstack v3 SDK, optional, defaults to false. If set, Rudderstack v3 SDK will be used instead of v1 +rudderstack_v3_sdk_url = + # Rudderstack Config url, optional, used by Rudderstack SDK to fetch source config rudderstack_config_url = @@ -2261,7 +2264,7 @@ fail_tests_on_console = true # List of targets that can be controlled by a repository, separated by |. # Instance means the whole grafana instance will be controlled by a repository. # Folder limits it to a folder within the grafana instance. -allowed_targets = instance|folder +allowed_targets = folder # Whether image rendering is allowed for dashboard previews. # Requires image rendering service to be configured. diff --git a/conf/sample.ini b/conf/sample.ini index d1d50f0a72a..0bb5b82fdc9 100644 --- a/conf/sample.ini +++ b/conf/sample.ini @@ -322,6 +322,9 @@ # Rudderstack SDK url, optional, only valid if rudderstack_write_key and rudderstack_data_plane_url is also set ;rudderstack_sdk_url = +# Rudderstack v3 SDK, optional, defaults to false. If set, Rudderstack v3 SDK will be used instead of v1 +;rudderstack_v3_sdk_url = + # Rudderstack Config url, optional, used by Rudderstack SDK to fetch source config ;rudderstack_config_url = diff --git a/devenv/dev-dashboards/migrations/migrations.json b/devenv/dev-dashboards/migrations/migrations.json index 4c2160e1f26..ad063b99cf4 100644 --- a/devenv/dev-dashboards/migrations/migrations.json +++ b/devenv/dev-dashboards/migrations/migrations.json @@ -299,15 +299,9 @@ "y": 0 }, "id": 6, - "options": { - "code": { - "language": "plaintext", - "showLineNumbers": false, - "showMiniMap": false - }, - "content": "# Graph panel >> Timeseries panel\n\nKnown issues:\n* hiding null/empty series\n* time regions", - "mode": "markdown" - }, + "options": {}, + "content": "# Graph panel >> Timeseries panel\n\nKnown issues:\n* hiding null/empty series\n* time regions", + "mode": "markdown", "pluginVersion": "11.0.0-pre", "targets": [ { diff --git a/devenv/docker/blocks/mysql/docker-compose.yaml b/devenv/docker/blocks/mysql/docker-compose.yaml index cd5de0e6e67..c0c5403ef25 100644 --- a/devenv/docker/blocks/mysql/docker-compose.yaml +++ b/devenv/docker/blocks/mysql/docker-compose.yaml @@ -7,7 +7,15 @@ MYSQL_PASSWORD: password ports: - "3306:3306" - command: [mysqld, --character-set-server=utf8mb4, --collation-server=utf8mb4_unicode_ci, --innodb_monitor_enable=all, --default-authentication-plugin=mysql_native_password] + command: + - mysqld + - --character-set-server=utf8mb4 + - --collation-server=utf8mb4_unicode_ci + - --innodb_monitor_enable=all + - --default-authentication-plugin=mysql_native_password + # Please keep sql-require-primary-key option enabled, to make sure we don't accidentally introduce migration + # adding new table without PK. + - --sql-require-primary-key=ON fake-mysql-data: image: grafana/fake-data-gen diff --git a/docs/sources/as-code/observability-as-code/provision-resources/file-path-setup.md b/docs/sources/as-code/observability-as-code/provision-resources/file-path-setup.md index d071ccca0de..ca71a0c0d9c 100644 --- a/docs/sources/as-code/observability-as-code/provision-resources/file-path-setup.md +++ b/docs/sources/as-code/observability-as-code/provision-resources/file-path-setup.md @@ -128,35 +128,48 @@ The set up process verifies the path and provides an error message if a problem #### Synchronization limitations -Full instance sync is not available in Grafana Cloud. +{{< admonition type="caution" >}} -In Grafana OSS/Enterprise: +Full instance sync is not available in Grafana Cloud and is experimental and unsupported in Grafana OSS/Enterprise. + +{{< /admonition >}} + +To have access to full instance sync you must explicitly enable the option. + +The following applies: -- If you try to perform a full instance sync with resources that contain alerts or panels, the connection will be blocked. - You won't be able to create new alerts or library panels after setup is completed. - If you opted for full instance sync and want to use alerts and library panels, you'll have to delete the provisioned repository and connect again with folder sync. #### Set up synchronization -Choose to either sync your entire organization resources with external storage, or to sync certain resources to a new Grafana folder (with up to 10 connections). +You can sync external resources into a new folder without affecting the rest of your instance. -- Choose **Sync all resources with external storage** if you want to sync and manage your entire Grafana instance through external storage. With this option, all of your dashboards are synced to that one repository. You can only have one provisioned connection with this selection, and you won't have the option of setting up additional repositories to connect to. +To set up synchronization: -- Choose **Sync external storage to new Grafana folder** to sync external resources into a new folder without affecting the rest of your instance. You can repeat this process for up to 10 connections. +1. Select which resources you want to sync. -Next, enter a **Display name** for the repository connection. Resources stored in this connection appear under the chosen display name in the Grafana UI. +1. Enter a **Display name** for the repository connection. Resources stored in this connection appear under the chosen display name in the Grafana UI. -Click **Synchronize** to continue. +1. Click **Synchronize** to continue. + +1. You can repeat this process for up to 10 connections. + +{{< admonition type="note" >}} + +Optionally, you can export any unmanaged resources into the provisioned folder. See how in [Synchronize with external storage](#synchronize-with-external-storage). + +{{< /admonition >}} ### Synchronize with external storage -After this one time step, all future updates are automatically saved to the local file path and provisioned back to the instance. +In this step you proceed to synchronize the resources selected in the previous step. Optionally, you can check the **Migrate existing resources** box to migrate your unmanaged dashboards to the provisioned folder. -During the initial synchronization, your dashboards will be temporarily unavailable. No data or configurations will be lost. +Select **Begin synchronization** to start the process. After this one time step, all future updates are automatically saved to the local file path and provisioned back to the instance. + +Note that during the initial synchronization, your dashboards will be temporarily unavailable. No data or configurations will be lost. How long the process takes depends upon the number of resources involved. -Select **Begin synchronization** to start the process. - ### Choose additional settings If you wish, you can make any files synchronized as as **Read only** so no changes can be made to the resources through Grafana. diff --git a/docs/sources/as-code/observability-as-code/provision-resources/git-sync-setup.md b/docs/sources/as-code/observability-as-code/provision-resources/git-sync-setup.md index cd07c532dae..b43c279fb44 100644 --- a/docs/sources/as-code/observability-as-code/provision-resources/git-sync-setup.md +++ b/docs/sources/as-code/observability-as-code/provision-resources/git-sync-setup.md @@ -132,17 +132,35 @@ To connect your GitHub repository: ### Choose what to synchronize -In this step, you can decide which elements to synchronize. The available options depend on the status of your Grafana instance: - -- If the instance contains resources in an incompatible data format, you'll have to migrate all the data using instance sync. Folder sync won't be supported. -- If there's already another connection using folder sync, instance sync won't be offered. +You can sync external resources into a new folder without affecting the rest of your instance. To set up synchronization: -- Choose **Sync all resources with external storage** if you want to sync and manage your entire Grafana instance through external storage. With this option, all of your dashboards are synced to that one repository. You can only have one provisioned connection with this selection, and you won't have the option of setting up additional repositories to connect to. -- Choose **Sync external storage to new Grafana folder** to sync external resources into a new folder without affecting the rest of your instance. You can repeat this process for up to 10 connections. +1. Select which resources you want to sync. -Next, enter a **Display name** for the repository connection. Resources stored in this connection appear under the chosen display name in the Grafana UI. Click **Synchronize** to continue. +1. Enter a **Display name** for the repository connection. Resources stored in this connection appear under the chosen display name in the Grafana UI. + +1. Click **Synchronize** to continue. + +1. You can repeat this process for up to 10 connections. + +{{< admonition type="note" >}} + +Optionally, you can export any unmanaged resources into the provisioned folder. See how in [Synchronize with external storage](#synchronize-with-external-storage). + +{{< /admonition >}} + +#### Full instance sync + +Full instance sync is not available in Grafana Cloud and is experimental and unsupported in Grafana OSS/Enterprise. + +To have access to this option you must enable experimental instance sync on purpose. + +### Synchronize with external storage + +After this one time step, all future updates are automatically saved to the Git repository and provisioned back to the instance. + +Check the **Migrate existing resources** box to migrate your unmanaged dashboards to the provisioned folder. ### Choose additional settings diff --git a/docs/sources/as-code/observability-as-code/provision-resources/intro-git-sync.md b/docs/sources/as-code/observability-as-code/provision-resources/intro-git-sync.md index 9e32ce32e8a..903df6303a6 100644 --- a/docs/sources/as-code/observability-as-code/provision-resources/intro-git-sync.md +++ b/docs/sources/as-code/observability-as-code/provision-resources/intro-git-sync.md @@ -47,7 +47,7 @@ Using Git Sync, you can: {{< admonition type="caution" >}} -Git Sync only works with specific folders for the moment. Full-instance sync is not currently supported. +Full instance sync is not available in Grafana Cloud and is experimental and unsupported in Grafana OSS/Enterprise. {{< /admonition >}} @@ -84,7 +84,7 @@ Refer to [Requirements](https://grafana.com/docs/grafana//obser - You can only sync dashboards and folders. Refer to [Supported resources](#supported-resources) for more information. - If you're using Git Sync in Grafana OSS and Grafana Enterprise, some resources might be in an incompatible data format and won't be synced. -- Full-instance sync is not available in Grafana Cloud and has limitations in Grafana OSS and Grafana Enterprise. Refer to [Choose what to synchronize](../git-sync-setup/#choose-what-to-synchronize) for more details. +- Full-instance sync is not available in Grafana Cloud and is experimental in Grafana OSS and Grafana Enterprise. Refer to [Choose what to synchronize](../git-sync-setup/#choose-what-to-synchronize) for more details. - When migrating to full instance sync, during the synchronization process your resources will be temporarily unavailable. No one will be able to create, edit, or delete resources during this process. - If you want to manage existing resources with Git Sync, you need to save them as JSON files and commit them to the synced repository. Open a PR to import, copy, move, or save a dashboard. - Restoring resources from the UI is currently not possible. As an alternative, you can restore dashboards directly in your GitHub repository by raising a PR, and they will be updated in Grafana. diff --git a/docs/sources/datasources/_index.md b/docs/sources/datasources/_index.md index e7da61ea2f5..28d46c9c600 100644 --- a/docs/sources/datasources/_index.md +++ b/docs/sources/datasources/_index.md @@ -112,6 +112,12 @@ For example, this video demonstrates the visual Prometheus query builder: For general information about querying in Grafana, and common options and user interface elements across all query editors, refer to [Query and transform data](ref:query-transform-data). +## Build a dashboard from the data source + +After you've configured a data source, you can start creating a dashboard directly from it, by clicking the **Build a dashboard** button. + +For more information, refer to [Begin dashboard creation from data source configuration](https://grafana.com/docs/grafana//visualizations/dashboards/build-dashboards/create-dashboard/#begin-dashboard-creation-from-connections). + ## Special data sources Grafana includes three special data sources: diff --git a/docs/sources/setup-grafana/configure-access/configure-scim-provisioning/_index.md b/docs/sources/setup-grafana/configure-access/configure-scim-provisioning/_index.md index 9ef98bbc433..a07dde69e08 100644 --- a/docs/sources/setup-grafana/configure-access/configure-scim-provisioning/_index.md +++ b/docs/sources/setup-grafana/configure-access/configure-scim-provisioning/_index.md @@ -54,18 +54,6 @@ SCIM offers several advantages for managing users and teams in Grafana: ## Authentication and access requirements -{{< admonition type="warning" title="Critical: Aligning SAML Identifier with SCIM externalId" >}} -When using SAML for authentication alongside SCIM provisioning, a critical security measure is to ensure proper alignment between the the SCIM user's `externalId` and the SAML user identifier. The unique identifier used for SCIM provisioning (which becomes the `externalId` in Grafana, often sourced from a stable IdP attribute like Entra ID's `user.objectid`) **must also be sent as a claim in the SAML assertion from your Identity Provider.** -Furthermore, the Grafana SAML configuration must be correctly set up to identify and use this specific claim for linking the authenticated SAML user to their SCIM-provisioned user. This can be achieved by either ensuring the primary SAML login identifier by using the `assertion_attribute_external_uid` setting in Grafana to explicitly set the name of the SAML claim that contains the stable unique identifier attribute. - -**Why is this important?** -A mismatch or inconsistent mapping between this SAML login identifier and the SCIM `externalId` creates a critical security vulnerability. If these two identifiers are not reliably and uniquely aligned for each individual user, Grafana may fail to correctly link an authenticated SAML session to the intended SCIM-provisioned user profile and its associated permissions. This can enable a malicious actor to impersonate another user—for instance, by crafting a SAML assertion that, due to the identifier misalignment, incorrectly grants them the access rights of the targeted user. - -Grafana relies on this linkage to correctly associate the authenticated user from SAML with the provisioned user from SCIM. Failure to ensure a consistent and unique identifier across both systems can break this linkage, leading to incorrect user mapping and potential unauthorized access. - -Always verify that your SAML identity provider is configured to send a stable, unique user identifier that your SCIM configuration maps to `externalId`. Refer to your identity provider's documentation and the specific Grafana SCIM integration guides (e.g., for [Entra ID](configure-scim-with-azuread/) or [Okta](configure-scim-with-okta/)) for detailed instructions on configuring these attributes correctly. -{{< /admonition >}} - When you enable SCIM in Grafana, the following requirements and restrictions apply: 1. **Use the same identity provider for user provisioning and for authentication flow**: You must use the same identity provider for both authentication and user provisioning. @@ -74,6 +62,12 @@ When you enable SCIM in Grafana, the following requirements and restrictions app - Configure `userUID` SAML assertion in [Entra ID](/docs/grafana//setup-grafana/configure-access/configure-authentication/saml/configure-saml-with-azuread/#configure-saml-assertions-when-using-scim-provisioning) - Configure `userUID` SAML assertion in [Okta](/docs/grafana//setup-grafana/configure-access/configure-authentication/saml/configure-saml-with-okta/#configure-saml-assertions-when-using-scim-provisioning) +### Align SAML identifier with SCIM `externalId` + +When you use SAML with SCIM provisioning, align the SCIM `externalId` with the SAML user identifier. Use a stable IdP attribute (for example, Entra ID `user.objectid`) as the SCIM `externalId`, and send that same value as a SAML claim. Configure Grafana to read this claim with the `assertion_attribute_external_uid` setting so SAML authentication links to the SCIM-provisioned user and its permissions. + +If the SAML identifier and SCIM `externalId` differ, Grafana may not link the authenticated user to the intended SCIM profile, which can result in incorrect access. Verify your IdP sends a stable, unique identifier and that it matches the SCIM `externalId`. Refer to your IdP docs and the Grafana SCIM integration guides for [Entra ID](configure-scim-with-azuread/) and [Okta](configure-scim-with-okta/) for attribute configuration details. + ## Configure SCIM using the Grafana user interface You can configure SCIM in Grafana using the Grafana user interface. To do this, navigate to **Administration > Authentication > SCIM**. diff --git a/docs/sources/setup-grafana/configure-grafana/_index.md b/docs/sources/setup-grafana/configure-grafana/_index.md index a82ca8f91dd..05d9cb66228 100644 --- a/docs/sources/setup-grafana/configure-grafana/_index.md +++ b/docs/sources/setup-grafana/configure-grafana/_index.md @@ -642,6 +642,12 @@ You must also provide the `rudderstack_write_key` to enable this feature. Optional. If tracking with RudderStack is enabled, you can provide a custom URL to load the RudderStack SDK. +#### `rudderstack_v3_sdk_url` + +Optional. +This is mirroring the old configuration option, which will be deprecated. +If `rudderstack_sdk_url` and `rudderstack_v3_sdk_url` are both set, the feature toggle `rudderstackUpgrade` will control which one is loaded. + #### `rudderstack_config_url` Optional. diff --git a/docs/sources/setup-grafana/configure-grafana/feature-toggles/index.md b/docs/sources/setup-grafana/configure-grafana/feature-toggles/index.md index b80fa49f815..16c97f6d10a 100644 --- a/docs/sources/setup-grafana/configure-grafana/feature-toggles/index.md +++ b/docs/sources/setup-grafana/configure-grafana/feature-toggles/index.md @@ -31,7 +31,6 @@ Most [generally available](https://grafana.com/docs/release-life-cycle/#general- | `logsContextDatasourceUi` | Allow datasource to provide custom UI for context view | Yes | | `lokiQuerySplitting` | Split large interval queries into subqueries with smaller time intervals | Yes | | `influxdbBackendMigration` | Query InfluxDB InfluxQL without the proxy | Yes | -| `unifiedRequestLog` | Writes error logs to the request logger | Yes | | `logsExploreTableVisualisation` | A table visualisation for logs in Explore | Yes | | `awsDatasourcesTempCredentials` | Support temporary security credentials in AWS plugins for Grafana Cloud customers | Yes | | `awsAsyncQueryCaching` | Enable caching for async queries for Redshift and Athena. Requires that the datasource has caching and async query support enabled | Yes | diff --git a/docs/sources/setup-grafana/installation/debian/index.md b/docs/sources/setup-grafana/installation/debian/index.md index 067bcb29f6a..900c4a4b9d1 100644 --- a/docs/sources/setup-grafana/installation/debian/index.md +++ b/docs/sources/setup-grafana/installation/debian/index.md @@ -46,7 +46,7 @@ Complete the following steps to install Grafana from the APT repository: 1. Install the prerequisite packages: ```bash - sudo apt-get install -y apt-transport-https software-properties-common wget + sudo apt-get install -y apt-transport-https wget ``` 1. Import the GPG key: diff --git a/docs/sources/upgrade-guide/upgrade-v12.0/index.md b/docs/sources/upgrade-guide/upgrade-v12.0/index.md index feb1061dceb..b166cc2c022 100644 --- a/docs/sources/upgrade-guide/upgrade-v12.0/index.md +++ b/docs/sources/upgrade-guide/upgrade-v12.0/index.md @@ -81,24 +81,26 @@ Since Grafana 10.2, the endpoint to check compatible versions when installing a We _do not_ recommend installing plugins declared as incompatible. However, if you need to force install a plugin despite it being declared as incompatible, refer to the [Installing a plugin from a ZIP](https://grafana.com/docs/grafana/latest/administration/plugin-management/#install-a-plugin-from-a-zip-file) guidance. -### PostgreSQL annotation table migration +### Annotation table migration **Plan for increased disk usage when upgrading from Grafana v11.x** -Upgrading from Grafana v11.x to Grafana v12.x triggers a full-table rewrite of the PostgreSQL `annotation` table. The migration populates the new `dashboard_uid` column, which causes PostgreSQL to rewrite the entire table and rebuild its indexes. +Upgrading from Grafana v11.x to Grafana v12.x triggers a full-table rewrite of the `annotation` table. The migration populates the new `dashboard_uid` column, which causes the database to rewrite the entire table and rebuild its indexes. Environments with large annotation datasets can experience significant temporary disk usage increase, which may lead to: -- Rapid disk consumption on the PostgreSQL data volume +- Rapid disk consumption on the database data volume - Database migration failures (for example, "could not extend file: No space left on device") - Grafana startup failures - Extended downtime during the upgrade process #### How do I know if I'm affected? -You're affected if you're upgrading from Grafana v11.x to v12.x and you have a large `annotation` table in your PostgreSQL database. +You're affected if you're upgrading from Grafana v11.x to v12.x and you have a large `annotation` table in your database. -To check your annotation table size, connect to your PostgreSQL database and run the following query: +To check your annotation table size, connect to your database and check the table size. + +For PostgreSQL, run the following query: ```sql SELECT @@ -107,26 +109,58 @@ SELECT pg_size_pretty(pg_total_relation_size('annotation')) AS total_size; ``` +For MySQL, run the following query: + +```sql +SELECT + ROUND(data_length / 1024 / 1024, 2) AS table_size_mb, + ROUND(index_length / 1024 / 1024, 2) AS indexes_size_mb, + ROUND((data_length + index_length) / 1024 / 1024, 2) AS total_size_mb +FROM information_schema.tables +WHERE table_schema = DATABASE() + AND table_name = 'annotation'; +``` + +For SQLite, check the database file size directly, as SQLite stores all tables in a single file. You can run the following command from your terminal: + +```bash +ls -lh +``` + If your total size is several gigabytes or more, you should plan accordingly before upgrading. #### What should I do before upgrading? Before you upgrade, take the following steps: -1. **Verify available disk space**: Ensure you have at least 2-3 times the current `annotation` table size available as free disk space on your PostgreSQL data volume. +1. **Verify available disk space**: Ensure you have at least 2-3 times the current `annotation` table size available as free disk space on your database data volume. -2. **Review your annotation data**: Consider whether you need to retain all historical annotations. +1. **Review your annotation data**: Consider whether you need to retain all historical annotations. -3. **Clean up old annotations (optional)**: If you have annotations you don't need, remove them before upgrading. +1. **Clean up old annotations (optional)**: If you have annotations you don't need, remove them before upgrading. -4. **Back up your database**: Always back up your Grafana database before performing an upgrade. For more information, refer to [Back up Grafana](#back-up-grafana). +1. **Back up your database**: Always back up your Grafana database before performing an upgrade. For more information, refer to [Back up Grafana](#back-up-grafana). #### What should I do after upgrading? -After successfully upgrading to Grafana v12.x, you can reclaim disk space by running a `VACUUM FULL` operation on the `annotation` table during a maintenance window: +After successfully upgrading to Grafana v12.x, you can reclaim disk space by performing database maintenance operations during a maintenance window. + +For PostgreSQL, run a `VACUUM FULL` operation on the `annotation` table: ```sql VACUUM FULL annotation; ``` -This operation requires a lock on the table and may take significant time depending on the table size. Plan to run this during a low-traffic period. +For MySQL, run an `OPTIMIZE TABLE` operation on the `annotation` table: + +```sql +OPTIMIZE TABLE annotation; +``` + +For SQLite, run a `VACUUM` operation on the database: + +```sql +VACUUM; +``` + +These operations require a lock on the table and may take significant time depending on the table size. Plan to run these during a low-traffic period. diff --git a/docs/sources/upgrade-guide/upgrade-v12.1/index.md b/docs/sources/upgrade-guide/upgrade-v12.1/index.md index 7dbcb11ece9..9a96c0cbc0a 100644 --- a/docs/sources/upgrade-guide/upgrade-v12.1/index.md +++ b/docs/sources/upgrade-guide/upgrade-v12.1/index.md @@ -21,24 +21,26 @@ weight: 499 ## Technical notes -### PostgreSQL annotation table migration +### Annotation table migration **Plan for increased disk usage when upgrading from Grafana v11.x** -Upgrading from Grafana v11.x to Grafana v12.x triggers a full-table rewrite of the PostgreSQL `annotation` table. The migration populates the new `dashboard_uid` column, which causes PostgreSQL to rewrite the entire table and rebuild its indexes. +Upgrading from Grafana v11.x to Grafana v12.x triggers a full-table rewrite of the `annotation` table. The migration populates the new `dashboard_uid` column, which causes the database to rewrite the entire table and rebuild its indexes. Environments with large annotation datasets can experience significant temporary disk usage increase, which may lead to: -- Rapid disk consumption on the PostgreSQL data volume +- Rapid disk consumption on the database data volume - Database migration failures (for example, "could not extend file: No space left on device") - Grafana startup failures - Extended downtime during the upgrade process #### How do I know if I'm affected? -You're affected if you're upgrading from Grafana v11.x to v12.x and you have a large `annotation` table in your PostgreSQL database. +You're affected if you're upgrading from Grafana v11.x to v12.x and you have a large `annotation` table in your database. -To check your annotation table size, connect to your PostgreSQL database and run the following query: +To check your annotation table size, connect to your database and check the table size. + +For PostgreSQL, run the following query: ```sql SELECT @@ -47,26 +49,58 @@ SELECT pg_size_pretty(pg_total_relation_size('annotation')) AS total_size; ``` +For MySQL, run the following query: + +```sql +SELECT + ROUND(data_length / 1024 / 1024, 2) AS table_size_mb, + ROUND(index_length / 1024 / 1024, 2) AS indexes_size_mb, + ROUND((data_length + index_length) / 1024 / 1024, 2) AS total_size_mb +FROM information_schema.tables +WHERE table_schema = DATABASE() + AND table_name = 'annotation'; +``` + +For SQLite, check the database file size directly, as SQLite stores all tables in a single file. You can run the following command from your terminal: + +```bash +ls -lh +``` + If your total size is several gigabytes or more, you should plan accordingly before upgrading. #### What should I do before upgrading? Before you upgrade, take the following steps: -1. **Verify available disk space**: Ensure you have at least 2-3 times the current `annotation` table size available as free disk space on your PostgreSQL data volume. +1. **Verify available disk space**: Ensure you have at least 2-3 times the current `annotation` table size available as free disk space on your database data volume. -2. **Review your annotation data**: Consider whether you need to retain all historical annotations. +1. **Review your annotation data**: Consider whether you need to retain all historical annotations. -3. **Clean up old annotations (optional)**: If you have annotations you don't need, remove them before upgrading. +1. **Clean up old annotations (optional)**: If you have annotations you don't need, remove them before upgrading. -4. **Back up your database**: Always back up your Grafana database before performing an upgrade. For more information, refer to [Back up Grafana](#back-up-grafana). +1. **Back up your database**: Always back up your Grafana database before performing an upgrade. For more information, refer to [Back up Grafana](#back-up-grafana). #### What should I do after upgrading? -After successfully upgrading to Grafana v12.x, you can reclaim disk space by running a `VACUUM FULL` operation on the `annotation` table during a maintenance window: +After successfully upgrading to Grafana v12.x, you can reclaim disk space by performing database maintenance operations during a maintenance window. + +For PostgreSQL, run a `VACUUM FULL` operation on the `annotation` table: ```sql VACUUM FULL annotation; ``` -This operation requires a lock on the table and may take significant time depending on the table size. Plan to run this during a low-traffic period. +For MySQL, run an `OPTIMIZE TABLE` operation on the `annotation` table: + +```sql +OPTIMIZE TABLE annotation; +``` + +For SQLite, run a `VACUUM` operation on the database: + +```sql +VACUUM; +``` + +These operations require a lock on the table and may take significant time depending on the table size. Plan to run these during a low-traffic period. diff --git a/docs/sources/upgrade-guide/upgrade-v12.2/index.md b/docs/sources/upgrade-guide/upgrade-v12.2/index.md index 1e900d65793..221ae3f152c 100644 --- a/docs/sources/upgrade-guide/upgrade-v12.2/index.md +++ b/docs/sources/upgrade-guide/upgrade-v12.2/index.md @@ -21,24 +21,26 @@ weight: 498 ## Technical notes -### PostgreSQL annotation table migration +### Annotation table migration **Plan for increased disk usage when upgrading from Grafana v11.x** -Upgrading from Grafana v11.x to Grafana v12.x triggers a full-table rewrite of the PostgreSQL `annotation` table. The migration populates the new `dashboard_uid` column, which causes PostgreSQL to rewrite the entire table and rebuild its indexes. +Upgrading from Grafana v11.x to Grafana v12.x triggers a full-table rewrite of the `annotation` table. The migration populates the new `dashboard_uid` column, which causes the database to rewrite the entire table and rebuild its indexes. Environments with large annotation datasets can experience significant temporary disk usage increase, which may lead to: -- Rapid disk consumption on the PostgreSQL data volume +- Rapid disk consumption on the database data volume - Database migration failures (for example, "could not extend file: No space left on device") - Grafana startup failures - Extended downtime during the upgrade process #### How do I know if I'm affected? -You're affected if you're upgrading from Grafana v11.x to v12.x and you have a large `annotation` table in your PostgreSQL database. +You're affected if you're upgrading from Grafana v11.x to v12.x and you have a large `annotation` table in your database. -To check your annotation table size, connect to your PostgreSQL database and run the following query: +To check your annotation table size, connect to your database and check the table size. + +For PostgreSQL, run the following query: ```sql SELECT @@ -47,26 +49,58 @@ SELECT pg_size_pretty(pg_total_relation_size('annotation')) AS total_size; ``` +For MySQL, run the following query: + +```sql +SELECT + ROUND(data_length / 1024 / 1024, 2) AS table_size_mb, + ROUND(index_length / 1024 / 1024, 2) AS indexes_size_mb, + ROUND((data_length + index_length) / 1024 / 1024, 2) AS total_size_mb +FROM information_schema.tables +WHERE table_schema = DATABASE() + AND table_name = 'annotation'; +``` + +For SQLite, check the database file size directly, as SQLite stores all tables in a single file. You can run the following command from your terminal: + +```bash +ls -lh +``` + If your total size is several gigabytes or more, you should plan accordingly before upgrading. #### What should I do before upgrading? Before you upgrade, take the following steps: -1. **Verify available disk space**: Ensure you have at least 2-3 times the current `annotation` table size available as free disk space on your PostgreSQL data volume. +1. **Verify available disk space**: Ensure you have at least 2-3 times the current `annotation` table size available as free disk space on your database data volume. -2. **Review your annotation data**: Consider whether you need to retain all historical annotations. +1. **Review your annotation data**: Consider whether you need to retain all historical annotations. -3. **Clean up old annotations (optional)**: If you have annotations you don't need, remove them before upgrading. +1. **Clean up old annotations (optional)**: If you have annotations you don't need, remove them before upgrading. -4. **Back up your database**: Always back up your Grafana database before performing an upgrade. For more information, refer to [Back up Grafana](#back-up-grafana). +1. **Back up your database**: Always back up your Grafana database before performing an upgrade. For more information, refer to [Back up Grafana](#back-up-grafana). #### What should I do after upgrading? -After successfully upgrading to Grafana v12.x, you can reclaim disk space by running a `VACUUM FULL` operation on the `annotation` table during a maintenance window: +After successfully upgrading to Grafana v12.x, you can reclaim disk space by performing database maintenance operations during a maintenance window. + +For PostgreSQL, run a `VACUUM FULL` operation on the `annotation` table: ```sql VACUUM FULL annotation; ``` -This operation requires a lock on the table and may take significant time depending on the table size. Plan to run this during a low-traffic period. +For MySQL, run an `OPTIMIZE TABLE` operation on the `annotation` table: + +```sql +OPTIMIZE TABLE annotation; +``` + +For SQLite, run a `VACUUM` operation on the database: + +```sql +VACUUM; +``` + +These operations require a lock on the table and may take significant time depending on the table size. Plan to run these during a low-traffic period. diff --git a/docs/sources/upgrade-guide/upgrade-v12.3/index.md b/docs/sources/upgrade-guide/upgrade-v12.3/index.md index dc8b1b8e398..6160c443e10 100644 --- a/docs/sources/upgrade-guide/upgrade-v12.3/index.md +++ b/docs/sources/upgrade-guide/upgrade-v12.3/index.md @@ -21,24 +21,26 @@ weight: 497 ## Technical notes -### PostgreSQL annotation table migration +### Annotation table migration **Plan for increased disk usage when upgrading from Grafana v11.x** -Upgrading from Grafana v11.x to Grafana v12.x triggers a full-table rewrite of the PostgreSQL `annotation` table. The migration populates the new `dashboard_uid` column, which causes PostgreSQL to rewrite the entire table and rebuild its indexes. +Upgrading from Grafana v11.x to Grafana v12.x triggers a full-table rewrite of the `annotation` table. The migration populates the new `dashboard_uid` column, which causes the database to rewrite the entire table and rebuild its indexes. Environments with large annotation datasets can experience significant temporary disk usage increase, which may lead to: -- Rapid disk consumption on the PostgreSQL data volume +- Rapid disk consumption on the database data volume - Database migration failures (for example, "could not extend file: No space left on device") - Grafana startup failures - Extended downtime during the upgrade process #### How do I know if I'm affected? -You're affected if you're upgrading from Grafana v11.x to v12.x and you have a large `annotation` table in your PostgreSQL database. +You're affected if you're upgrading from Grafana v11.x to v12.x and you have a large `annotation` table in your database. -To check your annotation table size, connect to your PostgreSQL database and run the following query: +To check your annotation table size, connect to your database and check the table size. + +For PostgreSQL, run the following query: ```sql SELECT @@ -47,26 +49,58 @@ SELECT pg_size_pretty(pg_total_relation_size('annotation')) AS total_size; ``` +For MySQL, run the following query: + +```sql +SELECT + ROUND(data_length / 1024 / 1024, 2) AS table_size_mb, + ROUND(index_length / 1024 / 1024, 2) AS indexes_size_mb, + ROUND((data_length + index_length) / 1024 / 1024, 2) AS total_size_mb +FROM information_schema.tables +WHERE table_schema = DATABASE() + AND table_name = 'annotation'; +``` + +For SQLite, check the database file size directly, as SQLite stores all tables in a single file. You can run the following command from your terminal: + +```bash +ls -lh +``` + If your total size is several gigabytes or more, you should plan accordingly before upgrading. #### What should I do before upgrading? Before you upgrade, take the following steps: -1. **Verify available disk space**: Ensure you have at least 2-3 times the current `annotation` table size available as free disk space on your PostgreSQL data volume. +1. **Verify available disk space**: Ensure you have at least 2-3 times the current `annotation` table size available as free disk space on your database data volume. -2. **Review your annotation data**: Consider whether you need to retain all historical annotations. +1. **Review your annotation data**: Consider whether you need to retain all historical annotations. -3. **Clean up old annotations (optional)**: If you have annotations you don't need, remove them before upgrading. +1. **Clean up old annotations (optional)**: If you have annotations you don't need, remove them before upgrading. -4. **Back up your database**: Always back up your Grafana database before performing an upgrade. For more information, refer to [Back up Grafana](#back-up-grafana). +1. **Back up your database**: Always back up your Grafana database before performing an upgrade. For more information, refer to [Back up Grafana](#back-up-grafana). #### What should I do after upgrading? -After successfully upgrading to Grafana v12.x, you can reclaim disk space by running a `VACUUM FULL` operation on the `annotation` table during a maintenance window: +After successfully upgrading to Grafana v12.x, you can reclaim disk space by performing database maintenance operations during a maintenance window. + +For PostgreSQL, run a `VACUUM FULL` operation on the `annotation` table: ```sql VACUUM FULL annotation; ``` -This operation requires a lock on the table and may take significant time depending on the table size. Plan to run this during a low-traffic period. +For MySQL, run an `OPTIMIZE TABLE` operation on the `annotation` table: + +```sql +OPTIMIZE TABLE annotation; +``` + +For SQLite, run a `VACUUM` operation on the database: + +```sql +VACUUM; +``` + +These operations require a lock on the table and may take significant time depending on the table size. Plan to run these during a low-traffic period. diff --git a/docs/sources/visualizations/dashboards/build-dashboards/annotate-visualizations/index.md b/docs/sources/visualizations/dashboards/build-dashboards/annotate-visualizations/index.md index f356d51c4a5..5458f90281e 100644 --- a/docs/sources/visualizations/dashboards/build-dashboards/annotate-visualizations/index.md +++ b/docs/sources/visualizations/dashboards/build-dashboards/annotate-visualizations/index.md @@ -163,9 +163,9 @@ To add a new annotation query to a dashboard, follow these steps: 1. To create a query, do one of the following: - Write or construct a query in the query language of your data source. The annotation query options are different for each data source. For information about annotations in a specific data source, refer to the specific [data source](ref:data-source) topic. - - Click **Replace with saved query** to reuse a [saved query](ref:saved-queries). + - Open the **Saved queries** drop-down menu and click **Replace query** to reuse a [saved query](ref:saved-queries). -1. (Optional) To [save the query](ref:save-query) for reuse, click the **Save query** button (or icon). +1. (Optional) To [save the query](ref:save-query) for reuse, open the **Saved queries** drop-down menu and click the **Save query** option. 1. (Optional) Click **Test annotation query** to ensure that the query is working properly. 1. (Optional) To add subsequent queries, click **+ Add query** or **+ Add from saved queries**, and test them as many times as needed. diff --git a/docs/sources/visualizations/dashboards/build-dashboards/create-dashboard/index.md b/docs/sources/visualizations/dashboards/build-dashboards/create-dashboard/index.md index feb6573c3e9..10196a40811 100644 --- a/docs/sources/visualizations/dashboards/build-dashboards/create-dashboard/index.md +++ b/docs/sources/visualizations/dashboards/build-dashboards/create-dashboard/index.md @@ -99,7 +99,7 @@ Dashboards and panels allow you to show your data in visual form. Each panel nee - Understand the query language of the target data source. - Ensure that data source for which you are writing a query has been added. For more information about adding a data source, refer to [Add a data source](ref:add-a-data-source) if you need instructions. -**To create a dashboard**: +To create a dashboard, follow these steps: {{< shared id="create-dashboard" >}} @@ -125,9 +125,9 @@ Dashboards and panels allow you to show your data in visual form. Each panel nee 1. To create a query, do one of the following: - Write or construct a query in the query language of your data source. - - Click **Replace with saved query** to reuse a [saved query](ref:saved-queries). + - Open the **Saved queries** drop-down menu and click **Replace query** to reuse a [saved query](ref:saved-queries). -1. (Optional) To [save the query](ref:save-query) for reuse, click the **Save query** button (or icon). +1. (Optional) To [save the query](ref:save-query) for reuse, open the **Saved queries** drop-down menu and click the **Save query** option. 1. Click **Refresh** to query the data source. 1. (Optional) To add subsequent queries, click **+ Add query** or **+ Add from saved queries**, and refresh the data source as many times as needed. @@ -171,6 +171,28 @@ Dashboards and panels allow you to show your data in visual form. Each panel nee Now, when you want to make more changes to the saved dashboard, click **Edit** in the top-right corner. +### Begin dashboard creation from data source configuration + +You can start the process of creating a dashboard directly from a data source rather than from the **Dashboards** page. + +To begin building a dashboard directly from a data source, follow these steps: + +1. Navigate to **Connections > Data sources**. +1. On the row of the data source for which you want to build a dashboard, click **Build a dashboard**. + + The empty dashboard page opens. + +1. Do one of the following: + - Click **+Add visualization** to configure all the elements of the new dashboard. + - Select one of the suggested dashboards by clicking its **Use dashboard** button. This can be helpful when you're not sure how to most effectively visualize your data. + The suggested dashboards are specific to your data source type (for example, Prometheus, Loki, or Elasticsearch). If there are more than three dashboard suggestions, you can click **View all** to see the rest of them. + + ![Empty dashboard with add visualization and suggested dashboard options](/media/docs/grafana/dashboards/screenshot-suggested-dashboards-v12.3.png) + + {{< docs/public-preview product="Suggested dashboards" >}} + +1. Complete the rest of the dashboard configuration. For more detailed steps, refer to [Create a dashboard](#create-a-dashboard), beginning at step five. + ## Copy a dashboard To copy a dashboard, follow these steps: diff --git a/docs/sources/visualizations/explore/get-started-with-explore.md b/docs/sources/visualizations/explore/get-started-with-explore.md index b59ac68c686..41f1f8c5c01 100644 --- a/docs/sources/visualizations/explore/get-started-with-explore.md +++ b/docs/sources/visualizations/explore/get-started-with-explore.md @@ -71,8 +71,9 @@ Explore consists of a toolbar, outline, query editor, the ability to add multipl - **Run query** - Click to run your query. - **Query editor** - Interface where you construct the query for a specific data source. Query editor elements differ based on data source. In order to run queries across multiple data sources you need to select **Mixed** from the data source picker. - - **Save query** - To [save the query](ref:save-query) for reuse, click the **Save query** button (or icon). - - **Replace with saved query** - Reuse a saved query. + - **Saved queries**: + - **Save query** - To [save the query](ref:save-query) for reuse, click the **Save query** button (or icon). + - **Replace query** - Reuse a saved query. - **+ Add query** - Add an additional query. - **+ Add from saved queries** - Add an additional query by reusing a saved query. diff --git a/docs/sources/visualizations/panels-visualizations/panel-editor-overview/index.md b/docs/sources/visualizations/panels-visualizations/panel-editor-overview/index.md index 4afbd8f71a6..f219f10a68a 100644 --- a/docs/sources/visualizations/panels-visualizations/panel-editor-overview/index.md +++ b/docs/sources/visualizations/panels-visualizations/panel-editor-overview/index.md @@ -88,8 +88,9 @@ The data section contains tabs where you enter queries, transform your data, and - **Queries** - Select your data source. You can also set or update the data source in existing dashboards using the drop-down menu in the **Queries** tab. - - **Save query** - To [save the query](ref:save-query) for reuse, click the **Save query** button (or icon). - - **Replace with saved query** - Reuse a saved query. + - **Saved queries**: + - **Save query** - To [save the query](ref:save-query) for reuse, click the **Save query** button (or icon). + - **Replace query** - Reuse a saved query. - **+ Add query** - Add an additional query. - **+ Add from saved queries** - Add an additional query by reusing a saved query. 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 5b121028404..0aafe41f524 100644 --- a/docs/sources/visualizations/panels-visualizations/query-transform-data/_index.md +++ b/docs/sources/visualizations/panels-visualizations/query-transform-data/_index.md @@ -156,11 +156,11 @@ In the **Saved queries** drawer, you can: - Edit a query title, description, tags, or the availability of the query to other users in your organization. By default, saved queries are locked for editing. - When you access the **Saved queries** drawer from Explore, you can use the **Edit in Explore** option to edit the body of a query. -To access your saved queries, click **+ Add from saved queries** or **Replace with saved query** in the query editor: +To access your saved queries, click **+ Add from saved queries** or open the **Saved queries** drop-down menu and click **Replace query** in the query editor: {{< figure src="/media/docs/grafana/dashboards/screenshot-use-saved-queries-v12.3.png" max-width="750px" alt="Access saved queries" >}} -Clicking **+ Add from saved queries** adds an additional query, while clicking **Replace with saved query** updates your existing query. +Clicking **+ Add from saved queries** adds an additional query, while clicking **Replace query** in the **Saved queries** drop-down menu updates your existing query. {{< admonition type="note" >}} Users with Admin and Editor roles can create and save queries for reuse. @@ -172,7 +172,7 @@ Viewers can only reuse queries. To save a query you've created: -1. From the query editor, click the **Save query** icon: +1. From the query editor, open the **Saved queries** drop-down menu and click the **Save query** option: {{< figure src="/media/docs/grafana/panels-visualizations/screenshot-save-query-v12.2.png" max-width="750px" alt="Save a query" >}} @@ -227,7 +227,7 @@ To add a query, follow these steps: 1. To create a query, do one of the following: - Write or construct a query in the query language of your data source. - - Click **Replace with saved query** to reuse a saved query. + - Open the **Saved queries** drop-down menu and click **Replace query** to reuse a saved query. {{< admonition type="note" >}} [Saved queries](#saved-queries) is currently in [public preview](https://grafana.com/docs/release-life-cycle/). Grafana Labs offers limited support, and breaking changes might occur prior to the feature being made generally available. @@ -235,7 +235,7 @@ To add a query, follow these steps: This feature is only available on Grafana Enterprise and Grafana Cloud. {{< /admonition >}} -1. (Optional) To [save the query](#save-a-query) for reuse, click the **Save query** button (or icon). +1. (Optional) To [save the query](#save-a-query) for reuse, click the **Save query** option in the **Saved queries** drop-down menu. 1. (Optional) Click **+ Add query** or **Add from saved queries** to add more queries as needed. 1. Click **Run queries**. diff --git a/e2e-playwright/alerting-suite/saved-searches.spec.ts b/e2e-playwright/alerting-suite/saved-searches.spec.ts new file mode 100644 index 00000000000..28de805a5a1 --- /dev/null +++ b/e2e-playwright/alerting-suite/saved-searches.spec.ts @@ -0,0 +1,271 @@ +import { Page } from '@playwright/test'; + +import { test, expect } from '@grafana/plugin-e2e'; + +/** + * UI selectors for Saved Searches e2e tests. + * Each selector is a function that takes the page and returns a locator. + */ +const ui = { + // Main elements + savedSearchesButton: (page: Page) => page.getByRole('button', { name: /saved searches/i }), + dropdown: (page: Page) => page.getByRole('dialog', { name: /saved searches/i }), + searchInput: (page: Page) => page.getByTestId('search-query-input'), + + // Save functionality + saveButton: (page: Page) => page.getByRole('button', { name: /save current search/i }), + saveConfirmButton: (page: Page) => page.getByRole('button', { name: /^save$/i }), + saveNameInput: (page: Page) => page.getByPlaceholder(/enter a name/i), + + // Action menu + actionsButton: (page: Page) => page.getByRole('button', { name: /actions/i }), + renameMenuItem: (page: Page) => page.getByText(/rename/i), + deleteMenuItem: (page: Page) => page.getByText(/^delete$/i), + setAsDefaultMenuItem: (page: Page) => page.getByText(/set as default/i), + deleteConfirmButton: (page: Page) => page.getByRole('button', { name: /^delete$/i }), + + // Indicators + emptyState: (page: Page) => page.getByText(/no saved searches/i), + defaultIcon: (page: Page) => page.locator('[title="Default search"]'), + duplicateError: (page: Page) => page.getByText(/already exists/i), +}; + +/** + * Helper to clear saved searches storage. + * UserStorage uses localStorage as fallback, so we clear both potential keys. + */ +async function clearSavedSearches(page: Page) { + await page.evaluate(() => { + // Clear localStorage keys that might contain saved searches + // UserStorage stores under 'grafana.userstorage.alerting' pattern + const keysToRemove = Object.keys(localStorage).filter( + (key) => key.includes('alerting') && (key.includes('savedSearches') || key.includes('userstorage')) + ); + keysToRemove.forEach((key) => localStorage.removeItem(key)); + + // Also clear session storage visited flag + const sessionKeysToRemove = Object.keys(sessionStorage).filter((key) => key.includes('alerting')); + sessionKeysToRemove.forEach((key) => sessionStorage.removeItem(key)); + }); +} + +test.describe( + 'Alert Rules - Saved Searches', + { + tag: ['@alerting'], + }, + () => { + test.beforeEach(async ({ page }) => { + // Clear any saved searches from previous tests before navigating + await page.goto('/alerting/list'); + await clearSavedSearches(page); + await page.reload(); + }); + + test.afterEach(async ({ page }) => { + // Clean up saved searches after each test + await clearSavedSearches(page); + }); + + test('should display Saved searches button', async ({ page }) => { + await expect(ui.savedSearchesButton(page)).toBeVisible(); + }); + + test('should open dropdown when clicking Saved searches button', async ({ page }) => { + await ui.savedSearchesButton(page).click(); + + await expect(ui.dropdown(page)).toBeVisible(); + }); + + test('should show empty state when no saved searches exist', async ({ page }) => { + // Storage is cleared in beforeEach, so we should see empty state + await ui.savedSearchesButton(page).click(); + + await expect(ui.emptyState(page)).toBeVisible(); + }); + + test('should enable Save current search button when search query is entered', async ({ page }) => { + // Enter a search query + await ui.searchInput(page).fill('state:firing'); + await ui.searchInput(page).press('Enter'); + + // Open saved searches + await ui.savedSearchesButton(page).click(); + + await expect(ui.saveButton(page)).toBeEnabled(); + }); + + test('should disable Save current search button when search query is empty', async ({ page }) => { + await ui.savedSearchesButton(page).click(); + + await expect(ui.saveButton(page)).toBeDisabled(); + }); + + test('should save a new search', async ({ page }) => { + // Enter a search query + await ui.searchInput(page).fill('state:firing'); + await ui.searchInput(page).press('Enter'); + + // Open saved searches + await ui.savedSearchesButton(page).click(); + + // Click save button + await ui.saveButton(page).click(); + + // Enter name and save + await ui.saveNameInput(page).fill('My Firing Rules'); + await ui.saveConfirmButton(page).click(); + + // Verify the saved search appears in the list + await expect(page.getByText('My Firing Rules')).toBeVisible(); + }); + + test('should show validation error for duplicate name', async ({ page }) => { + // First save a search + await ui.searchInput(page).fill('state:firing'); + await ui.searchInput(page).press('Enter'); + + await ui.savedSearchesButton(page).click(); + + await ui.saveButton(page).click(); + + await ui.saveNameInput(page).fill('Duplicate Test'); + await ui.saveConfirmButton(page).click(); + + // Try to save another with the same name + await ui.saveButton(page).click(); + await ui.saveNameInput(page).fill('Duplicate Test'); + await ui.saveConfirmButton(page).click(); + + // Verify validation error + await expect(ui.duplicateError(page)).toBeVisible(); + }); + + test('should apply a saved search', async ({ page }) => { + // Create a saved search first + await ui.searchInput(page).fill('state:firing'); + await ui.searchInput(page).press('Enter'); + + await ui.savedSearchesButton(page).click(); + + await ui.saveButton(page).click(); + + await ui.saveNameInput(page).fill('Apply Test'); + await ui.saveConfirmButton(page).click(); + + // Clear the search + await ui.searchInput(page).clear(); + await ui.searchInput(page).press('Enter'); + + // Apply the saved search + await ui.savedSearchesButton(page).click(); + await page.getByRole('button', { name: /apply search.*apply test/i }).click(); + + // Verify the search input is updated + await expect(ui.searchInput(page)).toHaveValue('state:firing'); + }); + + test('should rename a saved search', async ({ page }) => { + // Create a saved search + await ui.searchInput(page).fill('state:firing'); + await ui.searchInput(page).press('Enter'); + + await ui.savedSearchesButton(page).click(); + + await ui.saveButton(page).click(); + + await ui.saveNameInput(page).fill('Original Name'); + await ui.saveConfirmButton(page).click(); + + // Open action menu and click rename + await ui.actionsButton(page).click(); + await ui.renameMenuItem(page).click(); + + // Enter new name + const renameInput = page.getByDisplayValue('Original Name'); + await renameInput.clear(); + await renameInput.fill('Renamed Search'); + await page.keyboard.press('Enter'); + + // Verify the name was updated + await expect(page.getByText('Renamed Search')).toBeVisible(); + await expect(page.getByText('Original Name')).not.toBeVisible(); + }); + + test('should delete a saved search', async ({ page }) => { + // Create a saved search + await ui.searchInput(page).fill('state:firing'); + await ui.searchInput(page).press('Enter'); + + await ui.savedSearchesButton(page).click(); + + await ui.saveButton(page).click(); + + await ui.saveNameInput(page).fill('To Delete'); + await ui.saveConfirmButton(page).click(); + + // Verify it was saved + await expect(page.getByText('To Delete')).toBeVisible(); + + // Open action menu and click delete + await ui.actionsButton(page).click(); + await ui.deleteMenuItem(page).click(); + + // Confirm delete + await ui.deleteConfirmButton(page).click(); + + // Verify it was deleted + await expect(page.getByText('To Delete')).not.toBeVisible(); + }); + + test('should set a search as default', async ({ page }) => { + // Create a saved search + await ui.searchInput(page).fill('state:firing'); + await ui.searchInput(page).press('Enter'); + + await ui.savedSearchesButton(page).click(); + + await ui.saveButton(page).click(); + + await ui.saveNameInput(page).fill('Default Test'); + await ui.saveConfirmButton(page).click(); + + // Set as default + await ui.actionsButton(page).click(); + await ui.setAsDefaultMenuItem(page).click(); + + // Verify the star icon appears (indicating default) + await expect(ui.defaultIcon(page)).toBeVisible(); + }); + + test('should close dropdown when pressing Escape', async ({ page }) => { + await ui.savedSearchesButton(page).click(); + + await expect(ui.dropdown(page)).toBeVisible(); + + await page.keyboard.press('Escape'); + + await expect(ui.dropdown(page)).not.toBeVisible(); + }); + + test('should cancel save mode when pressing Escape', async ({ page }) => { + // Enter a search query + await ui.searchInput(page).fill('state:firing'); + await ui.searchInput(page).press('Enter'); + + await ui.savedSearchesButton(page).click(); + + // Start save mode + await ui.saveButton(page).click(); + + await expect(ui.saveNameInput(page)).toBeVisible(); + + // Press Escape to cancel + await page.keyboard.press('Escape'); + + // Verify we're back to list mode + await expect(ui.saveNameInput(page)).not.toBeVisible(); + await expect(ui.saveButton(page)).toBeVisible(); + }); + } +); diff --git a/e2e-playwright/dashboard-new-layouts/dashboard-keybindings.spec.ts b/e2e-playwright/dashboard-new-layouts/dashboard-keybindings.spec.ts new file mode 100644 index 00000000000..19ad38f16d5 --- /dev/null +++ b/e2e-playwright/dashboard-new-layouts/dashboard-keybindings.spec.ts @@ -0,0 +1,59 @@ +import { test, expect } from '@grafana/plugin-e2e'; + +test.use({ + featureToggles: { + kubernetesDashboards: true, + dashboardNewLayouts: true, + }, +}); + +test.describe('Dashboard keybindings with new layouts', { tag: ['@dashboards'] }, () => { + test.use({ + viewport: { width: 1280, height: 1080 }, + }); + + test('should collapse and expand all rows', async ({ gotoDashboardPage, page, selectors }) => { + const dashboardPage = await gotoDashboardPage({ uid: 'Repeating-rows-uid/repeating-rows' }); + + const panelContents = dashboardPage.getByGrafanaSelector(selectors.components.Panels.Panel.content); + await expect(panelContents).toHaveCount(5); + await expect( + dashboardPage.getByGrafanaSelector(selectors.components.Panels.Panel.title('server = A, pod = Bob')) + ).toBeVisible(); + await expect( + dashboardPage.getByGrafanaSelector(selectors.components.Panels.Panel.title('server = B, pod = Bob')) + ).toBeVisible(); + + // Collapse all rows using keyboard shortcut: d + Shift+C + await page.keyboard.press('d'); + await page.keyboard.press('Shift+C'); + + await expect(panelContents).toHaveCount(0); + await expect(page.getByText('server = A, pod = Bob')).toBeHidden(); + await expect(page.getByText('server = B, pod = Bob')).toBeHidden(); + + // Expand all rows using keyboard shortcut: d + Shift+E + await page.keyboard.press('d'); + await page.keyboard.press('Shift+E'); + + await expect(panelContents).toHaveCount(6); + await expect(page.getByText('server = A, pod = Bob')).toBeVisible(); + await expect(page.getByText('server = B, pod = Bob')).toBeVisible(); + }); + + test('should open panel inspect', async ({ gotoDashboardPage, page, selectors }) => { + const dashboardPage = await gotoDashboardPage({ uid: 'edediimbjhdz4b/a-tall-dashboard' }); + + // Find Panel #1 and press 'i' to open inspector + const panel1 = dashboardPage.getByGrafanaSelector(selectors.components.Panels.Panel.title('Panel #1')); + await expect(panel1).toBeVisible(); + await panel1.press('i'); + + await expect(dashboardPage.getByGrafanaSelector(selectors.components.PanelInspector.Json.content)).toBeVisible(); + + // Press Escape to close inspector + await page.keyboard.press('Escape'); + + await expect(page.getByTestId(selectors.components.PanelInspector.Json.content)).toBeHidden(); + }); +}); diff --git a/e2e/cypress/plugins/typescriptPreprocessor.js b/e2e/cypress/plugins/typescriptPreprocessor.js index 27765380994..ed054f6f943 100644 --- a/e2e/cypress/plugins/typescriptPreprocessor.js +++ b/e2e/cypress/plugins/typescriptPreprocessor.js @@ -18,6 +18,7 @@ const webpackOptions = { }, resolve: { extensions: ['.ts', '.js'], + conditionNames: ['@grafana-app/source', '...'], }, }; diff --git a/eslint-suppressions.json b/eslint-suppressions.json index e98c47ddfac..597f2b94a1a 100644 --- a/eslint-suppressions.json +++ b/eslint-suppressions.json @@ -763,11 +763,6 @@ "count": 1 } }, - "packages/grafana-ui/src/components/Select/resetSelectStyles.ts": { - "@typescript-eslint/no-explicit-any": { - "count": 1 - } - }, "packages/grafana-ui/src/components/Select/types.ts": { "@typescript-eslint/no-explicit-any": { "count": 6 @@ -1432,22 +1427,6 @@ "count": 1 } }, - "public/app/features/alerting/unified/components/receivers/form/ChannelOptions.tsx": { - "@typescript-eslint/consistent-type-assertions": { - "count": 1 - }, - "@typescript-eslint/no-explicit-any": { - "count": 2 - }, - "no-restricted-syntax": { - "count": 1 - } - }, - "public/app/features/alerting/unified/components/receivers/form/ChannelSubForm.tsx": { - "no-restricted-syntax": { - "count": 1 - } - }, "public/app/features/alerting/unified/components/receivers/form/CloudCommonChannelSettings.tsx": { "no-restricted-syntax": { "count": 1 @@ -1458,17 +1437,6 @@ "count": 1 } }, - "public/app/features/alerting/unified/components/receivers/form/ReceiverForm.tsx": { - "@typescript-eslint/consistent-type-assertions": { - "count": 2 - }, - "@typescript-eslint/no-explicit-any": { - "count": 1 - }, - "no-restricted-syntax": { - "count": 1 - } - }, "public/app/features/alerting/unified/components/receivers/form/fields/OptionField.tsx": { "@typescript-eslint/consistent-type-assertions": { "count": 1 @@ -1920,11 +1888,6 @@ "count": 1 } }, - "public/app/features/dashboard-scene/serialization/angularMigration.test.ts": { - "@typescript-eslint/no-explicit-any": { - "count": 1 - } - }, "public/app/features/dashboard-scene/serialization/buildNewDashboardSaveModel.ts": { "@typescript-eslint/consistent-type-assertions": { "count": 1 @@ -1948,11 +1911,6 @@ "count": 1 } }, - "public/app/features/dashboard-scene/settings/JsonModelEditView.tsx": { - "react/no-unescaped-entities": { - "count": 2 - } - }, "public/app/features/dashboard-scene/settings/variables/VariableEditableElement.tsx": { "react-hooks/rules-of-hooks": { "count": 4 @@ -2429,11 +2387,6 @@ "count": 1 } }, - "public/app/features/datasources/components/DataSourceLoadError.tsx": { - "no-restricted-syntax": { - "count": 1 - } - }, "public/app/features/datasources/components/DataSourcePluginState.tsx": { "no-restricted-syntax": { "count": 3 @@ -3107,11 +3060,6 @@ "count": 2 } }, - "public/app/features/teams/TeamGroupSync.tsx": { - "react-prefer-function-component/react-prefer-function-component": { - "count": 1 - } - }, "public/app/features/templating/fieldAccessorCache.ts": { "@typescript-eslint/no-explicit-any": { "count": 1 @@ -4288,9 +4236,6 @@ } }, "public/app/plugins/panel/geomap/components/DebugOverlay.tsx": { - "@grafana/no-aria-label-selectors": { - "count": 1 - }, "react-prefer-function-component/react-prefer-function-component": { "count": 1 } @@ -4384,7 +4329,7 @@ }, "public/app/plugins/panel/heatmap/utils.ts": { "@typescript-eslint/consistent-type-assertions": { - "count": 16 + "count": 14 } }, "public/app/plugins/panel/histogram/Histogram.tsx": { diff --git a/go.mod b/go.mod index 91d8a0a42fc..fb1ab1ce189 100644 --- a/go.mod +++ b/go.mod @@ -46,7 +46,7 @@ require ( github.com/blevesearch/bleve_index_api v1.2.7 // @grafana/grafana-search-and-storage github.com/blugelabs/bluge v0.2.2 // @grafana/grafana-backend-group github.com/blugelabs/bluge_segment_api v0.2.0 // @grafana/grafana-backend-group - github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874 // @grafana/grafana-backend-group + github.com/bradfitz/gomemcache v0.0.0-20250403215159-8d39553ac7cf // @grafana/grafana-backend-group github.com/bwmarrin/snowflake v0.3.0 // @grafana/grafana-app-platform-squad github.com/centrifugal/centrifuge v0.38.0 // @grafana/grafana-app-platform-squad github.com/crewjam/saml v0.4.14 // @grafana/identity-access-team @@ -97,8 +97,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.48.5 // @grafana/grafana-app-platform-squad - github.com/grafana/grafana-app-sdk/logging v0.48.3 // @grafana/grafana-app-platform-squad + github.com/grafana/grafana-app-sdk v0.48.7 // @grafana/grafana-app-platform-squad + github.com/grafana/grafana-app-sdk/logging v0.48.7 // @grafana/grafana-app-platform-squad github.com/grafana/grafana-aws-sdk v1.3.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 @@ -157,7 +157,7 @@ require ( github.com/prometheus/alertmanager v0.28.2 // @grafana/alerting-backend github.com/prometheus/client_golang v1.23.2 // @grafana/alerting-backend github.com/prometheus/client_model v0.6.2 // @grafana/grafana-backend-group - github.com/prometheus/common v0.67.3 // @grafana/alerting-backend + github.com/prometheus/common v0.67.4 // @grafana/alerting-backend github.com/prometheus/prometheus v0.303.1 // @grafana/alerting-backend github.com/prometheus/sigv4 v0.1.2 // @grafana/alerting-backend github.com/puzpuzpuz/xsync/v4 v4.2.0 // @grafana/grafana-backend-group @@ -166,7 +166,7 @@ require ( github.com/rs/cors v1.11.1 // @grafana/identity-access-team github.com/russellhaering/goxmldsig v1.4.0 // @grafana/grafana-backend-group github.com/shopspring/decimal v1.4.0 // @grafana/grafana-datasources-core-services - github.com/spf13/cobra v1.10.1 // @grafana/grafana-app-platform-squad + github.com/spf13/cobra v1.10.2 // @grafana/grafana-app-platform-squad github.com/spf13/pflag v1.0.10 // @grafana-app-platform-squad github.com/spyzhov/ajson v0.9.6 // @grafana/grafana-sharing-squad github.com/stretchr/testify v1.11.1 // @grafana/grafana-backend-group @@ -182,17 +182,17 @@ require ( 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.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/google.golang.org/grpc/otelgrpc v0.64.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 + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.64.0 // @grafana/sharing-squad go.opentelemetry.io/contrib/propagators/jaeger v1.38.0 // @grafana/grafana-backend-group go.opentelemetry.io/contrib/samplers/jaegerremote v0.32.0 // @grafana/grafana-backend-group - go.opentelemetry.io/otel v1.38.0 // @grafana/grafana-backend-group + go.opentelemetry.io/otel v1.39.0 // @grafana/grafana-backend-group go.opentelemetry.io/otel/exporters/jaeger v1.17.0 // @grafana/grafana-backend-group - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 // @grafana/grafana-backend-group - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 // @grafana/grafana-backend-group - go.opentelemetry.io/otel/sdk v1.38.0 // @grafana/grafana-backend-group - go.opentelemetry.io/otel/trace v1.38.0 // @grafana/grafana-backend-group + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0 // @grafana/grafana-backend-group + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0 // @grafana/grafana-backend-group + go.opentelemetry.io/otel/sdk v1.39.0 // @grafana/grafana-backend-group + go.opentelemetry.io/otel/trace v1.39.0 // @grafana/grafana-backend-group go.uber.org/atomic v1.11.0 // @grafana/alerting-backend go.uber.org/goleak v1.3.0 // @grafana/grafana-search-and-storage go.uber.org/mock v0.6.0 // @grafana/grafana-operator-experience-squad @@ -200,30 +200,30 @@ require ( go.yaml.in/yaml/v3 v3.0.4 // @grafana/alerting-backend 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.45.0 // @grafana/grafana-backend-group - golang.org/x/exp v0.0.0-20251002181428-27f1f14c8bb9 // @grafana/alerting-backend - golang.org/x/mod v0.30.0 // indirect; @grafana/grafana-backend-group - golang.org/x/net v0.47.0 // @grafana/oss-big-tent @grafana/partner-datasources - golang.org/x/oauth2 v0.33.0 // @grafana/identity-access-team - golang.org/x/sync v0.18.0 // @grafana/alerting-backend - golang.org/x/text v0.31.0 // @grafana/grafana-backend-group + golang.org/x/crypto v0.46.0 // @grafana/grafana-backend-group + golang.org/x/exp v0.0.0-20251209150349-8475f28825e9 // @grafana/alerting-backend + golang.org/x/mod v0.31.0 // indirect; @grafana/grafana-backend-group + golang.org/x/net v0.48.0 // @grafana/oss-big-tent @grafana/partner-datasources + golang.org/x/oauth2 v0.34.0 // @grafana/identity-access-team + golang.org/x/sync v0.19.0 // @grafana/alerting-backend + golang.org/x/text v0.32.0 // @grafana/grafana-backend-group golang.org/x/time v0.14.0 // @grafana/grafana-backend-group - golang.org/x/tools v0.39.0 // indirect; @grafana/grafana-as-code + golang.org/x/tools v0.40.0 // indirect; @grafana/grafana-as-code gonum.org/v1/gonum v0.16.0 // @grafana/oss-big-tent google.golang.org/api v0.242.0 // @grafana/grafana-backend-group google.golang.org/grpc v1.77.0 // @grafana/plugins-platform-backend - google.golang.org/protobuf v1.36.10 // @grafana/plugins-platform-backend + google.golang.org/protobuf v1.36.11 // @grafana/plugins-platform-backend gopkg.in/ini.v1 v1.67.0 // @grafana/alerting-backend gopkg.in/mail.v2 v2.3.1 // @grafana/grafana-backend-group - k8s.io/api v0.34.2 // @grafana/grafana-app-platform-squad - k8s.io/apimachinery v0.34.2 // @grafana/grafana-app-platform-squad - k8s.io/apiserver v0.34.2 // @grafana/grafana-app-platform-squad - k8s.io/client-go v0.34.2 // @grafana/grafana-app-platform-squad - k8s.io/component-base v0.34.2 // @grafana/grafana-app-platform-squad + k8s.io/api v0.34.3 // @grafana/grafana-app-platform-squad + k8s.io/apimachinery v0.34.3 // @grafana/grafana-app-platform-squad + k8s.io/apiserver v0.34.3 // @grafana/grafana-app-platform-squad + k8s.io/client-go v0.34.3 // @grafana/grafana-app-platform-squad + k8s.io/component-base v0.34.3 // @grafana/grafana-app-platform-squad k8s.io/klog/v2 v2.130.1 // @grafana/grafana-app-platform-squad - k8s.io/kube-aggregator v0.34.2 // @grafana/grafana-app-platform-squad - k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 // @grafana/grafana-app-platform-squad - k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 // @grafana/partner-datasources + k8s.io/kube-aggregator v0.34.3 // @grafana/grafana-app-platform-squad + k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e // @grafana/grafana-app-platform-squad + k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 // @grafana/partner-datasources modernc.org/sqlite v1.40.1 // @grafana/grafana-backend-group pgregory.net/rapid v1.2.0 // @grafana/grafana-operator-experience-squad sigs.k8s.io/randfill v1.0.0 // @grafana/grafana-app-platform-squad @@ -295,7 +295,7 @@ replace ( ) require ( - cel.dev/expr v0.24.0 // indirect + cel.dev/expr v0.25.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 @@ -303,7 +303,7 @@ require ( cloud.google.com/go/iam v1.5.2 // indirect cloud.google.com/go/longrunning v0.6.7 // indirect cloud.google.com/go/monitoring v1.24.2 // indirect - cuelabs.dev/go/oci/ociregistry v0.0.0-20240906074133-82eb438dd565 // indirect + cuelabs.dev/go/oci/ociregistry v0.0.0-20251212221603-3adeb8663819 // indirect github.com/Azure/azure-pipeline-go v0.2.3 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2 // indirect github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.1 // indirect @@ -397,7 +397,7 @@ require ( github.com/containerd/errdefs v1.0.0 // indirect github.com/containerd/errdefs/pkg v0.3.0 // indirect github.com/coreos/go-semver v0.3.1 // indirect - github.com/coreos/go-systemd/v22 v22.5.0 // indirect + github.com/coreos/go-systemd/v22 v22.6.0 // 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/dennwc/varint v1.0.0 // indirect @@ -413,7 +413,7 @@ require ( github.com/dolthub/maphash v0.1.0 // indirect github.com/edsrzf/mmap-go v1.2.0 // indirect github.com/elazarl/goproxy v1.7.2 // indirect - github.com/emicklei/proto v1.13.2 // indirect + github.com/emicklei/proto v1.14.2 // indirect github.com/emirpasic/gods v1.18.1 // indirect github.com/envoyproxy/go-control-plane/envoy v1.35.0 // indirect github.com/envoyproxy/protoc-gen-validate v1.2.1 // indirect @@ -427,10 +427,10 @@ require ( github.com/go-logr/stdr v1.2.2 // 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/jsonpointer v0.22.4 // indirect + github.com/go-openapi/jsonreference v0.21.4 // indirect github.com/go-openapi/spec v0.22.0 // indirect - github.com/go-openapi/swag v0.23.1 // indirect + github.com/go-openapi/swag v0.25.4 // indirect github.com/go-openapi/validate v0.25.0 // indirect github.com/go-viper/mapstructure/v2 v2.4.0 // indirect github.com/goccy/go-json v0.10.5 // indirect @@ -445,7 +445,7 @@ require ( github.com/google/btree v1.1.3 // indirect github.com/google/cel-go v0.26.1 // indirect github.com/google/flatbuffers v25.2.10+incompatible // indirect - github.com/google/gnostic-models v0.7.0 // indirect + github.com/google/gnostic-models v0.7.1 // indirect github.com/google/go-github/v64 v64.0.0 // indirect github.com/google/s2a-go v0.1.9 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect @@ -501,7 +501,7 @@ require ( github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect github.com/lestrrat-go/strftime v1.0.4 // indirect github.com/magefile/mage v1.15.0 // indirect - github.com/mailru/easyjson v0.9.0 // indirect + github.com/mailru/easyjson v0.9.1 // indirect github.com/matryer/is v1.4.1 // indirect github.com/mattbaird/jsonpatch v0.0.0-20240118010651-0ba75a80ca38 // indirect github.com/mattermost/xml-roundtrip-validator v0.1.0 // indirect @@ -559,8 +559,8 @@ require ( github.com/pressly/goose/v3 v3.26.0 // 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/protocolbuffers/txtpbfmt v0.0.0-20241112170944-20d2c9ebc01d // indirect + github.com/prometheus/procfs v0.19.2 // indirect + github.com/protocolbuffers/txtpbfmt v0.0.0-20251124094003-fcb97cc64c7b // indirect github.com/puzpuzpuz/xsync/v2 v2.5.1 // indirect github.com/redis/rueidis v1.0.68 // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect @@ -595,7 +595,7 @@ require ( github.com/unknwon/log v0.0.0-20200308114134-929b1006e34a // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect - github.com/woodsbury/decimal128 v1.3.0 // indirect + github.com/woodsbury/decimal128 v1.4.0 // indirect github.com/x448/float16 v0.8.4 // indirect github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 // indirect @@ -604,9 +604,9 @@ require ( github.com/zclconf/go-cty v1.16.3 // indirect github.com/zeebo/xxh3 v1.0.2 // indirect go.etcd.io/bbolt v1.4.2 // indirect - go.etcd.io/etcd/api/v3 v3.6.4 // indirect - go.etcd.io/etcd/client/pkg/v3 v3.6.4 // indirect - go.etcd.io/etcd/client/v3 v3.6.4 // indirect + go.etcd.io/etcd/api/v3 v3.6.6 // indirect + go.etcd.io/etcd/client/pkg/v3 v3.6.6 // indirect + go.etcd.io/etcd/client/v3 v3.6.6 // indirect go.mongodb.org/mongo-driver v1.17.4 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/collector/featuregate v1.44.0 // indirect @@ -618,29 +618,29 @@ require ( go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.12.2 // indirect go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.38.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.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.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 + go.opentelemetry.io/otel/metric v1.39.0 // indirect go.opentelemetry.io/otel/sdk/log v0.12.2 // indirect - go.opentelemetry.io/otel/sdk/metric v1.38.0 // indirect + go.opentelemetry.io/otel/sdk/metric v1.39.0 // indirect go.opentelemetry.io/proto/otlp v1.9.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect go4.org/netipx v0.0.0-20230125063823-8449b0a6169f // indirect - golang.org/x/sys v0.38.0 // indirect - golang.org/x/telemetry v0.0.0-20251111182119-bc8e575c7b54 // indirect - golang.org/x/term v0.37.0 // indirect + golang.org/x/sys v0.39.0 // indirect + golang.org/x/telemetry v0.0.0-20251203150158-8fff8a5912fc // indirect + golang.org/x/term v0.38.0 // 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-20250715232539-7130f93afb79 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20251111163417-95abcf5c77ba // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2 // indirect gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect - gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect + gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect gopkg.in/fsnotify/fsnotify.v1 v1.4.7 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect @@ -648,13 +648,13 @@ require ( 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/apiextensions-apiserver v0.34.2 // indirect - k8s.io/kms v0.34.2 // indirect + k8s.io/apiextensions-apiserver v0.34.3 // indirect + k8s.io/kms v0.34.3 // indirect modernc.org/libc v1.66.10 // indirect modernc.org/mathutil v1.7.1 // indirect modernc.org/memory v1.11.0 // indirect - sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2 // indirect - sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect + sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.34.0 // indirect + sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect sigs.k8s.io/yaml v1.6.0 // indirect ) @@ -668,15 +668,17 @@ require ( github.com/cpuguy83/dockercfg v0.3.2 // indirect github.com/ebitengine/purego v0.8.2 // indirect github.com/go-ole/go-ole v1.2.6 // 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/swag/cmdutils v0.25.4 // indirect + github.com/go-openapi/swag/conv v0.25.4 // indirect + github.com/go-openapi/swag/fileutils v0.25.4 // indirect + github.com/go-openapi/swag/jsonname v0.25.4 // indirect + github.com/go-openapi/swag/jsonutils v0.25.4 // indirect + github.com/go-openapi/swag/loading v0.25.4 // indirect + github.com/go-openapi/swag/mangling v0.25.4 // indirect + github.com/go-openapi/swag/netutils v0.25.4 // indirect + github.com/go-openapi/swag/stringutils v0.25.4 // indirect + github.com/go-openapi/swag/typeutils v0.25.4 // indirect + github.com/go-openapi/swag/yamlutils v0.25.4 // indirect github.com/lufia/plan9stats v0.0.0-20240909124753-873cd0166683 // indirect github.com/magiconair/properties v1.8.10 // indirect github.com/moby/go-archive v0.1.0 // indirect diff --git a/go.sum b/go.sum index d056a11c1cb..c1a8d8ad808 100644 --- a/go.sum +++ b/go.sum @@ -4,8 +4,8 @@ buf.build/gen/go/parca-dev/parca/protocolbuffers/go v1.36.2-20250703125925-3f0fc buf.build/gen/go/parca-dev/parca/protocolbuffers/go v1.36.2-20250703125925-3f0fcf4bff96.1/go.mod h1:1M7nlq2ljfzb95x9LaA2j1gYIvDkVZii58mGvTa9ExM= c2sp.org/CCTV/age v0.0.0-20240306222714-3ec4d716e805 h1:u2qwJeEvnypw+OCPUHmoZE3IqwfuN5kgDfo5MLzpNM0= c2sp.org/CCTV/age v0.0.0-20240306222714-3ec4d716e805/go.mod h1:FomMrUJ2Lxt5jCLmZkG3FHa72zUprnhd3v/Z18Snm4w= -cel.dev/expr v0.24.0 h1:56OvJKSH3hDGL0ml5uSxZmz3/3Pq4tJ+fb1unVLAFcY= -cel.dev/expr v0.24.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw= +cel.dev/expr v0.25.1 h1:1KrZg61W6TWSxuNZ37Xy49ps13NUovb66QLprthtwi4= +cel.dev/expr v0.25.1/go.mod h1:hrXvqGP6G6gyx8UAHSHJ5RGk//1Oj5nXQ2NI02Nrsg4= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7hw= @@ -630,8 +630,8 @@ cloud.google.com/go/workflows v1.10.0/go.mod h1:fZ8LmRmZQWacon9UCX1r/g/DfAXx5VcP connectrpc.com/connect v1.18.1 h1:PAg7CjSAGvscaf6YZKUefjoih5Z/qYkyaTrBW8xvYPw= connectrpc.com/connect v1.18.1/go.mod h1:0292hj1rnx8oFrStN7cB4jjVBeqs+Yx5yDIC2prWDO8= contrib.go.opencensus.io/exporter/ocagent v0.6.0/go.mod h1:zmKjrJcdo0aYcVS7bmEeSEBLPA9YJp5bjrofdU3pIXs= -cuelabs.dev/go/oci/ociregistry v0.0.0-20240906074133-82eb438dd565 h1:R5wwEcbEZSBmeyg91MJZTxfd7WpBo2jPof3AYjRbxwY= -cuelabs.dev/go/oci/ociregistry v0.0.0-20240906074133-82eb438dd565/go.mod h1:5A4xfTzHTXfeVJBU6RAUf+QrlfTCW+017q/QiW+sMLg= +cuelabs.dev/go/oci/ociregistry v0.0.0-20251212221603-3adeb8663819 h1:Zh+Ur3OsoWpvALHPLT45nOekHkgOt+IOfutBbPqM17I= +cuelabs.dev/go/oci/ociregistry v0.0.0-20251212221603-3adeb8663819/go.mod h1:WjmQxb+W6nVNCgj8nXrF24lIz95AHwnSl36tpjDZSU8= cuelang.org/go v0.11.1 h1:pV+49MX1mmvDm8Qh3Za3M786cty8VKPWzQ1Ho4gZRP0= cuelang.org/go v0.11.1/go.mod h1:PBY6XvPUswPPJ2inpvUozP9mebDVTXaeehQikhZPBz0= dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8= @@ -982,8 +982,8 @@ github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvF github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= -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/bradfitz/gomemcache v0.0.0-20250403215159-8d39553ac7cf h1:TqhNAT4zKbTdLa62d2HDBFdvgSbIGB3eJE8HqhgiL9I= +github.com/bradfitz/gomemcache v0.0.0-20250403215159-8d39553ac7cf/go.mod h1:r5xuitiExdLAJ09PR7vBVENGvp4ZuTBeWTGtxuX3K+c= 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= @@ -1064,8 +1064,9 @@ github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3Ee github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4= github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= -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/coreos/go-systemd/v22 v22.6.0 h1:aGVa/v8B7hpb0TKl0MWoAavPDmHvobFe5R5zn0bCJWo= +github.com/coreos/go-systemd/v22 v22.6.0/go.mod h1:iG+pp635Fo7ZmV/j14KUcmEyWF+0X7Lua8rrTWzYgWU= 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/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= @@ -1156,8 +1157,8 @@ github.com/elazarl/goproxy v1.7.2/go.mod h1:82vkLNir0ALaW14Rc399OTTjyNREgmdL2cVo github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= 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/emicklei/proto v1.13.2 h1:z/etSFO3uyXeuEsVPzfl56WNgzcvIr42aQazXaQmFZY= -github.com/emicklei/proto v1.13.2/go.mod h1:rn1FgRS/FANiZdD2djyH7TMA9jdRDcYQ9IEN9yvjX0A= +github.com/emicklei/proto v1.14.2 h1:wJPxPy2Xifja9cEMrcA/g08art5+7CGJNFNk35iXC1I= +github.com/emicklei/proto v1.14.2/go.mod h1:rn1FgRS/FANiZdD2djyH7TMA9jdRDcYQ9IEN9yvjX0A= 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= @@ -1287,16 +1288,16 @@ github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwds github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= github.com/go-openapi/jsonpointer v0.20.1/go.mod h1:bHen+N0u1KEO3YlmqOjTT9Adn1RfD91Ar825/PuiRVs= github.com/go-openapi/jsonpointer v0.20.2/go.mod h1:bHen+N0u1KEO3YlmqOjTT9Adn1RfD91Ar825/PuiRVs= -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/jsonpointer v0.22.4 h1:dZtK82WlNpVLDW2jlA1YCiVJFVqkED1MegOUy9kR5T4= +github.com/go-openapi/jsonpointer v0.22.4/go.mod h1:elX9+UgznpFhgBuaMQ7iu4lvvX1nvNsesQ3oxmYTw80= github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= github.com/go-openapi/jsonreference v0.18.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= github.com/go-openapi/jsonreference v0.20.3/go.mod h1:FviDZ46i9ivh810gqzFLl5NttD5q3tSlMLqLr6okedM= github.com/go-openapi/jsonreference v0.20.4/go.mod h1:5pZJyJP2MnYCpoeoMAql78cCHauHj0V9Lhc506VOpw4= -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/jsonreference v0.21.4 h1:24qaE2y9bx/q3uRK/qN+TDwbok1NhbSmGjjySRCHtC8= +github.com/go-openapi/jsonreference v0.21.4/go.mod h1:rIENPTjDbLpzQmQWCj5kKj3ZlmEh+EFVbz3RTUh30/4= github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= github.com/go-openapi/loads v0.18.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= github.com/go-openapi/loads v0.19.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= @@ -1336,28 +1337,36 @@ github.com/go-openapi/swag v0.19.4/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh github.com/go-openapi/swag v0.22.5/go.mod h1:Gl91UqO+btAM0plGGxHqJcQZ1ZTy6jbmridBTsDy8A0= github.com/go-openapi/swag v0.22.6/go.mod h1:Gl91UqO+btAM0plGGxHqJcQZ1ZTy6jbmridBTsDy8A0= github.com/go-openapi/swag v0.22.9/go.mod h1:3/OXnFfnMAwBD099SwYRk7GD3xOrr1iL7d/XNLXVVwE= -github.com/go-openapi/swag v0.23.1 h1:lpsStH0n2ittzTnbaSloVZLuB5+fvSY/+hnagBjSNZU= -github.com/go-openapi/swag v0.23.1/go.mod h1:STZs8TbRvEQQKUA+JZNAm3EWlgaOBGpyFDqQnDHMef0= -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/swag v0.25.4 h1:OyUPUFYDPDBMkqyxOTkqDYFnrhuhi9NR6QVUvIochMU= +github.com/go-openapi/swag v0.25.4/go.mod h1:zNfJ9WZABGHCFg2RnY0S4IOkAcVTzJ6z2Bi+Q4i6qFQ= +github.com/go-openapi/swag/cmdutils v0.25.4 h1:8rYhB5n6WawR192/BfUu2iVlxqVR9aRgGJP6WaBoW+4= +github.com/go-openapi/swag/cmdutils v0.25.4/go.mod h1:pdae/AFo6WxLl5L0rq87eRzVPm/XRHM3MoYgRMvG4A0= +github.com/go-openapi/swag/conv v0.25.4 h1:/Dd7p0LZXczgUcC/Ikm1+YqVzkEeCc9LnOWjfkpkfe4= +github.com/go-openapi/swag/conv v0.25.4/go.mod h1:3LXfie/lwoAv0NHoEuY1hjoFAYkvlqI/Bn5EQDD3PPU= +github.com/go-openapi/swag/fileutils v0.25.4 h1:2oI0XNW5y6UWZTC7vAxC8hmsK/tOkWXHJQH4lKjqw+Y= +github.com/go-openapi/swag/fileutils v0.25.4/go.mod h1:cdOT/PKbwcysVQ9Tpr0q20lQKH7MGhOEb6EwmHOirUk= +github.com/go-openapi/swag/jsonname v0.25.4 h1:bZH0+MsS03MbnwBXYhuTttMOqk+5KcQ9869Vye1bNHI= +github.com/go-openapi/swag/jsonname v0.25.4/go.mod h1:GPVEk9CWVhNvWhZgrnvRA6utbAltopbKwDu8mXNUMag= +github.com/go-openapi/swag/jsonutils v0.25.4 h1:VSchfbGhD4UTf4vCdR2F4TLBdLwHyUDTd1/q4i+jGZA= +github.com/go-openapi/swag/jsonutils v0.25.4/go.mod h1:7OYGXpvVFPn4PpaSdPHJBtF0iGnbEaTk8AvBkoWnaAY= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4 h1:IACsSvBhiNJwlDix7wq39SS2Fh7lUOCJRmx/4SN4sVo= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4/go.mod h1:Mt0Ost9l3cUzVv4OEZG+WSeoHwjWLnarzMePNDAOBiM= +github.com/go-openapi/swag/loading v0.25.4 h1:jN4MvLj0X6yhCDduRsxDDw1aHe+ZWoLjW+9ZQWIKn2s= +github.com/go-openapi/swag/loading v0.25.4/go.mod h1:rpUM1ZiyEP9+mNLIQUdMiD7dCETXvkkC30z53i+ftTE= +github.com/go-openapi/swag/mangling v0.25.4 h1:2b9kBJk9JvPgxr36V23FxJLdwBrpijI26Bx5JH4Hp48= +github.com/go-openapi/swag/mangling v0.25.4/go.mod h1:6dxwu6QyORHpIIApsdZgb6wBk/DPU15MdyYj/ikn0Hg= +github.com/go-openapi/swag/netutils v0.25.4 h1:Gqe6K71bGRb3ZQLusdI8p/y1KLgV4M/k+/HzVSqT8H0= +github.com/go-openapi/swag/netutils v0.25.4/go.mod h1:m2W8dtdaoX7oj9rEttLyTeEFFEBvnAx9qHd5nJEBzYg= +github.com/go-openapi/swag/stringutils v0.25.4 h1:O6dU1Rd8bej4HPA3/CLPciNBBDwZj9HiEpdVsb8B5A8= +github.com/go-openapi/swag/stringutils v0.25.4/go.mod h1:GTsRvhJW5xM5gkgiFe0fV3PUlFm0dr8vki6/VSRaZK0= +github.com/go-openapi/swag/typeutils v0.25.4 h1:1/fbZOUN472NTc39zpa+YGHn3jzHWhv42wAJSN91wRw= +github.com/go-openapi/swag/typeutils v0.25.4/go.mod h1:Ou7g//Wx8tTLS9vG0UmzfCsjZjKhpjxayRKTHXf2pTE= +github.com/go-openapi/swag/yamlutils v0.25.4 h1:6jdaeSItEUb7ioS9lFoCZ65Cne1/RZtPBZ9A56h92Sw= +github.com/go-openapi/swag/yamlutils v0.25.4/go.mod h1:MNzq1ulQu+yd8Kl7wPOut/YHAAU/H6hL91fF+E2RFwc= +github.com/go-openapi/testify/enable/yaml/v2 v2.0.2 h1:0+Y41Pz1NkbTHz8NngxTuAXxEodtNSI1WG1c/m5Akw4= +github.com/go-openapi/testify/enable/yaml/v2 v2.0.2/go.mod h1:kme83333GCtJQHXQ8UKX3IBZu6z8T5Dvy5+CW3NLUUg= +github.com/go-openapi/testify/v2 v2.0.2 h1:X999g3jeLcoY8qctY/c/Z8iBHTbwLz7R2WXd6Ub6wls= +github.com/go-openapi/testify/v2 v2.0.2/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4= github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA= github.com/go-openapi/validate v0.22.4/go.mod h1:qm6O8ZIcPVdSY5219468Jv7kBdGvkiZLPOmqnqTUZ2A= @@ -1490,8 +1499,8 @@ github.com/google/cel-go v0.26.1/go.mod h1:A9O8OU9rdvrK5MQyrqfIxo1a0u4g3sF8KB6PU github.com/google/flatbuffers v2.0.8+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= 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.7.0 h1:qwTtogB15McXDaNqTZdzPJRHvaVJlAl+HVQnLmJEJxo= -github.com/google/gnostic-models v0.7.0/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ= +github.com/google/gnostic-models v0.7.1 h1:SisTfuFKJSKM5CPZkffwi6coztzzeYUhc3v4yxLWH8c= +github.com/google/gnostic-models v0.7.1/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= @@ -1635,10 +1644,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.48.5 h1:MS8l9fTZz+VbTfgApn09jw27GxhQ6fNOWGhC4ydvZmM= -github.com/grafana/grafana-app-sdk v0.48.5/go.mod h1:HJsMOSBmt/D/Ihs1SvagOwmXKi0coBMVHlfvdd+qe9Y= -github.com/grafana/grafana-app-sdk/logging v0.48.3 h1:72NUpGNiJXCNQz/on++YSsl38xuVYYBKv5kKQaOClX4= -github.com/grafana/grafana-app-sdk/logging v0.48.3/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA= +github.com/grafana/grafana-app-sdk v0.48.7 h1:9mF7nqkqP0QUYYDlznoOt+GIyjzj45wGfUHB32u2ZMo= +github.com/grafana/grafana-app-sdk v0.48.7/go.mod h1:DWsaaH39ZMHwSOSoUBaeW8paMrRaYsjRYlLwCJYd78k= +github.com/grafana/grafana-app-sdk/logging v0.48.7 h1:Oa5qg473gka5+W/WQk61Xbw4YdAv+wV2Z4bJtzeCaQw= +github.com/grafana/grafana-app-sdk/logging v0.48.7/go.mod h1:5u3KalezoBAAo2Y3ytDYDAIIPvEqFLLDSxeiK99QxDU= github.com/grafana/grafana-aws-sdk v1.3.0 h1:/bfJzP93rCel1GbWoRSq0oUo424MZXt8jAp2BK9w8tM= github.com/grafana/grafana-aws-sdk v1.3.0/go.mod h1:VGycF0JkCGKND2O5je1ucOqPJ0ZNhZYzV3c2bNBAaGk= github.com/grafana/grafana-azure-sdk-go/v2 v2.3.1 h1:FFcEA01tW+SmuJIuDbHOdgUBL+d7DPrZ2N4zwzPhfGk= @@ -1979,8 +1988,8 @@ github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -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/mailru/easyjson v0.9.1 h1:LbtsOm5WAswyWbvTEOqhypdPeZzHavpZx96/n553mR8= +github.com/mailru/easyjson v0.9.1/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA= github.com/matryer/is v1.4.1 h1:55ehd8zaGABKLXQUe2awZ99BD/PTc2ls+KV/dXphgEQ= github.com/matryer/is v1.4.1/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= @@ -2299,8 +2308,8 @@ github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGy github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc= github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8= github.com/prometheus/common v0.60.1/go.mod h1:h0LYf1R1deLSKtD4Vdg8gy4RuOvENW2J/h19V5NADQw= -github.com/prometheus/common v0.67.3 h1:shd26MlnwTw5jksTDhC7rTQIteBxy+ZZDr3t7F2xN2Q= -github.com/prometheus/common v0.67.3/go.mod h1:gP0fq6YjjNCLssJCQp0yk4M8W6ikLURwkdd/YKtTbyI= +github.com/prometheus/common v0.67.4 h1:yR3NqWO1/UyO1w2PhUvXlGQs/PtFmoveVO0KZ4+Lvsc= +github.com/prometheus/common v0.67.4/go.mod h1:gP0fq6YjjNCLssJCQp0yk4M8W6ikLURwkdd/YKtTbyI= github.com/prometheus/common/assets v0.2.0/go.mod h1:D17UVUE12bHbim7HzwUvtqm6gwBEaDQ0F+hIGbFbccI= github.com/prometheus/common/sigv4 v0.1.0 h1:qoVebwtwwEhS85Czm2dSROY5fTo2PAPEVdDeppTwGX4= github.com/prometheus/common/sigv4 v0.1.0/go.mod h1:2Jkxxk9yYvCkE5G1sQT7GuEXm57JrvHu9k5YwTjsNtI= @@ -2321,15 +2330,15 @@ github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB github.com/prometheus/procfs v0.11.1/go.mod h1:eesXgaPo1q7lBpVMoMy0ZOFTth9hBn4W/y0/p/ScXhY= github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= -github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= -github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= +github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws= +github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw= github.com/prometheus/prometheus v0.0.0-20190818123050-43acd0e2e93f/go.mod h1:rMTlmxGCvukf2KMu3fClMDKLLoJ5hl61MhcJ7xKakf0= github.com/prometheus/prometheus v0.303.1 h1:He/2jRE6sB23Ew38AIoR1WRR3fCMgPlJA2E0obD2WSY= github.com/prometheus/prometheus v0.303.1/go.mod h1:WEq2ogBPZoLjj9x5K67VEk7ECR0nRD9XCjaOt1lsYck= github.com/prometheus/sigv4 v0.1.2 h1:R7570f8AoM5YnTUPFm3mjZH5q2k4D+I/phCWvZ4PXG8= github.com/prometheus/sigv4 v0.1.2/go.mod h1:GF9fwrvLgkQwDdQ5BXeV9XUSCH/IPNqzvAoaohfjqMU= -github.com/protocolbuffers/txtpbfmt v0.0.0-20241112170944-20d2c9ebc01d h1:HWfigq7lB31IeJL8iy7jkUmU/PG1Sr8jVGhS749dbUA= -github.com/protocolbuffers/txtpbfmt v0.0.0-20241112170944-20d2c9ebc01d/go.mod h1:jgxiZysxFPM+iWKwQwPR+y+Jvo54ARd4EisXxKYpB5c= +github.com/protocolbuffers/txtpbfmt v0.0.0-20251124094003-fcb97cc64c7b h1:fPVI9E6QNFYI0Ph3XpKUDrcAvbCifHvqYJcntFLPog8= +github.com/protocolbuffers/txtpbfmt v0.0.0-20251124094003-fcb97cc64c7b/go.mod h1:JSbkp0BviKovYYt9XunS95M3mLPibE9bGg+Y95DsEEY= 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/puzpuzpuz/xsync/v4 v4.2.0 h1:dlxm77dZj2c3rxq0/XNvvUKISAmovoXF4a4qM6Wvkr0= @@ -2446,8 +2455,8 @@ github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155 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 v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= -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/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU= +github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= @@ -2546,8 +2555,8 @@ github.com/wk8/go-ordered-map v1.0.0 h1:BV7z+2PaK8LTSd/mWgY12HyMAo5CEgkHqbkVq2th github.com/wk8/go-ordered-map v1.0.0/go.mod h1:9ZIbRunKbuvfPKyBP1SIKLcXNlv74YCOZ3t3VTS6gRk= 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/woodsbury/decimal128 v1.4.0 h1:xJATj7lLu4f2oObouMt2tgGiElE5gO6mSWUjQsBgUlc= +github.com/woodsbury/decimal128 v1.4.0/go.mod h1:BP46FUrVjVhdTbKT+XuQh2xfQaGki9LMIRJSFuh6THU= 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= @@ -2601,15 +2610,15 @@ gitlab.com/nyarla/go-crypt v0.0.0-20160106005555-d9a5dc2b789b/go.mod h1:T3BPAOm2 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.6.4 h1:7F6N7toCKcV72QmoUKa23yYLiiljMrT4xCeBL9BmXdo= -go.etcd.io/etcd/api/v3 v3.6.4/go.mod h1:eFhhvfR8Px1P6SEuLT600v+vrhdDTdcfMzmnxVXXSbk= +go.etcd.io/etcd/api/v3 v3.6.6 h1:mcaMp3+7JawWv69p6QShYWS8cIWUOl32bFLb6qf8pOQ= +go.etcd.io/etcd/api/v3 v3.6.6/go.mod h1:f/om26iXl2wSkcTA1zGQv8reJRSLVdoEBsi4JdfMrx4= go.etcd.io/etcd/client/pkg/v3 v3.5.4/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= -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/pkg/v3 v3.6.6 h1:uoqgzSOv2H9KlIF5O1Lsd8sW+eMLuV6wzE3q5GJGQNs= +go.etcd.io/etcd/client/pkg/v3 v3.6.6/go.mod h1:YngfUVmvsvOJ2rRgStIyHsKtOt9SZI2aBJrZiWJhCbI= 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.6.4 h1:YOMrCfMhRzY8NgtzUsHl8hC2EBSnuqbR3dh84Uryl7A= -go.etcd.io/etcd/client/v3 v3.6.4/go.mod h1:jaNNHCyg2FdALyKWnd7hxZXZxZANb0+KGY+YQaEMISo= +go.etcd.io/etcd/client/v3 v3.6.6 h1:G5z1wMf5B9SNexoxOHUGBaULurOZPIgGPsW6CN492ec= +go.etcd.io/etcd/client/v3 v3.6.6/go.mod h1:36Qv6baQ07znPR3+n7t+Rk5VHEzVYPvFfGmfF4wBHV8= go.etcd.io/etcd/pkg/v3 v3.6.4 h1:fy8bmXIec1Q35/jRZ0KOes8vuFxbvdN0aAFqmEfJZWA= go.etcd.io/etcd/pkg/v3 v3.6.4/go.mod h1:kKcYWP8gHuBRcteyv6MXWSN0+bVMnfgqiHueIZnKMtE= go.etcd.io/etcd/server/v3 v3.6.4 h1:LsCA7CzjVt+8WGrdsnh6RhC0XqCsLkBly3ve5rTxMAU= @@ -2648,14 +2657,14 @@ go.opentelemetry.io/contrib/detectors/gcp v1.38.0 h1:ZoYbqX7OaA/TAikspPl3ozPI6iY go.opentelemetry.io/contrib/detectors/gcp v1.38.0/go.mod h1:SU+iU7nu5ud4oCb3LQOhIZ3nRLj6FNVrKgtflbaf2ts= 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= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0/go.mod h1:fvPi2qXDqFs8M4B4fmJhE92TyQs9Ydjlg3RvfUp+NbQ= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.64.0 h1:RN3ifU8y4prNWeEnQp2kRRHz8UwonAEYZl8tUzHEXAk= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.64.0/go.mod h1:habDz3tEWiFANTo6oUE99EmaFUrCNYAAg3wiVmusm70= go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.55.0/go.mod h1:rsg1EO8LXSs2po50PB5CeY/MSVlhghuKBgXlKnqm6ks= 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.55.0/go.mod h1:DQAwmETtZV00skUwgD6+0U89g80NKsJE3DCKeLLPQMI= -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/instrumentation/net/http/otelhttp v0.64.0 h1:ssfIgGNANqpVFCndZvcuyKbl0g+UAVcbBcqGkG28H0Y= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.64.0/go.mod h1:GQ/474YrbE4Jx8gZ4q5I4hrhUzM6UPzyrqJYV2AqPoQ= 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= @@ -2663,8 +2672,8 @@ go.opentelemetry.io/contrib/samplers/jaegerremote v0.32.0/go.mod h1:B9Oka5QVD0bn go.opentelemetry.io/otel v1.17.0/go.mod h1:I2vmBGtFaODIVMBSTPVDlJSzBDNf93k60E6Ft0nyjo0= go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= go.opentelemetry.io/otel v1.30.0/go.mod h1:tFw4Br9b7fOS+uEao81PJjVMjW/5fvNCbpsDIXqP0pc= -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 v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48= +go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8= 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= @@ -2675,12 +2684,12 @@ go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0 h1:vl9 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/otlp/otlptrace v1.39.0 h1:f0cb2XPmrqn4XMy9PNliTgRKJgS5WcL/u0/WRYGz4t0= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0/go.mod h1:vnakAaFckOMiMtOIhFI2MNH4FYrZzXCYxmb1LlhoGz8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0 h1:in9O8ESIOlwJAEGTkkf34DesGRAc/Pn8qJ7k3r/42LM= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0/go.mod h1:Rp0EXBm5tfnv0WL+ARyO/PHBEaEAT8UUHQ6AGJcSq6c= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0 h1:Ckwye2FpXkYgiHX7fyVrN1uA/UYd9ounqqTuSNAv0k4= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0/go.mod h1:teIFJh5pW2y+AN7riv6IBPX2DuesS3HgP39mwOspKwU= 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= @@ -2694,23 +2703,23 @@ go.opentelemetry.io/otel/log v0.12.2/go.mod h1:ShIItIxSYxufUMt+1H5a2wbckGli3/iCf go.opentelemetry.io/otel/metric v1.17.0/go.mod h1:h4skoxdZI17AxwITdmdZjjYJQH5nzijUUjm+wtPph5o= go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM= go.opentelemetry.io/otel/metric v1.30.0/go.mod h1:aXTfST94tswhWEb+5QjlSqG+cZlmyXy/u8jFpor3WqQ= -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/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0= +go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs= go.opentelemetry.io/otel/sdk v1.17.0/go.mod h1:U87sE0f5vQB7hwUoW98pW5Rz4ZDuCFBZFNUBlSgmDFQ= go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E= -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 v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18= +go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE= 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/log/logtest v0.0.0-20250521073539-a85ae98dcedc h1:uqxdywfHqqCl6LmZzI3pUnXT1RGFYyUgxj0AkWPFxi0= go.opentelemetry.io/otel/sdk/log/logtest v0.0.0-20250521073539-a85ae98dcedc/go.mod h1:TY/N/FT7dmFrP/r5ym3g0yysP1DefqGpAZr4f82P0dE= -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/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8= +go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew= go.opentelemetry.io/otel/trace v1.17.0/go.mod h1:I/4vKTgFclIsXRVucpH25X0mpFSczM7aHeaz0ZBLWjY= go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ= go.opentelemetry.io/otel/trace v1.30.0/go.mod h1:5EyKqTzzmyqB9bwtCCq6pDLktPK6fmGf/Dph+8VI02o= -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/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI= +go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= @@ -2788,8 +2797,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.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q= -golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4= +golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU= +golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0= 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= @@ -2805,8 +2814,8 @@ golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u0 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-20220827204233-334a2380cb91/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE= -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/exp v0.0.0-20251209150349-8475f28825e9 h1:MDfG8Cvcqlt9XXrmEiD4epKn7VJHZO84hejP9Jmp0MM= +golang.org/x/exp v0.0.0-20251209150349-8475f28825e9/go.mod h1:EPRbTFwzwjXj9NpYyyrvenVh9Y+GFeEvMNh7Xuz7xgU= golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= 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= @@ -2852,8 +2861,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.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk= -golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc= +golang.org/x/mod v0.31.0 h1:HaW9xtz0+kOcWKwli0ZXy79Ix+UW/vOfmWI5QVd2tgI= +golang.org/x/mod v0.31.0/go.mod h1:43JraMp9cGx1Rx3AqioxrbrhNsLl2l/iNAvuBkrezpg= 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= @@ -2939,8 +2948,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.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= -golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= +golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= +golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= 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= @@ -2978,8 +2987,8 @@ golang.org/x/oauth2 v0.12.0/go.mod h1:A74bZ3aGXgCY0qaIC9Ahg6Lglin4AMAco8cIv9baba golang.org/x/oauth2 v0.16.0/go.mod h1:hqZ+0LWXsiVoZpeld6jVt06P3adbS2Uu911W1SsJv2o= golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= -golang.org/x/oauth2 v0.33.0 h1:4Q+qn+E5z8gPRJfmRy7C2gGG3T4jIprK6aSYgTXGRpo= -golang.org/x/oauth2 v0.33.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= +golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw= +golang.org/x/oauth2 v0.34.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= @@ -3003,8 +3012,8 @@ golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= -golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 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= @@ -3138,11 +3147,11 @@ golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= -golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= +golang.org/x/sys v0.39.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-20251111182119-bc8e575c7b54 h1:E2/AqCUMZGgd73TQkxUMcMla25GB9i/5HOdLr+uH7Vo= -golang.org/x/telemetry v0.0.0-20251111182119-bc8e575c7b54/go.mod h1:hKdjCMrbv9skySur+Nek8Hd0uJ0GuxJIoIX2payrIdQ= +golang.org/x/telemetry v0.0.0-20251203150158-8fff8a5912fc h1:bH6xUXay0AIFMElXG2rQ4uiE+7ncwtiOdPfYK1NK2XA= +golang.org/x/telemetry v0.0.0-20251203150158-8fff8a5912fc/go.mod h1:hKdjCMrbv9skySur+Nek8Hd0uJ0GuxJIoIX2payrIdQ= 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= @@ -3161,8 +3170,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.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU= -golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254= +golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q= +golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg= 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= @@ -3185,8 +3194,8 @@ golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= -golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= -golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= +golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= +golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= 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= @@ -3271,8 +3280,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.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ= -golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ= +golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA= +golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc= 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= @@ -3521,15 +3530,15 @@ google.golang.org/genproto/googleapis/api v0.0.0-20230525234020-1aefcd67740a/go. 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= google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= -google.golang.org/genproto/googleapis/api v0.0.0-20251111163417-95abcf5c77ba h1:B14OtaXuMaCQsl2deSvNkyPKIzq3BjfxQp8d00QyWx4= -google.golang.org/genproto/googleapis/api v0.0.0-20251111163417-95abcf5c77ba/go.mod h1:G5IanEx8/PgI9w6CFcYQf7jMtHQhZruvfM1i3qOqk5U= +google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2 h1:7LRqPCEdE4TP4/9psdaB7F2nhZFfBiGJomA5sojLWdU= +google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2/go.mod h1:+rXWjjaukWZun3mLfjmVnQi18E1AsFbDN9QdJ5YXLto= google.golang.org/genproto/googleapis/bytestream v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:ylj+BE99M198VPbBh6A8d9n3w8fChvyLK3wwBOjXBFA= google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234015-3fc162c6f38a/go.mod h1:xURIpW9ES5+/GZhnV6beoEtxQrnkRGIfP5VQG2tCBLc= google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= google.golang.org/genproto/googleapis/rpc v0.0.0-20230526203410-71b5a4ffd15e/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba h1:UKgtfRM7Yh93Sya0Fo8ZzhDP4qBckrrxEr2oF5UIVb8= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2 h1:2I6GHUeJ/4shcDpoUlLs/2WPnhg7yJwvXtqcMJt9liA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.18.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= @@ -3600,8 +3609,8 @@ google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= -google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= -google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/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= @@ -3612,8 +3621,8 @@ gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8 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/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -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/evanphx/json-patch.v4 v4.13.0 h1:czT3CmqEaQ1aanPc5SdlgQrrEIb8w/wwCvWWnfEbYzo= +gopkg.in/evanphx/json-patch.v4 v4.13.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/fsnotify/fsnotify.v1 v1.4.7 h1:XNNYLJHt73EyYiCZi6+xjupS9CpvmiDgjPTAjrBlQbo= gopkg.in/fsnotify/fsnotify.v1 v1.4.7/go.mod h1:Fyux9zXlo4rWoMSIzpn9fDAYjalPqJ/K1qJ27s+7ltE= @@ -3663,19 +3672,19 @@ honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9 honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= k8s.io/api v0.0.0-20190813020757-36bff7324fb7/go.mod h1:3Iy+myeAORNCLgjd/Xu9ebwN7Vh59Bw0vh9jhoX+V58= -k8s.io/api v0.34.2 h1:fsSUNZhV+bnL6Aqrp6O7lMTy6o5x2C4XLjnh//8SLYY= -k8s.io/api v0.34.2/go.mod h1:MMBPaWlED2a8w4RSeanD76f7opUoypY8TFYkSM+3XHw= -k8s.io/apiextensions-apiserver v0.34.2 h1:WStKftnGeoKP4AZRz/BaAAEJvYp4mlZGN0UCv+uvsqo= -k8s.io/apiextensions-apiserver v0.34.2/go.mod h1:398CJrsgXF1wytdaanynDpJ67zG4Xq7yj91GrmYN2SE= +k8s.io/api v0.34.3 h1:D12sTP257/jSH2vHV2EDYrb16bS7ULlHpdNdNhEw2S4= +k8s.io/api v0.34.3/go.mod h1:PyVQBF886Q5RSQZOim7DybQjAbVs8g7gwJNhGtY5MBk= +k8s.io/apiextensions-apiserver v0.34.3 h1:p10fGlkDY09eWKOTeUSioxwLukJnm+KuDZdrW71y40g= +k8s.io/apiextensions-apiserver v0.34.3/go.mod h1:aujxvqGFRdb/cmXYfcRTeppN7S2XV/t7WMEc64zB5A0= k8s.io/apimachinery v0.0.0-20190809020650-423f5d784010/go.mod h1:Waf/xTS2FGRrgXCkO5FP3XxTOWh0qLf2QhL1qFZZ/R8= -k8s.io/apimachinery v0.34.2 h1:zQ12Uk3eMHPxrsbUJgNF8bTauTVR2WgqJsTmwTE/NW4= -k8s.io/apimachinery v0.34.2/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= -k8s.io/apiserver v0.34.2 h1:2/yu8suwkmES7IzwlehAovo8dDE07cFRC7KMDb1+MAE= -k8s.io/apiserver v0.34.2/go.mod h1:gqJQy2yDOB50R3JUReHSFr+cwJnL8G1dzTA0YLEqAPI= -k8s.io/client-go v0.34.2 h1:Co6XiknN+uUZqiddlfAjT68184/37PS4QAzYvQvDR8M= -k8s.io/client-go v0.34.2/go.mod h1:2VYDl1XXJsdcAxw7BenFslRQX28Dxz91U9MWKjX97fE= -k8s.io/component-base v0.34.2 h1:HQRqK9x2sSAsd8+R4xxRirlTjowsg6fWCPwWYeSvogQ= -k8s.io/component-base v0.34.2/go.mod h1:9xw2FHJavUHBFpiGkZoKuYZ5pdtLKe97DEByaA+hHbM= +k8s.io/apimachinery v0.34.3 h1:/TB+SFEiQvN9HPldtlWOTp0hWbJ+fjU+wkxysf/aQnE= +k8s.io/apimachinery v0.34.3/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= +k8s.io/apiserver v0.34.3 h1:uGH1qpDvSiYG4HVFqc6A3L4CKiX+aBWDrrsxHYK0Bdo= +k8s.io/apiserver v0.34.3/go.mod h1:QPnnahMO5C2m3lm6fPW3+JmyQbvHZQ8uudAu/493P2w= +k8s.io/client-go v0.34.3 h1:wtYtpzy/OPNYf7WyNBTj3iUA0XaBHVqhv4Iv3tbrF5A= +k8s.io/client-go v0.34.3/go.mod h1:OxxeYagaP9Kdf78UrKLa3YZixMCfP6bgPwPwNBQBzpM= +k8s.io/component-base v0.34.3 h1:zsEgw6ELqK0XncCQomgO9DpUIzlrYuZYA0Cgo+JWpVk= +k8s.io/component-base v0.34.3/go.mod h1:5iIlD8wPfWE/xSHTRfbjuvUul2WZbI2nOUK65XL0E/c= k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= @@ -3683,17 +3692,17 @@ k8s.io/klog v0.3.1/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= k8s.io/klog v0.4.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= 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.34.2 h1:91rj4MDZLyIT9KxG8J5/CcMH666Z88CF/xJQeuPfJc8= -k8s.io/kms v0.34.2/go.mod h1:s1CFkLG7w9eaTYvctOxosx88fl4spqmixnNpys0JAtM= -k8s.io/kube-aggregator v0.34.2 h1:Nn0Vksj67WHBL2x7bJ6vuxL44RbMTK6uRtXX+3vMVJk= -k8s.io/kube-aggregator v0.34.2/go.mod h1:/tp4cc/1p2AvICsS4mjjSJakdrbhcGbRmj0mdHTdR2Q= +k8s.io/kms v0.34.3 h1:QzBOD0sk1bGQVMcZQAHGjtbP1iKZJUyhC6D0I+BTxIE= +k8s.io/kms v0.34.3/go.mod h1:s1CFkLG7w9eaTYvctOxosx88fl4spqmixnNpys0JAtM= +k8s.io/kube-aggregator v0.34.3 h1:rKsZWTD2As4dKuv+zzdJU0uo5H7bFlAEoSucai4mW6M= +k8s.io/kube-aggregator v0.34.3/go.mod h1:d4D8PV2FK4Qlq6u442FSum1tHPhK9tKdKBfH/A3R0I0= k8s.io/kube-openapi v0.0.0-20190709113604-33be087ad058/go.mod h1:nfDlWeOsu3pUf4yWGL+ERqohP4YsZcBJXWMK+gkzOA4= k8s.io/kube-openapi v0.0.0-20190722073852-5e22f3d471e6/go.mod h1:RZvgC8MSN6DjiMV6oIfEE9pDL9CYXokkfaCKZeHm3nc= -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/kube-openapi v0.0.0-20251125145642-4e65d59e963e h1:iW9ChlU0cU16w8MpVYjXk12dqQ4BPFBEgif+ap7/hqQ= +k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e/go.mod h1:kdmbQkyfwUagLfXIad1y2TdrjPFWp2Q89B3qkRwf/pQ= k8s.io/utils v0.0.0-20190809000727-6c36bc71fc4a/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= -k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 h1:hwvWFiBzdWw1FhfY1FooPn3kzWuJ8tmbZBHi4zVsl1Y= -k8s.io/utils v0.0.0-20250604170112-4c0f3b243397/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 h1:SjGebBtkBqHFOli+05xYbK8YF1Dzkbzn+gDM4X9T4Ck= +k8s.io/utils v0.0.0-20251002143259-bc988d571ff4/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= modernc.org/cc/v3 v3.36.0/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= @@ -3760,10 +3769,10 @@ rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8 rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= -sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2 h1:jpcvIRr3GLoUoEKRkHKSmGjxb6lWwrBlJsXc+eUYQHM= -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/apiserver-network-proxy/konnectivity-client v0.34.0 h1:hSfpvjjTQXQY2Fol2CS0QHMNs/WI1MOSGzCm1KhM5ec= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.34.0/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw= +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg= +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/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 v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= diff --git a/go.work.sum b/go.work.sum index 2e51fd8a06e..73813d12650 100644 --- a/go.work.sum +++ b/go.work.sum @@ -13,6 +13,7 @@ cel.dev/expr v0.16.0/go.mod h1:TRSuuV7DlVCE/uwv5QbAiW/v8l5O8C4eEPHeu7gf7Sg= cel.dev/expr v0.19.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= +cel.dev/expr v0.24.0/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= @@ -329,6 +330,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/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ= +github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE= 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= @@ -410,6 +413,7 @@ github.com/apache/arrow/go/v15 v15.0.2/go.mod h1:DGXsR3ajT524njufqf95822i+KTh+ye github.com/apache/thrift v0.21.0/go.mod h1:W1H8aR/QRtYNvrPeFXBtobyRkd0/YVhTc6i07XIAgDw= 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/at-wat/mqtt-go v0.19.4/go.mod h1:AsiWc9kqVOhqq7LzUeWT/AkKUBfx3Sw5cEe8lc06fqA= 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= @@ -489,6 +493,8 @@ github.com/aws/smithy-go v1.22.5/go.mod h1:t1ufH5HMublsJYulve2RKmHDC15xu1f26kHCp github.com/aws/smithy-go v1.23.0/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/aymanbagabas/go-udiff v0.2.0 h1:TK0fH4MteXUDspT88n8CKzvK0X9O2xu9yQjWpi6yML8= +github.com/aymanbagabas/go-udiff v0.2.0/go.mod h1:RE4Ex0qsGkTAJoQdQQCA0uG+nAzJO/pI/QwceO5fgrA= 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= @@ -517,6 +523,7 @@ github.com/bsm/sarama-cluster v2.1.13+incompatible h1:bqU3gMJbWZVxLZ9PGWVKP05yOm github.com/bsm/sarama-cluster v2.1.13+incompatible/go.mod h1:r7ao+4tTNXvWm+VRpRJchr2kQhqxgmAp2iEX5W96gMM= github.com/bufbuild/protovalidate-go v0.2.1 h1:pJr07sYhliyfj/STAM7hU4J3FKpVeLVKvOBmOTN8j+s= github.com/bufbuild/protovalidate-go v0.2.1/go.mod h1:e7XXDtlxj5vlEyAgsrxpzayp4cEMKCSSb8ZCkin+MVA= +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= @@ -526,6 +533,10 @@ 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/charmbracelet/harmonica v0.2.0 h1:8NxJWRWg/bzKqqEaaeFNipOu77YR5t8aSwG4pgaUBiQ= +github.com/charmbracelet/harmonica v0.2.0/go.mod h1:KSri/1RMQOZLbw7AHqgcBycp8pgJnQMYYT8QZRqZ1Ao= +github.com/charmbracelet/x/exp/golden v0.0.0-20241011142426-46044092ad91 h1:payRxjMjKgx2PaCWLZ4p3ro9y97+TVLZNaRZgJwSVDQ= +github.com/charmbracelet/x/exp/golden v0.0.0-20241011142426-46044092ad91/go.mod h1:wDlXFlCrmJ8J+swcL/MnGUuYnqgQdW9rhSD61oNMb6U= github.com/centrifugal/centrifuge v0.37.2/go.mod h1:aj4iRJGhzi3SlL8iUtVezxway1Xf8g+hmNQkLLO7sS8= github.com/centrifugal/protocol v0.16.2/go.mod h1:Q7OpS/8HMXDnL7f9DpNx24IhG96MP88WPpVTTCdrokI= github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ0g/qfRdp61a3Uu/AWrgIq2s0ClJV1g0= @@ -553,6 +564,7 @@ github.com/cncf/xds/go v0.0.0-20240905190251-b4127c9b8d78/go.mod h1:W+zGtBO5Y1Ig github.com/cncf/xds/go v0.0.0-20250326154945-ae57f3c0d45f/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443/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= @@ -560,6 +572,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/coder/websocket v1.8.13/go.mod h1:LNVeNrXQZfe5qhS9ALED3uA+l5pPqvwXg3CKoDBB2gs= github.com/containerd/btrfs/v2 v2.0.0/go.mod h1:swkD/7j9HApWpzl8OHfrHNxppPd9l44DFZdF94BUj9k= github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw= github.com/containerd/cgroups/v3 v3.0.2/go.mod h1:JUgITrzdFqp42uI2ryGA+ge0ap/nxzYgkGmIcetmErE= @@ -682,6 +695,7 @@ github.com/eapache/go-resiliency v1.7.0/go.mod h1:5yPzW0MIvSe0JDsv0v+DvcjEv2FyD6 github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3 h1:Oy0F4ALJ04o5Qqpdz8XLIpNA3WM/iSIXqxtqo7UGVws= github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3/go.mod h1:YvSRo5mw33fLEx1+DlK6L2VV43tJt5Eyel9n9XBcR+0= github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc= +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= @@ -714,6 +728,7 @@ github.com/ericlagergren/decimal v0.0.0-20240411145413-00de7ca16731 h1:R/ZjJpjQK github.com/ericlagergren/decimal v0.0.0-20240411145413-00de7ca16731/go.mod h1:M9R1FoZ3y//hwwnJtO51ypFGwm8ZfpxPT/ZLtO1mcgQ= github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch/v5 v5.9.11/go.mod h1:3j+LviiESTElxA4p3EMKAB9HXj3/XEtnUf6OZxqIQTM= +github.com/expr-lang/expr v1.17.6/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= @@ -763,6 +778,7 @@ 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-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= +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-openapi/analysis v0.23.0/go.mod h1:9mz9ZWaSlV8TvjQHLl2mUW2PbZtemkE8yA5v22ohupo= @@ -777,6 +793,7 @@ github.com/go-openapi/loads v0.22.0/go.mod h1:yLsaTCS92mnSAZX5WWoxszLj0u+Ojl+Zs5 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/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= 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= @@ -799,6 +816,7 @@ github.com/gocql/gocql v1.7.0/go.mod h1:vnlvXyFZeLBF0Wy+RS8hrOdbn0UWsWtdg07XJnFx github.com/gocraft/dbr/v2 v2.7.2 h1:ccUxMuz6RdZvD7VPhMRRMSS/ECF3gytPhPtcavjktHk= github.com/gocraft/dbr/v2 v2.7.2/go.mod h1:5bCqyIXO5fYn3jEp/L06QF4K1siFdhxChMjdNu6YJrg= github.com/godbus/dbus/v5 v5.0.4 h1:9349emZab16e7zQvpmsbtjc18ykshndd8y2PG3sgJbA= +github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= @@ -858,10 +876,13 @@ github.com/gorilla/handlers v1.5.2/go.mod h1:dX+xVpaxdSw+q0Qek8SSsl3dfMk3jNddUkM 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/alerting v0.0.0-20251009192429-9427c24835ae/go.mod h1:VGjS5gDwWEADPP6pF/drqLxEImgeuHlEW5u8E5EfIrM= 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/authlib/types v0.0.0-20250926065801-df98203cff37/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/codejen v0.0.4-0.20230321061741-77f656893a3d/go.mod h1:zmwwM/DRyQB7pfuBjTWII3CWtxcXh8LTwAYGfDfpR6s= github.com/grafana/cog v0.0.43/go.mod h1:TDunc7TYF7EfzjwFOlC5AkMe3To/U2KqyyG3QVvrF38= 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= @@ -910,6 +931,7 @@ github.com/grafana/grafana-plugin-sdk-go v0.277.0/go.mod h1:mAUWg68w5+1f5TLDqagI 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/grafana-plugin-sdk-go v0.280.0/go.mod h1:Z15Wiq3c4I0tzHYrLYpOqrO8u3+2RJ+HN2Q9uiZTILA= +github.com/grafana/grafana-plugin-sdk-go v0.281.0/go.mod h1:3I0g+v6jAwVmrt6BEjDUP4V6pkhGP5QKY5NkXY4Ayr4= github.com/grafana/grafana-plugin-sdk-go v0.283.0/go.mod h1:20qhoYxIgbZRmwCEO1KMP8q2yq/Kge5+xE/99/hLEk0= 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= @@ -954,11 +976,13 @@ github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2 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/go-grpc-middleware/v2 v2.3.2/go.mod h1:wd1YpapPLivG6nQgbf7ZkG1hhSOXDhhn4MLTknx2aAc= github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg= github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1/go.mod h1:5SN9VR2LTsRFsrEC6FHgRbTWrTHu6tqPeKxEQv15giM= 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-gateway/v2 v2.27.2/go.mod h1:pkJQ2tZHJ0aFOVEEot6oZmaVEZcRme73eIFmhiVuRWs= 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= @@ -1349,6 +1373,7 @@ github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkq 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 v0.67.1/go.mod h1:RpmT9v35q2Y+lsieQsdOh5sXZ6ajUGC8NjZAmr8vb0Q= github.com/prometheus/common v0.67.2/go.mod h1:63W3KZb1JOKgcjlIr64WW/LvFGAqKPj0atm+knVGEko= 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= @@ -1379,6 +1404,7 @@ github.com/richardartoul/molecule v1.0.0/go.mod h1:uvX/8buq8uVeiZiFht+0lqSLBHF+u 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/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/russross/blackfriday v1.6.0 h1:KqfZb0pUVN2lYqZUYRddxF4OR8ZMURnJIG5Y3VRLtww= github.com/russross/blackfriday v1.6.0/go.mod h1:ti0ldHuxg49ri4ksnFxlkCfN+hvslNlmVHqNRXXJNAY= @@ -1390,6 +1416,8 @@ github.com/sagikazarmark/crypt v0.6.0 h1:REOEXCs/NFY/1jOCEouMuT4zEniE5YoXbvpC5X/ github.com/sagikazarmark/locafero v0.9.0/go.mod h1:UBUyz37V+EdMS3hDF3QWIiVr/2dPrx49OMO0Bn0hJqk= github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= +github.com/sahilm/fuzzy v0.1.1 h1:ceu5RHF8DGgoi+/dR5PsECjCDH1BE3Fnmpo7aVXOdRA= +github.com/sahilm/fuzzy v0.1.1/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y= github.com/samber/lo v1.47.0 h1:z7RynLwP5nbyRscyvcD043DWYoOcYRv3mV8lBeqOCLc= github.com/samber/lo v1.47.0/go.mod h1:RmDH9Ct32Qy3gduHQuKJ3gW1fMHAnE/fAzQuf6He5cU= github.com/samber/slog-common v0.18.1 h1:c0EipD/nVY9HG5shgm/XAs67mgpWDMF+MmtptdJNCkQ= @@ -1595,6 +1623,7 @@ go.mongodb.org/mongo-driver v1.11.4/go.mod h1:PTSz5yu21bkT/wXpkS7WR5f0ddqw5queth 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/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= go.opentelemetry.io/collector v0.121.0/go.mod h1:M4TlnmkjIgishm2DNCk9K3hMKTmAsY9w8cNFsp9EchM= go.opentelemetry.io/collector v0.124.0/go.mod h1:QzERYfmHUedawjr8Ph/CBEEkVqWS8IlxRLAZt+KHlCg= go.opentelemetry.io/collector/client v1.29.0/go.mod h1:LCUoEV2KCTKA1i+/txZaGsSPVWUcqeOV6wCfNsAippE= @@ -1881,9 +1910,11 @@ go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v8 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.opentelemetry.io/proto/otlp v1.7.1/go.mod h1:b2rVh6rfI/s2pHWNlB7ILJcRALpcNDzKhACevjI+ZnE= 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/goleak v1.2.0/go.mod h1:XJYK+MuIchqpmGmUSAzotztawfKvYLUIgg7guXrwVUo= go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o= go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= @@ -1925,6 +1956,7 @@ 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.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= 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= @@ -1936,6 +1968,7 @@ 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/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w= +golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc= 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-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= @@ -2030,9 +2063,11 @@ golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= 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.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= 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.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= @@ -2083,7 +2118,9 @@ google.golang.org/genproto/googleapis/api v0.0.0-20250728155136-f173205681a0/go. 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/api v0.0.0-20250908214217-97024824d090/go.mod h1:U8EXRNSd8sUYyDfs/It7KVWodQr+Hf9xtxyxWudSwEw= google.golang.org/genproto/googleapis/api v0.0.0-20250929231259-57b25ae835d4/go.mod h1:NnuHhy+bxcg30o7FnVAZbXsPHUDQ9qKWAQKCD7VxFtk= +google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217/go.mod h1:+rXWjjaukWZun3mLfjmVnQi18E1AsFbDN9QdJ5YXLto= 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-20230822172742-b8732ec3820d/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= @@ -2113,10 +2150,15 @@ 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/genproto/googleapis/rpc v0.0.0-20250929231259-57b25ae835d4/go.mod h1:HSkG/KdJWusxU1F6CNrwNDjBMgisKxGnc5dAZfT0mjQ= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251002232023-7c0ddcbb5797/go.mod h1:HSkG/KdJWusxU1F6CNrwNDjBMgisKxGnc5dAZfT0mjQ= google.golang.org/genproto/googleapis/rpc v0.0.0-20251014184007-4626949a642f/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/genproto/googleapis/rpc v0.0.0-20251103181224-f26f9409b101/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251124214823-79d6a2a48846/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= 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.56.3/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= google.golang.org/grpc v1.58.2/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= google.golang.org/grpc v1.61.0/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs= @@ -2135,6 +2177,7 @@ google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7E 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 v1.76.0/go.mod h1:Ju12QI8M6iQJtbcsV+awF5a4hfJMLi4X0JLo94ULZ6c= 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= @@ -2178,30 +2221,37 @@ k8s.io/api v0.33.3/go.mod h1:01Y/iLUjNBM3TAvypct7DIj0M0NIZc+PzAHCIo0CYGE= k8s.io/api v0.34.0/go.mod h1:YzgkIzOOlhl9uwWCZNqpw6RJy9L2FK4dlJeayUoydug= k8s.io/api v0.34.1/go.mod h1:SB80FxFtXn5/gwzCoN6QCtPD7Vbu5w2n1S0J5gFfTYk= k8s.io/apiextensions-apiserver v0.33.3/go.mod h1:oROuctgo27mUsyp9+Obahos6CWcMISSAPzQ77CAQGz8= +k8s.io/apiextensions-apiserver v0.34.1/go.mod h1:hP9Rld3zF5Ay2Of3BeEpLAToP+l4s5UlxiHfqRaRcMc= k8s.io/apimachinery v0.26.2/go.mod h1:ats7nN1LExKHvJ9TmwootT00Yz05MuYqPXEXaVeOy5I= k8s.io/apimachinery v0.33.3/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM= k8s.io/apimachinery v0.34.0/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= k8s.io/apimachinery v0.34.1/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= k8s.io/apiserver v0.26.2/go.mod h1:GHcozwXgXsPuOJ28EnQ/jXEM9QeG6HT22YxSNmpYNh8= k8s.io/apiserver v0.33.3/go.mod h1:05632ifFEe6TxwjdAIrwINHWE2hLwyADFk5mBsQa15E= +k8s.io/apiserver v0.34.1/go.mod h1:eOOc9nrVqlBI1AFCvVzsob0OxtPZUCPiUJL45JOTBG0= k8s.io/client-go v0.26.2/go.mod h1:u5EjOuSyBa09yqqyY7m3abZeovO/7D/WehVVlZ2qcqU= k8s.io/client-go v0.33.3/go.mod h1:luqKBQggEf3shbxHY4uVENAxrDISLOarxpTKMiUuujg= k8s.io/client-go v0.34.0/go.mod h1:ozgMnEKXkRjeMvBZdV1AijMHLTh3pbACPvK7zFR+QQY= k8s.io/client-go v0.34.1/go.mod h1:kA8v0FP+tk6sZA0yKLRG67LWjqufAoSHA2xVGKw9Of8= -k8s.io/code-generator v0.34.1 h1:WpphT26E+j7tEgIUfFr5WfbJrktCGzB3JoJH9149xYc= -k8s.io/code-generator v0.34.1/go.mod h1:DeWjekbDnJWRwpw3s0Jat87c+e0TgkxoR4ar608yqvg= -k8s.io/code-generator v0.34.2 h1:9bG6jTxmsU3HXE5BNYJTC8AZ1D6hVVfkm8yYSkdkGY0= -k8s.io/code-generator v0.34.2/go.mod h1:dnDDEd6S/z4uZ+PG1aE58ySCi/lR4+qT3a4DddE4/2I= +k8s.io/code-generator v0.34.3 h1:6ipJKsJZZ9q21BO8I2jEj4OLN3y8/1n4aihKN0xKmQk= +k8s.io/code-generator v0.34.3/go.mod h1:oW73UPYpGLsbRN8Ozkhd6ZzkF8hzFCiYmvEuWZDroI4= k8s.io/component-base v0.26.2/go.mod h1:DxbuIe9M3IZPRxPIzhch2m1eT7uFrSBJUBuVCQEBivs= k8s.io/component-base v0.33.3/go.mod h1:ktBVsBzkI3imDuxYXmVxZ2zxJnYTZ4HAsVj9iF09qp4= +k8s.io/component-base v0.34.1/go.mod h1:mknCpLlTSKHzAQJJnnHVKqjxR7gBeHRv0rPXA7gdtQ0= k8s.io/cri-api v0.27.1/go.mod h1:+Ts/AVYbIo04S86XbTD73UPp/DkTiYxtsFeOFEu32L0= 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/gengo/v2 v2.0.0-20250922181213-ec3ebc5fd46b h1:gMplByicHV/TJBizHd9aVEsTYoJBnnUAT5MHlTkbjhQ= +k8s.io/gengo/v2 v2.0.0-20250922181213-ec3ebc5fd46b/go.mod h1:CgujABENc3KuTrcsdpGmrrASjtQsWCT7R99mEV4U/fM= 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.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= +k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= k8s.io/klog/v2 v2.80.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= k8s.io/klog/v2 v2.90.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/kms v0.34.1/go.mod h1:s1CFkLG7w9eaTYvctOxosx88fl4spqmixnNpys0JAtM= +k8s.io/kube-aggregator v0.34.1/go.mod h1:RU8j+5ERfp0h+gIvWtxRPfsa5nK7rboDm8RST8BJfYQ= 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-20230220204549-a5ecb0141aa5/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= @@ -2249,6 +2299,7 @@ sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ih 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/structured-merge-diff/v6 v6.3.0/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= 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= diff --git a/hack/go.mod b/hack/go.mod index e9ecfdc60b4..57179bc0550 100644 --- a/hack/go.mod +++ b/hack/go.mod @@ -2,7 +2,7 @@ module github.com/grafana/grafana/hack go 1.25.5 -require k8s.io/code-generator v0.34.2 +require k8s.io/code-generator v0.34.3 require ( github.com/go-logr/logr v1.4.2 // indirect diff --git a/hack/go.sum b/hack/go.sum index 25c035d777a..b427dbd73ef 100644 --- a/hack/go.sum +++ b/hack/go.sum @@ -12,8 +12,8 @@ golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ= golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs= -k8s.io/code-generator v0.34.2 h1:9bG6jTxmsU3HXE5BNYJTC8AZ1D6hVVfkm8yYSkdkGY0= -k8s.io/code-generator v0.34.2/go.mod h1:dnDDEd6S/z4uZ+PG1aE58ySCi/lR4+qT3a4DddE4/2I= +k8s.io/code-generator v0.34.3 h1:6ipJKsJZZ9q21BO8I2jEj4OLN3y8/1n4aihKN0xKmQk= +k8s.io/code-generator v0.34.3/go.mod h1:oW73UPYpGLsbRN8Ozkhd6ZzkF8hzFCiYmvEuWZDroI4= 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/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= diff --git a/hack/update-codegen.sh b/hack/update-codegen.sh index 59976c9bf3c..03dd95943a2 100755 --- a/hack/update-codegen.sh +++ b/hack/update-codegen.sh @@ -11,7 +11,7 @@ set -o pipefail SCRIPT_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. pushd "${SCRIPT_ROOT}/hack" && GO111MODULE=on go mod tidy && popd -CODEGEN_PKG=${CODEGEN_PKG:-$(cd "${SCRIPT_ROOT}"; ls -d -1 ./vendor/k8s.io/code-generator 2>/dev/null || echo $(go env GOPATH)/pkg/mod/k8s.io/code-generator@v0.34.2)} +CODEGEN_PKG=${CODEGEN_PKG:-$(cd "${SCRIPT_ROOT}"; ls -d -1 ./vendor/k8s.io/code-generator 2>/dev/null || echo $(go env GOPATH)/pkg/mod/k8s.io/code-generator@v0.34.3)} OUTDIR="${HOME}/go/src" OPENAPI_VIOLATION_EXCEPTIONS_FILENAME="zz_generated.openapi_violation_exceptions.list" diff --git a/jest.config.js b/jest.config.js index ef107c8cc24..17a2ce9ca32 100644 --- a/jest.config.js +++ b/jest.config.js @@ -40,6 +40,9 @@ const esModules = [ module.exports = { verbose: false, testEnvironment: 'jsdom', + testEnvironmentOptions: { + customExportConditions: ['@grafana-app/source', 'browser'], + }, transform: { '^.+\\.(ts|tsx|js|jsx)$': [require.resolve('ts-jest')], }, diff --git a/kinds/dashboard/dashboard_kind.cue b/kinds/dashboard/dashboard_kind.cue index 454d02f270f..08b7a1b2b6e 100644 --- a/kinds/dashboard/dashboard_kind.cue +++ b/kinds/dashboard/dashboard_kind.cue @@ -702,6 +702,10 @@ lineage: schemas: [{ // Field options allow you to change how the data is displayed in your visualizations. fieldConfig?: #FieldConfigSource + + // When a panel is migrated from a previous version (Angular to React), this field is set to the original panel type. + // This is used to determine the original panel type when migrating to a new version so the plugin migration can be applied. + autoMigrateFrom?: string } @cuetsy(kind="interface") @grafana(TSVeneer="type") @grafanamaturity(NeedsExpertReview) // The data model used in Grafana, namely the data frame, is a columnar-oriented table structure that unifies both time series and table query results. diff --git a/package.json b/package.json index 7a21333b222..73dec9dbc90 100644 --- a/package.json +++ b/package.json @@ -26,10 +26,10 @@ "e2e:enterprise": "./e2e/start-and-run-suite enterprise", "e2e:enterprise:dev": "./e2e/start-and-run-suite enterprise dev", "e2e:enterprise:debug": "./e2e/start-and-run-suite enterprise debug", - "e2e:playwright": "yarn playwright test --grep-invert @cloud-plugins", - "e2e:playwright:cloud-plugins": "yarn playwright test --grep @cloud-plugins", - "e2e:playwright:storybook": "yarn playwright test -c playwright.storybook.config.ts", - "e2e:acceptance": "yarn playwright test --grep @acceptance", + "e2e:playwright": "NODE_OPTIONS='-C @grafana-app/source' yarn playwright test --grep-invert @cloud-plugins", + "e2e:playwright:cloud-plugins": "NODE_OPTIONS='-C @grafana-app/source' yarn playwright test --grep @cloud-plugins", + "e2e:playwright:storybook": "NODE_OPTIONS='-C @grafana-app/source' yarn playwright test -c playwright.storybook.config.ts", + "e2e:acceptance": "NODE_OPTIONS='-C @grafana-app/source' yarn playwright test --grep @acceptance", "e2e:storybook": "PORT=9001 ./e2e/run-suite storybook true", "e2e:plugin:build": "nx run-many -t build --projects='@test-plugins/*'", "e2e:plugin:build:dev": "nx run-many -t dev --projects='@test-plugins/*' --maxParallel=100", @@ -63,7 +63,7 @@ "storybook": "yarn workspace @grafana/ui storybook --ci", "storybook:build": "yarn workspace @grafana/ui storybook:build", "themes-schema": "typescript-json-schema ./tsconfig.json NewThemeOptions --include 'packages/grafana-data/src/themes/createTheme.ts' --out public/app/features/theme-playground/schema.generated.json", - "themes-generate": "yarn themes-schema && esbuild --target=es6 ./scripts/cli/generateSassVariableFiles.ts --bundle --platform=node --tsconfig=./scripts/cli/tsconfig.json | node", + "themes-generate": "yarn themes-schema && esbuild --target=es6 ./scripts/cli/generateSassVariableFiles.ts --bundle --conditions=@grafana-app/source --platform=node --tsconfig=./scripts/cli/tsconfig.json | node", "themes:usage": "eslint . --ignore-pattern '*.test.ts*' --ignore-pattern '*.spec.ts*' --cache --plugin '@grafana' --rule '{ @grafana/theme-token-usage: \"error\" }'", "typecheck": "tsc --noEmit && yarn run packages:typecheck", "plugins:build-bundled": "echo 'bundled plugins are no longer supported'", @@ -92,7 +92,7 @@ "@emotion/eslint-plugin": "11.12.0", "@grafana/eslint-config": "8.2.0", "@grafana/eslint-plugin": "link:./packages/grafana-eslint-rules", - "@grafana/plugin-e2e": "^3.0.3", + "@grafana/plugin-e2e": "^3.1.0", "@grafana/test-utils": "workspace:*", "@manypkg/get-packages": "^3.0.0", "@npmcli/package-json": "^6.0.0", @@ -295,8 +295,8 @@ "@grafana/plugin-ui": "^0.11.1", "@grafana/prometheus": "workspace:*", "@grafana/runtime": "workspace:*", - "@grafana/scenes": "6.49.0", - "@grafana/scenes-react": "6.49.0", + "@grafana/scenes": "6.52.0", + "@grafana/scenes-react": "6.52.0", "@grafana/schema": "workspace:*", "@grafana/sql": "workspace:*", "@grafana/ui": "workspace:*", @@ -460,7 +460,8 @@ "tmp@npm:^0.0.33": "~0.2.1", "js-yaml@npm:4.1.0": "^4.1.0", "js-yaml@npm:=4.1.0": "^4.1.0", - "nodemailer": "7.0.7" + "nodemailer": "7.0.7", + "@storybook/core@npm:8.6.2": "patch:@storybook/core@npm%3A8.6.2#~/.yarn/patches/@storybook-core-npm-8.6.2-8c752112c0.patch" }, "workspaces": { "packages": [ diff --git a/packages/README.md b/packages/README.md index b42f7082c5c..3fa0dceebc7 100644 --- a/packages/README.md +++ b/packages/README.md @@ -2,13 +2,32 @@ ## Exporting code conventions -`@grafana/ui`, `@grafana/data` and `@grafana/runtime` makes use of `exports` in package.json to define three entrypoints that Grafana core and Grafana plugins can access. Before exposing anything in these packages please consider the table below to better understand the use case of each export. +All the `@grafana` packages in this repo (except `@grafana/schema`) make use of `exports` in package.json to define entrypoints that Grafana core and Grafana plugins can access. Exports can also be used to restrict access to internal files in packages. -| Export Name | Import Path | Description | Available to Grafana | Available to plugins | -| ------------ | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------- | -------------------- | -| `./` | `@grafana/ui` | The public API entrypoint. If the code is stable and you want to share it everywhere, this is the place to export it. | ✅ | ✅ | -| `./unstable` | `@grafana/ui/unstable` | The public API entrypoint for all experimental code. If you want to iterate and test code from Grafana and plugins, this is the place to export it. | ✅ | ✅ | -| `./internal` | `@grafana/ui/internal` | The private API entrypoint for internal code shared with Grafana. If you need to import code in Grafana but don't want to expose it to plugins, this is the place to export it. | ✅ | ❌ | +Package authors are free to create as many exports as they like but should consider the following points: + +1. Resolution of source code within this repo is handled by the [customCondition](https://www.typescriptlang.org/tsconfig/#customConditions) `@grafana-app/source`. This allows the frontend tooling in this repo to resolve to the source code preventing the need to build all the packages up front. When adding exports it is important to add an entry for the custom condition as the first item. All other entries should point to the built, bundled files. For example: + + ```json + "exports": { + ".": { + "@grafana-app/source": "./src/index.ts", + "types": "./dist/types/index.d.ts", + "import": "./dist/esm/index.mjs", + "require": "./dist/cjs/index.cjs" + } + } + ``` + +2. If you add exports to your package you must export the `package.json` file. + +3. Before exposing anything in these packages please consider the table below to better understand the conventions we have put in place for most of the packages in this repository. + +| Export Name | Import Path | Description | Available to Grafana | Available to plugins | +| ------------ | ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------- | -------------------- | +| `./` | `@grafana/ui` | The public API entrypoint. If the code is stable and you want to share it everywhere, this is the place to export it. | ✅ | ✅ | +| `./unstable` | `@grafana/ui/unstable` | The public API entrypoint for all experimental code. If you want to iterate and test code from Grafana and plugins, this is the place to export it. | ✅ | ✅ | +| `./internal` | `@grafana/ui/internal` | The private API entrypoint for internal code shared with Grafana. If you want to co-locate code in a package with it's public API but only want the Grafana application to access it, this is the place to export it. | ✅ | ❌ | ## Versioning diff --git a/packages/grafana-alerting/package.json b/packages/grafana-alerting/package.json index 1c3ab2bf9b4..d64f1c01893 100644 --- a/packages/grafana-alerting/package.json +++ b/packages/grafana-alerting/package.json @@ -17,32 +17,34 @@ "url": "http://github.com/grafana/grafana.git", "directory": "packages/grafana-alerting" }, - "main": "src/index.ts", - "types": "src/index.ts", - "module": "src/index.ts", + "main": "./dist/cjs/index.cjs", + "module": "./dist/esm/index.mjs", + "types": "./dist/types/index.d.ts", "exports": { "./package.json": "./package.json", ".": { - "import": "./src/index.ts", - "require": "./src/index.ts" - }, - "./internal": { - "import": "./src/internal.ts", - "require": "./src/internal.ts" + "@grafana-app/source": "./src/index.ts", + "types": "./dist/types/index.d.ts", + "import": "./dist/esm/index.mjs", + "require": "./dist/cjs/index.cjs" }, "./unstable": { - "import": "./src/unstable.ts", - "require": "./src/unstable.ts" + "@grafana-app/source": "./src/unstable.ts", + "types": "./dist/types/unstable.d.ts", + "import": "./dist/esm/unstable.mjs", + "require": "./dist/cjs/unstable.cjs" + }, + "./internal": { + "@grafana-app/source": "./src/internal.ts" }, "./testing": { - "import": "./src/testing.ts", - "require": "./src/testing.ts" + "@grafana-app/source": "./src/testing.ts", + "types": "./dist/types/testing.d.ts", + "import": "./dist/esm/testing.mjs", + "require": "./dist/cjs/testing.cjs" } }, "publishConfig": { - "main": "./dist/cjs/index.cjs", - "module": "./dist/esm/index.mjs", - "types": "./dist/types/index.d.ts", "access": "public" }, "files": [ @@ -57,8 +59,8 @@ "clean": "rimraf ./dist ./compiled ./unstable ./testing ./package.tgz", "typecheck": "tsc --emitDeclarationOnly false --noEmit", "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", + "prepack": "cp package.json package.json.bak && node ../../scripts/prepare-npm-package.js", + "postpack": "mv package.json.bak package.json", "i18n-extract": "i18next-cli extract --sync-primary" }, "devDependencies": { diff --git a/packages/grafana-alerting/rollup.config.ts b/packages/grafana-alerting/rollup.config.ts index f8f41e3ad2c..43914b47b70 100644 --- a/packages/grafana-alerting/rollup.config.ts +++ b/packages/grafana-alerting/rollup.config.ts @@ -9,19 +9,19 @@ export default [ { input: entryPoint, plugins, - output: [cjsOutput(pkg), esmOutput(pkg, 'grafana-alerting')], + output: [cjsOutput(pkg, 'grafana-alerting'), esmOutput(pkg, 'grafana-alerting')], treeshake: false, }, { input: 'src/unstable.ts', plugins, - output: [cjsOutput(pkg), esmOutput(pkg, 'grafana-alerting')], + output: [cjsOutput(pkg, 'grafana-alerting'), esmOutput(pkg, 'grafana-alerting')], treeshake: false, }, { input: 'src/testing.ts', plugins, - output: [cjsOutput(pkg), esmOutput(pkg, 'grafana-alerting')], + output: [cjsOutput(pkg, 'grafana-alerting'), esmOutput(pkg, 'grafana-alerting')], treeshake: false, }, ]; diff --git a/packages/grafana-api-clients/package.json b/packages/grafana-api-clients/package.json index 2d976b3a890..39accb04535 100644 --- a/packages/grafana-api-clients/package.json +++ b/packages/grafana-api-clients/package.json @@ -15,88 +15,121 @@ "url": "https://github.com/grafana/grafana.git", "directory": "packages/grafana-api-clients" }, - "main": "src/index.ts", - "module": "src/index.ts", - "types": "src/index.ts", + "main": "./dist/cjs/index.cjs", + "module": "./dist/esm/index.mjs", + "types": "./dist/types/index.d.ts", "exports": { "./package.json": "./package.json", ".": { - "import": "./src/index.ts", - "require": "./src/index.ts" + "@grafana-app/source": "./src/index.ts", + "types": "./dist/types/index.d.ts", + "import": "./dist/esm/index.mjs", + "require": "./dist/cjs/index.cjs" }, "./rtkq": { - "import": "./src/clients/rtkq/index.ts", - "require": "./src/clients/rtkq/index.ts" + "@grafana-app/source": "./src/clients/rtkq/index.ts", + "types": "./dist/types/clients/rtkq/index.d.ts", + "import": "./dist/esm/clients/rtkq/index.mjs", + "require": "./dist/cjs/clients/rtkq/index.cjs" }, "./rtkq/advisor/v0alpha1": { - "import": "./src/clients/rtkq/advisor/v0alpha1/index.ts", - "require": "./src/clients/rtkq/advisor/v0alpha1/index.ts" - }, - "./rtkq/correlations/v0alpha1": { - "import": "./src/clients/rtkq/correlations/v0alpha1/index.ts", - "require": "./src/clients/rtkq/correlations/v0alpha1/index.ts" - }, - "./rtkq/dashboard/v0alpha1": { - "import": "./src/clients/rtkq/dashboard/v0alpha1/index.ts", - "require": "./src/clients/rtkq/dashboard/v0alpha1/index.ts" - }, - "./rtkq/folder/v1beta1": { - "import": "./src/clients/rtkq/folder/v1beta1/index.ts", - "require": "./src/clients/rtkq/folder/v1beta1/index.ts" - }, - "./rtkq/iam/v0alpha1": { - "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" - }, - "./rtkq/legacy/preferences": { - "import": "./src/clients/rtkq/preferences/user/index.ts", - "require": "./src/clients/rtkq/preferences/user/index.ts" - }, - "./rtkq/legacy/user": { - "import": "./src/clients/rtkq/user/index.ts", - "require": "./src/clients/rtkq/user/index.ts" - }, - "./rtkq/playlist/v0alpha1": { - "import": "./src/clients/rtkq/playlist/v0alpha1/index.ts", - "require": "./src/clients/rtkq/playlist/v0alpha1/index.ts" - }, - "./rtkq/preferences/v1alpha1": { - "import": "./src/clients/rtkq/preferences/v1alpha1/index.ts", - "require": "./src/clients/rtkq/preferences/v1alpha1/index.ts" + "@grafana-app/source": "./src/clients/rtkq/advisor/v0alpha1/index.ts", + "types": "./dist/types/clients/rtkq/advisor/v0alpha1/index.d.ts", + "import": "./dist/esm/clients/rtkq/advisor/v0alpha1/index.mjs", + "require": "./dist/cjs/clients/rtkq/advisor/v0alpha1/index.cjs" }, "./rtkq/collections/v1alpha1": { - "import": "./src/clients/rtkq/collections/v1alpha1/index.ts", - "require": "./src/clients/rtkq/collections/v1alpha1/index.ts" + "@grafana-app/source": "./src/clients/rtkq/collections/v1alpha1/index.ts", + "types": "./dist/types/clients/rtkq/collections/v1alpha1/index.d.ts", + "import": "./dist/esm/clients/rtkq/collections/v1alpha1/index.mjs", + "require": "./dist/cjs/clients/rtkq/collections/v1alpha1/index.cjs" + }, + "./rtkq/correlations/v0alpha1": { + "@grafana-app/source": "./src/clients/rtkq/correlations/v0alpha1/index.ts", + "types": "./dist/types/clients/rtkq/correlations/v0alpha1/index.d.ts", + "import": "./dist/esm/clients/rtkq/correlations/v0alpha1/index.mjs", + "require": "./dist/cjs/clients/rtkq/correlations/v0alpha1/index.cjs" + }, + "./rtkq/dashboard/v0alpha1": { + "@grafana-app/source": "./src/clients/rtkq/dashboard/v0alpha1/index.ts", + "types": "./dist/types/clients/rtkq/dashboard/v0alpha1/index.d.ts", + "import": "./dist/esm/clients/rtkq/dashboard/v0alpha1/index.mjs", + "require": "./dist/cjs/clients/rtkq/dashboard/v0alpha1/index.cjs" + }, + "./rtkq/folder/v1beta1": { + "@grafana-app/source": "./src/clients/rtkq/folder/v1beta1/index.ts", + "types": "./dist/types/clients/rtkq/folder/v1beta1/index.d.ts", + "import": "./dist/esm/clients/rtkq/folder/v1beta1/index.mjs", + "require": "./dist/cjs/clients/rtkq/folder/v1beta1/index.cjs" + }, + "./rtkq/iam/v0alpha1": { + "@grafana-app/source": "./src/clients/rtkq/iam/v0alpha1/index.ts", + "types": "./dist/types/clients/rtkq/iam/v0alpha1/index.d.ts", + "import": "./dist/esm/clients/rtkq/iam/v0alpha1/index.mjs", + "require": "./dist/cjs/clients/rtkq/iam/v0alpha1/index.cjs" + }, + "./rtkq/legacy": { + "@grafana-app/source": "./src/clients/rtkq/legacy/index.ts", + "types": "./dist/types/clients/rtkq/legacy/index.d.ts", + "import": "./dist/esm/clients/rtkq/legacy/index.mjs", + "require": "./dist/cjs/clients/rtkq/legacy/index.cjs" + }, + "./rtkq/legacy/migrate-to-cloud": { + "@grafana-app/source": "./src/clients/rtkq/migrate-to-cloud/index.ts", + "types": "./dist/types/clients/rtkq/migrate-to-cloud/index.d.ts", + "import": "./dist/esm/clients/rtkq/migrate-to-cloud/index.mjs", + "require": "./dist/cjs/clients/rtkq/migrate-to-cloud/index.cjs" + }, + "./rtkq/legacy/preferences": { + "@grafana-app/source": "./src/clients/rtkq/preferences/user/index.ts", + "types": "./dist/types/clients/rtkq/preferences/user/index.d.ts", + "import": "./dist/esm/clients/rtkq/preferences/user/index.mjs", + "require": "./dist/cjs/clients/rtkq/preferences/user/index.cjs" + }, + "./rtkq/legacy/user": { + "@grafana-app/source": "./src/clients/rtkq/user/index.ts", + "types": "./dist/types/clients/rtkq/user/index.d.ts", + "import": "./dist/esm/clients/rtkq/user/index.mjs", + "require": "./dist/cjs/clients/rtkq/user/index.cjs" + }, + "./rtkq/playlist/v0alpha1": { + "@grafana-app/source": "./src/clients/rtkq/playlist/v0alpha1/index.ts", + "types": "./dist/types/clients/rtkq/playlist/v0alpha1/index.d.ts", + "import": "./dist/esm/clients/rtkq/playlist/v0alpha1/index.mjs", + "require": "./dist/cjs/clients/rtkq/playlist/v0alpha1/index.cjs" + }, + "./rtkq/preferences/v1alpha1": { + "@grafana-app/source": "./src/clients/rtkq/preferences/v1alpha1/index.ts", + "types": "./dist/types/clients/rtkq/preferences/v1alpha1/index.d.ts", + "import": "./dist/esm/clients/rtkq/preferences/v1alpha1/index.mjs", + "require": "./dist/cjs/clients/rtkq/preferences/v1alpha1/index.cjs" }, "./rtkq/provisioning/v0alpha1": { - "import": "./src/clients/rtkq/provisioning/v0alpha1/index.ts", - "require": "./src/clients/rtkq/provisioning/v0alpha1/index.ts" + "@grafana-app/source": "./src/clients/rtkq/provisioning/v0alpha1/index.ts", + "types": "./dist/types/clients/rtkq/provisioning/v0alpha1/index.d.ts", + "import": "./dist/esm/clients/rtkq/provisioning/v0alpha1/index.mjs", + "require": "./dist/cjs/clients/rtkq/provisioning/v0alpha1/index.cjs" }, "./rtkq/shorturl/v1beta1": { - "import": "./src/clients/rtkq/shorturl/v1beta1/index.ts", - "require": "./src/clients/rtkq/shorturl/v1beta1/index.ts" + "@grafana-app/source": "./src/clients/rtkq/shorturl/v1beta1/index.ts", + "types": "./dist/types/clients/rtkq/shorturl/v1beta1/index.d.ts", + "import": "./dist/esm/clients/rtkq/shorturl/v1beta1/index.mjs", + "require": "./dist/cjs/clients/rtkq/shorturl/v1beta1/index.cjs" }, "./rtkq/historian.alerting/v0alpha1": { - "import": "./src/clients/rtkq/historian.alerting/v0alpha1/index.ts", - "require": "./src/clients/rtkq/historian.alerting/v0alpha1/index.ts" + "@grafana-app/source": "./src/clients/rtkq/historian.alerting/v0alpha1/index.ts", + "types": "./dist/types/clients/rtkq/historian.alerting/v0alpha1/index.d.ts", + "import": "./dist/esm/clients/rtkq/historian.alerting/v0alpha1/index.mjs", + "require": "./dist/cjs/clients/rtkq/historian.alerting/v0alpha1/index.cjs" }, "./rtkq/logsdrilldown/v1alpha1": { - "import": "./src/clients/rtkq/logsdrilldown/v1alpha1/index.ts", - "require": "./src/clients/rtkq/logsdrilldown/v1alpha1/index.ts" + "@grafana-app/source": "./src/clients/rtkq/logsdrilldown/v1alpha1/index.ts", + "types": "./dist/types/clients/rtkq/logsdrilldown/v1alpha1/index.d.ts", + "import": "./dist/esm/clients/rtkq/logsdrilldown/v1alpha1/index.mjs", + "require": "./dist/cjs/clients/rtkq/logsdrilldown/v1alpha1/index.cjs" } }, "publishConfig": { - "main": "./dist/cjs/index.cjs", - "module": "./dist/esm/index.mjs", - "types": "./dist/types/index.d.ts", "access": "public" }, "files": [ diff --git a/packages/grafana-api-clients/rollup.config.ts b/packages/grafana-api-clients/rollup.config.ts index b36d59278fc..976a0c000fa 100644 --- a/packages/grafana-api-clients/rollup.config.ts +++ b/packages/grafana-api-clients/rollup.config.ts @@ -5,35 +5,17 @@ import { cjsOutput, entryPoint, esmOutput, plugins } from '../rollup.config.part const rq = createRequire(import.meta.url); const pkg = rq('./package.json'); -const apiClients = Object.entries<{ import: string; require: string }>(pkg.exports).filter(([key]) => - key.startsWith('./rtkq/') -); - -const apiClientConfigs = apiClients.map(([name, { import: importPath }]) => { - const baseCjsOutput = cjsOutput(pkg); - const entryFileNames = name.replace('./', '') + '.cjs'; - const cjsOutputConfig = { ...baseCjsOutput, entryFileNames }; - return { - input: importPath.replace('./', ''), - - plugins, - output: [cjsOutputConfig, esmOutput(pkg, 'grafana-api-clients')], - treeshake: false, - }; -}); - export default [ { input: entryPoint, plugins, - output: [cjsOutput(pkg), esmOutput(pkg, 'grafana-api-clients')], + output: [cjsOutput(pkg, 'grafana-api-clients'), esmOutput(pkg, 'grafana-api-clients')], treeshake: false, }, { input: 'src/clients/rtkq/index.ts', plugins, - output: [cjsOutput(pkg), esmOutput(pkg, 'grafana-api-clients')], + output: [cjsOutput(pkg, 'grafana-api-clients'), esmOutput(pkg, 'grafana-api-clients')], treeshake: false, }, - ...apiClientConfigs, ]; 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 f614aed35a8..4f17bb46ecf 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 @@ -3440,16 +3440,16 @@ export type RemoveTeamGroupApiQueryApiResponse = /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; export type RemoveTeamGroupApiQueryApiArg = { groupId?: string; - teamId: number; + teamId: string; }; export type GetTeamGroupsApiApiResponse = /** status 200 (empty) */ TeamGroupDto[]; export type GetTeamGroupsApiApiArg = { - teamId: number; + teamId: string; }; export type AddTeamGroupApiApiResponse = /** status 200 An OKResponse is returned if the request was successful. */ SuccessResponseBody; export type AddTeamGroupApiApiArg = { - teamId: number; + teamId: string; teamGroupMapping: TeamGroupMapping; }; export type SearchTeamGroupsApiResponse = /** status 200 (empty) */ SearchTeamGroupsQueryResult; 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 cb2aa3d08e2..be22503f3bf 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 @@ -1585,8 +1585,6 @@ export type DeleteJobOptions = { resources?: ResourceRef[]; }; export type MigrateJobOptions = { - /** Preserve history (if possible) */ - history?: boolean; /** Message to use when committing the changes in a single commit */ message?: string; }; @@ -1731,6 +1729,9 @@ export type BitbucketRepositoryConfig = { /** The repository URL (e.g. `https://bitbucket.org/example/test`). */ url?: string; }; +export type ConnectionInfo = { + name: string; +}; export type GitRepositoryConfig = { /** The branch to use in the repository. */ branch: string; @@ -1783,6 +1784,8 @@ export type SyncOptions = { export type RepositorySpec = { /** The repository on Bitbucket. Mutually exclusive with local | github | git. */ bitbucket?: BitbucketRepositoryConfig; + /** The connection the repository references. This means the Repository is interacting with git via a Connection. */ + connection?: ConnectionInfo; /** Repository description */ description?: string; /** The repository on Git. Mutually exclusive with local | github | git. */ @@ -2042,8 +2045,6 @@ export type RepositoryViewList = { items: RepositoryView[]; /** 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; - /** The backend is using legacy storage FIXME: Not sure where this should be exposed... but we need it somewhere The UI should force the onboarding workflow when this is true */ - legacyStorage?: boolean; }; export type ManagerStats = { /** Manager identity */ diff --git a/packages/grafana-api-clients/src/generator/helpers.ts b/packages/grafana-api-clients/src/generator/helpers.ts index 2ac2ce01389..daba285787c 100644 --- a/packages/grafana-api-clients/src/generator/helpers.ts +++ b/packages/grafana-api-clients/src/generator/helpers.ts @@ -143,8 +143,10 @@ export const updatePackageJsonExports = // Create the new export entry const newExportKey = `./rtkq/${groupName}/${version}`; const newExportValue = { - import: `./src/clients/rtkq/${groupName}/${version}/index.ts`, - require: `./src/clients/rtkq/${groupName}/${version}/index.ts`, + '@grafana-app/source': `./src/clients/rtkq/${groupName}/${version}/index.ts`, + types: `./dist/types/clients/rtkq/${groupName}/${version}/index.d.ts`, + import: `./dist/esm/clients/rtkq/${groupName}/${version}/index.mjs`, + require: `./dist/cjs/clients/rtkq/${groupName}/${version}/index.cjs`, }; // Check if export already exists diff --git a/packages/grafana-api-clients/tsconfig.json b/packages/grafana-api-clients/tsconfig.json index ed1c294703e..e75b58104b0 100644 --- a/packages/grafana-api-clients/tsconfig.json +++ b/packages/grafana-api-clients/tsconfig.json @@ -8,7 +8,8 @@ "emitDeclarationOnly": true, "isolatedModules": true, "rootDirs": ["."], - "allowImportingTsExtensions": true + "allowImportingTsExtensions": true, + "moduleResolution": "bundler" }, "exclude": ["dist/**/*"], "include": [ @@ -17,5 +18,12 @@ "../grafana-ui/src/types/*.d.ts", "../grafana-i18n/src/types/*.d.ts", "src/**/*.ts*" - ] + ], + "ts-node": { + "swc": true, + "compilerOptions": { + "module": "es2020", + "moduleResolution": "Bundler" + } + } } diff --git a/packages/grafana-data/package.json b/packages/grafana-data/package.json index ff90b2c295d..df595973cca 100644 --- a/packages/grafana-data/package.json +++ b/packages/grafana-data/package.json @@ -13,32 +13,31 @@ "url": "http://github.com/grafana/grafana.git", "directory": "packages/grafana-data" }, - "main": "src/index.ts", - "types": "src/index.ts", - "module": "src/index.ts", + "main": "./dist/cjs/index.cjs", + "module": "./dist/esm/index.mjs", + "types": "./dist/types/index.d.ts", "exports": { "./package.json": "./package.json", ".": { - "import": "./src/index.ts", - "require": "./src/index.ts" - }, - "./internal": { - "import": "./src/internal/index.ts", - "require": "./src/internal/index.ts" + "@grafana-app/source": "./src/index.ts", + "types": "./dist/types/index.d.ts", + "import": "./dist/esm/index.mjs", + "require": "./dist/cjs/index.cjs" }, "./unstable": { - "import": "./src/unstable.ts", - "require": "./src/unstable.ts" + "@grafana-app/source": "./src/unstable.ts", + "types": "./dist/types/unstable.d.ts", + "import": "./dist/esm/unstable.mjs", + "require": "./dist/cjs/unstable.cjs" + }, + "./internal": { + "@grafana-app/source": "./src/internal/index.ts" }, "./test": { - "import": "./test/index.ts", - "require": "./test/index.ts" + "@grafana-app/source": "./test/index.ts" } }, "publishConfig": { - "main": "./dist/cjs/index.cjs", - "module": "./dist/esm/index.mjs", - "types": "./dist/types/index.d.ts", "access": "public" }, "files": [ @@ -51,8 +50,8 @@ "build": "tsc -p ./tsconfig.build.json && rollup -c rollup.config.ts --configPlugin esbuild", "clean": "rimraf ./dist ./compiled ./unstable ./package.tgz", "typecheck": "tsc --emitDeclarationOnly false --noEmit", - "prepack": "cp package.json package.json.bak && ALIAS_PACKAGE_NAME=unstable node ../../scripts/prepare-npm-package.js", - "postpack": "mv package.json.bak package.json && rimraf ./unstable" + "prepack": "cp package.json package.json.bak && node ../../scripts/prepare-npm-package.js", + "postpack": "mv package.json.bak package.json" }, "dependencies": { "@braintree/sanitize-url": "7.0.1", diff --git a/packages/grafana-data/rollup.config.ts b/packages/grafana-data/rollup.config.ts index 378ab225769..87008ddc45f 100644 --- a/packages/grafana-data/rollup.config.ts +++ b/packages/grafana-data/rollup.config.ts @@ -9,13 +9,13 @@ export default [ { input: entryPoint, plugins, - output: [cjsOutput(pkg), esmOutput(pkg, 'grafana-data')], + output: [cjsOutput(pkg, 'grafana-data'), esmOutput(pkg, 'grafana-data')], treeshake: false, }, { input: 'src/unstable.ts', plugins, - output: [cjsOutput(pkg), esmOutput(pkg, 'grafana-data')], + output: [cjsOutput(pkg, 'grafana-data'), esmOutput(pkg, 'grafana-data')], treeshake: false, }, ]; diff --git a/packages/grafana-data/src/index.ts b/packages/grafana-data/src/index.ts index 63c36639e25..6027b566764 100644 --- a/packages/grafana-data/src/index.ts +++ b/packages/grafana-data/src/index.ts @@ -664,6 +664,7 @@ export { type DataSourceGetTagKeysOptions, type DataSourceGetTagValuesOptions, type DataSourceGetDrilldownsApplicabilityOptions, + type DataSourceGetRecommendedDrilldownsOptions, type MetadataInspectorProps, type LegacyMetricFindQueryOptions, type QueryEditorProps, @@ -681,6 +682,7 @@ export { type QueryHint, type MetricFindValue, type DrilldownsApplicability, + type DrilldownRecommendation, type DataSourceJsonData, type DataSourceSettings, type DataSourceInstanceSettings, diff --git a/packages/grafana-data/src/types/config.ts b/packages/grafana-data/src/types/config.ts index f519b1d56b4..b2d3c16a3b1 100644 --- a/packages/grafana-data/src/types/config.ts +++ b/packages/grafana-data/src/types/config.ts @@ -289,6 +289,7 @@ export interface GrafanaConfig { rudderstackWriteKey: string; rudderstackDataPlaneUrl: string; rudderstackSdkUrl: string; + rudderstackV3SdkUrl: string; rudderstackConfigUrl: string; rudderstackIntegrationsUrl: string; applicationInsightsConnectionString: string; diff --git a/packages/grafana-data/src/types/datasource.ts b/packages/grafana-data/src/types/datasource.ts index 538e7a051e8..f50e126a5c7 100644 --- a/packages/grafana-data/src/types/datasource.ts +++ b/packages/grafana-data/src/types/datasource.ts @@ -313,6 +313,13 @@ abstract class DataSourceApi< options?: DataSourceGetDrilldownsApplicabilityOptions ): Promise; + /** + * Get recommended drilldowns for a dashboard + */ + getRecommendedDrilldowns?( + options?: DataSourceGetRecommendedDrilldownsOptions + ): Promise; + /** * Get tag keys for adhoc filters */ @@ -398,13 +405,9 @@ abstract class DataSourceApi< } /** - * Options argument to DataSourceAPI.getTagKeys + * Base options shared across datasource filtering operations. */ -export interface DataSourceGetTagKeysOptions { - /** - * The other existing filters or base filters. New in v10.3 - */ - filters: AdHocVariableFilter[]; +export interface DataSourceFilteringRequestOptions { /** * Context time range. New in v10.3 */ @@ -413,21 +416,27 @@ export interface DataSourceGetTagKeysOptions + extends DataSourceFilteringRequestOptions { + /** + * The other existing filters or base filters. New in v10.3 + */ + filters: AdHocVariableFilter[]; +} + /** * Options argument to DataSourceAPI.getTagValues */ -export interface DataSourceGetTagValuesOptions { +export interface DataSourceGetTagValuesOptions + extends DataSourceFilteringRequestOptions { key: string; /** * The other existing filters or base filters. New in v10.3 */ filters: AdHocVariableFilter[]; - /** - * Context time range. New in v10.3 - */ - timeRange?: TimeRange; - queries?: TQuery[]; - scopes?: Scope[] | undefined; } export interface MetadataInspectorProps< @@ -646,12 +655,22 @@ export interface MetricFindValue { properties?: Record; } -export interface DataSourceGetDrilldownsApplicabilityOptions { +export interface DataSourceGetDrilldownsApplicabilityOptions + extends DataSourceFilteringRequestOptions { + filters?: AdHocVariableFilter[]; + groupByKeys?: string[]; +} + +export interface DataSourceGetRecommendedDrilldownsOptions + extends DataSourceFilteringRequestOptions { + dashboardUid?: string; + filters?: AdHocVariableFilter[]; + groupByKeys?: string[]; +} + +export interface DrilldownRecommendation { filters?: AdHocVariableFilter[]; groupByKeys?: string[]; - timeRange?: TimeRange; - queries?: TQuery[]; - scopes?: Scope[] | undefined; } export interface DrilldownsApplicability { diff --git a/packages/grafana-data/src/types/featureToggles.gen.ts b/packages/grafana-data/src/types/featureToggles.gen.ts index 0eab199b022..981b10dfb1c 100644 --- a/packages/grafana-data/src/types/featureToggles.gen.ts +++ b/packages/grafana-data/src/types/featureToggles.gen.ts @@ -126,11 +126,6 @@ export interface FeatureToggles { */ disableSSEDataplane?: boolean; /** - * Writes error logs to the request logger - * @default true - */ - unifiedRequestLog?: boolean; - /** * Uses JWT-based auth for rendering instead of relying on remote cache */ renderAuthJWT?: boolean; @@ -309,10 +304,6 @@ export interface FeatureToggles { */ queryServiceFromUI?: boolean; /** - * Routes explore requests to the new query service - */ - queryServiceFromExplore?: boolean; - /** * Runs CloudWatch metrics queries as separate batches */ cloudWatchBatchQueries?: boolean; @@ -377,6 +368,10 @@ export interface FeatureToggles { */ unlimitedLayoutsNesting?: boolean; /** + * Enables showing recently used drilldowns or recommendations given by the datasource in the AdHocFilters and GroupBy variables + */ + drilldownRecommendations?: boolean; + /** * Enables viewing non-applicable drilldowns on a panel level */ perPanelNonApplicableDrilldowns?: boolean; @@ -499,6 +494,10 @@ export interface FeatureToggles { */ newDashboardWithFiltersAndGroupBy?: boolean; /** + * Wraps the ad hoc and group by variables in a single wrapper, with all other variables below it + */ + dashboardAdHocAndGroupByWrapper?: boolean; + /** * Updates CloudWatch label parsing to be more accurate * @default true */ @@ -536,6 +535,10 @@ export interface FeatureToggles { */ alertingListViewV2?: boolean; /** + * Enables saved searches for alert rules list + */ + alertingSavedSearches?: boolean; + /** * Disables the ability to send alerts to an external Alertmanager datasource. */ alertingDisableSendAlertsExternal?: boolean; @@ -828,6 +831,10 @@ export interface FeatureToggles { */ fetchRulesUsingPost?: boolean; /** + * Add compact=true when fetching rules + */ + fetchRulesInCompactMode?: boolean; + /** * Enables the new logs panel * @default true */ @@ -1161,6 +1168,11 @@ export interface FeatureToggles { */ externalVizSuggestions?: boolean; /** + * Enable Y-axis scale configuration options for pre-bucketed heatmap data (heatmap-rows) + * @default false + */ + heatmapRowsAxisOptions?: boolean; + /** * Restrict PanelChrome contents with overflow: hidden; * @default true */ diff --git a/packages/grafana-data/tsconfig.json b/packages/grafana-data/tsconfig.json index d13025d3115..8e6013e32d9 100644 --- a/packages/grafana-data/tsconfig.json +++ b/packages/grafana-data/tsconfig.json @@ -3,10 +3,12 @@ "compilerOptions": { "declaration": true, "jsx": "react-jsx", + "baseUrl": "./", "declarationDir": "./dist/types", "emitDeclarationOnly": true, "isolatedModules": true, - "rootDirs": ["."] + "rootDirs": ["."], + "moduleResolution": "bundler" }, "exclude": ["dist/**/*"], "include": [ diff --git a/packages/grafana-e2e-selectors/package.json b/packages/grafana-e2e-selectors/package.json index 0dd5c5a9925..5527f4c0ca6 100644 --- a/packages/grafana-e2e-selectors/package.json +++ b/packages/grafana-e2e-selectors/package.json @@ -16,12 +16,19 @@ "url": "http://github.com/grafana/grafana.git", "directory": "packages/grafana-e2e-selectors" }, - "main": "src/index.ts", - "types": "src/index.ts", + "main": "./dist/cjs/index.cjs", + "module": "./dist/esm/index.mjs", + "types": "./dist/types/index.d.ts", + "exports": { + "./package.json": "./package.json", + ".": { + "@grafana-app/source": "./src/index.ts", + "types": "./dist/types/index.d.ts", + "import": "./dist/esm/index.mjs", + "require": "./dist/cjs/index.cjs" + } + }, "publishConfig": { - "main": "./dist/cjs/index.cjs", - "module": "./dist/esm/index.mjs", - "types": "./dist/types/index.d.ts", "access": "public" }, "files": [ diff --git a/packages/grafana-e2e-selectors/rollup.config.ts b/packages/grafana-e2e-selectors/rollup.config.ts index 1d47540a42a..a17799cc9a7 100644 --- a/packages/grafana-e2e-selectors/rollup.config.ts +++ b/packages/grafana-e2e-selectors/rollup.config.ts @@ -9,7 +9,7 @@ export default [ { input: entryPoint, plugins, - output: [cjsOutput(pkg), esmOutput(pkg, 'grafana-e2e-selectors')], + output: [cjsOutput(pkg, 'grafana-e2e-selectors'), esmOutput(pkg, 'grafana-e2e-selectors')], treeshake: false, }, ]; diff --git a/packages/grafana-e2e-selectors/src/resolver.test.ts b/packages/grafana-e2e-selectors/src/resolver.test.ts index a306f9261ed..888cf4fdc54 100644 --- a/packages/grafana-e2e-selectors/src/resolver.test.ts +++ b/packages/grafana-e2e-selectors/src/resolver.test.ts @@ -51,7 +51,7 @@ describe('Resolver', () => { expect(pages.Alerting.AddAlertRule.url).toBe('/alerting/new'); }); - it('should throw error if an invalid semver range is used in versioned selector', () => { + it('should throw an error if an invalid semver range is used in versioned selector', () => { expect(() => resolveSelectors({ Alerting: { diff --git a/packages/grafana-e2e-selectors/src/selectors/components.ts b/packages/grafana-e2e-selectors/src/selectors/components.ts index 0755477f93b..de04398a3e1 100644 --- a/packages/grafana-e2e-selectors/src/selectors/components.ts +++ b/packages/grafana-e2e-selectors/src/selectors/components.ts @@ -1332,6 +1332,7 @@ export const versionedComponents = { }, DebugOverlay: { wrapper: { + '12.3.0': 'data-testid debug-overlay-wrapper', '9.2.0': 'debug-overlay', }, }, diff --git a/packages/grafana-e2e-selectors/src/selectors/index.ts b/packages/grafana-e2e-selectors/src/selectors/index.ts index bfe90848026..3abef8119dd 100644 --- a/packages/grafana-e2e-selectors/src/selectors/index.ts +++ b/packages/grafana-e2e-selectors/src/selectors/index.ts @@ -9,7 +9,7 @@ const Components = resolveSelectors(versionedComponents); const selectors = { pages: Pages, components: Components }; /** - * Exposes Pages, Component selectors and E2ESelectors type in package for easy use in e2e tests and in production code + * Exposes Pages, Component selectors, and E2ESelectors type in package for easy use in e2e tests and in production code. */ export { Pages, diff --git a/packages/grafana-e2e-selectors/src/types/selectors.ts b/packages/grafana-e2e-selectors/src/types/selectors.ts index 036d6f36d4d..dbce9c93bd7 100644 --- a/packages/grafana-e2e-selectors/src/types/selectors.ts +++ b/packages/grafana-e2e-selectors/src/types/selectors.ts @@ -15,7 +15,7 @@ export type FunctionSelector = (id: string) => string; export type FunctionSelectorTwoArgs = (arg1: string, arg2: string) => string; /** - * A function selector without argument + * A function selector without arguments */ export type CssSelector = () => string; diff --git a/packages/grafana-e2e-selectors/tsconfig.json b/packages/grafana-e2e-selectors/tsconfig.json index 41f1fb8efb0..b3fd8756461 100644 --- a/packages/grafana-e2e-selectors/tsconfig.json +++ b/packages/grafana-e2e-selectors/tsconfig.json @@ -5,7 +5,8 @@ "declarationDir": "./dist/types", "emitDeclarationOnly": true, "isolatedModules": true, - "rootDirs": ["."] + "rootDirs": ["."], + "moduleResolution": "bundler" }, "exclude": ["dist/**/*"], "include": ["src/**/*.ts"] diff --git a/packages/grafana-flamegraph/package.json b/packages/grafana-flamegraph/package.json index f4ec11c7cfa..b1c16ed68d1 100644 --- a/packages/grafana-flamegraph/package.json +++ b/packages/grafana-flamegraph/package.json @@ -16,12 +16,19 @@ "url": "http://github.com/grafana/grafana.git", "directory": "packages/grafana-flamegraph" }, - "main": "src/index.ts", - "types": "src/index.ts", + "main": "./dist/cjs/index.cjs", + "module": "./dist/esm/index.mjs", + "types": "./dist/types/index.d.ts", + "exports": { + "./package.json": "./package.json", + ".": { + "@grafana-app/source": "./src/index.ts", + "types": "./dist/types/index.d.ts", + "import": "./dist/esm/index.mjs", + "require": "./dist/cjs/index.cjs" + } + }, "publishConfig": { - "main": "./dist/cjs/index.cjs", - "module": "./dist/esm/index.mjs", - "types": "./dist/types/index.d.ts", "access": "public" }, "files": [ diff --git a/packages/grafana-flamegraph/rollup.config.ts b/packages/grafana-flamegraph/rollup.config.ts index 967916710d6..190cd7a6922 100644 --- a/packages/grafana-flamegraph/rollup.config.ts +++ b/packages/grafana-flamegraph/rollup.config.ts @@ -9,7 +9,7 @@ export default [ { input: entryPoint, plugins, - output: [cjsOutput(pkg), esmOutput(pkg, 'grafana-flamegraph')], + output: [cjsOutput(pkg, 'grafana-flamegraph'), esmOutput(pkg, 'grafana-flamegraph')], treeshake: false, }, ]; diff --git a/packages/grafana-flamegraph/src/FlameGraph/FlameGraph.test.tsx b/packages/grafana-flamegraph/src/FlameGraph/FlameGraph.test.tsx index 64dc10da72e..b79074cfc6b 100644 --- a/packages/grafana-flamegraph/src/FlameGraph/FlameGraph.test.tsx +++ b/packages/grafana-flamegraph/src/FlameGraph/FlameGraph.test.tsx @@ -1,5 +1,5 @@ import { fireEvent, render, screen } from '@testing-library/react'; -import * as React from 'react'; +import { type ComponentProps, useRef } from 'react'; import { createDataFrame } from '@grafana/data'; @@ -16,14 +16,14 @@ jest.mock('react-use', () => { return { ...reactUse, useMeasure: () => { - const ref = React.useRef(); + const ref = useRef(null); return [ref, { width: 1600 }]; }, }; }); describe('FlameGraph', () => { - function setup(props?: Partial>) { + function setup(props?: Partial>) { const flameGraphData = createDataFrame(data); const container = new FlameGraphDataContainer(flameGraphData, { collapsing: true }); diff --git a/packages/grafana-flamegraph/src/FlameGraphContainer.test.tsx b/packages/grafana-flamegraph/src/FlameGraphContainer.test.tsx index 4fdb00d6748..f7e7c09957c 100644 --- a/packages/grafana-flamegraph/src/FlameGraphContainer.test.tsx +++ b/packages/grafana-flamegraph/src/FlameGraphContainer.test.tsx @@ -21,7 +21,7 @@ jest.mock('@grafana/assistant', () => ({ jest.mock('react-use', () => ({ ...jest.requireActual('react-use'), useMeasure: () => { - const ref = useRef(); + const ref = useRef(null); return [ref, { width: 1600 }]; }, })); diff --git a/packages/grafana-flamegraph/tsconfig.json b/packages/grafana-flamegraph/tsconfig.json index 0a1330e2114..7d4e07d6534 100644 --- a/packages/grafana-flamegraph/tsconfig.json +++ b/packages/grafana-flamegraph/tsconfig.json @@ -7,7 +7,8 @@ "declarationDir": "./dist/types", "emitDeclarationOnly": true, "isolatedModules": true, - "rootDirs": ["."] + "rootDirs": ["."], + "moduleResolution": "bundler" }, "exclude": ["dist/**/*"], "include": ["src/**/*.ts*", "../../public/app/types/*.d.ts", "../grafana-ui/src/types/*.d.ts"] diff --git a/packages/grafana-i18n/package.json b/packages/grafana-i18n/package.json index 824f594f8e6..36a9faa541b 100644 --- a/packages/grafana-i18n/package.json +++ b/packages/grafana-i18n/package.json @@ -14,33 +14,32 @@ "url": "http://github.com/grafana/grafana.git", "directory": "packages/grafana-i18n" }, - "main": "src/index.ts", - "types": "src/index.ts", - "module": "src/index.ts", + "main": "./dist/cjs/index.cjs", + "module": "./dist/esm/index.mjs", + "types": "./dist/types/index.d.ts", "exports": { "./package.json": "./package.json", ".": { - "import": "./src/index.ts", - "require": "./src/index.ts" + "@grafana-app/source": "./src/index.ts", + "types": "./dist/types/index.d.ts", + "import": "./dist/esm/index.mjs", + "require": "./dist/cjs/index.cjs" }, "./internal": { - "import": "./src/internal/index.ts", - "require": "./src/internal/index.ts" + "@grafana-app/source": "./src/internal/index.ts" }, "./eslint-plugin": { + "@grafana-app/source": "./src/eslint/index.cjs", "types": "./src/eslint/index.d.ts", - "import": "./src/eslint/index.cjs", - "require": "./src/eslint/index.cjs" + "default": "./src/eslint/index.cjs" } }, "publishConfig": { - "main": "./dist/cjs/index.cjs", - "module": "./dist/esm/index.mjs", - "types": "./dist/types/index.d.ts", "access": "public" }, "files": [ "dist", + "src/eslint/**/*", "./README.md", "./CHANGELOG.md", "LICENSE_APACHE2" diff --git a/packages/grafana-i18n/rollup.config.ts b/packages/grafana-i18n/rollup.config.ts index 1b1115f65c9..913791e7d69 100644 --- a/packages/grafana-i18n/rollup.config.ts +++ b/packages/grafana-i18n/rollup.config.ts @@ -1,5 +1,4 @@ import { createRequire } from 'node:module'; -import copy from 'rollup-plugin-copy'; import { entryPoint, plugins, esmOutput, cjsOutput } from '../rollup.config.parts'; @@ -9,13 +8,8 @@ const pkg = rq('./package.json'); export default [ { input: entryPoint, - plugins: [ - ...plugins, - copy({ - targets: [{ src: 'src/eslint', dest: 'dist' }], - }), - ], - output: [cjsOutput(pkg), esmOutput(pkg, 'grafana-i18n')], + plugins, + output: [cjsOutput(pkg, 'grafana-i18n'), esmOutput(pkg, 'grafana-i18n')], treeshake: false, }, ]; diff --git a/packages/grafana-i18n/tsconfig.json b/packages/grafana-i18n/tsconfig.json index 2c83128f0f1..b1340cd69d0 100644 --- a/packages/grafana-i18n/tsconfig.json +++ b/packages/grafana-i18n/tsconfig.json @@ -6,7 +6,8 @@ "declarationDir": "./dist/types", "emitDeclarationOnly": true, "isolatedModules": true, - "rootDirs": ["."] + "rootDirs": ["."], + "moduleResolution": "bundler" }, "exclude": ["dist/**/*"], "include": ["src/**/*.ts*"] diff --git a/packages/grafana-o11y-ds-frontend/tsconfig.json b/packages/grafana-o11y-ds-frontend/tsconfig.json index c77d4f035c9..1817cc219ce 100644 --- a/packages/grafana-o11y-ds-frontend/tsconfig.json +++ b/packages/grafana-o11y-ds-frontend/tsconfig.json @@ -8,7 +8,8 @@ "emitDeclarationOnly": true, "isolatedModules": true, "allowJs": true, - "rootDirs": ["."] + "rootDirs": ["."], + "moduleResolution": "bundler" }, "exclude": ["dist/**/*"], "include": [ diff --git a/packages/grafana-plugin-configs/jest/jest.config.js b/packages/grafana-plugin-configs/jest/jest.config.js index 1f87fd10556..05e5a701226 100644 --- a/packages/grafana-plugin-configs/jest/jest.config.js +++ b/packages/grafana-plugin-configs/jest/jest.config.js @@ -17,6 +17,9 @@ export default { setupFiles: ['jest-canvas-mock'], setupFilesAfterEnv: ['/jest-setup.js'], testEnvironment: 'jsdom', + testEnvironmentOptions: { + customExportConditions: ['@grafana-app/source', 'browser'], + }, testMatch: ['/**/__tests__/**/*.{js,jsx,ts,tsx}', '/**/*.{spec,test,jest}.{js,jsx,ts,tsx}'], transform: { '^.+\\.(t|j)sx?$': [ diff --git a/packages/grafana-plugin-configs/tsconfig.json b/packages/grafana-plugin-configs/tsconfig.json index b7a0dd239e8..db619d2b1c2 100644 --- a/packages/grafana-plugin-configs/tsconfig.json +++ b/packages/grafana-plugin-configs/tsconfig.json @@ -1,12 +1,13 @@ { "compilerOptions": { - "jsx": "react-jsx", + "allowImportingTsExtensions": true, "alwaysStrict": true, + "customConditions": ["@grafana-app/source"], "declaration": false, - "resolveJsonModule": true, + "jsx": "react-jsx", "moduleResolution": "bundler", "noEmit": true, - "allowImportingTsExtensions": true + "resolveJsonModule": true }, "extends": "@grafana/tsconfig", "exclude": ["**/*.test.ts", "**/*.test.tsx", "**/*.spec.ts", "**/*.spec.tsx"], diff --git a/packages/grafana-plugin-configs/webpack.config.ts b/packages/grafana-plugin-configs/webpack.config.ts index 6f2846b5a97..8bfcdcec69a 100644 --- a/packages/grafana-plugin-configs/webpack.config.ts +++ b/packages/grafana-plugin-configs/webpack.config.ts @@ -312,6 +312,7 @@ const config = async (env: Env): Promise => { resolve: { extensions: ['.ts', '.tsx', '.js', '.jsx'], + conditionNames: ['@grafana-app/source', '...'], unsafeCache: true, }, diff --git a/packages/grafana-prometheus/package.json b/packages/grafana-prometheus/package.json index 8ed4bd95d5a..6d6fa062635 100644 --- a/packages/grafana-prometheus/package.json +++ b/packages/grafana-prometheus/package.json @@ -15,8 +15,18 @@ "url": "http://github.com/grafana/grafana.git", "directory": "packages/grafana-prometheus" }, - "main": "src/index.ts", - "types": "src/index.ts", + "main": "./dist/cjs/index.cjs", + "module": "./dist/esm/index.mjs", + "types": "./dist/types/index.d.ts", + "exports": { + "./package.json": "./package.json", + ".": { + "@grafana-app/source": "./src/index.ts", + "types": "./dist/types/index.d.ts", + "import": "./dist/esm/index.mjs", + "require": "./dist/cjs/index.cjs" + } + }, "files": [ "./dist", "./README.md", @@ -24,9 +34,6 @@ "./LICENSE_AGPL" ], "publishConfig": { - "main": "./dist/cjs/index.cjs", - "module": "./dist/esm/index.mjs", - "types": "./dist/types/index.d.ts", "access": "public" }, "scripts": { diff --git a/packages/grafana-prometheus/rollup.config.ts b/packages/grafana-prometheus/rollup.config.ts index 8dbc60c8935..28083b2d26f 100644 --- a/packages/grafana-prometheus/rollup.config.ts +++ b/packages/grafana-prometheus/rollup.config.ts @@ -12,7 +12,7 @@ export default [ { input: entryPoint, plugins: [...plugins, image(), json(), dynamicImportVars()], - output: [cjsOutput(pkg), esmOutput(pkg, 'grafana-prometheus')], + output: [cjsOutput(pkg, 'grafana-prometheus'), esmOutput(pkg, 'grafana-prometheus')], treeshake: false, }, ]; diff --git a/packages/grafana-runtime/package.json b/packages/grafana-runtime/package.json index a46d08d4623..acf3f60bbc3 100644 --- a/packages/grafana-runtime/package.json +++ b/packages/grafana-runtime/package.json @@ -14,28 +14,28 @@ "url": "http://github.com/grafana/grafana.git", "directory": "packages/grafana-runtime" }, - "main": "src/index.ts", - "types": "src/index.ts", - "module": "src/index.ts", + "main": "./dist/cjs/index.cjs", + "module": "./dist/esm/index.mjs", + "types": "./dist/types/index.d.ts", "exports": { "./package.json": "./package.json", ".": { - "import": "./src/index.ts", - "require": "./src/index.ts" - }, - "./internal": { - "import": "./src/internal/index.ts", - "require": "./src/internal/index.ts" + "@grafana-app/source": "./src/index.ts", + "types": "./dist/types/index.d.ts", + "import": "./dist/esm/index.mjs", + "require": "./dist/cjs/index.cjs" }, "./unstable": { - "import": "./src/unstable.ts", - "require": "./src/unstable.ts" + "@grafana-app/source": "./src/unstable.ts", + "types": "./dist/types/unstable.d.ts", + "import": "./dist/esm/unstable.mjs", + "require": "./dist/cjs/unstable.cjs" + }, + "./internal": { + "@grafana-app/source": "./src/internal/index.ts" } }, "publishConfig": { - "main": "./dist/cjs/index.cjs", - "module": "./dist/esm/index.mjs", - "types": "./dist/types/index.d.ts", "access": "public" }, "files": [ @@ -49,8 +49,8 @@ "bundle": "rollup -c rollup.config.ts --configPlugin esbuild", "clean": "rimraf ./dist ./compiled ./unstable ./package.tgz", "typecheck": "tsc --emitDeclarationOnly false --noEmit", - "prepack": "cp package.json package.json.bak && ALIAS_PACKAGE_NAME=unstable node ../../scripts/prepare-npm-package.js", - "postpack": "mv package.json.bak package.json && rimraf ./unstable" + "prepack": "cp package.json package.json.bak && node ../../scripts/prepare-npm-package.js", + "postpack": "mv package.json.bak package.json" }, "dependencies": { "@grafana/data": "12.4.0-pre", diff --git a/packages/grafana-runtime/rollup.config.ts b/packages/grafana-runtime/rollup.config.ts index 5807c919136..120ad98645d 100644 --- a/packages/grafana-runtime/rollup.config.ts +++ b/packages/grafana-runtime/rollup.config.ts @@ -9,13 +9,13 @@ export default [ { input: entryPoint, plugins, - output: [cjsOutput(pkg), esmOutput(pkg, 'grafana-runtime')], + output: [cjsOutput(pkg, 'grafana-runtime'), esmOutput(pkg, 'grafana-runtime')], treeshake: false, }, { input: 'src/unstable.ts', plugins, - output: [cjsOutput(pkg), esmOutput(pkg, 'grafana-runtime')], + output: [cjsOutput(pkg, 'grafana-runtime'), esmOutput(pkg, 'grafana-runtime')], treeshake: false, }, ]; diff --git a/packages/grafana-runtime/src/config.ts b/packages/grafana-runtime/src/config.ts index 17fbbef447a..18cce14f236 100644 --- a/packages/grafana-runtime/src/config.ts +++ b/packages/grafana-runtime/src/config.ts @@ -224,6 +224,7 @@ export class GrafanaBootConfig { rudderstackWriteKey?: string; rudderstackDataPlaneUrl?: string; rudderstackSdkUrl?: string; + rudderstackV3SdkUrl?: string; rudderstackConfigUrl?: string; rudderstackIntegrationsUrl?: string; analyticsConsoleReporting = false; diff --git a/packages/grafana-runtime/src/index.ts b/packages/grafana-runtime/src/index.ts index 489f9157700..58b30be8542 100644 --- a/packages/grafana-runtime/src/index.ts +++ b/packages/grafana-runtime/src/index.ts @@ -9,7 +9,15 @@ export * from './analytics/types'; export { loadPluginCss, type PluginCssOptions, setPluginImportUtils, getPluginImportUtils } from './utils/plugin'; export { reportMetaAnalytics, reportInteraction, reportPageview, reportExperimentView } from './analytics/utils'; export { featureEnabled } from './utils/licensing'; -export { logInfo, logDebug, logWarning, logError, createMonitoringLogger, logMeasurement } from './utils/logging'; +export { + logInfo, + logDebug, + logWarning, + logError, + createMonitoringLogger, + logMeasurement, + type MonitoringLogger, +} from './utils/logging'; export { DataSourceWithBackend, HealthCheckError, diff --git a/packages/grafana-runtime/src/services/pluginExtensions/utils.test.tsx b/packages/grafana-runtime/src/services/pluginExtensions/utils.test.tsx index b62ae46f27c..b139fa80a75 100644 --- a/packages/grafana-runtime/src/services/pluginExtensions/utils.test.tsx +++ b/packages/grafana-runtime/src/services/pluginExtensions/utils.test.tsx @@ -262,24 +262,18 @@ function createComponent( pluginId?: string, id?: string ): ComponentTypeWithExtensionMeta { - function ComponentWithMeta(props: Props) { - if (Implementation) { - return ; + const ComponentWithMeta: ComponentTypeWithExtensionMeta = Object.assign( + Implementation || (() =>
Test
), + { + meta: { + id: id ?? '', + pluginId: pluginId ?? '', + title: '', + description: '', + type: PluginExtensionTypes.component, + } satisfies PluginExtensionComponentMeta, } - - return
Test
; - } - - ComponentWithMeta.displayName = ''; - ComponentWithMeta.propTypes = {}; - ComponentWithMeta.contextTypes = {}; - ComponentWithMeta.meta = { - id: id ?? '', - pluginId: pluginId ?? '', - title: '', - description: '', - type: PluginExtensionTypes.component, - } satisfies PluginExtensionComponentMeta; + ); return ComponentWithMeta; } diff --git a/packages/grafana-runtime/src/utils/DataSourceWithBackend.ts b/packages/grafana-runtime/src/utils/DataSourceWithBackend.ts index 2e7153328e9..047e8c8fce9 100644 --- a/packages/grafana-runtime/src/utils/DataSourceWithBackend.ts +++ b/packages/grafana-runtime/src/utils/DataSourceWithBackend.ts @@ -17,7 +17,6 @@ import { parseLiveChannelAddress, ScopedVars, AdHocVariableFilter, - CoreApp, } from '@grafana/data'; import { reportInteraction } from '../analytics/utils'; @@ -209,11 +208,6 @@ class DataSourceWithBackend< let url = '/api/ds/query?ds_type=' + this.type; - // Use the new query service for explore - if (config.featureToggles.queryServiceFromExplore && request.app === CoreApp.Explore) { - url = `/apis/query.grafana.app/v0alpha1/namespaces/${config.namespace}/query?ds_type=${this.type}`; - } - // Use the new query service if (config.featureToggles.queryServiceFromUI) { url = `/apis/query.grafana.app/v0alpha1/namespaces/${config.namespace}/query?ds_type=${this.type}`; diff --git a/packages/grafana-runtime/tsconfig.json b/packages/grafana-runtime/tsconfig.json index 9dec8dd53ed..bbfc33b77ed 100644 --- a/packages/grafana-runtime/tsconfig.json +++ b/packages/grafana-runtime/tsconfig.json @@ -8,7 +8,8 @@ "emitDeclarationOnly": true, "isolatedModules": true, "allowJs": true, - "rootDirs": ["."] + "rootDirs": ["."], + "moduleResolution": "bundler" }, "exclude": ["dist/**/*"], "include": [ diff --git a/packages/grafana-schema/package.json b/packages/grafana-schema/package.json index 067475cd209..4f48e1511b2 100644 --- a/packages/grafana-schema/package.json +++ b/packages/grafana-schema/package.json @@ -13,13 +13,14 @@ "url": "http://github.com/grafana/grafana.git", "directory": "packages/grafana-schema" }, - "main": "src/index.ts", - "types": "src/index.ts", + "main": "./src/index.ts", + "module": "./src/index.ts", + "types": "./src/index.ts", "publishConfig": { + "access": "public", "main": "./dist/cjs/index.cjs", "module": "./dist/esm/index.mjs", - "types": "./dist/types/index.d.ts", - "access": "public" + "types": "./dist/types/index.d.ts" }, "files": [ "dist", diff --git a/packages/grafana-schema/rollup.config.ts b/packages/grafana-schema/rollup.config.ts index 04928f75c47..4e5f77b3deb 100644 --- a/packages/grafana-schema/rollup.config.ts +++ b/packages/grafana-schema/rollup.config.ts @@ -15,7 +15,12 @@ export default [ { input: entryPoint, plugins, - output: [cjsOutput(pkg), esmOutput(pkg, 'grafana-schema')], + output: [ + // Schema still uses publishConfig to define output directory. + // TODO: Migrate this package to use exports. + cjsOutput(pkg, 'grafana-schema', { dir: path.dirname(pkg.publishConfig.main) }), + esmOutput(pkg, 'grafana-schema', { dir: path.dirname(pkg.publishConfig.module) }), + ], treeshake: false, }, { diff --git a/packages/grafana-schema/src/raw/composable/heatmap/panelcfg/x/HeatmapPanelCfg_types.gen.ts b/packages/grafana-schema/src/raw/composable/heatmap/panelcfg/x/HeatmapPanelCfg_types.gen.ts index 1ff4370c9a2..b67a8cf5980 100644 --- a/packages/grafana-schema/src/raw/composable/heatmap/panelcfg/x/HeatmapPanelCfg_types.gen.ts +++ b/packages/grafana-schema/src/raw/composable/heatmap/panelcfg/x/HeatmapPanelCfg_types.gen.ts @@ -185,6 +185,10 @@ export interface RowsHeatmapOptions { * Sets the name of the cell when not calculating from data */ value?: string; + /** + * Controls the scale distribution of the y-axis buckets + */ + yBucketScale?: ui.ScaleDistributionConfig; } export interface Options { 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 34aa9ac015b..f2423566ff5 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 @@ -838,6 +838,11 @@ export const defaultDashboardCursorSync: DashboardCursorSync = DashboardCursorSy * Dashboard panels are the basic visualization building blocks. */ export interface Panel { + /** + * When a panel is migrated from a previous version (Angular to React), this field is set to the original panel type. + * This is used to determine the original panel type when migrating to a new version so the plugin migration can be applied. + */ + autoMigrateFrom?: string; /** * Sets panel queries cache timeout. */ diff --git a/packages/grafana-schema/tsconfig.json b/packages/grafana-schema/tsconfig.json index 2c83128f0f1..8012f3267e6 100644 --- a/packages/grafana-schema/tsconfig.json +++ b/packages/grafana-schema/tsconfig.json @@ -3,10 +3,12 @@ "compilerOptions": { "declaration": true, "jsx": "react-jsx", + "baseUrl": "./", "declarationDir": "./dist/types", "emitDeclarationOnly": true, "isolatedModules": true, - "rootDirs": ["."] + "rootDirs": ["."], + "moduleResolution": "bundler" }, "exclude": ["dist/**/*"], "include": ["src/**/*.ts*"] diff --git a/packages/grafana-sql/src/utils/logging.ts b/packages/grafana-sql/src/utils/logging.ts index 95900184359..2d481dc4b8a 100644 --- a/packages/grafana-sql/src/utils/logging.ts +++ b/packages/grafana-sql/src/utils/logging.ts @@ -1,3 +1,3 @@ -import { createMonitoringLogger } from '@grafana/runtime'; +import { createMonitoringLogger, MonitoringLogger } from '@grafana/runtime'; -export const sqlPluginLogger = createMonitoringLogger('features.plugins.sql'); +export const sqlPluginLogger: MonitoringLogger = createMonitoringLogger('features.plugins.sql'); diff --git a/packages/grafana-sql/tsconfig.json b/packages/grafana-sql/tsconfig.json index 4bd2161f0e0..87f6db544ad 100644 --- a/packages/grafana-sql/tsconfig.json +++ b/packages/grafana-sql/tsconfig.json @@ -8,7 +8,8 @@ "emitDeclarationOnly": true, "isolatedModules": true, "strict": true, - "rootDirs": ["."] + "rootDirs": ["."], + "moduleResolution": "bundler" }, "exclude": ["dist/**/*"], "include": ["src/**/*.ts*", "../../public/app/types/*.d.ts", "../grafana-ui/src/types/*.d.ts"] diff --git a/packages/grafana-test-utils/src/fixtures/teams.ts b/packages/grafana-test-utils/src/fixtures/teams.ts index 4039129fb5d..e12cee069dd 100644 --- a/packages/grafana-test-utils/src/fixtures/teams.ts +++ b/packages/grafana-test-utils/src/fixtures/teams.ts @@ -24,13 +24,15 @@ export const MOCK_TEAMS = [ }, ]; +export const MOCK_TEAM_GROUPS = [{ groupId: 'cn=users,ou=groups,dc=grafana,dc=org' }, { groupId: 'another-group' }]; + export const setupMockTeams = () => { mockTeamsMap.clear(); MOCK_TEAMS.forEach((team) => { - mockTeamsMap.set(team.metadata.name, { team, groups: [] }); + mockTeamsMap.set(team.metadata.name, { team, groups: [...MOCK_TEAM_GROUPS] }); }); }; export const mockTeamsMap = new Map }>( - MOCK_TEAMS.map((team) => [team.metadata.name, { team, groups: [] }]) + MOCK_TEAMS.map((team) => [team.metadata.name, { team, groups: [...MOCK_TEAM_GROUPS] }]) ); diff --git a/packages/grafana-test-utils/src/handlers/api/teams/handlers.ts b/packages/grafana-test-utils/src/handlers/api/teams/handlers.ts index c8a42bf9bba..55cbf7a5621 100644 --- a/packages/grafana-test-utils/src/handlers/api/teams/handlers.ts +++ b/packages/grafana-test-utils/src/handlers/api/teams/handlers.ts @@ -79,7 +79,7 @@ const teamsGroupsHandler = () => return HttpResponse.json(team.groups); }); -const teamsUpdateGroupsHandler = () => +const teamsAddGroupHandler = () => http.post<{ uid: string }, { groupId: string }>('/api/teams/:uid/groups', async ({ params, request }) => { const teamData = mockTeamsMap.get(params.uid); const body = await request.json(); @@ -95,6 +95,29 @@ const teamsUpdateGroupsHandler = () => return HttpResponse.json({ message: 'Group added to Team' }); }); +const teamsRemoveGroupHandler = () => + http.delete<{ uid: string }>('/api/teams/:uid/groups', async ({ params, request }) => { + const teamData = mockTeamsMap.get(params.uid); + const url = new URL(request.url); + const groupId = url.searchParams.get('groupId'); + + if (!teamData) { + return HttpResponse.json({ message: 'Not found' }, { status: 404 }); + } + + if (!groupId) { + return HttpResponse.json({ message: 'Missing groupId' }, { status: 400 }); + } + + const updatedTeam = { + ...teamData, + groups: teamData.groups.filter((g) => g.groupId !== groupId), + }; + mockTeamsMap.set(params.uid, updatedTeam); + + return HttpResponse.json({ message: 'Group removed from Team' }); + }); + const searchTeamsHandler = () => http.get('/api/teams/search', async ({ request }) => { const url = new URL(request.url); @@ -150,7 +173,8 @@ const updateTeamHandler = () => const handlers = [ teamsPreferencesHandler(), teamsGroupsHandler(), - teamsUpdateGroupsHandler(), + teamsAddGroupHandler(), + teamsRemoveGroupHandler(), searchTeamsHandler(), getTeamHandler(), deleteTeamHandler(), diff --git a/packages/grafana-test-utils/src/unstable.ts b/packages/grafana-test-utils/src/unstable.ts index 8758e294464..d03bc685d9e 100644 --- a/packages/grafana-test-utils/src/unstable.ts +++ b/packages/grafana-test-utils/src/unstable.ts @@ -1,4 +1,4 @@ import { wellFormedTree } from './fixtures/folders'; export const getFolderFixtures = wellFormedTree; -export { MOCK_TEAMS } from './fixtures/teams'; +export { MOCK_TEAMS, MOCK_TEAM_GROUPS } from './fixtures/teams'; diff --git a/packages/grafana-ui/.storybook/main.ts b/packages/grafana-ui/.storybook/main.ts index 29258c4a228..9bbf711b5c2 100644 --- a/packages/grafana-ui/.storybook/main.ts +++ b/packages/grafana-ui/.storybook/main.ts @@ -95,6 +95,16 @@ const mainConfig: StorybookConfig = { }, }); + // Tell storybook to resolve imports with the @grafana-app/source condition for + // the packages in this repo. + if (config && config.resolve) { + if (Array.isArray(config.resolve.conditionNames)) { + config.resolve.conditionNames.unshift('@grafana-app/source'); + } else { + config.resolve.conditionNames = ['@grafana-app/source', '...']; + } + } + return config; }, }; diff --git a/packages/grafana-ui/.storybook/tsconfig.json b/packages/grafana-ui/.storybook/tsconfig.json index cbcee5966e1..9d5c974f558 100644 --- a/packages/grafana-ui/.storybook/tsconfig.json +++ b/packages/grafana-ui/.storybook/tsconfig.json @@ -1,8 +1,7 @@ { "compilerOptions": { "declarationDir": "dist", - "noUnusedLocals": false, - "outDir": "compiled" + "noUnusedLocals": false }, "extends": "../tsconfig.json", "include": ["../src/**/*.ts*", "../../../public/app/types/svg.d.ts"] diff --git a/packages/grafana-ui/package.json b/packages/grafana-ui/package.json index f4a358d1654..478c44704ed 100644 --- a/packages/grafana-ui/package.json +++ b/packages/grafana-ui/package.json @@ -16,28 +16,28 @@ "url": "http://github.com/grafana/grafana.git", "directory": "packages/grafana-ui" }, - "main": "src/index.ts", - "types": "src/index.ts", - "module": "src/index.ts", + "main": "./dist/cjs/index.cjs", + "module": "./dist/esm/index.mjs", + "types": "./dist/types/index.d.ts", "exports": { "./package.json": "./package.json", ".": { - "import": "./src/index.ts", - "require": "./src/index.ts" - }, - "./internal": { - "import": "./src/internal/index.ts", - "require": "./src/internal/index.ts" + "@grafana-app/source": "./src/index.ts", + "types": "./dist/types/index.d.ts", + "import": "./dist/esm/index.mjs", + "require": "./dist/cjs/index.cjs" }, "./unstable": { - "import": "./src/unstable.ts", - "require": "./src/unstable.ts" + "@grafana-app/source": "./src/unstable.ts", + "types": "./dist/types/unstable.d.ts", + "import": "./dist/esm/unstable.mjs", + "require": "./dist/cjs/unstable.cjs" + }, + "./internal": { + "@grafana-app/source": "./src/internal/index.ts" } }, "publishConfig": { - "main": "./dist/cjs/index.cjs", - "module": "./dist/esm/index.mjs", - "types": "./dist/types/index.d.ts", "access": "public" }, "files": [ @@ -55,8 +55,8 @@ "storybook:build": "storybook build -o ./dist/storybook -c .storybook", "storybook:test": "test-storybook --url http://localhost:9001", "typecheck": "tsc --emitDeclarationOnly false --noEmit", - "prepack": "cp package.json package.json.bak && ALIAS_PACKAGE_NAME=unstable node ../../scripts/prepare-npm-package.js", - "postpack": "mv package.json.bak package.json && rimraf ./unstable" + "prepack": "cp package.json package.json.bak && node ../../scripts/prepare-npm-package.js", + "postpack": "mv package.json.bak package.json" }, "browserslist": [ "defaults", diff --git a/packages/grafana-ui/rollup.config.ts b/packages/grafana-ui/rollup.config.ts index 16c81ca4af8..14ff11d279b 100644 --- a/packages/grafana-ui/rollup.config.ts +++ b/packages/grafana-ui/rollup.config.ts @@ -24,7 +24,7 @@ export default [ flatten: false, }), ], - output: [cjsOutput(pkg), esmOutput(pkg, 'grafana-ui')], + output: [cjsOutput(pkg, 'grafana-ui'), esmOutput(pkg, 'grafana-ui')], treeshake: false, }, { @@ -37,7 +37,7 @@ export default [ flatten: false, }), ], - output: [cjsOutput(pkg), esmOutput(pkg, 'grafana-ui')], + output: [cjsOutput(pkg, 'grafana-ui'), esmOutput(pkg, 'grafana-ui')], treeshake: false, }, ]; diff --git a/packages/grafana-ui/src/components/Dropdown/Dropdown.tsx b/packages/grafana-ui/src/components/Dropdown/Dropdown.tsx index 6332b5ceefa..ed1053f09a4 100644 --- a/packages/grafana-ui/src/components/Dropdown/Dropdown.tsx +++ b/packages/grafana-ui/src/components/Dropdown/Dropdown.tsx @@ -111,7 +111,7 @@ export const Dropdown = React.memo(({ children, overlay, placement, offset, root timeout={{ appear: animationDuration, exit: 0, enter: 0 }} classNames={animationStyles} > -
{renderOrCallToRender(overlay, { ...getFloatingProps() })}
+
{renderOrCallToRender(overlay, {})}
diff --git a/packages/grafana-ui/src/components/Forms/Legacy/Select/SelectOptionGroup.tsx b/packages/grafana-ui/src/components/Forms/Legacy/Select/SelectOptionGroup.tsx index aecc7bf4514..a249db3eb2e 100644 --- a/packages/grafana-ui/src/components/Forms/Legacy/Select/SelectOptionGroup.tsx +++ b/packages/grafana-ui/src/components/Forms/Legacy/Select/SelectOptionGroup.tsx @@ -94,4 +94,5 @@ class UnthemedSelectOptionGroup extends PureComponent } } -export const SelectOptionGroup = withTheme2(UnthemedSelectOptionGroup); +// TODO: type this properly +export const SelectOptionGroup: React.FC = withTheme2(UnthemedSelectOptionGroup); diff --git a/packages/grafana-ui/src/components/Modal/getModalStyles.ts b/packages/grafana-ui/src/components/Modal/getModalStyles.ts index 3c124d24e68..f1e92cfa3f6 100644 --- a/packages/grafana-ui/src/components/Modal/getModalStyles.ts +++ b/packages/grafana-ui/src/components/Modal/getModalStyles.ts @@ -79,7 +79,7 @@ export const getModalStyles = (theme: GrafanaTheme2) => { modalContent: css({ overflow: 'auto', padding: theme.spacing(3, 3, 0, 3), - marginBottom: theme.spacing(3), + marginBottom: theme.spacing(2.5), scrollbarWidth: 'thin', width: '100%', diff --git a/packages/grafana-ui/src/components/Select/ValueContainer.tsx b/packages/grafana-ui/src/components/Select/ValueContainer.tsx index 6eb8326ae5d..f39666c8c5f 100644 --- a/packages/grafana-ui/src/components/Select/ValueContainer.tsx +++ b/packages/grafana-ui/src/components/Select/ValueContainer.tsx @@ -76,4 +76,5 @@ class UnthemedValueContainer>> = + withTheme2(UnthemedValueContainer); diff --git a/packages/grafana-ui/src/components/Select/resetSelectStyles.ts b/packages/grafana-ui/src/components/Select/resetSelectStyles.ts index 90ac3877c2a..1432c01e1da 100644 --- a/packages/grafana-ui/src/components/Select/resetSelectStyles.ts +++ b/packages/grafana-ui/src/components/Select/resetSelectStyles.ts @@ -1,9 +1,9 @@ import { useMemo } from 'react'; -import { CSSObjectWithLabel } from 'react-select'; +import { StylesConfig } from 'react-select'; import { GrafanaTheme2 } from '@grafana/data'; -export default function resetSelectStyles(theme: GrafanaTheme2) { +export default function resetSelectStyles(theme: GrafanaTheme2): Partial { return { clearIndicator: () => ({}), container: () => ({}), @@ -13,7 +13,7 @@ export default function resetSelectStyles(theme: GrafanaTheme2) { groupHeading: () => ({}), indicatorsContainer: () => ({}), indicatorSeparator: () => ({}), - input: function (originalStyles: CSSObjectWithLabel) { + input: function (originalStyles) { return { ...originalStyles, color: 'inherit', @@ -27,7 +27,7 @@ export default function resetSelectStyles(theme: GrafanaTheme2) { loadingIndicator: () => ({}), loadingMessage: () => ({}), menu: () => ({}), - menuList: ({ maxHeight }: { maxHeight: number }) => ({ + menuList: ({ maxHeight }) => ({ maxHeight, }), multiValue: () => ({}), @@ -38,7 +38,7 @@ export default function resetSelectStyles(theme: GrafanaTheme2) { multiValueRemove: () => ({}), noOptionsMessage: () => ({}), option: () => ({}), - placeholder: (originalStyles: CSSObjectWithLabel) => ({ + placeholder: (originalStyles) => ({ ...originalStyles, color: theme.colors.text.secondary, }), @@ -47,11 +47,11 @@ export default function resetSelectStyles(theme: GrafanaTheme2) { }; } -export function useCustomSelectStyles(theme: GrafanaTheme2, width: number | string | undefined) { +export function useCustomSelectStyles(theme: GrafanaTheme2, width: number | string | undefined): Partial { return useMemo(() => { return { ...resetSelectStyles(theme), - menuPortal: (base: CSSObjectWithLabel) => { + menuPortal: (base) => { // Would like to correct top position when menu is placed bottom, but have props are not sent to this style function. // Only state is. https://github.com/JedWatson/react-select/blob/master/packages/react-select/src/components/Menu.tsx#L605 return { @@ -60,7 +60,7 @@ export function useCustomSelectStyles(theme: GrafanaTheme2, width: number | stri }; }, //These are required for the menu positioning to function - menu: ({ top, bottom, position }: CSSObjectWithLabel) => { + menu: ({ top, bottom, position }) => { return { top, bottom, @@ -73,7 +73,7 @@ export function useCustomSelectStyles(theme: GrafanaTheme2, width: number | stri width: width ? theme.spacing(width) : '100%', display: width === 'auto' ? 'inline-flex' : 'flex', }), - option: (provided: CSSObjectWithLabel, state: any) => ({ + option: (provided, state) => ({ ...provided, opacity: state.isDisabled ? 0.5 : 1, }), diff --git a/packages/grafana-ui/src/components/Table/CellActions.tsx b/packages/grafana-ui/src/components/Table/CellActions.tsx index e2fe8a658ba..f21be659c4f 100644 --- a/packages/grafana-ui/src/components/Table/CellActions.tsx +++ b/packages/grafana-ui/src/components/Table/CellActions.tsx @@ -1,3 +1,4 @@ +import { isPlainObject } from 'lodash'; import { useCallback } from 'react'; import * as React from 'react'; @@ -63,7 +64,18 @@ export function CellActions({ tooltip={t('grafana-ui.table.cell-inspect', 'Inspect value')} onClick={() => { if (setInspectCell) { - setInspectCell({ value: cell.value, mode: previewMode }); + let mode = TableCellInspectorMode.text; + let inspectValue = cell.value; + try { + const parsed = typeof inspectValue === 'string' ? JSON.parse(inspectValue) : inspectValue; + if (Array.isArray(parsed) || isPlainObject(parsed)) { + inspectValue = JSON.stringify(parsed, null, 2); + mode = TableCellInspectorMode.code; + } + } catch { + // do nothing + } + setInspectCell({ value: inspectValue, mode }); } }} {...commonButtonProps} diff --git a/packages/grafana-ui/src/components/Table/Table.story.tsx b/packages/grafana-ui/src/components/Table/Table.story.tsx index b6c97df317e..e3d5e4b56cc 100644 --- a/packages/grafana-ui/src/components/Table/Table.story.tsx +++ b/packages/grafana-ui/src/components/Table/Table.story.tsx @@ -263,7 +263,16 @@ export const Footer: StoryFn = (args) => { ); }; -export const Pagination: StoryFn = (args) => ; +export const Pagination: StoryFn = (args) => { + const theme = useTheme2(); + const data = buildData(theme, {}); + + return ( + + + + ); +}; Pagination.args = { enablePagination: true, }; diff --git a/packages/grafana-ui/src/components/VizLegend/VizLegendTable.test.tsx b/packages/grafana-ui/src/components/VizLegend/VizLegendTable.test.tsx new file mode 100644 index 00000000000..131133bcdfb --- /dev/null +++ b/packages/grafana-ui/src/components/VizLegend/VizLegendTable.test.tsx @@ -0,0 +1,78 @@ +import { render, screen } from '@testing-library/react'; + +import { VizLegendTable } from './VizLegendTable'; +import { VizLegendItem } from './types'; + +describe('VizLegendTable', () => { + const mockItems: VizLegendItem[] = [ + { label: 'Series 1', color: 'red', yAxis: 1 }, + { label: 'Series 2', color: 'blue', yAxis: 1 }, + { label: 'Series 3', color: 'green', yAxis: 1 }, + ]; + + it('renders without crashing', () => { + const { container } = render(); + expect(container.querySelector('table')).toBeInTheDocument(); + }); + + it('renders all items', () => { + render(); + expect(screen.getByText('Series 1')).toBeInTheDocument(); + expect(screen.getByText('Series 2')).toBeInTheDocument(); + expect(screen.getByText('Series 3')).toBeInTheDocument(); + }); + + it('renders table headers when items have display values', () => { + const itemsWithStats: VizLegendItem[] = [ + { + label: 'Series 1', + color: 'red', + yAxis: 1, + getDisplayValues: () => [ + { numeric: 100, text: '100', title: 'Max' }, + { numeric: 50, text: '50', title: 'Min' }, + ], + }, + ]; + render(); + expect(screen.getByText('Max')).toBeInTheDocument(); + expect(screen.getByText('Min')).toBeInTheDocument(); + }); + + it('renders sort icon when sorted', () => { + const { container } = render( + + ); + expect(container.querySelector('svg')).toBeInTheDocument(); + }); + + it('calls onToggleSort when header is clicked', () => { + const onToggleSort = jest.fn(); + render(); + const header = screen.getByText('Name'); + header.click(); + expect(onToggleSort).toHaveBeenCalledWith('Name'); + }); + + it('does not call onToggleSort when not sortable', () => { + const onToggleSort = jest.fn(); + render(); + const header = screen.getByText('Name'); + header.click(); + expect(onToggleSort).not.toHaveBeenCalled(); + }); + + it('renders with long labels', () => { + const itemsWithLongLabels: VizLegendItem[] = [ + { + label: 'This is a very long series name that should be scrollable within its table cell', + color: 'red', + yAxis: 1, + }, + ]; + render(); + expect( + screen.getByText('This is a very long series name that should be scrollable within its table cell') + ).toBeInTheDocument(); + }); +}); diff --git a/packages/grafana-ui/src/components/VizLegend/VizLegendTable.tsx b/packages/grafana-ui/src/components/VizLegend/VizLegendTable.tsx index b654a2d3ac6..0c2859453eb 100644 --- a/packages/grafana-ui/src/components/VizLegend/VizLegendTable.tsx +++ b/packages/grafana-ui/src/components/VizLegend/VizLegendTable.tsx @@ -119,7 +119,6 @@ const getStyles = (theme: GrafanaTheme2) => ({ table: css({ width: '100%', 'th:first-child': { - width: '100%', borderBottom: `1px solid ${theme.colors.border.weak}`, }, }), diff --git a/packages/grafana-ui/src/components/VizLegend/VizLegendTableItem.test.tsx b/packages/grafana-ui/src/components/VizLegend/VizLegendTableItem.test.tsx new file mode 100644 index 00000000000..4ca95aa395c --- /dev/null +++ b/packages/grafana-ui/src/components/VizLegend/VizLegendTableItem.test.tsx @@ -0,0 +1,112 @@ +import { render, screen } from '@testing-library/react'; + +import { LegendTableItem } from './VizLegendTableItem'; +import { VizLegendItem } from './types'; + +describe('LegendTableItem', () => { + const mockItem: VizLegendItem = { + label: 'Series 1', + color: 'red', + yAxis: 1, + }; + + it('renders without crashing', () => { + const { container } = render( +
+ + + +
+ ); + expect(container.querySelector('tr')).toBeInTheDocument(); + }); + + it('renders label text', () => { + render( + + + + +
+ ); + expect(screen.getByText('Series 1')).toBeInTheDocument(); + }); + + it('renders with long label text', () => { + const longLabelItem: VizLegendItem = { + ...mockItem, + label: 'This is a very long series name that should be scrollable in the table cell', + }; + render( + + + + +
+ ); + expect( + screen.getByText('This is a very long series name that should be scrollable in the table cell') + ).toBeInTheDocument(); + }); + + it('renders stat values when provided', () => { + const itemWithStats: VizLegendItem = { + ...mockItem, + getDisplayValues: () => [ + { numeric: 100, text: '100', title: 'Max' }, + { numeric: 50, text: '50', title: 'Min' }, + ], + }; + render( + + + + +
+ ); + expect(screen.getByText('100')).toBeInTheDocument(); + expect(screen.getByText('50')).toBeInTheDocument(); + }); + + it('renders right y-axis indicator when yAxis is 2', () => { + const rightAxisItem: VizLegendItem = { + ...mockItem, + yAxis: 2, + }; + render( + + + + +
+ ); + expect(screen.getByText('(right y-axis)')).toBeInTheDocument(); + }); + + it('calls onLabelClick when label is clicked', () => { + const onLabelClick = jest.fn(); + render( + + + + +
+ ); + const button = screen.getByRole('button'); + button.click(); + expect(onLabelClick).toHaveBeenCalledWith(mockItem, expect.any(Object)); + }); + + it('does not call onClick when readonly', () => { + const onLabelClick = jest.fn(); + render( + + + + +
+ ); + const button = screen.getByRole('button'); + expect(button).toBeDisabled(); + }); +}); diff --git a/packages/grafana-ui/src/components/VizLegend/VizLegendTableItem.tsx b/packages/grafana-ui/src/components/VizLegend/VizLegendTableItem.tsx index 335cf4309e9..56ec6cb733e 100644 --- a/packages/grafana-ui/src/components/VizLegend/VizLegendTableItem.tsx +++ b/packages/grafana-ui/src/components/VizLegend/VizLegendTableItem.tsx @@ -69,7 +69,7 @@ export const LegendTableItem = ({ return ( - + - +
+ +
{item.getDisplayValues && @@ -128,6 +130,27 @@ const getStyles = (theme: GrafanaTheme2) => { background: rowHoverBg, }, }), + labelCell: css({ + label: 'LegendLabelCell', + maxWidth: 0, + width: '100%', + }), + labelCellInner: css({ + label: 'LegendLabelCellInner', + display: 'block', + flex: 1, + minWidth: 0, + overflowX: 'auto', + overflowY: 'hidden', + paddingRight: theme.spacing(3), + scrollbarWidth: 'none', + msOverflowStyle: 'none', + maskImage: `linear-gradient(to right, black calc(100% - ${theme.spacing(3)}), transparent 100%)`, + WebkitMaskImage: `linear-gradient(to right, black calc(100% - ${theme.spacing(3)}), transparent 100%)`, + '&::-webkit-scrollbar': { + display: 'none', + }, + }), label: css({ label: 'LegendLabel', whiteSpace: 'nowrap', @@ -135,9 +158,6 @@ const getStyles = (theme: GrafanaTheme2) => { border: 'none', fontSize: 'inherit', padding: 0, - maxWidth: '600px', - textOverflow: 'ellipsis', - overflow: 'hidden', userSelect: 'text', }), labelDisabled: css({ diff --git a/packages/grafana-ui/tsconfig.json b/packages/grafana-ui/tsconfig.json index 502d1958513..95871844f67 100644 --- a/packages/grafana-ui/tsconfig.json +++ b/packages/grafana-ui/tsconfig.json @@ -8,7 +8,8 @@ "emitDeclarationOnly": true, "isolatedModules": true, "allowJs": true, - "rootDirs": ["."] + "rootDirs": ["."], + "moduleResolution": "bundler" }, "exclude": ["dist/**/*"], "include": ["../../public/test/setupTests.ts", "../../public/app/types/*.d.ts", "src/**/*.ts*"], diff --git a/packages/rollup.config.parts.ts b/packages/rollup.config.parts.ts index 31116f56bdb..534b8cd7d25 100644 --- a/packages/rollup.config.parts.ts +++ b/packages/rollup.config.parts.ts @@ -23,25 +23,29 @@ export const plugins = [ ]; // Generates a rollup configuration for commonjs output. -export function cjsOutput(pkg) { +export function cjsOutput(pkg, pkgName, overrides = {}) { return { format: 'cjs', sourcemap: true, - dir: dirname(pkg.publishConfig.main), + dir: dirname(pkg.main), entryFileNames: '[name].cjs', + preserveModules: true, + preserveModulesRoot: resolve(projectCwd, `packages/${pkgName}/src`), esModule: true, interop: 'compat', + ...overrides, }; } // Generate a rollup configuration for es module output. -export function esmOutput(pkg, pkgName) { +export function esmOutput(pkg, pkgName, overrides = {}) { return { format: 'esm', sourcemap: true, - dir: dirname(pkg.publishConfig.module), + dir: dirname(pkg.module), entryFileNames: '[name].mjs', preserveModules: true, preserveModulesRoot: resolve(projectCwd, `packages/${pkgName}/src`), + ...overrides, }; } diff --git a/pkg/aggregator/go.mod b/pkg/aggregator/go.mod index 96b596f71fb..f583105112e 100644 --- a/pkg/aggregator/go.mod +++ b/pkg/aggregator/go.mod @@ -9,19 +9,19 @@ require ( github.com/grafana/grafana/pkg/semconv v0.0.0-20250514132646-acbc7b54ed9e github.com/mattbaird/jsonpatch v0.0.0-20240118010651-0ba75a80ca38 github.com/stretchr/testify v1.11.1 - go.opentelemetry.io/otel v1.38.0 - k8s.io/api v0.34.2 - k8s.io/apimachinery v0.34.2 - k8s.io/apiserver v0.34.2 - k8s.io/client-go v0.34.2 - k8s.io/component-base v0.34.2 + go.opentelemetry.io/otel v1.39.0 + k8s.io/api v0.34.3 + k8s.io/apimachinery v0.34.3 + k8s.io/apiserver v0.34.3 + k8s.io/client-go v0.34.3 + k8s.io/component-base v0.34.3 k8s.io/klog/v2 v2.130.1 - k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 + k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e sigs.k8s.io/structured-merge-diff/v6 v6.3.1 ) require ( - cel.dev/expr v0.24.0 // indirect + cel.dev/expr v0.25.1 // indirect github.com/NYTimes/gziphandler v1.1.1 // indirect github.com/antlr4-go/antlr/v4 v4.13.1 // indirect github.com/apache/arrow-go/v18 v18.4.1 // indirect @@ -31,7 +31,7 @@ require ( github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cheekybits/genny v1.0.0 // indirect github.com/coreos/go-semver v0.3.1 // indirect - github.com/coreos/go-systemd/v22 v22.5.0 // indirect + github.com/coreos/go-systemd/v22 v22.6.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/evanphx/json-patch v5.9.11+incompatible // indirect github.com/fatih/color v1.18.0 // indirect @@ -40,10 +40,20 @@ require ( github.com/fxamacker/cbor/v2 v2.9.0 // 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.1 // indirect - github.com/go-openapi/swag/jsonname v0.25.1 // indirect + github.com/go-openapi/jsonpointer v0.22.4 // indirect + github.com/go-openapi/jsonreference v0.21.4 // indirect + github.com/go-openapi/swag v0.25.4 // indirect + github.com/go-openapi/swag/cmdutils v0.25.4 // indirect + github.com/go-openapi/swag/conv v0.25.4 // indirect + github.com/go-openapi/swag/fileutils v0.25.4 // indirect + github.com/go-openapi/swag/jsonname v0.25.4 // indirect + github.com/go-openapi/swag/jsonutils v0.25.4 // indirect + github.com/go-openapi/swag/loading v0.25.4 // indirect + github.com/go-openapi/swag/mangling v0.25.4 // indirect + github.com/go-openapi/swag/netutils v0.25.4 // indirect + github.com/go-openapi/swag/stringutils v0.25.4 // indirect + github.com/go-openapi/swag/typeutils v0.25.4 // indirect + github.com/go-openapi/swag/yamlutils v0.25.4 // indirect github.com/goccy/go-json v0.10.5 // indirect github.com/gogo/googleapis v1.4.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect @@ -51,7 +61,7 @@ require ( github.com/google/btree v1.1.3 // indirect github.com/google/cel-go v0.26.1 // indirect github.com/google/flatbuffers v25.2.10+incompatible // indirect - github.com/google/gnostic-models v0.7.0 // indirect + github.com/google/gnostic-models v0.7.1 // 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 @@ -66,13 +76,11 @@ require ( github.com/hashicorp/yamux v0.1.2 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jaegertracing/jaeger-idl v0.5.0 // indirect - github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/jszwedko/go-datemath v0.1.1-0.20230526204004-640a500621d6 // indirect github.com/klauspost/compress v1.18.0 // indirect github.com/klauspost/cpuid/v2 v2.3.0 // indirect github.com/kylelemons/godebug v1.1.0 // indirect - github.com/mailru/easyjson v0.9.0 // indirect github.com/mattetti/filebuffer v1.0.1 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect @@ -85,61 +93,60 @@ require ( github.com/onsi/ginkgo/v2 v2.22.2 // indirect github.com/onsi/gomega v1.36.2 // indirect github.com/pierrec/lz4/v4 v4.1.22 // indirect - github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/client_golang v1.23.2 // indirect github.com/prometheus/client_model v0.6.2 // indirect - github.com/prometheus/common v0.67.3 // indirect - github.com/prometheus/procfs v0.16.1 // indirect + github.com/prometheus/common v0.67.4 // indirect + github.com/prometheus/procfs v0.19.2 // indirect github.com/rivo/uniseg v0.4.7 // indirect - github.com/spf13/cobra v1.10.1 // indirect + github.com/spf13/cobra v1.10.2 // indirect github.com/spf13/pflag v1.0.10 // indirect github.com/stoewer/go-strcase v1.3.1 // indirect github.com/stretchr/objx v0.5.2 // indirect github.com/x448/float16 v0.8.4 // indirect github.com/zeebo/xxh3 v1.0.2 // indirect - go.etcd.io/etcd/api/v3 v3.6.4 // indirect - go.etcd.io/etcd/client/pkg/v3 v3.6.4 // indirect - go.etcd.io/etcd/client/v3 v3.6.4 // indirect + go.etcd.io/etcd/api/v3 v3.6.6 // indirect + go.etcd.io/etcd/client/pkg/v3 v3.6.6 // indirect + go.etcd.io/etcd/client/v3 v3.6.6 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.64.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/instrumentation/net/http/otelhttp v0.64.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/exporters/otlp/otlptrace v1.38.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc 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/otel/exporters/otlp/otlptrace v1.39.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0 // indirect + go.opentelemetry.io/otel/metric v1.39.0 // indirect + go.opentelemetry.io/otel/sdk v1.39.0 // indirect + go.opentelemetry.io/otel/trace v1.39.0 // indirect go.opentelemetry.io/proto/otlp v1.9.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.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.45.0 // indirect - golang.org/x/exp v0.0.0-20251002181428-27f1f14c8bb9 // indirect - golang.org/x/mod v0.30.0 // indirect - golang.org/x/net v0.47.0 // indirect - golang.org/x/oauth2 v0.33.0 // indirect - golang.org/x/sync v0.18.0 // indirect - golang.org/x/sys v0.38.0 // indirect - golang.org/x/telemetry v0.0.0-20251111182119-bc8e575c7b54 // indirect - golang.org/x/term v0.37.0 // indirect - golang.org/x/text v0.31.0 // indirect + golang.org/x/crypto v0.46.0 // indirect + golang.org/x/exp v0.0.0-20251209150349-8475f28825e9 // indirect + golang.org/x/mod v0.31.0 // indirect + golang.org/x/net v0.48.0 // indirect + golang.org/x/oauth2 v0.34.0 // indirect + golang.org/x/sync v0.19.0 // indirect + golang.org/x/sys v0.39.0 // indirect + golang.org/x/telemetry v0.0.0-20251203150158-8fff8a5912fc // indirect + golang.org/x/term v0.38.0 // indirect + golang.org/x/text v0.32.0 // indirect golang.org/x/time v0.14.0 // indirect - golang.org/x/tools v0.39.0 // indirect + golang.org/x/tools v0.40.0 // indirect golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20251111163417-95abcf5c77ba // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2 // indirect google.golang.org/grpc v1.77.0 // indirect - google.golang.org/protobuf v1.36.10 // indirect - gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect + google.golang.org/protobuf v1.36.11 // indirect + gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 // indirect - sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2 // indirect - sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect + k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 // indirect + sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.34.0 // indirect + sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect sigs.k8s.io/randfill v1.0.0 // indirect sigs.k8s.io/yaml v1.6.0 // indirect ) diff --git a/pkg/aggregator/go.sum b/pkg/aggregator/go.sum index 246b05907cc..6def7534ecf 100644 --- a/pkg/aggregator/go.sum +++ b/pkg/aggregator/go.sum @@ -1,5 +1,5 @@ -cel.dev/expr v0.24.0 h1:56OvJKSH3hDGL0ml5uSxZmz3/3Pq4tJ+fb1unVLAFcY= -cel.dev/expr v0.24.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw= +cel.dev/expr v0.25.1 h1:1KrZg61W6TWSxuNZ37Xy49ps13NUovb66QLprthtwi4= +cel.dev/expr v0.25.1/go.mod h1:hrXvqGP6G6gyx8UAHSHJ5RGk//1Oj5nXQ2NI02Nrsg4= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I= github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= @@ -27,8 +27,8 @@ github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wX github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4= github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec= -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/coreos/go-systemd/v22 v22.6.0 h1:aGVa/v8B7hpb0TKl0MWoAavPDmHvobFe5R5zn0bCJWo= +github.com/coreos/go-systemd/v22 v22.6.0/go.mod h1:iG+pp635Fo7ZmV/j14KUcmEyWF+0X7Lua8rrTWzYgWU= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= 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= @@ -57,19 +57,44 @@ 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-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg= -github.com/go-openapi/jsonpointer v0.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.1 h1:lpsStH0n2ittzTnbaSloVZLuB5+fvSY/+hnagBjSNZU= -github.com/go-openapi/swag v0.23.1/go.mod h1:STZs8TbRvEQQKUA+JZNAm3EWlgaOBGpyFDqQnDHMef0= -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/jsonpointer v0.22.4 h1:dZtK82WlNpVLDW2jlA1YCiVJFVqkED1MegOUy9kR5T4= +github.com/go-openapi/jsonpointer v0.22.4/go.mod h1:elX9+UgznpFhgBuaMQ7iu4lvvX1nvNsesQ3oxmYTw80= +github.com/go-openapi/jsonreference v0.21.4 h1:24qaE2y9bx/q3uRK/qN+TDwbok1NhbSmGjjySRCHtC8= +github.com/go-openapi/jsonreference v0.21.4/go.mod h1:rIENPTjDbLpzQmQWCj5kKj3ZlmEh+EFVbz3RTUh30/4= +github.com/go-openapi/swag v0.25.4 h1:OyUPUFYDPDBMkqyxOTkqDYFnrhuhi9NR6QVUvIochMU= +github.com/go-openapi/swag v0.25.4/go.mod h1:zNfJ9WZABGHCFg2RnY0S4IOkAcVTzJ6z2Bi+Q4i6qFQ= +github.com/go-openapi/swag/cmdutils v0.25.4 h1:8rYhB5n6WawR192/BfUu2iVlxqVR9aRgGJP6WaBoW+4= +github.com/go-openapi/swag/cmdutils v0.25.4/go.mod h1:pdae/AFo6WxLl5L0rq87eRzVPm/XRHM3MoYgRMvG4A0= +github.com/go-openapi/swag/conv v0.25.4 h1:/Dd7p0LZXczgUcC/Ikm1+YqVzkEeCc9LnOWjfkpkfe4= +github.com/go-openapi/swag/conv v0.25.4/go.mod h1:3LXfie/lwoAv0NHoEuY1hjoFAYkvlqI/Bn5EQDD3PPU= +github.com/go-openapi/swag/fileutils v0.25.4 h1:2oI0XNW5y6UWZTC7vAxC8hmsK/tOkWXHJQH4lKjqw+Y= +github.com/go-openapi/swag/fileutils v0.25.4/go.mod h1:cdOT/PKbwcysVQ9Tpr0q20lQKH7MGhOEb6EwmHOirUk= +github.com/go-openapi/swag/jsonname v0.25.4 h1:bZH0+MsS03MbnwBXYhuTttMOqk+5KcQ9869Vye1bNHI= +github.com/go-openapi/swag/jsonname v0.25.4/go.mod h1:GPVEk9CWVhNvWhZgrnvRA6utbAltopbKwDu8mXNUMag= +github.com/go-openapi/swag/jsonutils v0.25.4 h1:VSchfbGhD4UTf4vCdR2F4TLBdLwHyUDTd1/q4i+jGZA= +github.com/go-openapi/swag/jsonutils v0.25.4/go.mod h1:7OYGXpvVFPn4PpaSdPHJBtF0iGnbEaTk8AvBkoWnaAY= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4 h1:IACsSvBhiNJwlDix7wq39SS2Fh7lUOCJRmx/4SN4sVo= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4/go.mod h1:Mt0Ost9l3cUzVv4OEZG+WSeoHwjWLnarzMePNDAOBiM= +github.com/go-openapi/swag/loading v0.25.4 h1:jN4MvLj0X6yhCDduRsxDDw1aHe+ZWoLjW+9ZQWIKn2s= +github.com/go-openapi/swag/loading v0.25.4/go.mod h1:rpUM1ZiyEP9+mNLIQUdMiD7dCETXvkkC30z53i+ftTE= +github.com/go-openapi/swag/mangling v0.25.4 h1:2b9kBJk9JvPgxr36V23FxJLdwBrpijI26Bx5JH4Hp48= +github.com/go-openapi/swag/mangling v0.25.4/go.mod h1:6dxwu6QyORHpIIApsdZgb6wBk/DPU15MdyYj/ikn0Hg= +github.com/go-openapi/swag/netutils v0.25.4 h1:Gqe6K71bGRb3ZQLusdI8p/y1KLgV4M/k+/HzVSqT8H0= +github.com/go-openapi/swag/netutils v0.25.4/go.mod h1:m2W8dtdaoX7oj9rEttLyTeEFFEBvnAx9qHd5nJEBzYg= +github.com/go-openapi/swag/stringutils v0.25.4 h1:O6dU1Rd8bej4HPA3/CLPciNBBDwZj9HiEpdVsb8B5A8= +github.com/go-openapi/swag/stringutils v0.25.4/go.mod h1:GTsRvhJW5xM5gkgiFe0fV3PUlFm0dr8vki6/VSRaZK0= +github.com/go-openapi/swag/typeutils v0.25.4 h1:1/fbZOUN472NTc39zpa+YGHn3jzHWhv42wAJSN91wRw= +github.com/go-openapi/swag/typeutils v0.25.4/go.mod h1:Ou7g//Wx8tTLS9vG0UmzfCsjZjKhpjxayRKTHXf2pTE= +github.com/go-openapi/swag/yamlutils v0.25.4 h1:6jdaeSItEUb7ioS9lFoCZ65Cne1/RZtPBZ9A56h92Sw= +github.com/go-openapi/swag/yamlutils v0.25.4/go.mod h1:MNzq1ulQu+yd8Kl7wPOut/YHAAU/H6hL91fF+E2RFwc= +github.com/go-openapi/testify/enable/yaml/v2 v2.0.2 h1:0+Y41Pz1NkbTHz8NngxTuAXxEodtNSI1WG1c/m5Akw4= +github.com/go-openapi/testify/enable/yaml/v2 v2.0.2/go.mod h1:kme83333GCtJQHXQ8UKX3IBZu6z8T5Dvy5+CW3NLUUg= +github.com/go-openapi/testify/v2 v2.0.2 h1:X999g3jeLcoY8qctY/c/Z8iBHTbwLz7R2WXd6Ub6wls= +github.com/go-openapi/testify/v2 v2.0.2/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= 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/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= -github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/googleapis v1.4.1 h1:1Yx4Myt7BxzvUr5ldGSbwYiZG6t9wGBZ+8/fX3Wvtq0= github.com/gogo/googleapis v1.4.1/go.mod h1:2lpHqI5OcWCtVElxXnPt+s8oJvMpySlOyM6xDCrzib4= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= @@ -89,8 +114,8 @@ 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.7.0 h1:qwTtogB15McXDaNqTZdzPJRHvaVJlAl+HVQnLmJEJxo= -github.com/google/gnostic-models v0.7.0/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ= +github.com/google/gnostic-models v0.7.1 h1:SisTfuFKJSKM5CPZkffwi6coztzzeYUhc3v4yxLWH8c= +github.com/google/gnostic-models v0.7.1/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ= 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= @@ -133,8 +158,6 @@ github.com/jhump/protoreflect v1.17.0 h1:qOEr613fac2lOuTgWN4tPAtLL7fUSbuJL5X5Xum github.com/jhump/protoreflect v1.17.0/go.mod h1:h9+vUUL38jiBzck8ck+6G/aeMX8Z4QUY/NiJPwPNi+8= 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= -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/jszwedko/go-datemath v0.1.1-0.20230526204004-640a500621d6 h1:SwcnSwBR7X/5EHJQlXBockkJVIMRVt5yKaesBPMtyZQ= @@ -153,8 +176,6 @@ 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/mattbaird/jsonpatch v0.0.0-20240118010651-0ba75a80ca38 h1:hQWBtNqRYrI7CWIaUSXXtNKR90KzcUA5uiuxFVWw7sU= github.com/mattbaird/jsonpatch v0.0.0-20240118010651-0ba75a80ca38/go.mod h1:M1qoD/MqPgTZIk0EWKB38wE28ACRfVcn+cU08jyArI0= github.com/mattetti/filebuffer v1.0.1 h1:gG7pyfnSIZCxdoKq+cPa8T0hhYtD9NxCdI4D7PTjRLM= @@ -195,8 +216,6 @@ 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/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU= github.com/pierrec/lz4/v4 v4.1.22/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= -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= @@ -208,11 +227,11 @@ github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1: 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.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.67.3 h1:shd26MlnwTw5jksTDhC7rTQIteBxy+ZZDr3t7F2xN2Q= -github.com/prometheus/common v0.67.3/go.mod h1:gP0fq6YjjNCLssJCQp0yk4M8W6ikLURwkdd/YKtTbyI= +github.com/prometheus/common v0.67.4 h1:yR3NqWO1/UyO1w2PhUvXlGQs/PtFmoveVO0KZ4+Lvsc= +github.com/prometheus/common v0.67.4/go.mod h1:gP0fq6YjjNCLssJCQp0yk4M8W6ikLURwkdd/YKtTbyI= github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= -github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= +github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws= +github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= @@ -223,8 +242,8 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js= github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= -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/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU= +github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4= github.com/spf13/pflag v1.0.9/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= @@ -257,12 +276,12 @@ github.com/zeebo/xxh3 v1.0.2 h1:xZmwmqxHZA8AI603jOQ0tMqmBr9lPeFwGg6d+xy9DC0= github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA= go.etcd.io/bbolt v1.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.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.6.4 h1:9HBYrjppeOfFjBjaMTRxT3R7xT0GLK8EJMVC4xg6ok0= -go.etcd.io/etcd/client/pkg/v3 v3.6.4/go.mod h1:sbdzr2cl3HzVmxNw//PH7aLGVtY4QySjQFuaCgcRFAI= -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.etcd.io/etcd/api/v3 v3.6.6 h1:mcaMp3+7JawWv69p6QShYWS8cIWUOl32bFLb6qf8pOQ= +go.etcd.io/etcd/api/v3 v3.6.6/go.mod h1:f/om26iXl2wSkcTA1zGQv8reJRSLVdoEBsi4JdfMrx4= +go.etcd.io/etcd/client/pkg/v3 v3.6.6 h1:uoqgzSOv2H9KlIF5O1Lsd8sW+eMLuV6wzE3q5GJGQNs= +go.etcd.io/etcd/client/pkg/v3 v3.6.6/go.mod h1:YngfUVmvsvOJ2rRgStIyHsKtOt9SZI2aBJrZiWJhCbI= +go.etcd.io/etcd/client/v3 v3.6.6 h1:G5z1wMf5B9SNexoxOHUGBaULurOZPIgGPsW6CN492ec= +go.etcd.io/etcd/client/v3 v3.6.6/go.mod h1:36Qv6baQ07znPR3+n7t+Rk5VHEzVYPvFfGmfF4wBHV8= go.etcd.io/etcd/pkg/v3 v3.6.4 h1:fy8bmXIec1Q35/jRZ0KOes8vuFxbvdN0aAFqmEfJZWA= go.etcd.io/etcd/pkg/v3 v3.6.4/go.mod h1:kKcYWP8gHuBRcteyv6MXWSN0+bVMnfgqiHueIZnKMtE= go.etcd.io/etcd/server/v3 v3.6.4 h1:LsCA7CzjVt+8WGrdsnh6RhC0XqCsLkBly3ve5rTxMAU= @@ -271,34 +290,34 @@ go.etcd.io/raft/v3 v3.6.0 h1:5NtvbDVYpnfZWcIHgGRk9DyzkBIXOi8j+DDp1IcnUWQ= go.etcd.io/raft/v3 v3.6.0/go.mod h1:nLvLevg6+xrVtHUmVaTcTz603gQPHfh7kUAwV6YpfGo= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= -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/google.golang.org/grpc/otelgrpc v0.64.0 h1:RN3ifU8y4prNWeEnQp2kRRHz8UwonAEYZl8tUzHEXAk= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.64.0/go.mod h1:habDz3tEWiFANTo6oUE99EmaFUrCNYAAg3wiVmusm70= 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/instrumentation/net/http/otelhttp v0.64.0 h1:ssfIgGNANqpVFCndZvcuyKbl0g+UAVcbBcqGkG28H0Y= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.64.0/go.mod h1:GQ/474YrbE4Jx8gZ4q5I4hrhUzM6UPzyrqJYV2AqPoQ= 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.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 v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48= +go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0 h1:f0cb2XPmrqn4XMy9PNliTgRKJgS5WcL/u0/WRYGz4t0= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0/go.mod h1:vnakAaFckOMiMtOIhFI2MNH4FYrZzXCYxmb1LlhoGz8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0 h1:in9O8ESIOlwJAEGTkkf34DesGRAc/Pn8qJ7k3r/42LM= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0/go.mod h1:Rp0EXBm5tfnv0WL+ARyO/PHBEaEAT8UUHQ6AGJcSq6c= go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM= -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/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0= +go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs= go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E= -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/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18= +go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE= +go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8= +go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew= go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ= -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/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI= +go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA= go.opentelemetry.io/proto/otlp v1.9.0 h1:l706jCMITVouPOqEnii2fIAuO3IVGBRPV5ICjceRb/A= go.opentelemetry.io/proto/otlp v1.9.0/go.mod h1:xE+Cx5E/eEHw+ISFkwPLwCZefwVjY+pqKg1qcK03+/4= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= @@ -314,15 +333,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.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q= -golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4= -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/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU= +golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0= +golang.org/x/exp v0.0.0-20251209150349-8475f28825e9 h1:MDfG8Cvcqlt9XXrmEiD4epKn7VJHZO84hejP9Jmp0MM= +golang.org/x/exp v0.0.0-20251209150349-8475f28825e9/go.mod h1:EPRbTFwzwjXj9NpYyyrvenVh9Y+GFeEvMNh7Xuz7xgU= 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.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk= -golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc= +golang.org/x/mod v0.31.0 h1:HaW9xtz0+kOcWKwli0ZXy79Ix+UW/vOfmWI5QVd2tgI= +golang.org/x/mod v0.31.0/go.mod h1:43JraMp9cGx1Rx3AqioxrbrhNsLl2l/iNAvuBkrezpg= 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,18 +349,18 @@ 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.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= -golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= +golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= +golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.33.0 h1:4Q+qn+E5z8gPRJfmRy7C2gGG3T4jIprK6aSYgTXGRpo= -golang.org/x/oauth2 v0.33.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= +golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw= +golang.org/x/oauth2 v0.34.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-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.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= -golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 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= @@ -353,16 +372,16 @@ golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 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.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= -golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/telemetry v0.0.0-20251111182119-bc8e575c7b54 h1:E2/AqCUMZGgd73TQkxUMcMla25GB9i/5HOdLr+uH7Vo= -golang.org/x/telemetry v0.0.0-20251111182119-bc8e575c7b54/go.mod h1:hKdjCMrbv9skySur+Nek8Hd0uJ0GuxJIoIX2payrIdQ= -golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU= -golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254= +golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= +golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/telemetry v0.0.0-20251203150158-8fff8a5912fc h1:bH6xUXay0AIFMElXG2rQ4uiE+7ncwtiOdPfYK1NK2XA= +golang.org/x/telemetry v0.0.0-20251203150158-8fff8a5912fc/go.mod h1:hKdjCMrbv9skySur+Nek8Hd0uJ0GuxJIoIX2payrIdQ= +golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q= +golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg= 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.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= -golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= +golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= +golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= 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= @@ -370,8 +389,8 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm 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.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ= -golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ= +golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA= +golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc= 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= @@ -382,20 +401,20 @@ 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/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto/googleapis/api v0.0.0-20251111163417-95abcf5c77ba h1:B14OtaXuMaCQsl2deSvNkyPKIzq3BjfxQp8d00QyWx4= -google.golang.org/genproto/googleapis/api v0.0.0-20251111163417-95abcf5c77ba/go.mod h1:G5IanEx8/PgI9w6CFcYQf7jMtHQhZruvfM1i3qOqk5U= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba h1:UKgtfRM7Yh93Sya0Fo8ZzhDP4qBckrrxEr2oF5UIVb8= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= +google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2 h1:7LRqPCEdE4TP4/9psdaB7F2nhZFfBiGJomA5sojLWdU= +google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2/go.mod h1:+rXWjjaukWZun3mLfjmVnQi18E1AsFbDN9QdJ5YXLto= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2 h1:2I6GHUeJ/4shcDpoUlLs/2WPnhg7yJwvXtqcMJt9liA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/grpc v1.18.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM= google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= -google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= -google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/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/evanphx/json-patch.v4 v4.13.0 h1:czT3CmqEaQ1aanPc5SdlgQrrEIb8w/wwCvWWnfEbYzo= +gopkg.in/evanphx/json-patch.v4 v4.13.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/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= @@ -404,26 +423,26 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -k8s.io/api v0.34.2 h1:fsSUNZhV+bnL6Aqrp6O7lMTy6o5x2C4XLjnh//8SLYY= -k8s.io/api v0.34.2/go.mod h1:MMBPaWlED2a8w4RSeanD76f7opUoypY8TFYkSM+3XHw= -k8s.io/apimachinery v0.34.2 h1:zQ12Uk3eMHPxrsbUJgNF8bTauTVR2WgqJsTmwTE/NW4= -k8s.io/apimachinery v0.34.2/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= -k8s.io/apiserver v0.34.2 h1:2/yu8suwkmES7IzwlehAovo8dDE07cFRC7KMDb1+MAE= -k8s.io/apiserver v0.34.2/go.mod h1:gqJQy2yDOB50R3JUReHSFr+cwJnL8G1dzTA0YLEqAPI= -k8s.io/client-go v0.34.2 h1:Co6XiknN+uUZqiddlfAjT68184/37PS4QAzYvQvDR8M= -k8s.io/client-go v0.34.2/go.mod h1:2VYDl1XXJsdcAxw7BenFslRQX28Dxz91U9MWKjX97fE= -k8s.io/component-base v0.34.2 h1:HQRqK9x2sSAsd8+R4xxRirlTjowsg6fWCPwWYeSvogQ= -k8s.io/component-base v0.34.2/go.mod h1:9xw2FHJavUHBFpiGkZoKuYZ5pdtLKe97DEByaA+hHbM= +k8s.io/api v0.34.3 h1:D12sTP257/jSH2vHV2EDYrb16bS7ULlHpdNdNhEw2S4= +k8s.io/api v0.34.3/go.mod h1:PyVQBF886Q5RSQZOim7DybQjAbVs8g7gwJNhGtY5MBk= +k8s.io/apimachinery v0.34.3 h1:/TB+SFEiQvN9HPldtlWOTp0hWbJ+fjU+wkxysf/aQnE= +k8s.io/apimachinery v0.34.3/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= +k8s.io/apiserver v0.34.3 h1:uGH1qpDvSiYG4HVFqc6A3L4CKiX+aBWDrrsxHYK0Bdo= +k8s.io/apiserver v0.34.3/go.mod h1:QPnnahMO5C2m3lm6fPW3+JmyQbvHZQ8uudAu/493P2w= +k8s.io/client-go v0.34.3 h1:wtYtpzy/OPNYf7WyNBTj3iUA0XaBHVqhv4Iv3tbrF5A= +k8s.io/client-go v0.34.3/go.mod h1:OxxeYagaP9Kdf78UrKLa3YZixMCfP6bgPwPwNBQBzpM= +k8s.io/component-base v0.34.3 h1:zsEgw6ELqK0XncCQomgO9DpUIzlrYuZYA0Cgo+JWpVk= +k8s.io/component-base v0.34.3/go.mod h1:5iIlD8wPfWE/xSHTRfbjuvUul2WZbI2nOUK65XL0E/c= 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/apiserver-network-proxy/konnectivity-client v0.31.2 h1:jpcvIRr3GLoUoEKRkHKSmGjxb6lWwrBlJsXc+eUYQHM= -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= +k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e h1:iW9ChlU0cU16w8MpVYjXk12dqQ4BPFBEgif+ap7/hqQ= +k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e/go.mod h1:kdmbQkyfwUagLfXIad1y2TdrjPFWp2Q89B3qkRwf/pQ= +k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 h1:SjGebBtkBqHFOli+05xYbK8YF1Dzkbzn+gDM4X9T4Ck= +k8s.io/utils v0.0.0-20251002143259-bc988d571ff4/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.34.0 h1:hSfpvjjTQXQY2Fol2CS0QHMNs/WI1MOSGzCm1KhM5ec= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.34.0/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw= +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg= +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/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.1 h1:JrhdFMqOd/+3ByqlP2I45kTOZmTRLBUm5pvRjeheg7E= diff --git a/pkg/api/alerting.go b/pkg/api/alerting.go index 27abb6ebbfc..8fb2f366bf2 100644 --- a/pkg/api/alerting.go +++ b/pkg/api/alerting.go @@ -10,6 +10,7 @@ import ( "github.com/grafana/grafana/pkg/api/response" contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model" + "github.com/grafana/grafana/pkg/services/ngalert/models" ) func (hs *HTTPServer) GetAlertNotifiers() func(*contextmodel.ReqContext) response.Response { @@ -23,13 +24,13 @@ func (hs *HTTPServer) GetAlertNotifiers() func(*contextmodel.ReqContext) respons } type NotifierPlugin struct { - Type string `json:"type"` - TypeAlias string `json:"typeAlias,omitempty"` - Name string `json:"name"` - Heading string `json:"heading"` - Description string `json:"description"` - Info string `json:"info"` - Options []schema.Field `json:"options"` + Type string `json:"type"` + TypeAlias string `json:"typeAlias,omitempty"` + Name string `json:"name"` + Heading string `json:"heading"` + Description string `json:"description"` + Info string `json:"info"` + Options []Field `json:"options"` } result := make([]*NotifierPlugin, 0, len(v2)) @@ -44,9 +45,56 @@ func (hs *HTTPServer) GetAlertNotifiers() func(*contextmodel.ReqContext) respons Description: s.Description, Heading: s.Heading, Info: s.Info, - Options: v1.Options, + Options: schemaFieldsToFields(s.Type, nil, v1.Options), }) } return response.JSON(http.StatusOK, result) } } + +type Field struct { + Element schema.ElementType `json:"element"` + InputType schema.InputType `json:"inputType"` + Label string `json:"label"` + Description string `json:"description"` + Placeholder string `json:"placeholder"` + PropertyName string `json:"propertyName"` + SelectOptions []schema.SelectOption `json:"selectOptions"` + ShowWhen schema.ShowWhen `json:"showWhen"` + Required bool `json:"required"` + Protected bool `json:"protected,omitempty"` + ValidationRule string `json:"validationRule"` + Secure bool `json:"secure"` + DependsOn string `json:"dependsOn"` + SubformOptions []Field `json:"subformOptions"` +} + +func schemaFieldsToFields(iType schema.IntegrationType, parent schema.IntegrationFieldPath, fields []schema.Field) []Field { + if fields == nil { + return nil + } + result := make([]Field, 0, len(fields)) + for _, f := range fields { + result = append(result, schemaFieldToField(iType, parent, f)) + } + return result +} + +func schemaFieldToField(iType schema.IntegrationType, parent schema.IntegrationFieldPath, f schema.Field) Field { + return Field{ + Element: f.Element, + InputType: f.InputType, + Label: f.Label, + Description: f.Description, + Placeholder: f.Placeholder, + PropertyName: f.PropertyName, + SelectOptions: f.SelectOptions, + ShowWhen: f.ShowWhen, + Required: f.Required, + ValidationRule: f.ValidationRule, + Secure: f.Secure, + DependsOn: f.DependsOn, + SubformOptions: schemaFieldsToFields(iType, append(parent, f.PropertyName), f.SubformOptions), + Protected: models.IsProtectedField(iType, append(parent, f.PropertyName)), + } +} diff --git a/pkg/api/apierrors/folder.go b/pkg/api/apierrors/folder.go index 9509ff4ff55..a938b165852 100644 --- a/pkg/api/apierrors/folder.go +++ b/pkg/api/apierrors/folder.go @@ -29,7 +29,8 @@ func ToFolderErrorResponse(err error) response.Response { errors.Is(err, dashboards.ErrDashboardTypeMismatch) || errors.Is(err, dashboards.ErrDashboardInvalidUid) || errors.Is(err, dashboards.ErrDashboardUidTooLong) || - errors.Is(err, folder.ErrFolderCannotBeParentOfItself) { + errors.Is(err, folder.ErrFolderCannotBeParentOfItself) || + errors.Is(err, folder.ErrMaximumDepthReached) { return response.Error(http.StatusBadRequest, err.Error(), nil) } diff --git a/pkg/api/apierrors/folder_test.go b/pkg/api/apierrors/folder_test.go index 0ca8b16fc87..233254dc6cc 100644 --- a/pkg/api/apierrors/folder_test.go +++ b/pkg/api/apierrors/folder_test.go @@ -30,7 +30,7 @@ func TestToFolderErrorResponse(t *testing.T) { { name: "maximum depth reached", input: folder.ErrMaximumDepthReached.Errorf("Maximum nested folder depth reached"), - want: response.Err(folder.ErrMaximumDepthReached.Errorf("Maximum nested folder depth reached")), + want: response.Error(http.StatusBadRequest, "[folder.maximum-depth-reached] Maximum nested folder depth reached", nil), }, { name: "bad request errors", diff --git a/pkg/api/dtos/frontend_settings.go b/pkg/api/dtos/frontend_settings.go index 218817c6801..d140c328242 100644 --- a/pkg/api/dtos/frontend_settings.go +++ b/pkg/api/dtos/frontend_settings.go @@ -200,6 +200,7 @@ type FrontendSettingsDTO struct { RudderstackWriteKey string `json:"rudderstackWriteKey"` RudderstackDataPlaneUrl string `json:"rudderstackDataPlaneUrl"` RudderstackSdkUrl string `json:"rudderstackSdkUrl"` + RudderstackV3SdkUrl string `json:"rudderstackV3SdkUrl"` RudderstackConfigUrl string `json:"rudderstackConfigUrl"` RudderstackIntegrationsUrl string `json:"rudderstackIntegrationsUrl"` diff --git a/pkg/api/folder.go b/pkg/api/folder.go index 851910a9e1d..5b0bf9d121e 100644 --- a/pkg/api/folder.go +++ b/pkg/api/folder.go @@ -214,7 +214,7 @@ func (hs *HTTPServer) MoveFolder(c *contextmodel.ReqContext) response.Response { cmd.SignedInUser = c.SignedInUser theFolder, err := hs.folderService.Move(c.Req.Context(), &cmd) if err != nil { - return response.ErrOrFallback(http.StatusInternalServerError, "move folder failed", err) + return apierrors.ToFolderErrorResponse(err) } folderDTO, err := hs.newToFolderDto(c, theFolder) diff --git a/pkg/api/frontendsettings.go b/pkg/api/frontendsettings.go index c105b5ee829..b57262087e5 100644 --- a/pkg/api/frontendsettings.go +++ b/pkg/api/frontendsettings.go @@ -229,6 +229,7 @@ func (hs *HTTPServer) getFrontendSettings(c *contextmodel.ReqContext) (*dtos.Fro RudderstackWriteKey: hs.Cfg.RudderstackWriteKey, RudderstackDataPlaneUrl: hs.Cfg.RudderstackDataPlaneURL, RudderstackSdkUrl: hs.Cfg.RudderstackSDKURL, + RudderstackV3SdkUrl: hs.Cfg.RudderstackV3SDKURL, RudderstackConfigUrl: hs.Cfg.RudderstackConfigURL, RudderstackIntegrationsUrl: hs.Cfg.RudderstackIntegrationsURL, AnalyticsConsoleReporting: hs.Cfg.FrontendAnalyticsConsoleReporting, diff --git a/pkg/apimachinery/go.mod b/pkg/apimachinery/go.mod index 8261fc94967..4cc4a499bc0 100644 --- a/pkg/apimachinery/go.mod +++ b/pkg/apimachinery/go.mod @@ -8,28 +8,37 @@ require ( github.com/grafana/authlib/types v0.0.0-20251119142549-be091cf2f4d4 // @grafana/identity-access-team github.com/stretchr/testify v1.11.1 go.yaml.in/yaml/v3 v3.0.4 - k8s.io/apimachinery v0.34.2 - k8s.io/apiserver v0.34.2 - k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 - k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 + k8s.io/apimachinery v0.34.3 + k8s.io/apiserver v0.34.3 + k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e + k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 ) require ( + 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/fxamacker/cbor/v2 v2.9.0 // 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.1 // indirect - github.com/go-openapi/swag/jsonname v0.25.1 // indirect + github.com/go-openapi/jsonpointer v0.22.4 // indirect + github.com/go-openapi/jsonreference v0.21.4 // indirect + github.com/go-openapi/swag v0.25.4 // indirect + github.com/go-openapi/swag/cmdutils v0.25.4 // indirect + github.com/go-openapi/swag/conv v0.25.4 // indirect + github.com/go-openapi/swag/fileutils v0.25.4 // indirect + github.com/go-openapi/swag/jsonname v0.25.4 // indirect + github.com/go-openapi/swag/jsonutils v0.25.4 // indirect + github.com/go-openapi/swag/loading v0.25.4 // indirect + github.com/go-openapi/swag/mangling v0.25.4 // indirect + github.com/go-openapi/swag/netutils v0.25.4 // indirect + github.com/go-openapi/swag/stringutils v0.25.4 // indirect + github.com/go-openapi/swag/typeutils v0.25.4 // indirect + github.com/go-openapi/swag/yamlutils v0.25.4 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/google/gnostic-models v0.7.0 // indirect + github.com/google/gnostic-models v0.7.1 // indirect github.com/grafana/dskit v0.0.0-20250908063411-6b6da59b5cc4 // 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/patrickmn/go-cache v2.1.0+incompatible // indirect @@ -38,21 +47,22 @@ require ( github.com/stretchr/objx v0.5.2 // indirect github.com/x448/float16 v0.8.4 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect - go.opentelemetry.io/otel v1.38.0 // indirect - go.opentelemetry.io/otel/metric v1.38.0 // indirect - go.opentelemetry.io/otel/trace v1.38.0 // indirect + go.opentelemetry.io/otel v1.39.0 // indirect + go.opentelemetry.io/otel/metric v1.39.0 // indirect + go.opentelemetry.io/otel/sdk/metric v1.39.0 // indirect + go.opentelemetry.io/otel/trace v1.39.0 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect - golang.org/x/net v0.47.0 // indirect - golang.org/x/sync v0.18.0 // indirect - golang.org/x/sys v0.38.0 // indirect - golang.org/x/text v0.31.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba // indirect + golang.org/x/net v0.48.0 // indirect + golang.org/x/sync v0.19.0 // indirect + golang.org/x/sys v0.39.0 // indirect + golang.org/x/text v0.32.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2 // indirect google.golang.org/grpc v1.77.0 // indirect - google.golang.org/protobuf v1.36.10 // indirect + google.golang.org/protobuf v1.36.11 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/klog/v2 v2.130.1 // indirect - sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect + sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect sigs.k8s.io/randfill v1.0.0 // indirect sigs.k8s.io/structured-merge-diff/v6 v6.3.1 // indirect ) diff --git a/pkg/apimachinery/go.sum b/pkg/apimachinery/go.sum index 77c81a0b698..47519c2a832 100644 --- a/pkg/apimachinery/go.sum +++ b/pkg/apimachinery/go.sum @@ -1,3 +1,5 @@ +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= @@ -13,20 +15,46 @@ 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.1 h1:lpsStH0n2ittzTnbaSloVZLuB5+fvSY/+hnagBjSNZU= -github.com/go-openapi/swag v0.23.1/go.mod h1:STZs8TbRvEQQKUA+JZNAm3EWlgaOBGpyFDqQnDHMef0= -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/jsonpointer v0.22.4 h1:dZtK82WlNpVLDW2jlA1YCiVJFVqkED1MegOUy9kR5T4= +github.com/go-openapi/jsonpointer v0.22.4/go.mod h1:elX9+UgznpFhgBuaMQ7iu4lvvX1nvNsesQ3oxmYTw80= +github.com/go-openapi/jsonreference v0.21.4 h1:24qaE2y9bx/q3uRK/qN+TDwbok1NhbSmGjjySRCHtC8= +github.com/go-openapi/jsonreference v0.21.4/go.mod h1:rIENPTjDbLpzQmQWCj5kKj3ZlmEh+EFVbz3RTUh30/4= +github.com/go-openapi/swag v0.25.4 h1:OyUPUFYDPDBMkqyxOTkqDYFnrhuhi9NR6QVUvIochMU= +github.com/go-openapi/swag v0.25.4/go.mod h1:zNfJ9WZABGHCFg2RnY0S4IOkAcVTzJ6z2Bi+Q4i6qFQ= +github.com/go-openapi/swag/cmdutils v0.25.4 h1:8rYhB5n6WawR192/BfUu2iVlxqVR9aRgGJP6WaBoW+4= +github.com/go-openapi/swag/cmdutils v0.25.4/go.mod h1:pdae/AFo6WxLl5L0rq87eRzVPm/XRHM3MoYgRMvG4A0= +github.com/go-openapi/swag/conv v0.25.4 h1:/Dd7p0LZXczgUcC/Ikm1+YqVzkEeCc9LnOWjfkpkfe4= +github.com/go-openapi/swag/conv v0.25.4/go.mod h1:3LXfie/lwoAv0NHoEuY1hjoFAYkvlqI/Bn5EQDD3PPU= +github.com/go-openapi/swag/fileutils v0.25.4 h1:2oI0XNW5y6UWZTC7vAxC8hmsK/tOkWXHJQH4lKjqw+Y= +github.com/go-openapi/swag/fileutils v0.25.4/go.mod h1:cdOT/PKbwcysVQ9Tpr0q20lQKH7MGhOEb6EwmHOirUk= +github.com/go-openapi/swag/jsonname v0.25.4 h1:bZH0+MsS03MbnwBXYhuTttMOqk+5KcQ9869Vye1bNHI= +github.com/go-openapi/swag/jsonname v0.25.4/go.mod h1:GPVEk9CWVhNvWhZgrnvRA6utbAltopbKwDu8mXNUMag= +github.com/go-openapi/swag/jsonutils v0.25.4 h1:VSchfbGhD4UTf4vCdR2F4TLBdLwHyUDTd1/q4i+jGZA= +github.com/go-openapi/swag/jsonutils v0.25.4/go.mod h1:7OYGXpvVFPn4PpaSdPHJBtF0iGnbEaTk8AvBkoWnaAY= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4 h1:IACsSvBhiNJwlDix7wq39SS2Fh7lUOCJRmx/4SN4sVo= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4/go.mod h1:Mt0Ost9l3cUzVv4OEZG+WSeoHwjWLnarzMePNDAOBiM= +github.com/go-openapi/swag/loading v0.25.4 h1:jN4MvLj0X6yhCDduRsxDDw1aHe+ZWoLjW+9ZQWIKn2s= +github.com/go-openapi/swag/loading v0.25.4/go.mod h1:rpUM1ZiyEP9+mNLIQUdMiD7dCETXvkkC30z53i+ftTE= +github.com/go-openapi/swag/mangling v0.25.4 h1:2b9kBJk9JvPgxr36V23FxJLdwBrpijI26Bx5JH4Hp48= +github.com/go-openapi/swag/mangling v0.25.4/go.mod h1:6dxwu6QyORHpIIApsdZgb6wBk/DPU15MdyYj/ikn0Hg= +github.com/go-openapi/swag/netutils v0.25.4 h1:Gqe6K71bGRb3ZQLusdI8p/y1KLgV4M/k+/HzVSqT8H0= +github.com/go-openapi/swag/netutils v0.25.4/go.mod h1:m2W8dtdaoX7oj9rEttLyTeEFFEBvnAx9qHd5nJEBzYg= +github.com/go-openapi/swag/stringutils v0.25.4 h1:O6dU1Rd8bej4HPA3/CLPciNBBDwZj9HiEpdVsb8B5A8= +github.com/go-openapi/swag/stringutils v0.25.4/go.mod h1:GTsRvhJW5xM5gkgiFe0fV3PUlFm0dr8vki6/VSRaZK0= +github.com/go-openapi/swag/typeutils v0.25.4 h1:1/fbZOUN472NTc39zpa+YGHn3jzHWhv42wAJSN91wRw= +github.com/go-openapi/swag/typeutils v0.25.4/go.mod h1:Ou7g//Wx8tTLS9vG0UmzfCsjZjKhpjxayRKTHXf2pTE= +github.com/go-openapi/swag/yamlutils v0.25.4 h1:6jdaeSItEUb7ioS9lFoCZ65Cne1/RZtPBZ9A56h92Sw= +github.com/go-openapi/swag/yamlutils v0.25.4/go.mod h1:MNzq1ulQu+yd8Kl7wPOut/YHAAU/H6hL91fF+E2RFwc= +github.com/go-openapi/testify/enable/yaml/v2 v2.0.2 h1:0+Y41Pz1NkbTHz8NngxTuAXxEodtNSI1WG1c/m5Akw4= +github.com/go-openapi/testify/enable/yaml/v2 v2.0.2/go.mod h1:kme83333GCtJQHXQ8UKX3IBZu6z8T5Dvy5+CW3NLUUg= +github.com/go-openapi/testify/v2 v2.0.2 h1:X999g3jeLcoY8qctY/c/Z8iBHTbwLz7R2WXd6Ub6wls= +github.com/go-openapi/testify/v2 v2.0.2/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= 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/gnostic-models v0.7.1 h1:SisTfuFKJSKM5CPZkffwi6coztzzeYUhc3v4yxLWH8c= +github.com/google/gnostic-models v0.7.1/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= @@ -38,8 +66,6 @@ github.com/grafana/authlib/types v0.0.0-20251119142549-be091cf2f4d4 h1:Muoy+FMGr github.com/grafana/authlib/types v0.0.0-20251119142549-be091cf2f4d4/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/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= @@ -48,8 +74,6 @@ 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/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= @@ -79,16 +103,16 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= -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/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/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48= +go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8= +go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0= +go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs= +go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18= +go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE= +go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8= +go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew= +go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI= +go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA= 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= @@ -102,22 +126,22 @@ 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.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= -golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= +golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= +golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= 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.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= -golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.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.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= -golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= +golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= 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.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= -golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= +golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= +golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= 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= @@ -128,12 +152,12 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 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/rpc v0.0.0-20251111163417-95abcf5c77ba h1:UKgtfRM7Yh93Sya0Fo8ZzhDP4qBckrrxEr2oF5UIVb8= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2 h1:2I6GHUeJ/4shcDpoUlLs/2WPnhg7yJwvXtqcMJt9liA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM= google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= -google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= -google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/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= @@ -141,18 +165,18 @@ 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/apimachinery v0.34.2 h1:zQ12Uk3eMHPxrsbUJgNF8bTauTVR2WgqJsTmwTE/NW4= -k8s.io/apimachinery v0.34.2/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= -k8s.io/apiserver v0.34.2 h1:2/yu8suwkmES7IzwlehAovo8dDE07cFRC7KMDb1+MAE= -k8s.io/apiserver v0.34.2/go.mod h1:gqJQy2yDOB50R3JUReHSFr+cwJnL8G1dzTA0YLEqAPI= +k8s.io/apimachinery v0.34.3 h1:/TB+SFEiQvN9HPldtlWOTp0hWbJ+fjU+wkxysf/aQnE= +k8s.io/apimachinery v0.34.3/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= +k8s.io/apiserver v0.34.3 h1:uGH1qpDvSiYG4HVFqc6A3L4CKiX+aBWDrrsxHYK0Bdo= +k8s.io/apiserver v0.34.3/go.mod h1:QPnnahMO5C2m3lm6fPW3+JmyQbvHZQ8uudAu/493P2w= 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= +k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e h1:iW9ChlU0cU16w8MpVYjXk12dqQ4BPFBEgif+ap7/hqQ= +k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e/go.mod h1:kdmbQkyfwUagLfXIad1y2TdrjPFWp2Q89B3qkRwf/pQ= +k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 h1:SjGebBtkBqHFOli+05xYbK8YF1Dzkbzn+gDM4X9T4Ck= +k8s.io/utils v0.0.0-20251002143259-bc988d571ff4/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg= +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/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.1 h1:JrhdFMqOd/+3ByqlP2I45kTOZmTRLBUm5pvRjeheg7E= diff --git a/pkg/apiserver/go.mod b/pkg/apiserver/go.mod index feb659b9a0a..89edb050ed8 100644 --- a/pkg/apiserver/go.mod +++ b/pkg/apiserver/go.mod @@ -5,18 +5,18 @@ go 1.25.5 require ( github.com/google/go-cmp v0.7.0 github.com/grafana/authlib/types v0.0.0-20251119142549-be091cf2f4d4 - github.com/grafana/grafana-app-sdk/logging v0.48.3 + github.com/grafana/grafana-app-sdk/logging v0.48.7 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 go.opentelemetry.io/contrib/propagators/jaeger v1.38.0 - go.opentelemetry.io/otel v1.38.0 - go.opentelemetry.io/otel/trace v1.38.0 - k8s.io/apimachinery v0.34.2 - k8s.io/apiserver v0.34.2 - k8s.io/component-base v0.34.2 + go.opentelemetry.io/otel v1.39.0 + go.opentelemetry.io/otel/trace v1.39.0 + k8s.io/apimachinery v0.34.3 + k8s.io/apiserver v0.34.3 + k8s.io/component-base v0.34.3 k8s.io/klog/v2 v2.130.1 - k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 + k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 sigs.k8s.io/structured-merge-diff/v6 v6.3.1 ) @@ -26,7 +26,7 @@ require ( github.com/cenkalti/backoff/v5 v5.0.3 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/coreos/go-semver v0.3.1 // indirect - github.com/coreos/go-systemd/v22 v22.5.0 // indirect + github.com/coreos/go-systemd/v22 v22.6.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/felixge/httpsnoop v1.0.4 // indirect @@ -34,14 +34,24 @@ require ( github.com/go-jose/go-jose/v4 v4.1.3 // 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.1 // indirect - github.com/go-openapi/swag/jsonname v0.25.1 // indirect + github.com/go-openapi/jsonpointer v0.22.4 // indirect + github.com/go-openapi/jsonreference v0.21.4 // indirect + github.com/go-openapi/swag v0.25.4 // indirect + github.com/go-openapi/swag/cmdutils v0.25.4 // indirect + github.com/go-openapi/swag/conv v0.25.4 // indirect + github.com/go-openapi/swag/fileutils v0.25.4 // indirect + github.com/go-openapi/swag/jsonname v0.25.4 // indirect + github.com/go-openapi/swag/jsonutils v0.25.4 // indirect + github.com/go-openapi/swag/loading v0.25.4 // indirect + github.com/go-openapi/swag/mangling v0.25.4 // indirect + github.com/go-openapi/swag/netutils v0.25.4 // indirect + github.com/go-openapi/swag/stringutils v0.25.4 // indirect + github.com/go-openapi/swag/typeutils v0.25.4 // indirect + github.com/go-openapi/swag/yamlutils v0.25.4 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/google/btree v1.1.3 // indirect - github.com/google/gnostic-models v0.7.0 // indirect + github.com/google/gnostic-models v0.7.1 // 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 @@ -50,60 +60,56 @@ require ( github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.3 // indirect github.com/grpc-ecosystem/go-grpc-prometheus v1.2.1-0.20191002090509-6af20e3a5340 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3 // indirect - github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/kylelemons/godebug v1.1.0 // 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/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // 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/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/client_model v0.6.2 // indirect - github.com/prometheus/common v0.67.3 // indirect - github.com/prometheus/procfs v0.16.1 // indirect + github.com/prometheus/common v0.67.4 // indirect + github.com/prometheus/procfs v0.19.2 // indirect github.com/spf13/pflag v1.0.10 // indirect github.com/stretchr/objx v0.5.2 // indirect github.com/x448/float16 v0.8.4 // indirect - go.etcd.io/etcd/api/v3 v3.6.4 // indirect - go.etcd.io/etcd/client/pkg/v3 v3.6.4 // indirect - go.etcd.io/etcd/client/v3 v3.6.4 // indirect + go.etcd.io/etcd/api/v3 v3.6.6 // indirect + go.etcd.io/etcd/client/pkg/v3 v3.6.6 // indirect + go.etcd.io/etcd/client/v3 v3.6.6 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.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/metric v1.38.0 // indirect - go.opentelemetry.io/otel/sdk v1.38.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.64.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.64.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0 // indirect + go.opentelemetry.io/otel/metric v1.39.0 // indirect + go.opentelemetry.io/otel/sdk v1.39.0 // indirect go.opentelemetry.io/proto/otlp v1.9.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.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.45.0 // indirect - golang.org/x/net v0.47.0 // indirect - golang.org/x/oauth2 v0.33.0 // indirect - golang.org/x/sync v0.18.0 // indirect - golang.org/x/sys v0.38.0 // indirect - golang.org/x/term v0.37.0 // indirect - golang.org/x/text v0.31.0 // indirect + golang.org/x/net v0.48.0 // indirect + golang.org/x/oauth2 v0.34.0 // indirect + golang.org/x/sync v0.19.0 // indirect + golang.org/x/sys v0.39.0 // indirect + golang.org/x/term v0.38.0 // indirect + golang.org/x/text v0.32.0 // indirect golang.org/x/time v0.14.0 // indirect - golang.org/x/tools v0.39.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20251111163417-95abcf5c77ba // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba // indirect + golang.org/x/tools v0.40.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2 // indirect google.golang.org/grpc v1.77.0 // indirect - google.golang.org/protobuf v1.36.10 // indirect - gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect + google.golang.org/protobuf v1.36.11 // indirect + gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/api v0.34.2 // indirect - k8s.io/client-go v0.34.2 // indirect - k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 // indirect - sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2 // indirect - sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect + k8s.io/api v0.34.3 // indirect + k8s.io/client-go v0.34.3 // indirect + k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e // indirect + sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.34.0 // indirect + sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect sigs.k8s.io/randfill v1.0.0 // indirect sigs.k8s.io/yaml v1.6.0 // indirect ) diff --git a/pkg/apiserver/go.sum b/pkg/apiserver/go.sum index 3eaa748643e..af28e90fadc 100644 --- a/pkg/apiserver/go.sum +++ b/pkg/apiserver/go.sum @@ -11,8 +11,8 @@ github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4= github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec= -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/coreos/go-systemd/v22 v22.6.0 h1:aGVa/v8B7hpb0TKl0MWoAavPDmHvobFe5R5zn0bCJWo= +github.com/coreos/go-systemd/v22 v22.6.0/go.mod h1:iG+pp635Fo7ZmV/j14KUcmEyWF+0X7Lua8rrTWzYgWU= 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= @@ -32,17 +32,42 @@ 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.1 h1:lpsStH0n2ittzTnbaSloVZLuB5+fvSY/+hnagBjSNZU= -github.com/go-openapi/swag v0.23.1/go.mod h1:STZs8TbRvEQQKUA+JZNAm3EWlgaOBGpyFDqQnDHMef0= -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/jsonpointer v0.22.4 h1:dZtK82WlNpVLDW2jlA1YCiVJFVqkED1MegOUy9kR5T4= +github.com/go-openapi/jsonpointer v0.22.4/go.mod h1:elX9+UgznpFhgBuaMQ7iu4lvvX1nvNsesQ3oxmYTw80= +github.com/go-openapi/jsonreference v0.21.4 h1:24qaE2y9bx/q3uRK/qN+TDwbok1NhbSmGjjySRCHtC8= +github.com/go-openapi/jsonreference v0.21.4/go.mod h1:rIENPTjDbLpzQmQWCj5kKj3ZlmEh+EFVbz3RTUh30/4= +github.com/go-openapi/swag v0.25.4 h1:OyUPUFYDPDBMkqyxOTkqDYFnrhuhi9NR6QVUvIochMU= +github.com/go-openapi/swag v0.25.4/go.mod h1:zNfJ9WZABGHCFg2RnY0S4IOkAcVTzJ6z2Bi+Q4i6qFQ= +github.com/go-openapi/swag/cmdutils v0.25.4 h1:8rYhB5n6WawR192/BfUu2iVlxqVR9aRgGJP6WaBoW+4= +github.com/go-openapi/swag/cmdutils v0.25.4/go.mod h1:pdae/AFo6WxLl5L0rq87eRzVPm/XRHM3MoYgRMvG4A0= +github.com/go-openapi/swag/conv v0.25.4 h1:/Dd7p0LZXczgUcC/Ikm1+YqVzkEeCc9LnOWjfkpkfe4= +github.com/go-openapi/swag/conv v0.25.4/go.mod h1:3LXfie/lwoAv0NHoEuY1hjoFAYkvlqI/Bn5EQDD3PPU= +github.com/go-openapi/swag/fileutils v0.25.4 h1:2oI0XNW5y6UWZTC7vAxC8hmsK/tOkWXHJQH4lKjqw+Y= +github.com/go-openapi/swag/fileutils v0.25.4/go.mod h1:cdOT/PKbwcysVQ9Tpr0q20lQKH7MGhOEb6EwmHOirUk= +github.com/go-openapi/swag/jsonname v0.25.4 h1:bZH0+MsS03MbnwBXYhuTttMOqk+5KcQ9869Vye1bNHI= +github.com/go-openapi/swag/jsonname v0.25.4/go.mod h1:GPVEk9CWVhNvWhZgrnvRA6utbAltopbKwDu8mXNUMag= +github.com/go-openapi/swag/jsonutils v0.25.4 h1:VSchfbGhD4UTf4vCdR2F4TLBdLwHyUDTd1/q4i+jGZA= +github.com/go-openapi/swag/jsonutils v0.25.4/go.mod h1:7OYGXpvVFPn4PpaSdPHJBtF0iGnbEaTk8AvBkoWnaAY= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4 h1:IACsSvBhiNJwlDix7wq39SS2Fh7lUOCJRmx/4SN4sVo= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4/go.mod h1:Mt0Ost9l3cUzVv4OEZG+WSeoHwjWLnarzMePNDAOBiM= +github.com/go-openapi/swag/loading v0.25.4 h1:jN4MvLj0X6yhCDduRsxDDw1aHe+ZWoLjW+9ZQWIKn2s= +github.com/go-openapi/swag/loading v0.25.4/go.mod h1:rpUM1ZiyEP9+mNLIQUdMiD7dCETXvkkC30z53i+ftTE= +github.com/go-openapi/swag/mangling v0.25.4 h1:2b9kBJk9JvPgxr36V23FxJLdwBrpijI26Bx5JH4Hp48= +github.com/go-openapi/swag/mangling v0.25.4/go.mod h1:6dxwu6QyORHpIIApsdZgb6wBk/DPU15MdyYj/ikn0Hg= +github.com/go-openapi/swag/netutils v0.25.4 h1:Gqe6K71bGRb3ZQLusdI8p/y1KLgV4M/k+/HzVSqT8H0= +github.com/go-openapi/swag/netutils v0.25.4/go.mod h1:m2W8dtdaoX7oj9rEttLyTeEFFEBvnAx9qHd5nJEBzYg= +github.com/go-openapi/swag/stringutils v0.25.4 h1:O6dU1Rd8bej4HPA3/CLPciNBBDwZj9HiEpdVsb8B5A8= +github.com/go-openapi/swag/stringutils v0.25.4/go.mod h1:GTsRvhJW5xM5gkgiFe0fV3PUlFm0dr8vki6/VSRaZK0= +github.com/go-openapi/swag/typeutils v0.25.4 h1:1/fbZOUN472NTc39zpa+YGHn3jzHWhv42wAJSN91wRw= +github.com/go-openapi/swag/typeutils v0.25.4/go.mod h1:Ou7g//Wx8tTLS9vG0UmzfCsjZjKhpjxayRKTHXf2pTE= +github.com/go-openapi/swag/yamlutils v0.25.4 h1:6jdaeSItEUb7ioS9lFoCZ65Cne1/RZtPBZ9A56h92Sw= +github.com/go-openapi/swag/yamlutils v0.25.4/go.mod h1:MNzq1ulQu+yd8Kl7wPOut/YHAAU/H6hL91fF+E2RFwc= +github.com/go-openapi/testify/enable/yaml/v2 v2.0.2 h1:0+Y41Pz1NkbTHz8NngxTuAXxEodtNSI1WG1c/m5Akw4= +github.com/go-openapi/testify/enable/yaml/v2 v2.0.2/go.mod h1:kme83333GCtJQHXQ8UKX3IBZu6z8T5Dvy5+CW3NLUUg= +github.com/go-openapi/testify/v2 v2.0.2 h1:X999g3jeLcoY8qctY/c/Z8iBHTbwLz7R2WXd6Ub6wls= +github.com/go-openapi/testify/v2 v2.0.2/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= 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/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo= @@ -54,8 +79,8 @@ github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= -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/gnostic-models v0.7.1 h1:SisTfuFKJSKM5CPZkffwi6coztzzeYUhc3v4yxLWH8c= +github.com/google/gnostic-models v0.7.1/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= @@ -71,8 +96,8 @@ github.com/grafana/authlib/types v0.0.0-20251119142549-be091cf2f4d4 h1:Muoy+FMGr github.com/grafana/authlib/types v0.0.0-20251119142549-be091cf2f4d4/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.48.3 h1:72NUpGNiJXCNQz/on++YSsl38xuVYYBKv5kKQaOClX4= -github.com/grafana/grafana-app-sdk/logging v0.48.3/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA= +github.com/grafana/grafana-app-sdk/logging v0.48.7 h1:Oa5qg473gka5+W/WQk61Xbw4YdAv+wV2Z4bJtzeCaQw= +github.com/grafana/grafana-app-sdk/logging v0.48.7/go.mod h1:5u3KalezoBAAo2Y3ytDYDAIIPvEqFLLDSxeiK99QxDU= 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= @@ -85,8 +110,6 @@ github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3 h1:NmZ1PKzSTQbuGHw9DGPFomqkkLW github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3/go.mod h1:zQrxl1YP88HQlA6i9c63DSVPFklWpGX4OWAc9bFuaH4= 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= -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= @@ -99,8 +122,6 @@ 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/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= 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= @@ -129,11 +150,11 @@ github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1: 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.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.67.3 h1:shd26MlnwTw5jksTDhC7rTQIteBxy+ZZDr3t7F2xN2Q= -github.com/prometheus/common v0.67.3/go.mod h1:gP0fq6YjjNCLssJCQp0yk4M8W6ikLURwkdd/YKtTbyI= +github.com/prometheus/common v0.67.4 h1:yR3NqWO1/UyO1w2PhUvXlGQs/PtFmoveVO0KZ4+Lvsc= +github.com/prometheus/common v0.67.4/go.mod h1:gP0fq6YjjNCLssJCQp0yk4M8W6ikLURwkdd/YKtTbyI= github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= -github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= +github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws= +github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw= 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/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= @@ -158,12 +179,12 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= go.etcd.io/bbolt v1.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.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.6.4 h1:9HBYrjppeOfFjBjaMTRxT3R7xT0GLK8EJMVC4xg6ok0= -go.etcd.io/etcd/client/pkg/v3 v3.6.4/go.mod h1:sbdzr2cl3HzVmxNw//PH7aLGVtY4QySjQFuaCgcRFAI= -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.etcd.io/etcd/api/v3 v3.6.6 h1:mcaMp3+7JawWv69p6QShYWS8cIWUOl32bFLb6qf8pOQ= +go.etcd.io/etcd/api/v3 v3.6.6/go.mod h1:f/om26iXl2wSkcTA1zGQv8reJRSLVdoEBsi4JdfMrx4= +go.etcd.io/etcd/client/pkg/v3 v3.6.6 h1:uoqgzSOv2H9KlIF5O1Lsd8sW+eMLuV6wzE3q5GJGQNs= +go.etcd.io/etcd/client/pkg/v3 v3.6.6/go.mod h1:YngfUVmvsvOJ2rRgStIyHsKtOt9SZI2aBJrZiWJhCbI= +go.etcd.io/etcd/client/v3 v3.6.6 h1:G5z1wMf5B9SNexoxOHUGBaULurOZPIgGPsW6CN492ec= +go.etcd.io/etcd/client/v3 v3.6.6/go.mod h1:36Qv6baQ07znPR3+n7t+Rk5VHEzVYPvFfGmfF4wBHV8= go.etcd.io/etcd/pkg/v3 v3.6.4 h1:fy8bmXIec1Q35/jRZ0KOes8vuFxbvdN0aAFqmEfJZWA= go.etcd.io/etcd/pkg/v3 v3.6.4/go.mod h1:kKcYWP8gHuBRcteyv6MXWSN0+bVMnfgqiHueIZnKMtE= go.etcd.io/etcd/server/v3 v3.6.4 h1:LsCA7CzjVt+8WGrdsnh6RhC0XqCsLkBly3ve5rTxMAU= @@ -172,26 +193,26 @@ go.etcd.io/raft/v3 v3.6.0 h1:5NtvbDVYpnfZWcIHgGRk9DyzkBIXOi8j+DDp1IcnUWQ= go.etcd.io/raft/v3 v3.6.0/go.mod h1:nLvLevg6+xrVtHUmVaTcTz603gQPHfh7kUAwV6YpfGo= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= -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/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/instrumentation/google.golang.org/grpc/otelgrpc v0.64.0 h1:RN3ifU8y4prNWeEnQp2kRRHz8UwonAEYZl8tUzHEXAk= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.64.0/go.mod h1:habDz3tEWiFANTo6oUE99EmaFUrCNYAAg3wiVmusm70= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.64.0 h1:ssfIgGNANqpVFCndZvcuyKbl0g+UAVcbBcqGkG28H0Y= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.64.0/go.mod h1:GQ/474YrbE4Jx8gZ4q5I4hrhUzM6UPzyrqJYV2AqPoQ= 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/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/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/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48= +go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0 h1:f0cb2XPmrqn4XMy9PNliTgRKJgS5WcL/u0/WRYGz4t0= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0/go.mod h1:vnakAaFckOMiMtOIhFI2MNH4FYrZzXCYxmb1LlhoGz8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0 h1:in9O8ESIOlwJAEGTkkf34DesGRAc/Pn8qJ7k3r/42LM= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0/go.mod h1:Rp0EXBm5tfnv0WL+ARyO/PHBEaEAT8UUHQ6AGJcSq6c= +go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0= +go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs= +go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18= +go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE= +go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8= +go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew= +go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI= +go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA= go.opentelemetry.io/proto/otlp v1.9.0 h1:l706jCMITVouPOqEnii2fIAuO3IVGBRPV5ICjceRb/A= go.opentelemetry.io/proto/otlp v1.9.0/go.mod h1:xE+Cx5E/eEHw+ISFkwPLwCZefwVjY+pqKg1qcK03+/4= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= @@ -207,8 +228,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.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q= -golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4= +golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU= +golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0= 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,30 +240,30 @@ 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.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= -golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= +golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= +golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.33.0 h1:4Q+qn+E5z8gPRJfmRy7C2gGG3T4jIprK6aSYgTXGRpo= -golang.org/x/oauth2 v0.33.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= +golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw= +golang.org/x/oauth2 v0.34.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-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.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= -golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 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.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= -golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU= -golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254= +golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= +golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q= +golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg= 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.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= -golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= +golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= +golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= 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= @@ -250,8 +271,8 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm 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.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ= -golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ= +golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA= +golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc= 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= @@ -260,20 +281,20 @@ 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/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto/googleapis/api v0.0.0-20251111163417-95abcf5c77ba h1:B14OtaXuMaCQsl2deSvNkyPKIzq3BjfxQp8d00QyWx4= -google.golang.org/genproto/googleapis/api v0.0.0-20251111163417-95abcf5c77ba/go.mod h1:G5IanEx8/PgI9w6CFcYQf7jMtHQhZruvfM1i3qOqk5U= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba h1:UKgtfRM7Yh93Sya0Fo8ZzhDP4qBckrrxEr2oF5UIVb8= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= +google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2 h1:7LRqPCEdE4TP4/9psdaB7F2nhZFfBiGJomA5sojLWdU= +google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2/go.mod h1:+rXWjjaukWZun3mLfjmVnQi18E1AsFbDN9QdJ5YXLto= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2 h1:2I6GHUeJ/4shcDpoUlLs/2WPnhg7yJwvXtqcMJt9liA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/grpc v1.18.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM= google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= -google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= -google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/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/evanphx/json-patch.v4 v4.13.0 h1:czT3CmqEaQ1aanPc5SdlgQrrEIb8w/wwCvWWnfEbYzo= +gopkg.in/evanphx/json-patch.v4 v4.13.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/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= @@ -281,26 +302,26 @@ gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYs gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -k8s.io/api v0.34.2 h1:fsSUNZhV+bnL6Aqrp6O7lMTy6o5x2C4XLjnh//8SLYY= -k8s.io/api v0.34.2/go.mod h1:MMBPaWlED2a8w4RSeanD76f7opUoypY8TFYkSM+3XHw= -k8s.io/apimachinery v0.34.2 h1:zQ12Uk3eMHPxrsbUJgNF8bTauTVR2WgqJsTmwTE/NW4= -k8s.io/apimachinery v0.34.2/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= -k8s.io/apiserver v0.34.2 h1:2/yu8suwkmES7IzwlehAovo8dDE07cFRC7KMDb1+MAE= -k8s.io/apiserver v0.34.2/go.mod h1:gqJQy2yDOB50R3JUReHSFr+cwJnL8G1dzTA0YLEqAPI= -k8s.io/client-go v0.34.2 h1:Co6XiknN+uUZqiddlfAjT68184/37PS4QAzYvQvDR8M= -k8s.io/client-go v0.34.2/go.mod h1:2VYDl1XXJsdcAxw7BenFslRQX28Dxz91U9MWKjX97fE= -k8s.io/component-base v0.34.2 h1:HQRqK9x2sSAsd8+R4xxRirlTjowsg6fWCPwWYeSvogQ= -k8s.io/component-base v0.34.2/go.mod h1:9xw2FHJavUHBFpiGkZoKuYZ5pdtLKe97DEByaA+hHbM= +k8s.io/api v0.34.3 h1:D12sTP257/jSH2vHV2EDYrb16bS7ULlHpdNdNhEw2S4= +k8s.io/api v0.34.3/go.mod h1:PyVQBF886Q5RSQZOim7DybQjAbVs8g7gwJNhGtY5MBk= +k8s.io/apimachinery v0.34.3 h1:/TB+SFEiQvN9HPldtlWOTp0hWbJ+fjU+wkxysf/aQnE= +k8s.io/apimachinery v0.34.3/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= +k8s.io/apiserver v0.34.3 h1:uGH1qpDvSiYG4HVFqc6A3L4CKiX+aBWDrrsxHYK0Bdo= +k8s.io/apiserver v0.34.3/go.mod h1:QPnnahMO5C2m3lm6fPW3+JmyQbvHZQ8uudAu/493P2w= +k8s.io/client-go v0.34.3 h1:wtYtpzy/OPNYf7WyNBTj3iUA0XaBHVqhv4Iv3tbrF5A= +k8s.io/client-go v0.34.3/go.mod h1:OxxeYagaP9Kdf78UrKLa3YZixMCfP6bgPwPwNBQBzpM= +k8s.io/component-base v0.34.3 h1:zsEgw6ELqK0XncCQomgO9DpUIzlrYuZYA0Cgo+JWpVk= +k8s.io/component-base v0.34.3/go.mod h1:5iIlD8wPfWE/xSHTRfbjuvUul2WZbI2nOUK65XL0E/c= 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/apiserver-network-proxy/konnectivity-client v0.31.2 h1:jpcvIRr3GLoUoEKRkHKSmGjxb6lWwrBlJsXc+eUYQHM= -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= +k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e h1:iW9ChlU0cU16w8MpVYjXk12dqQ4BPFBEgif+ap7/hqQ= +k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e/go.mod h1:kdmbQkyfwUagLfXIad1y2TdrjPFWp2Q89B3qkRwf/pQ= +k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 h1:SjGebBtkBqHFOli+05xYbK8YF1Dzkbzn+gDM4X9T4Ck= +k8s.io/utils v0.0.0-20251002143259-bc988d571ff4/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.34.0 h1:hSfpvjjTQXQY2Fol2CS0QHMNs/WI1MOSGzCm1KhM5ec= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.34.0/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw= +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg= +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/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.1 h1:JrhdFMqOd/+3ByqlP2I45kTOZmTRLBUm5pvRjeheg7E= diff --git a/pkg/build/go.mod b/pkg/build/go.mod index 2bc514fcfd5..5170c87da05 100644 --- a/pkg/build/go.mod +++ b/pkg/build/go.mod @@ -10,14 +10,14 @@ replace github.com/docker/docker => github.com/moby/moby v28.0.1+incompatible require ( github.com/google/uuid v1.6.0 // indirect; @grafana/grafana-backend-group github.com/urfave/cli/v2 v2.27.7 // @grafana/grafana-backend-group - 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.47.0 // indirect; @grafana/oss-big-tent @grafana/partner-datasources - golang.org/x/sync v0.18.0 // @grafana/alerting-backend - golang.org/x/text v0.31.0 // indirect; @grafana/grafana-backend-group + go.opentelemetry.io/otel v1.39.0 // indirect; @grafana/grafana-backend-group + go.opentelemetry.io/otel/sdk v1.39.0 // indirect; @grafana/grafana-backend-group + go.opentelemetry.io/otel/trace v1.39.0 // indirect; @grafana/grafana-backend-group + golang.org/x/net v0.48.0 // indirect; @grafana/oss-big-tent @grafana/partner-datasources + golang.org/x/sync v0.19.0 // @grafana/alerting-backend + golang.org/x/text v0.32.0 // indirect; @grafana/grafana-backend-group google.golang.org/grpc v1.77.0 // indirect; @grafana/plugins-platform-backend - google.golang.org/protobuf v1.36.10 // indirect; @grafana/plugins-platform-backend + google.golang.org/protobuf v1.36.11 // indirect; @grafana/plugins-platform-backend ) require ( @@ -28,10 +28,10 @@ require ( github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect - go.opentelemetry.io/otel/metric v1.38.0 // indirect - golang.org/x/sys v0.38.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20251111163417-95abcf5c77ba // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba // indirect + go.opentelemetry.io/otel/metric v1.39.0 // indirect + golang.org/x/sys v0.39.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2 // indirect ) require ( @@ -46,6 +46,7 @@ require ( github.com/Khan/genqlient v0.8.1 // indirect github.com/adrg/xdg v0.5.3 // indirect github.com/cenkalti/backoff/v5 v5.0.3 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect @@ -56,12 +57,12 @@ require ( go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.12.2 // indirect go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp 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/exporters/otlp/otlptrace v1.39.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0 // indirect go.opentelemetry.io/otel/log v0.12.2 // indirect go.opentelemetry.io/otel/sdk/log v0.12.2 // indirect - go.opentelemetry.io/otel/sdk/metric v1.38.0 // indirect + go.opentelemetry.io/otel/sdk/metric v1.39.0 // indirect go.opentelemetry.io/proto/otlp v1.9.0 // indirect ) diff --git a/pkg/build/go.sum b/pkg/build/go.sum index cdd5828ebd8..ae3e2125dc5 100644 --- a/pkg/build/go.sum +++ b/pkg/build/go.sum @@ -12,6 +12,8 @@ github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNg github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= 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/cpuguy83/go-md2man/v2 v2.0.7 h1:zbFlGlXEAKlwXpmvle3d8Oe3YnkKIK4xSRTd3sHPnBo= github.com/cpuguy83/go-md2man/v2 v2.0.7/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -61,8 +63,8 @@ github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGC github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= -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 v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48= +go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8= 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= @@ -71,48 +73,48 @@ go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0 h1:vl9 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/otlp/otlptrace v1.39.0 h1:f0cb2XPmrqn4XMy9PNliTgRKJgS5WcL/u0/WRYGz4t0= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0/go.mod h1:vnakAaFckOMiMtOIhFI2MNH4FYrZzXCYxmb1LlhoGz8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0 h1:in9O8ESIOlwJAEGTkkf34DesGRAc/Pn8qJ7k3r/42LM= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0/go.mod h1:Rp0EXBm5tfnv0WL+ARyO/PHBEaEAT8UUHQ6AGJcSq6c= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0 h1:Ckwye2FpXkYgiHX7fyVrN1uA/UYd9ounqqTuSNAv0k4= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0/go.mod h1:teIFJh5pW2y+AN7riv6IBPX2DuesS3HgP39mwOspKwU= 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.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/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0= +go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs= +go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18= +go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE= 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/log/logtest v0.0.0-20250521073539-a85ae98dcedc h1:uqxdywfHqqCl6LmZzI3pUnXT1RGFYyUgxj0AkWPFxi0= go.opentelemetry.io/otel/sdk/log/logtest v0.0.0-20250521073539-a85ae98dcedc/go.mod h1:TY/N/FT7dmFrP/r5ym3g0yysP1DefqGpAZr4f82P0dE= -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/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8= +go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew= +go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI= +go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA= go.opentelemetry.io/proto/otlp v1.9.0 h1:l706jCMITVouPOqEnii2fIAuO3IVGBRPV5ICjceRb/A= go.opentelemetry.io/proto/otlp v1.9.0/go.mod h1:xE+Cx5E/eEHw+ISFkwPLwCZefwVjY+pqKg1qcK03+/4= 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.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= -golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= -golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= -golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= -golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= -golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= -golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= +golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= +golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= +golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= +golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= 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-20251111163417-95abcf5c77ba h1:B14OtaXuMaCQsl2deSvNkyPKIzq3BjfxQp8d00QyWx4= -google.golang.org/genproto/googleapis/api v0.0.0-20251111163417-95abcf5c77ba/go.mod h1:G5IanEx8/PgI9w6CFcYQf7jMtHQhZruvfM1i3qOqk5U= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba h1:UKgtfRM7Yh93Sya0Fo8ZzhDP4qBckrrxEr2oF5UIVb8= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= +google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2 h1:7LRqPCEdE4TP4/9psdaB7F2nhZFfBiGJomA5sojLWdU= +google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2/go.mod h1:+rXWjjaukWZun3mLfjmVnQi18E1AsFbDN9QdJ5YXLto= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2 h1:2I6GHUeJ/4shcDpoUlLs/2WPnhg7yJwvXtqcMJt9liA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM= google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= -google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= -google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/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-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/pkg/build/wire/go.mod b/pkg/build/wire/go.mod index b3ac434ea53..fc7aa317583 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.39.0 + golang.org/x/tools v0.40.0 ) require ( - golang.org/x/mod v0.30.0 // indirect - golang.org/x/sync v0.18.0 // indirect + golang.org/x/mod v0.31.0 // indirect + golang.org/x/sync v0.19.0 // indirect ) diff --git a/pkg/build/wire/go.sum b/pkg/build/wire/go.sum index bd76c016a3e..7091ed41da2 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.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk= -golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc= -golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= -golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= -golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ= -golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ= +golang.org/x/mod v0.31.0 h1:HaW9xtz0+kOcWKwli0ZXy79Ix+UW/vOfmWI5QVd2tgI= +golang.org/x/mod v0.31.0/go.mod h1:43JraMp9cGx1Rx3AqioxrbrhNsLl2l/iNAvuBkrezpg= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA= +golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc= diff --git a/pkg/codegen/go.mod b/pkg/codegen/go.mod index 7d01f823e78..f608e1fb1c1 100644 --- a/pkg/codegen/go.mod +++ b/pkg/codegen/go.mod @@ -9,18 +9,18 @@ require ( github.com/grafana/cog v0.0.46 github.com/grafana/cuetsy v0.1.11 github.com/matryer/is v1.4.1 - golang.org/x/tools v0.39.0 + golang.org/x/tools v0.40.0 ) require ( github.com/cockroachdb/apd/v2 v2.0.2 // indirect github.com/dave/jennifer v1.7.1 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect - github.com/emicklei/proto v1.13.2 // indirect - github.com/expr-lang/expr v1.17.6 // indirect + github.com/emicklei/proto v1.14.2 // indirect + github.com/expr-lang/expr v1.17.7 // indirect github.com/getkin/kin-openapi v0.133.0 // indirect - github.com/go-openapi/jsonpointer v0.22.1 // indirect - github.com/go-openapi/swag/jsonname v0.25.1 // indirect + github.com/go-openapi/jsonpointer v0.22.4 // indirect + github.com/go-openapi/swag/jsonname v0.25.4 // indirect github.com/go-test/deep v1.1.1 // indirect github.com/golang/glog v1.2.5 // indirect github.com/google/go-cmp v0.7.0 // indirect @@ -29,9 +29,10 @@ require ( github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/huandu/xstrings v1.5.0 // indirect github.com/josharian/intern v1.0.0 // indirect + github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect github.com/lib/pq v1.10.9 // indirect - github.com/mailru/easyjson v0.9.0 // indirect + github.com/mailru/easyjson v0.9.1 // indirect github.com/mitchellh/go-wordwrap v1.0.1 // indirect github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect github.com/mpvl/unique v0.0.0-20150818121801-cbe035fff7de // indirect @@ -39,18 +40,19 @@ require ( github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 // indirect github.com/perimeterx/marshmallow v1.1.5 // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/protocolbuffers/txtpbfmt v0.0.0-20241112170944-20d2c9ebc01d // indirect + github.com/protocolbuffers/txtpbfmt v0.0.0-20251124094003-fcb97cc64c7b // indirect github.com/rogpeppe/go-internal v1.14.1 // indirect github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 // indirect github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect github.com/ugorji/go/codec v1.2.11 // indirect - github.com/woodsbury/decimal128 v1.3.0 // indirect + github.com/woodsbury/decimal128 v1.4.0 // indirect github.com/xlab/treeprint v1.2.0 // indirect github.com/yalue/merged_fs v1.3.0 // indirect - golang.org/x/mod v0.30.0 // indirect - golang.org/x/net v0.47.0 // indirect - golang.org/x/sync v0.18.0 // indirect - golang.org/x/text v0.31.0 // indirect + golang.org/x/mod v0.31.0 // indirect + golang.org/x/net v0.48.0 // indirect + golang.org/x/sync v0.19.0 // indirect + golang.org/x/text v0.32.0 // indirect + gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/pkg/codegen/go.sum b/pkg/codegen/go.sum index 5e2bca5c947..a5303120de5 100644 --- a/pkg/codegen/go.sum +++ b/pkg/codegen/go.sum @@ -9,16 +9,18 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/emicklei/proto v1.13.2 h1:z/etSFO3uyXeuEsVPzfl56WNgzcvIr42aQazXaQmFZY= -github.com/emicklei/proto v1.13.2/go.mod h1:rn1FgRS/FANiZdD2djyH7TMA9jdRDcYQ9IEN9yvjX0A= -github.com/expr-lang/expr v1.17.6 h1:1h6i8ONk9cexhDmowO/A64VPxHScu7qfSl2k8OlINec= -github.com/expr-lang/expr v1.17.6/go.mod h1:8/vRC7+7HBzESEqt5kKpYXxrxkr31SaO8r40VO/1IT4= +github.com/emicklei/proto v1.14.2 h1:wJPxPy2Xifja9cEMrcA/g08art5+7CGJNFNk35iXC1I= +github.com/emicklei/proto v1.14.2/go.mod h1:rn1FgRS/FANiZdD2djyH7TMA9jdRDcYQ9IEN9yvjX0A= +github.com/expr-lang/expr v1.17.7 h1:Q0xY/e/2aCIp8g9s/LGvMDCC5PxYlvHgDZRQ4y16JX8= +github.com/expr-lang/expr v1.17.7/go.mod h1:8/vRC7+7HBzESEqt5kKpYXxrxkr31SaO8r40VO/1IT4= 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-openapi/jsonpointer v0.22.1 h1:sHYI1He3b9NqJ4wXLoJDKmUmHkWy/L7rtEo92JUxBNk= -github.com/go-openapi/jsonpointer v0.22.1/go.mod h1:pQT9OsLkfz1yWoMgYFy4x3U5GY5nUlsOn1qSBH5MkCM= -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/jsonpointer v0.22.4 h1:dZtK82WlNpVLDW2jlA1YCiVJFVqkED1MegOUy9kR5T4= +github.com/go-openapi/jsonpointer v0.22.4/go.mod h1:elX9+UgznpFhgBuaMQ7iu4lvvX1nvNsesQ3oxmYTw80= +github.com/go-openapi/swag/jsonname v0.25.4 h1:bZH0+MsS03MbnwBXYhuTttMOqk+5KcQ9869Vye1bNHI= +github.com/go-openapi/swag/jsonname v0.25.4/go.mod h1:GPVEk9CWVhNvWhZgrnvRA6utbAltopbKwDu8mXNUMag= +github.com/go-openapi/testify/v2 v2.0.2 h1:X999g3jeLcoY8qctY/c/Z8iBHTbwLz7R2WXd6Ub6wls= +github.com/go-openapi/testify/v2 v2.0.2/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= 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/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= @@ -47,6 +49,7 @@ github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq 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/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= @@ -57,8 +60,8 @@ github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0 github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -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/mailru/easyjson v0.9.1 h1:LbtsOm5WAswyWbvTEOqhypdPeZzHavpZx96/n553mR8= +github.com/mailru/easyjson v0.9.1/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= github.com/matryer/is v1.4.1 h1:55ehd8zaGABKLXQUe2awZ99BD/PTc2ls+KV/dXphgEQ= github.com/matryer/is v1.4.1/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= @@ -73,6 +76,7 @@ github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 h1:bQx3WeLcUWy+RletI github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90/go.mod h1:y5+oSEHCPT/DGrS++Wc/479ERge0zTFxaF8PbGKcg2o= github.com/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX50IvK2s= github.com/perimeterx/marshmallow v1.1.5/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -81,6 +85,7 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/protocolbuffers/txtpbfmt v0.0.0-20220428173112-74888fd59c2b h1:zd/2RNzIRkoGGMjE+YIsZ85CnDIz672JK2F3Zl4vux4= github.com/protocolbuffers/txtpbfmt v0.0.0-20220428173112-74888fd59c2b/go.mod h1:KjY0wibdYKc4DYkerHSbguaf3JeIPGhNJBp2BNiFH78= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= 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/santhosh-tekuri/jsonschema/v5 v5.3.1 h1:lZUw3E0/J3roVtGQ+SCrUrg3ON6NgVqpn3+iol9aGu4= @@ -94,22 +99,22 @@ 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/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/woodsbury/decimal128 v1.4.0 h1:xJATj7lLu4f2oObouMt2tgGiElE5gO6mSWUjQsBgUlc= +github.com/woodsbury/decimal128 v1.4.0/go.mod h1:BP46FUrVjVhdTbKT+XuQh2xfQaGki9LMIRJSFuh6THU= 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.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk= -golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc= -golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= -golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= -golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= -golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= -golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= -golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= -golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ= -golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ= +golang.org/x/mod v0.31.0 h1:HaW9xtz0+kOcWKwli0ZXy79Ix+UW/vOfmWI5QVd2tgI= +golang.org/x/mod v0.31.0/go.mod h1:43JraMp9cGx1Rx3AqioxrbrhNsLl2l/iNAvuBkrezpg= +golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= +golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= +golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= +golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA= +golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc= 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/infra/log/log.go b/pkg/infra/log/log.go index 9e7a51a8dc7..abae387729e 100644 --- a/pkg/infra/log/log.go +++ b/pkg/infra/log/log.go @@ -54,7 +54,8 @@ func init() { } logger := level.NewFilter(format(os.Stderr), level.AllowInfo()) root = newManager(logger) - initAppSDKLogger(logger) + // Use default Info level during package initialization before config is loaded + initAppSDKLogger(logger, slog.LevelInfo) RegisterContextualLogProvider(func(ctx context.Context) ([]any, bool) { pFromCtx := ctx.Value(logParamsContextKey{}) @@ -80,7 +81,7 @@ func newManager(logger gokitlog.Logger) *logManager { } } -func (lm *logManager) initialize(loggers []logWithFilters) { +func (lm *logManager) initialize(loggers []logWithFilters, levelStr string) { lm.mutex.Lock() defer lm.mutex.Unlock() @@ -113,7 +114,7 @@ func (lm *logManager) initialize(loggers []logWithFilters) { lm.loggersByName[name].Swap(&compositeLogger{loggers: ctxLoggers}) } - initAppSDKLogger(lm.ConcreteLogger) + initAppSDKLogger(lm.ConcreteLogger, stringToSlogLevel(levelStr)) } func (lm *logManager) New(ctx ...any) *ConcreteLogger { @@ -514,7 +515,7 @@ func ReadLoggingConfig(modes []string, logsPath string, cfg *ini.File) error { configLoggers = append(configLoggers, handler) } if len(configLoggers) > 0 { - root.initialize(configLoggers) + root.initialize(configLoggers, defaultLevelName) } return nil @@ -551,8 +552,22 @@ func SetupConsoleLogger(level string) error { return nil } -func initAppSDKLogger(gkl gokitlog.Logger) { - // We need to allow Debug logs here. go-kit/log does not support sharing the level we're using. - // TODO: Refactor such that we can pass in a level in a more appropriate manner. - logging.DefaultLogger = logging.NewSLogLogger(sloggokit.NewGoKitHandler(gkl, slog.LevelDebug)) +// stringToSlogLevel converts a log level string to slog.Level +func stringToSlogLevel(levelStr string) slog.Level { + switch strings.ToLower(levelStr) { + case "trace", "debug": + return slog.LevelDebug + case "info": + return slog.LevelInfo + case "warn", "warning": + return slog.LevelWarn + case "error", "critical": + return slog.LevelError + default: + return slog.LevelInfo + } +} + +func initAppSDKLogger(gkl gokitlog.Logger, level slog.Level) { + logging.DefaultLogger = logging.NewSLogLogger(sloggokit.NewGoKitHandler(gkl, level)) } diff --git a/pkg/infra/log/log_test.go b/pkg/infra/log/log_test.go index 98fee4be8c0..5302e565964 100644 --- a/pkg/infra/log/log_test.go +++ b/pkg/infra/log/log_test.go @@ -88,7 +88,7 @@ func TestNew(t *testing.T) { val: swapLogger, maxLevel: level.AllowAll(), }, - }) + }, "info") err := log1.Log("msg", "hello 1") require.NoError(t, err) diff --git a/pkg/infra/metrics/metrics.go b/pkg/infra/metrics/metrics.go index c1995545df8..19113ed3b1f 100644 --- a/pkg/infra/metrics/metrics.go +++ b/pkg/infra/metrics/metrics.go @@ -224,7 +224,7 @@ var ( MStatTotalRepositories prometheus.Gauge // MUnifiedStorageMigrationStatus indicates the migration status for unified storage in this instance. - // Possible values: 0 (default/undefined), 1 (migration disabled), 2 (migration would run). + // Possible values: 0 (default/undefined), 1 (migration disabled), 2 (migration would run), 3 (migration will run). MUnifiedStorageMigrationStatus prometheus.Gauge ) diff --git a/pkg/kinds/dashboard/dashboard_spec_gen.go b/pkg/kinds/dashboard/dashboard_spec_gen.go index bd73e527534..7d2a0ba5439 100644 --- a/pkg/kinds/dashboard/dashboard_spec_gen.go +++ b/pkg/kinds/dashboard/dashboard_spec_gen.go @@ -204,6 +204,9 @@ type Panel struct { Options map[string]any `json:"options,omitempty"` // Field options allow you to change how the data is displayed in your visualizations. FieldConfig *FieldConfigSource `json:"fieldConfig,omitempty"` + // When a panel is migrated from a previous version (Angular to React), this field is set to the original panel type. + // This is used to determine the original panel type when migrating to a new version so the plugin migration can be applied. + AutoMigrateFrom *string `json:"autoMigrateFrom,omitempty"` } // NewPanel creates a new Panel object. diff --git a/pkg/login/social/connectors/google_oauth.go b/pkg/login/social/connectors/google_oauth.go index 81c7cd31f9d..b94f0514879 100644 --- a/pkg/login/social/connectors/google_oauth.go +++ b/pkg/login/social/connectors/google_oauth.go @@ -81,7 +81,15 @@ func (s *SocialGoogle) Validate(ctx context.Context, newSettings ssoModels.SSOSe return validation.Validate(info, requester, validation.MustBeEmptyValidator(info.AuthUrl, "Auth URL"), validation.MustBeEmptyValidator(info.TokenUrl, "Token URL"), - validation.MustBeEmptyValidator(info.ApiUrl, "API URL")) + validation.MustBeEmptyValidator(info.ApiUrl, "API URL"), + loginPromptValidator) +} + +func loginPromptValidator(info *social.OAuthInfo, requester identity.Requester) error { + if info.UseRefreshToken && !slices.Contains([]string{"", "consent"}, info.LoginPrompt) { + return ssosettings.ErrInvalidOAuthConfig("If provided, login_prompt must be set to consent when use_refresh_token is enabled.") + } + return nil } func (s *SocialGoogle) Reload(ctx context.Context, settings ssoModels.SSOSettings) error { diff --git a/pkg/login/social/connectors/google_oauth_test.go b/pkg/login/social/connectors/google_oauth_test.go index d330c39d78d..620c448013b 100644 --- a/pkg/login/social/connectors/google_oauth_test.go +++ b/pkg/login/social/connectors/google_oauth_test.go @@ -9,6 +9,7 @@ import ( "fmt" "net/http" "net/http/httptest" + "net/url" "testing" "time" @@ -18,6 +19,7 @@ import ( "github.com/stretchr/testify/require" "golang.org/x/oauth2" + "github.com/grafana/grafana/pkg/apimachinery/errutil" "github.com/grafana/grafana/pkg/apimachinery/identity" "github.com/grafana/grafana/pkg/login/social" "github.com/grafana/grafana/pkg/services/featuremgmt" @@ -871,6 +873,39 @@ func TestSocialGoogle_Validate(t *testing.T) { }, wantErr: ssosettings.ErrBaseInvalidOAuthConfig, }, + { + name: "fails if use_refresh_token is enabled and login prompt is neither empty or 'consent'", + settings: ssoModels.SSOSettings{ + Settings: map[string]any{ + "client_id": "client-id", + "use_refresh_token": "true", + "login_prompt": "login", + }, + }, + wantErr: ssosettings.ErrBaseInvalidOAuthConfig, + }, + { + name: "succeeds if use_refresh_token is enabled and login prompt is empty", + settings: ssoModels.SSOSettings{ + Settings: map[string]any{ + "client_id": "client-id", + "use_refresh_token": "true", + "login_prompt": "", + }, + }, + wantErr: nil, + }, + { + name: "succeeds if use_refresh_token is enabled and login prompt is consent", + settings: ssoModels.SSOSettings{ + Settings: map[string]any{ + "client_id": "client-id", + "use_refresh_token": "true", + "login_prompt": "consent", + }, + }, + wantErr: nil, + }, } for _, tc := range testCases { @@ -886,7 +921,13 @@ func TestSocialGoogle_Validate(t *testing.T) { require.ErrorIs(t, err, tc.wantErr) return } - require.NoError(t, err) + + if err != nil { + var e errutil.Error + require.True(t, errors.As(err, &e)) + require.NoError(t, e, "expected no error, got %v", e.PublicMessage) + return + } }) } } @@ -1024,3 +1065,102 @@ func TestIsHDAllowed(t *testing.T) { }) } } + +func TestSocialGoogle_AuthCodeURL(t *testing.T) { + testCases := []struct { + name string + info *social.OAuthInfo + opts []oauth2.AuthCodeOption + state string + wantURL *url.URL + }{ + { + name: "should return the correct auth code URL", + info: &social.OAuthInfo{ + ClientId: "client-id", + ClientSecret: "client-secret", + AuthUrl: "https://example.com/auth", + LoginPrompt: "login", + Scopes: []string{"openid", "email", "profile"}, + }, + state: "test-state", + opts: []oauth2.AuthCodeOption{ + oauth2.SetAuthURLParam("extra_param", "extra_value"), + }, + wantURL: &url.URL{ + Scheme: "https", + Host: "example.com", + Path: "/auth", + RawQuery: url.Values{ + "state": {"test-state"}, + "prompt": {"login"}, + "response_type": {"code"}, + "client_id": {"client-id"}, + "redirect_uri": {"/login/google"}, + "scope": {"openid email profile"}, + "extra_param": {"extra_value"}, + }.Encode(), + }, + }, + { + name: "should add access type offline and approval force if use refresh token is enabled", + info: &social.OAuthInfo{ + ClientId: "client-id", + ClientSecret: "client-secret", + AuthUrl: "https://example.com/auth", + Scopes: []string{"openid", "email", "profile"}, + UseRefreshToken: true, + }, + state: "test-state", + wantURL: &url.URL{ + Scheme: "https", + Host: "example.com", + Path: "/auth", + RawQuery: url.Values{ + "state": {"test-state"}, + "prompt": {"consent"}, + "response_type": {"code"}, + "client_id": {"client-id"}, + "redirect_uri": {"/login/google"}, + "scope": {"openid email profile"}, + "access_type": {"offline"}, + }.Encode(), + }, + }, + { + name: "should override configured login prompt if use refresh token is enabled", + info: &social.OAuthInfo{ + ClientId: "client-id", + ClientSecret: "client-secret", + AuthUrl: "https://example.com/auth", + Scopes: []string{"openid", "email", "profile"}, + UseRefreshToken: true, + }, + state: "test-state", + wantURL: &url.URL{ + Scheme: "https", + Host: "example.com", + Path: "/auth", + RawQuery: url.Values{ + "state": {"test-state"}, + "prompt": {"consent"}, + "response_type": {"code"}, + "client_id": {"client-id"}, + "redirect_uri": {"/login/google"}, + "scope": {"openid email profile"}, + "access_type": {"offline"}, + }.Encode(), + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + s := NewGoogleProvider(tc.info, &setting.Cfg{}, nil, ssosettingstests.NewFakeService(), featuremgmt.WithFeatures()) + gotURL := s.AuthCodeURL(tc.state, tc.opts...) + parsedURL, err := url.Parse(gotURL) + require.NoError(t, err) + require.EqualValues(t, tc.wantURL, parsedURL) + }) + } +} diff --git a/pkg/login/social/connectors/social_base.go b/pkg/login/social/connectors/social_base.go index 0db4d81baeb..3ecbf8e334e 100644 --- a/pkg/login/social/connectors/social_base.go +++ b/pkg/login/social/connectors/social_base.go @@ -91,7 +91,11 @@ func (s *SocialBase) AuthCodeURL(state string, opts ...oauth2.AuthCodeOption) st func (s *SocialBase) getAuthCodeURL(state string, opts ...oauth2.AuthCodeOption) string { if s.info.LoginPrompt != "" { promptOpt := oauth2.SetAuthURLParam("prompt", s.info.LoginPrompt) - opts = append(opts, promptOpt) + + // Prepend the prompt option to the opts slice to ensure it is applied last. + // This is necessary in case the caller provides an option that overrides the prompt, + // such as `oauth2.ApprovalForce`. + opts = append([]oauth2.AuthCodeOption{promptOpt}, opts...) } return s.Config.AuthCodeURL(state, opts...) diff --git a/pkg/middleware/loggermw/logger.go b/pkg/middleware/loggermw/logger.go index 1255d87aa0e..1b4f3d4d2d4 100644 --- a/pkg/middleware/loggermw/logger.go +++ b/pkg/middleware/loggermw/logger.go @@ -64,10 +64,7 @@ func (l *loggerImpl) Middleware() web.Middleware { // put the start time on context so we can measure it later. r = r.WithContext(log.InitstartTime(r.Context(), time.Now())) - //nolint:staticcheck // not yet migrated to OpenFeature - if l.flags.IsEnabled(r.Context(), featuremgmt.FlagUnifiedRequestLog) { - r = r.WithContext(errutil.SetUnifiedLogging(r.Context())) - } + r = r.WithContext(errutil.SetUnifiedLogging(r.Context())) rw := web.Rw(w, r) next.ServeHTTP(rw, r) diff --git a/pkg/operators/provisioning/config.go b/pkg/operators/provisioning/config.go index 8e496e5e556..05552e56095 100644 --- a/pkg/operators/provisioning/config.go +++ b/pkg/operators/provisioning/config.go @@ -178,7 +178,7 @@ func setupFromConfig(cfg *setting.Cfg, registry prometheus.Registerer) (controll APIPath: "/apis", Host: url, WrapTransport: transport.WrapperFunc(func(rt http.RoundTripper) http.RoundTripper { - return authrt.NewRoundTripper(tokenExchangeClient, rt, group) + return authrt.NewRoundTripper(tokenExchangeClient, rt, group, authrt.ExtraAudience(provisioning.GROUP)) }), Transport: &http.Transport{ MaxConnsPerHost: 100, diff --git a/pkg/operators/provisioning/repo_operator.go b/pkg/operators/provisioning/repo_operator.go index 1651a126ffe..416eb5c0e3f 100644 --- a/pkg/operators/provisioning/repo_operator.go +++ b/pkg/operators/provisioning/repo_operator.go @@ -85,7 +85,6 @@ func RunRepoController(deps server.OperatorDependencies) error { resourceLister, controllerCfg.clients, jobs, - nil, // dualwrite -- standalone operator assumes it is backed by unified storage healthChecker, statusPatcher, deps.Registerer, diff --git a/pkg/plugins/codegen/go.mod b/pkg/plugins/codegen/go.mod index b4e296c934a..641cf9f9b49 100644 --- a/pkg/plugins/codegen/go.mod +++ b/pkg/plugins/codegen/go.mod @@ -16,11 +16,11 @@ require ( cuelabs.dev/go/oci/ociregistry v0.0.0-20240906074133-82eb438dd565 // indirect github.com/cockroachdb/apd/v3 v3.2.1 // indirect github.com/dave/dst v0.27.3 // indirect - github.com/emicklei/proto v1.13.2 // indirect - github.com/expr-lang/expr v1.17.6 // indirect + github.com/emicklei/proto v1.14.2 // indirect + github.com/expr-lang/expr v1.17.7 // indirect github.com/getkin/kin-openapi v0.133.0 // indirect - github.com/go-openapi/jsonpointer v0.22.1 // indirect - github.com/go-openapi/swag/jsonname v0.25.1 // indirect + github.com/go-openapi/jsonpointer v0.22.4 // indirect + github.com/go-openapi/swag/jsonname v0.25.4 // indirect github.com/google/go-cmp v0.7.0 // indirect github.com/google/uuid v1.6.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect @@ -28,7 +28,7 @@ require ( github.com/huandu/xstrings v1.5.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/kr/text v0.2.0 // indirect - github.com/mailru/easyjson v0.9.0 // indirect + github.com/mailru/easyjson v0.9.1 // indirect github.com/mitchellh/go-wordwrap v1.0.1 // indirect github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 // indirect @@ -37,17 +37,18 @@ require ( github.com/opencontainers/image-spec v1.1.0 // indirect github.com/pelletier/go-toml/v2 v2.2.3 // indirect github.com/perimeterx/marshmallow v1.1.5 // indirect - github.com/protocolbuffers/txtpbfmt v0.0.0-20241112170944-20d2c9ebc01d // indirect + github.com/protocolbuffers/txtpbfmt v0.0.0-20251124094003-fcb97cc64c7b // indirect github.com/rogpeppe/go-internal v1.14.1 // indirect github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 // indirect - github.com/woodsbury/decimal128 v1.3.0 // indirect + github.com/woodsbury/decimal128 v1.4.0 // indirect github.com/xlab/treeprint v1.2.0 // indirect github.com/yalue/merged_fs v1.3.0 // indirect - golang.org/x/mod v0.30.0 // indirect - golang.org/x/net v0.47.0 // indirect + golang.org/x/mod v0.31.0 // indirect + golang.org/x/net v0.48.0 // indirect golang.org/x/oauth2 v0.27.0 // indirect - golang.org/x/sync v0.18.0 // indirect - golang.org/x/text v0.31.0 // indirect - golang.org/x/tools v0.39.0 // indirect + golang.org/x/sync v0.19.0 // indirect + golang.org/x/text v0.32.0 // indirect + golang.org/x/tools v0.40.0 // indirect + google.golang.org/protobuf v1.33.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 635c691a7be..a514789135c 100644 --- a/pkg/plugins/codegen/go.sum +++ b/pkg/plugins/codegen/go.sum @@ -10,16 +10,18 @@ github.com/dave/dst v0.27.3/go.mod h1:jHh6EOibnHgcUW3WjKHisiooEkYwqpHLBSX1iOBhEy github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/emicklei/proto v1.13.2 h1:z/etSFO3uyXeuEsVPzfl56WNgzcvIr42aQazXaQmFZY= -github.com/emicklei/proto v1.13.2/go.mod h1:rn1FgRS/FANiZdD2djyH7TMA9jdRDcYQ9IEN9yvjX0A= -github.com/expr-lang/expr v1.17.6 h1:1h6i8ONk9cexhDmowO/A64VPxHScu7qfSl2k8OlINec= -github.com/expr-lang/expr v1.17.6/go.mod h1:8/vRC7+7HBzESEqt5kKpYXxrxkr31SaO8r40VO/1IT4= +github.com/emicklei/proto v1.14.2 h1:wJPxPy2Xifja9cEMrcA/g08art5+7CGJNFNk35iXC1I= +github.com/emicklei/proto v1.14.2/go.mod h1:rn1FgRS/FANiZdD2djyH7TMA9jdRDcYQ9IEN9yvjX0A= +github.com/expr-lang/expr v1.17.7 h1:Q0xY/e/2aCIp8g9s/LGvMDCC5PxYlvHgDZRQ4y16JX8= +github.com/expr-lang/expr v1.17.7/go.mod h1:8/vRC7+7HBzESEqt5kKpYXxrxkr31SaO8r40VO/1IT4= 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-openapi/jsonpointer v0.22.1 h1:sHYI1He3b9NqJ4wXLoJDKmUmHkWy/L7rtEo92JUxBNk= -github.com/go-openapi/jsonpointer v0.22.1/go.mod h1:pQT9OsLkfz1yWoMgYFy4x3U5GY5nUlsOn1qSBH5MkCM= -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/jsonpointer v0.22.4 h1:dZtK82WlNpVLDW2jlA1YCiVJFVqkED1MegOUy9kR5T4= +github.com/go-openapi/jsonpointer v0.22.4/go.mod h1:elX9+UgznpFhgBuaMQ7iu4lvvX1nvNsesQ3oxmYTw80= +github.com/go-openapi/swag/jsonname v0.25.4 h1:bZH0+MsS03MbnwBXYhuTttMOqk+5KcQ9869Vye1bNHI= +github.com/go-openapi/swag/jsonname v0.25.4/go.mod h1:GPVEk9CWVhNvWhZgrnvRA6utbAltopbKwDu8mXNUMag= +github.com/go-openapi/testify/v2 v2.0.2 h1:X999g3jeLcoY8qctY/c/Z8iBHTbwLz7R2WXd6Ub6wls= +github.com/go-openapi/testify/v2 v2.0.2/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= github.com/go-quicktest/qt v1.101.0 h1:O1K29Txy5P2OK0dGo59b7b0LR6wKfIhttaAhHUyn7eI= github.com/go-quicktest/qt v1.101.0/go.mod h1:14Bz/f7NwaXPtdYEgzsx46kqSxVwTbzVZsDC26tQJow= github.com/go-test/deep v1.1.1 h1:0r/53hagsehfO4bzD2Pgr/+RgHqhmf+k1Bpse2cTu1U= @@ -51,8 +53,8 @@ github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0 github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -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/mailru/easyjson v0.9.1 h1:LbtsOm5WAswyWbvTEOqhypdPeZzHavpZx96/n553mR8= +github.com/mailru/easyjson v0.9.1/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= github.com/matryer/is v1.4.1 h1:55ehd8zaGABKLXQUe2awZ99BD/PTc2ls+KV/dXphgEQ= github.com/matryer/is v1.4.1/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= @@ -76,8 +78,8 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/protocolbuffers/txtpbfmt v0.0.0-20241112170944-20d2c9ebc01d h1:HWfigq7lB31IeJL8iy7jkUmU/PG1Sr8jVGhS749dbUA= -github.com/protocolbuffers/txtpbfmt v0.0.0-20241112170944-20d2c9ebc01d/go.mod h1:jgxiZysxFPM+iWKwQwPR+y+Jvo54ARd4EisXxKYpB5c= +github.com/protocolbuffers/txtpbfmt v0.0.0-20251124094003-fcb97cc64c7b h1:fPVI9E6QNFYI0Ph3XpKUDrcAvbCifHvqYJcntFLPog8= +github.com/protocolbuffers/txtpbfmt v0.0.0-20251124094003-fcb97cc64c7b/go.mod h1:JSbkp0BviKovYYt9XunS95M3mLPibE9bGg+Y95DsEEY= 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/santhosh-tekuri/jsonschema/v5 v5.3.1 h1:lZUw3E0/J3roVtGQ+SCrUrg3ON6NgVqpn3+iol9aGu4= @@ -88,26 +90,28 @@ 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/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/woodsbury/decimal128 v1.4.0 h1:xJATj7lLu4f2oObouMt2tgGiElE5gO6mSWUjQsBgUlc= +github.com/woodsbury/decimal128 v1.4.0/go.mod h1:BP46FUrVjVhdTbKT+XuQh2xfQaGki9LMIRJSFuh6THU= 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.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk= -golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc= -golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= -golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= +golang.org/x/mod v0.31.0 h1:HaW9xtz0+kOcWKwli0ZXy79Ix+UW/vOfmWI5QVd2tgI= +golang.org/x/mod v0.31.0/go.mod h1:43JraMp9cGx1Rx3AqioxrbrhNsLl2l/iNAvuBkrezpg= +golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= +golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= 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.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= -golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= -golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= -golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= -golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= -golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ= -golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= +golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= +golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= +golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA= +golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= 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/plugins/manager/pipeline/bootstrap/bootstrap.go b/pkg/plugins/manager/pipeline/bootstrap/bootstrap.go index 0fb1217ec70..e6845322516 100644 --- a/pkg/plugins/manager/pipeline/bootstrap/bootstrap.go +++ b/pkg/plugins/manager/pipeline/bootstrap/bootstrap.go @@ -3,11 +3,16 @@ package bootstrap import ( "context" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/trace" + + "github.com/grafana/grafana/pkg/infra/tracing" "github.com/grafana/grafana/pkg/plugins" "github.com/grafana/grafana/pkg/plugins/config" "github.com/grafana/grafana/pkg/plugins/log" "github.com/grafana/grafana/pkg/plugins/manager/signature" "github.com/grafana/grafana/pkg/plugins/pluginassets" + "github.com/grafana/grafana/pkg/semconv" ) // Bootstrapper is responsible for the Bootstrap stage of the plugin loader pipeline. @@ -34,6 +39,7 @@ type Bootstrap struct { constructStep ConstructFunc decorateSteps []DecorateFunc log log.Logger + tracer trace.Tracer } type Opts struct { @@ -55,14 +61,21 @@ func New(cfg *config.PluginManagementCfg, opts Opts) *Bootstrap { constructStep: opts.ConstructFunc, decorateSteps: opts.DecorateFuncs, log: log.New("plugins.bootstrap"), + tracer: otel.Tracer("github.com/grafana/grafana/pkg/plugins/manager/pipeline/bootstrap"), } } // Bootstrap will execute the Construct and Decorate steps of the Bootstrap stage. func (b *Bootstrap) Bootstrap(ctx context.Context, src plugins.PluginSource, found *plugins.FoundBundle) ([]*plugins.Plugin, error) { + pluginClass := src.PluginClass(ctx) + ctx, span := b.tracer.Start(ctx, "bootstrap.Bootstrap", trace.WithAttributes( + semconv.PluginSourceClass(pluginClass), + )) + defer span.End() + ps, err := b.constructStep(ctx, src, found) if err != nil { - return nil, err + return nil, tracing.Error(span, err) } if len(b.decorateSteps) == 0 { @@ -76,7 +89,7 @@ func (b *Bootstrap) Bootstrap(ctx context.Context, src plugins.PluginSource, fou ip, err = decorate(ctx, p) if err != nil { b.log.Error("Could not decorate plugin", "pluginId", p.ID, "error", err) - return nil, err + return nil, tracing.Error(span, err) } } bootstrappedPlugins = append(bootstrappedPlugins, ip) diff --git a/pkg/plugins/manager/pipeline/discovery/discovery.go b/pkg/plugins/manager/pipeline/discovery/discovery.go index e624fbb3fcc..e5bdc50dd62 100644 --- a/pkg/plugins/manager/pipeline/discovery/discovery.go +++ b/pkg/plugins/manager/pipeline/discovery/discovery.go @@ -3,6 +3,11 @@ package discovery import ( "context" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" + + "github.com/grafana/grafana/pkg/infra/tracing" "github.com/grafana/grafana/pkg/plugins" "github.com/grafana/grafana/pkg/plugins/config" "github.com/grafana/grafana/pkg/plugins/log" @@ -26,6 +31,7 @@ type FilterFunc func(ctx context.Context, class plugins.Class, bundles []*plugin type Discovery struct { filterSteps []FilterFunc log log.Logger + tracer trace.Tracer } type Opts struct { @@ -41,29 +47,37 @@ func New(_ *config.PluginManagementCfg, opts Opts) *Discovery { return &Discovery{ filterSteps: opts.FilterFuncs, log: log.New("plugins.discovery"), + tracer: otel.Tracer("github.com/grafana/grafana/pkg/plugins/manager/pipeline/discovery"), } } // Discover will execute the Filter step of the Discovery stage. func (d *Discovery) Discover(ctx context.Context, src plugins.PluginSource) ([]*plugins.FoundBundle, error) { + pluginClass := src.PluginClass(ctx) + ctx, span := d.tracer.Start(ctx, "discovery.Discover", trace.WithAttributes( + attribute.String("grafana.plugins.class", string(pluginClass)), + )) + defer span.End() + ctxLogger := d.log.FromContext(ctx) + // Use the source's own Discover method found, err := src.Discover(ctx) if err != nil { - d.log.Warn("Discovery source failed", "class", src.PluginClass(ctx), "error", err) - return nil, err + ctxLogger.Warn("Discovery source failed", "class", pluginClass, "error", err) + return nil, tracing.Error(span, err) } - d.log.Debug("Found plugins", "class", src.PluginClass(ctx), "count", len(found)) + ctxLogger.Debug("Found plugins", "class", pluginClass, "count", len(found)) // Apply filtering steps result := found for _, filter := range d.filterSteps { result, err = filter(ctx, src.PluginClass(ctx), result) if err != nil { - return nil, err + return nil, tracing.Error(span, err) } } - d.log.Debug("Discovery complete", "class", src.PluginClass(ctx), "found", len(found), "filtered", len(result)) + ctxLogger.Debug("Discovery complete", "class", pluginClass, "found", len(found), "filtered", len(result)) return result, nil } diff --git a/pkg/plugins/manager/pipeline/initialization/initialization.go b/pkg/plugins/manager/pipeline/initialization/initialization.go index 52a638a00f0..4319f4811a7 100644 --- a/pkg/plugins/manager/pipeline/initialization/initialization.go +++ b/pkg/plugins/manager/pipeline/initialization/initialization.go @@ -3,9 +3,14 @@ package initialization import ( "context" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/trace" + + "github.com/grafana/grafana/pkg/infra/tracing" "github.com/grafana/grafana/pkg/plugins" "github.com/grafana/grafana/pkg/plugins/config" "github.com/grafana/grafana/pkg/plugins/log" + "github.com/grafana/grafana/pkg/semconv" ) // Initializer is responsible for the Initialization stage of the plugin loader pipeline. @@ -20,6 +25,7 @@ type Initialize struct { cfg *config.PluginManagementCfg initializeSteps []InitializeFunc log log.Logger + tracer trace.Tracer } type Opts struct { @@ -36,11 +42,17 @@ func New(cfg *config.PluginManagementCfg, opts Opts) *Initialize { cfg: cfg, initializeSteps: opts.InitializeFuncs, log: log.New("plugins.initialization"), + tracer: otel.Tracer("github.com/grafana/grafana/pkg/plugins/manager/pipeline/initialization"), } } // Initialize will execute the Initialize steps of the Initialization stage. func (i *Initialize) Initialize(ctx context.Context, ps *plugins.Plugin) (*plugins.Plugin, error) { + ctx, span := i.tracer.Start(ctx, "initialization.Initialize", trace.WithAttributes( + semconv.GrafanaPluginId(ps.ID), + )) + defer span.End() + if len(i.initializeSteps) == 0 { return ps, nil } @@ -51,7 +63,7 @@ func (i *Initialize) Initialize(ctx context.Context, ps *plugins.Plugin) (*plugi ip, err = init(ctx, ps) if err != nil { i.log.Error("Could not initialize plugin", "pluginId", ps.ID, "error", err) - return nil, err + return nil, tracing.Error(span, err) } } diff --git a/pkg/plugins/manager/pipeline/termination/termination.go b/pkg/plugins/manager/pipeline/termination/termination.go index 66e76d8a548..fdb28396bbf 100644 --- a/pkg/plugins/manager/pipeline/termination/termination.go +++ b/pkg/plugins/manager/pipeline/termination/termination.go @@ -3,9 +3,14 @@ package termination import ( "context" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/trace" + + "github.com/grafana/grafana/pkg/infra/tracing" "github.com/grafana/grafana/pkg/plugins" "github.com/grafana/grafana/pkg/plugins/config" "github.com/grafana/grafana/pkg/plugins/log" + "github.com/grafana/grafana/pkg/semconv" ) // Terminator is responsible for the Termination stage of the plugin loader pipeline. @@ -20,6 +25,7 @@ type Terminate struct { cfg *config.PluginManagementCfg terminateSteps []TerminateFunc log log.Logger + tracer trace.Tracer } type Opts struct { @@ -36,14 +42,20 @@ func New(cfg *config.PluginManagementCfg, opts Opts) (*Terminate, error) { cfg: cfg, terminateSteps: opts.TerminateFuncs, log: log.New("plugins.termination"), + tracer: otel.Tracer("github.com/grafana/grafana/pkg/plugins/manager/pipeline/termination"), }, nil } // Terminate will execute the Terminate steps of the Termination stage. func (t *Terminate) Terminate(ctx context.Context, p *plugins.Plugin) (*plugins.Plugin, error) { + ctx, span := t.tracer.Start(ctx, "termination.Terminate", trace.WithAttributes( + semconv.GrafanaPluginId(p.ID), + )) + defer span.End() + for _, terminate := range t.terminateSteps { if err := terminate(ctx, p); err != nil { - return nil, err + return nil, tracing.Error(span, err) } } return p, nil diff --git a/pkg/plugins/manager/pipeline/validation/validation.go b/pkg/plugins/manager/pipeline/validation/validation.go index 9ea7be9b3a7..36db1f25163 100644 --- a/pkg/plugins/manager/pipeline/validation/validation.go +++ b/pkg/plugins/manager/pipeline/validation/validation.go @@ -3,9 +3,14 @@ package validation import ( "context" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/trace" + + "github.com/grafana/grafana/pkg/infra/tracing" "github.com/grafana/grafana/pkg/plugins" "github.com/grafana/grafana/pkg/plugins/config" "github.com/grafana/grafana/pkg/plugins/log" + "github.com/grafana/grafana/pkg/semconv" ) // Validator is responsible for the Validation stage of the plugin loader pipeline. @@ -20,6 +25,7 @@ type Validate struct { cfg *config.PluginManagementCfg validateSteps []ValidateFunc log log.Logger + tracer trace.Tracer } type Opts struct { @@ -36,11 +42,17 @@ func New(cfg *config.PluginManagementCfg, opts Opts) *Validate { cfg: cfg, validateSteps: opts.ValidateFuncs, log: log.New("plugins.validation"), + tracer: otel.Tracer("github.com/grafana/grafana/pkg/plugins/manager/pipeline/validation"), } } // Validate will execute the Validate steps of the Validation stage. func (v *Validate) Validate(ctx context.Context, ps *plugins.Plugin) error { + ctx, span := v.tracer.Start(ctx, "validation.Validate", trace.WithAttributes( + semconv.GrafanaPluginId(ps.ID), + )) + defer span.End() + if len(v.validateSteps) == 0 { return nil } @@ -49,7 +61,7 @@ func (v *Validate) Validate(ctx context.Context, ps *plugins.Plugin) error { err := validate(ctx, ps) if err != nil { v.log.Error("Plugin validation failed", "pluginId", ps.ID, "error", err) - return err + return tracing.Error(span, err) } } diff --git a/pkg/promlib/go.mod b/pkg/promlib/go.mod index efbcd9222a6..ae8439e8663 100644 --- a/pkg/promlib/go.mod +++ b/pkg/promlib/go.mod @@ -8,13 +8,13 @@ require ( github.com/grafana/grafana/apps/scope v0.0.0-20251007093103-792853df9134 github.com/json-iterator/go v1.1.12 github.com/prometheus/client_golang v1.23.2 - github.com/prometheus/common v0.67.3 + github.com/prometheus/common v0.67.4 github.com/prometheus/prometheus v0.303.1 github.com/stretchr/testify v1.11.1 - go.opentelemetry.io/otel v1.38.0 - go.opentelemetry.io/otel/trace v1.38.0 - google.golang.org/protobuf v1.36.10 - k8s.io/apimachinery v0.34.2 + go.opentelemetry.io/otel v1.39.0 + go.opentelemetry.io/otel/trace v1.39.0 + google.golang.org/protobuf v1.36.11 + k8s.io/apimachinery v0.34.3 ) require ( @@ -36,16 +36,26 @@ require ( github.com/fxamacker/cbor/v2 v2.9.0 // 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.1 // indirect - github.com/go-openapi/swag/jsonname v0.25.1 // indirect + github.com/go-openapi/jsonpointer v0.22.4 // indirect + github.com/go-openapi/jsonreference v0.21.4 // indirect + github.com/go-openapi/swag v0.25.4 // indirect + github.com/go-openapi/swag/cmdutils v0.25.4 // indirect + github.com/go-openapi/swag/conv v0.25.4 // indirect + github.com/go-openapi/swag/fileutils v0.25.4 // indirect + github.com/go-openapi/swag/jsonname v0.25.4 // indirect + github.com/go-openapi/swag/jsonutils v0.25.4 // indirect + github.com/go-openapi/swag/loading v0.25.4 // indirect + github.com/go-openapi/swag/mangling v0.25.4 // indirect + github.com/go-openapi/swag/netutils v0.25.4 // indirect + github.com/go-openapi/swag/stringutils v0.25.4 // indirect + github.com/go-openapi/swag/typeutils v0.25.4 // indirect + github.com/go-openapi/swag/yamlutils v0.25.4 // indirect github.com/goccy/go-json v0.10.5 // indirect github.com/gogo/googleapis v1.4.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/google/flatbuffers v25.2.10+incompatible // indirect - github.com/google/gnostic-models v0.7.0 // indirect + github.com/google/gnostic-models v0.7.1 // 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 @@ -61,11 +71,10 @@ require ( github.com/hashicorp/yamux v0.1.2 // indirect github.com/invopop/jsonschema v0.13.0 // indirect github.com/jaegertracing/jaeger-idl v0.5.0 // indirect - github.com/josharian/intern v1.0.0 // indirect github.com/jszwedko/go-datemath v0.1.1-0.20230526204004-640a500621d6 // indirect github.com/klauspost/compress v1.18.0 // indirect github.com/klauspost/cpuid/v2 v2.3.0 // indirect - github.com/mailru/easyjson v0.9.0 // indirect + github.com/mailru/easyjson v0.9.1 // indirect github.com/mattetti/filebuffer v1.0.1 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect @@ -80,47 +89,48 @@ require ( github.com/pierrec/lz4/v4 v4.1.22 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/client_model v0.6.2 // indirect - github.com/prometheus/procfs v0.16.1 // indirect + github.com/prometheus/procfs v0.19.2 // indirect github.com/rivo/uniseg v0.4.7 // indirect github.com/stretchr/objx v0.5.2 // indirect github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect github.com/x448/float16 v0.8.4 // indirect github.com/zeebo/xxh3 v1.0.2 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.64.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.63.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.64.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/exporters/otlp/otlptrace v1.38.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc 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/exporters/otlp/otlptrace v1.39.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0 // indirect + go.opentelemetry.io/otel/metric v1.39.0 // indirect + go.opentelemetry.io/otel/sdk v1.39.0 // indirect go.opentelemetry.io/proto/otlp v1.9.0 // indirect go.uber.org/atomic v1.11.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.45.0 // indirect - golang.org/x/exp v0.0.0-20251002181428-27f1f14c8bb9 // indirect - golang.org/x/mod v0.30.0 // indirect - golang.org/x/net v0.47.0 // indirect - golang.org/x/sync v0.18.0 // indirect - golang.org/x/sys v0.38.0 // indirect - golang.org/x/telemetry v0.0.0-20251111182119-bc8e575c7b54 // indirect - golang.org/x/text v0.31.0 // indirect + golang.org/x/exp v0.0.0-20251209150349-8475f28825e9 // indirect + golang.org/x/mod v0.31.0 // indirect + golang.org/x/net v0.48.0 // indirect + golang.org/x/oauth2 v0.34.0 // indirect + golang.org/x/sync v0.19.0 // indirect + golang.org/x/sys v0.39.0 // indirect + golang.org/x/telemetry v0.0.0-20251203150158-8fff8a5912fc // indirect + golang.org/x/text v0.32.0 // indirect golang.org/x/time v0.14.0 // indirect - golang.org/x/tools v0.39.0 // indirect + golang.org/x/tools v0.40.0 // indirect golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect google.golang.org/api v0.242.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20251111163417-95abcf5c77ba // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2 // indirect google.golang.org/grpc v1.77.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/client-go v0.34.2 // indirect + k8s.io/client-go v0.34.3 // indirect k8s.io/klog/v2 v2.130.1 // indirect - k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 // indirect - k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 // indirect - sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect + k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e // indirect + k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 // indirect + sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect sigs.k8s.io/randfill v1.0.0 // indirect sigs.k8s.io/structured-merge-diff/v6 v6.3.1 // indirect ) diff --git a/pkg/promlib/go.sum b/pkg/promlib/go.sum index 9810bb19828..eec9ab3dffd 100644 --- a/pkg/promlib/go.sum +++ b/pkg/promlib/go.sum @@ -66,36 +66,46 @@ github.com/go-openapi/analysis v0.24.0 h1:vE/VFFkICKyYuTWYnplQ+aVr45vlG6NcZKC7Bd 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/jsonpointer v0.22.4 h1:dZtK82WlNpVLDW2jlA1YCiVJFVqkED1MegOUy9kR5T4= +github.com/go-openapi/jsonpointer v0.22.4/go.mod h1:elX9+UgznpFhgBuaMQ7iu4lvvX1nvNsesQ3oxmYTw80= +github.com/go-openapi/jsonreference v0.21.4 h1:24qaE2y9bx/q3uRK/qN+TDwbok1NhbSmGjjySRCHtC8= +github.com/go-openapi/jsonreference v0.21.4/go.mod h1:rIENPTjDbLpzQmQWCj5kKj3ZlmEh+EFVbz3RTUh30/4= 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/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.1 h1:lpsStH0n2ittzTnbaSloVZLuB5+fvSY/+hnagBjSNZU= -github.com/go-openapi/swag v0.23.1/go.mod h1:STZs8TbRvEQQKUA+JZNAm3EWlgaOBGpyFDqQnDHMef0= -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/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/swag v0.25.4 h1:OyUPUFYDPDBMkqyxOTkqDYFnrhuhi9NR6QVUvIochMU= +github.com/go-openapi/swag v0.25.4/go.mod h1:zNfJ9WZABGHCFg2RnY0S4IOkAcVTzJ6z2Bi+Q4i6qFQ= +github.com/go-openapi/swag/cmdutils v0.25.4 h1:8rYhB5n6WawR192/BfUu2iVlxqVR9aRgGJP6WaBoW+4= +github.com/go-openapi/swag/cmdutils v0.25.4/go.mod h1:pdae/AFo6WxLl5L0rq87eRzVPm/XRHM3MoYgRMvG4A0= +github.com/go-openapi/swag/conv v0.25.4 h1:/Dd7p0LZXczgUcC/Ikm1+YqVzkEeCc9LnOWjfkpkfe4= +github.com/go-openapi/swag/conv v0.25.4/go.mod h1:3LXfie/lwoAv0NHoEuY1hjoFAYkvlqI/Bn5EQDD3PPU= +github.com/go-openapi/swag/fileutils v0.25.4 h1:2oI0XNW5y6UWZTC7vAxC8hmsK/tOkWXHJQH4lKjqw+Y= +github.com/go-openapi/swag/fileutils v0.25.4/go.mod h1:cdOT/PKbwcysVQ9Tpr0q20lQKH7MGhOEb6EwmHOirUk= +github.com/go-openapi/swag/jsonname v0.25.4 h1:bZH0+MsS03MbnwBXYhuTttMOqk+5KcQ9869Vye1bNHI= +github.com/go-openapi/swag/jsonname v0.25.4/go.mod h1:GPVEk9CWVhNvWhZgrnvRA6utbAltopbKwDu8mXNUMag= +github.com/go-openapi/swag/jsonutils v0.25.4 h1:VSchfbGhD4UTf4vCdR2F4TLBdLwHyUDTd1/q4i+jGZA= +github.com/go-openapi/swag/jsonutils v0.25.4/go.mod h1:7OYGXpvVFPn4PpaSdPHJBtF0iGnbEaTk8AvBkoWnaAY= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4 h1:IACsSvBhiNJwlDix7wq39SS2Fh7lUOCJRmx/4SN4sVo= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4/go.mod h1:Mt0Ost9l3cUzVv4OEZG+WSeoHwjWLnarzMePNDAOBiM= +github.com/go-openapi/swag/loading v0.25.4 h1:jN4MvLj0X6yhCDduRsxDDw1aHe+ZWoLjW+9ZQWIKn2s= +github.com/go-openapi/swag/loading v0.25.4/go.mod h1:rpUM1ZiyEP9+mNLIQUdMiD7dCETXvkkC30z53i+ftTE= +github.com/go-openapi/swag/mangling v0.25.4 h1:2b9kBJk9JvPgxr36V23FxJLdwBrpijI26Bx5JH4Hp48= +github.com/go-openapi/swag/mangling v0.25.4/go.mod h1:6dxwu6QyORHpIIApsdZgb6wBk/DPU15MdyYj/ikn0Hg= +github.com/go-openapi/swag/netutils v0.25.4 h1:Gqe6K71bGRb3ZQLusdI8p/y1KLgV4M/k+/HzVSqT8H0= +github.com/go-openapi/swag/netutils v0.25.4/go.mod h1:m2W8dtdaoX7oj9rEttLyTeEFFEBvnAx9qHd5nJEBzYg= +github.com/go-openapi/swag/stringutils v0.25.4 h1:O6dU1Rd8bej4HPA3/CLPciNBBDwZj9HiEpdVsb8B5A8= +github.com/go-openapi/swag/stringutils v0.25.4/go.mod h1:GTsRvhJW5xM5gkgiFe0fV3PUlFm0dr8vki6/VSRaZK0= +github.com/go-openapi/swag/typeutils v0.25.4 h1:1/fbZOUN472NTc39zpa+YGHn3jzHWhv42wAJSN91wRw= +github.com/go-openapi/swag/typeutils v0.25.4/go.mod h1:Ou7g//Wx8tTLS9vG0UmzfCsjZjKhpjxayRKTHXf2pTE= +github.com/go-openapi/swag/yamlutils v0.25.4 h1:6jdaeSItEUb7ioS9lFoCZ65Cne1/RZtPBZ9A56h92Sw= +github.com/go-openapi/swag/yamlutils v0.25.4/go.mod h1:MNzq1ulQu+yd8Kl7wPOut/YHAAU/H6hL91fF+E2RFwc= +github.com/go-openapi/testify/enable/yaml/v2 v2.0.2 h1:0+Y41Pz1NkbTHz8NngxTuAXxEodtNSI1WG1c/m5Akw4= +github.com/go-openapi/testify/enable/yaml/v2 v2.0.2/go.mod h1:kme83333GCtJQHXQ8UKX3IBZu6z8T5Dvy5+CW3NLUUg= +github.com/go-openapi/testify/v2 v2.0.2 h1:X999g3jeLcoY8qctY/c/Z8iBHTbwLz7R2WXd6Ub6wls= +github.com/go-openapi/testify/v2 v2.0.2/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= 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-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= @@ -114,8 +124,8 @@ github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs= github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= 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.7.0 h1:qwTtogB15McXDaNqTZdzPJRHvaVJlAl+HVQnLmJEJxo= -github.com/google/gnostic-models v0.7.0/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ= +github.com/google/gnostic-models v0.7.1 h1:SisTfuFKJSKM5CPZkffwi6coztzzeYUhc3v4yxLWH8c= +github.com/google/gnostic-models v0.7.1/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ= 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= @@ -162,8 +172,6 @@ github.com/jhump/protoreflect v1.17.0 h1:qOEr613fac2lOuTgWN4tPAtLL7fUSbuJL5X5Xum github.com/jhump/protoreflect v1.17.0/go.mod h1:h9+vUUL38jiBzck8ck+6G/aeMX8Z4QUY/NiJPwPNi+8= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= -github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= -github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= @@ -184,8 +192,8 @@ 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/mailru/easyjson v0.9.1 h1:LbtsOm5WAswyWbvTEOqhypdPeZzHavpZx96/n553mR8= +github.com/mailru/easyjson v0.9.1/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= github.com/mattetti/filebuffer v1.0.1 h1:gG7pyfnSIZCxdoKq+cPa8T0hhYtD9NxCdI4D7PTjRLM= github.com/mattetti/filebuffer v1.0.1/go.mod h1:YdMURNDOttIiruleeVr6f56OrMc+MydEnTcXwtkxNVs= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= @@ -239,10 +247,10 @@ github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h 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.3 h1:shd26MlnwTw5jksTDhC7rTQIteBxy+ZZDr3t7F2xN2Q= -github.com/prometheus/common v0.67.3/go.mod h1:gP0fq6YjjNCLssJCQp0yk4M8W6ikLURwkdd/YKtTbyI= -github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= -github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= +github.com/prometheus/common v0.67.4 h1:yR3NqWO1/UyO1w2PhUvXlGQs/PtFmoveVO0KZ4+Lvsc= +github.com/prometheus/common v0.67.4/go.mod h1:gP0fq6YjjNCLssJCQp0yk4M8W6ikLURwkdd/YKtTbyI= +github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws= +github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw= github.com/prometheus/prometheus v0.303.1 h1:He/2jRE6sB23Ew38AIoR1WRR3fCMgPlJA2E0obD2WSY= github.com/prometheus/prometheus v0.303.1/go.mod h1:WEq2ogBPZoLjj9x5K67VEk7ECR0nRD9XCjaOt1lsYck= github.com/prometheus/sigv4 v0.1.2 h1:R7570f8AoM5YnTUPFm3mjZH5q2k4D+I/phCWvZ4PXG8= @@ -280,34 +288,34 @@ go.mongodb.org/mongo-driver v1.17.4 h1:jUorfmVzljjr0FLzYQsGP8cgN/qzzxlY9Vh0C9KFX go.mongodb.org/mongo-driver v1.17.4/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= -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/google.golang.org/grpc/otelgrpc v0.64.0 h1:RN3ifU8y4prNWeEnQp2kRRHz8UwonAEYZl8tUzHEXAk= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.64.0/go.mod h1:habDz3tEWiFANTo6oUE99EmaFUrCNYAAg3wiVmusm70= 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/instrumentation/net/http/otelhttp v0.64.0 h1:ssfIgGNANqpVFCndZvcuyKbl0g+UAVcbBcqGkG28H0Y= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.64.0/go.mod h1:GQ/474YrbE4Jx8gZ4q5I4hrhUzM6UPzyrqJYV2AqPoQ= 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.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 v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48= +go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0 h1:f0cb2XPmrqn4XMy9PNliTgRKJgS5WcL/u0/WRYGz4t0= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0/go.mod h1:vnakAaFckOMiMtOIhFI2MNH4FYrZzXCYxmb1LlhoGz8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0 h1:in9O8ESIOlwJAEGTkkf34DesGRAc/Pn8qJ7k3r/42LM= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0/go.mod h1:Rp0EXBm5tfnv0WL+ARyO/PHBEaEAT8UUHQ6AGJcSq6c= go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM= -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/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0= +go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs= go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E= -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/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18= +go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE= +go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8= +go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew= go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ= -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/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI= +go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA= go.opentelemetry.io/proto/otlp v1.9.0 h1:l706jCMITVouPOqEnii2fIAuO3IVGBRPV5ICjceRb/A= go.opentelemetry.io/proto/otlp v1.9.0/go.mod h1:xE+Cx5E/eEHw+ISFkwPLwCZefwVjY+pqKg1qcK03+/4= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= @@ -321,27 +329,27 @@ 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.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q= -golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4= -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/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU= +golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0= +golang.org/x/exp v0.0.0-20251209150349-8475f28825e9 h1:MDfG8Cvcqlt9XXrmEiD4epKn7VJHZO84hejP9Jmp0MM= +golang.org/x/exp v0.0.0-20251209150349-8475f28825e9/go.mod h1:EPRbTFwzwjXj9NpYyyrvenVh9Y+GFeEvMNh7Xuz7xgU= 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.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk= -golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc= +golang.org/x/mod v0.31.0 h1:HaW9xtz0+kOcWKwli0ZXy79Ix+UW/vOfmWI5QVd2tgI= +golang.org/x/mod v0.31.0/go.mod h1:43JraMp9cGx1Rx3AqioxrbrhNsLl2l/iNAvuBkrezpg= 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.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= -golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= -golang.org/x/oauth2 v0.33.0 h1:4Q+qn+E5z8gPRJfmRy7C2gGG3T4jIprK6aSYgTXGRpo= -golang.org/x/oauth2 v0.33.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= +golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= +golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= +golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw= +golang.org/x/oauth2 v0.34.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.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= -golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.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-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -352,22 +360,22 @@ golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 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.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= -golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/telemetry v0.0.0-20251111182119-bc8e575c7b54 h1:E2/AqCUMZGgd73TQkxUMcMla25GB9i/5HOdLr+uH7Vo= -golang.org/x/telemetry v0.0.0-20251111182119-bc8e575c7b54/go.mod h1:hKdjCMrbv9skySur+Nek8Hd0uJ0GuxJIoIX2payrIdQ= +golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= +golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/telemetry v0.0.0-20251203150158-8fff8a5912fc h1:bH6xUXay0AIFMElXG2rQ4uiE+7ncwtiOdPfYK1NK2XA= +golang.org/x/telemetry v0.0.0-20251203150158-8fff8a5912fc/go.mod h1:hKdjCMrbv9skySur+Nek8Hd0uJ0GuxJIoIX2payrIdQ= 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.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= -golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= +golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= +golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= 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.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ= -golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ= +golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA= +golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc= 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= @@ -378,14 +386,14 @@ 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.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-20251111163417-95abcf5c77ba h1:B14OtaXuMaCQsl2deSvNkyPKIzq3BjfxQp8d00QyWx4= -google.golang.org/genproto/googleapis/api v0.0.0-20251111163417-95abcf5c77ba/go.mod h1:G5IanEx8/PgI9w6CFcYQf7jMtHQhZruvfM1i3qOqk5U= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba h1:UKgtfRM7Yh93Sya0Fo8ZzhDP4qBckrrxEr2oF5UIVb8= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251111163417-95abcf5c77ba/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= +google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2 h1:7LRqPCEdE4TP4/9psdaB7F2nhZFfBiGJomA5sojLWdU= +google.golang.org/genproto/googleapis/api v0.0.0-20251213004720-97cd9d5aeac2/go.mod h1:+rXWjjaukWZun3mLfjmVnQi18E1AsFbDN9QdJ5YXLto= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2 h1:2I6GHUeJ/4shcDpoUlLs/2WPnhg7yJwvXtqcMJt9liA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251213004720-97cd9d5aeac2/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM= google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= -google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= -google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/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= @@ -396,18 +404,18 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 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/apimachinery v0.34.2 h1:zQ12Uk3eMHPxrsbUJgNF8bTauTVR2WgqJsTmwTE/NW4= -k8s.io/apimachinery v0.34.2/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= -k8s.io/client-go v0.34.2 h1:Co6XiknN+uUZqiddlfAjT68184/37PS4QAzYvQvDR8M= -k8s.io/client-go v0.34.2/go.mod h1:2VYDl1XXJsdcAxw7BenFslRQX28Dxz91U9MWKjX97fE= +k8s.io/apimachinery v0.34.3 h1:/TB+SFEiQvN9HPldtlWOTp0hWbJ+fjU+wkxysf/aQnE= +k8s.io/apimachinery v0.34.3/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= +k8s.io/client-go v0.34.3 h1:wtYtpzy/OPNYf7WyNBTj3iUA0XaBHVqhv4Iv3tbrF5A= +k8s.io/client-go v0.34.3/go.mod h1:OxxeYagaP9Kdf78UrKLa3YZixMCfP6bgPwPwNBQBzpM= 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= +k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e h1:iW9ChlU0cU16w8MpVYjXk12dqQ4BPFBEgif+ap7/hqQ= +k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e/go.mod h1:kdmbQkyfwUagLfXIad1y2TdrjPFWp2Q89B3qkRwf/pQ= +k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 h1:SjGebBtkBqHFOli+05xYbK8YF1Dzkbzn+gDM4X9T4Ck= +k8s.io/utils v0.0.0-20251002143259-bc988d571ff4/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg= +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/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.1 h1:JrhdFMqOd/+3ByqlP2I45kTOZmTRLBUm5pvRjeheg7E= diff --git a/pkg/registry/apis/dashboard/dashboard_storage.go b/pkg/registry/apis/dashboard/dashboard_storage.go index 7ab91f8ec66..8bde214129b 100644 --- a/pkg/registry/apis/dashboard/dashboard_storage.go +++ b/pkg/registry/apis/dashboard/dashboard_storage.go @@ -8,6 +8,7 @@ import ( "k8s.io/apiserver/pkg/registry/rest" "github.com/grafana/grafana-app-sdk/logging" + "github.com/grafana/grafana/pkg/apimachinery/utils" grafanarest "github.com/grafana/grafana/pkg/apiserver/rest" "github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/apiserver/endpoints/request" @@ -33,8 +34,11 @@ func (d dashboardStorageWrapper) Update(ctx context.Context, name string, objInf obj, created, err := d.Storage.Update(ctx, name, objInfo, createValidation, updateValidation, forceAllowCreate, options) if err == nil && ns.OrgID > 0 && d.live != nil { - if err := d.live.DashboardSaved(ns.OrgID, name); err != nil { - logging.FromContext(ctx).Info("live dashboard update failed", "err", err) + m, err := utils.MetaAccessor(obj) + if err == nil { + if err := d.live.DashboardSaved(ns.OrgID, name, m.GetResourceVersion()); err != nil { + logging.FromContext(ctx).Info("live dashboard update failed", "err", err) + } } } return obj, created, err diff --git a/pkg/registry/apis/dashboard/legacy/sql_dashboards.go b/pkg/registry/apis/dashboard/legacy/sql_dashboards.go index 077cf0a6700..0b7ffa04ea4 100644 --- a/pkg/registry/apis/dashboard/legacy/sql_dashboards.go +++ b/pkg/registry/apis/dashboard/legacy/sql_dashboards.go @@ -113,6 +113,7 @@ func ProvideMigratorDashboardAccessor( dashboardPermissionSvc: nil, // not needed for migration libraryPanelSvc: nil, // not needed for migration accessControl: accessControl, + log: log.New("legacy.dashboard.migrator.accessor"), } } @@ -136,6 +137,7 @@ func NewDashboardSQLAccess(sql legacysql.LegacyDatabaseProvider, dashboardPermissionSvc: dashboardPermissionSvc, libraryPanelSvc: libraryPanelSvc, accessControl: accessControl, + log: log.New("legacy.dashboard.accessor"), } } @@ -154,12 +156,6 @@ func (a *dashboardSqlAccess) executeQuery(ctx context.Context, helper *legacysql return nil }) - // Use transaction from unified storage if available in the context. - // This allows us to run migrations in a transaction which is specifically required for SQLite. - if tx == nil { - tx = resource.TransactionFromContext(ctx) - } - if tx != nil { return tx.QueryContext(ctx, query, args...) } @@ -507,7 +503,7 @@ func (a *dashboardSqlAccess) MigratePlaylists(ctx context.Context, orgId int64, return nil, err } - // Group playlist items by playlist ID + // Group playlist items by playlist ID while preserving order type playlistData struct { id int64 uid string @@ -518,7 +514,8 @@ func (a *dashboardSqlAccess) MigratePlaylists(ctx context.Context, orgId int64, updatedAt int64 } - playlists := make(map[int64]*playlistData) + playlistIndex := make(map[int64]int) // maps playlist ID to index in playlists slice + playlists := []*playlistData{} var currentID int64 var orgID int64 var uid, name, interval string @@ -533,7 +530,8 @@ func (a *dashboardSqlAccess) MigratePlaylists(ctx context.Context, orgId int64, } // Get or create playlist entry - pl, exists := playlists[currentID] + idx, exists := playlistIndex[currentID] + var pl *playlistData if !exists { pl = &playlistData{ id: currentID, @@ -544,7 +542,10 @@ func (a *dashboardSqlAccess) MigratePlaylists(ctx context.Context, orgId int64, createdAt: createdAt, updatedAt: updatedAt, } - playlists[currentID] = pl + playlistIndex[currentID] = len(playlists) + playlists = append(playlists, pl) + } else { + pl = playlists[idx] } // Add item if it exists (LEFT JOIN can return NULL for playlists without items) @@ -560,7 +561,7 @@ func (a *dashboardSqlAccess) MigratePlaylists(ctx context.Context, orgId int64, return nil, err } - // Convert to K8s objects and send to stream + // Convert to K8s objects and send to stream (order is preserved) for _, pl := range playlists { playlist := &playlistv0.Playlist{ TypeMeta: metav1.TypeMeta{ diff --git a/pkg/registry/apis/dashboard/legacysearcher/search_client.go b/pkg/registry/apis/dashboard/legacysearcher/search_client.go index 9782ce6326d..2ad9c11582a 100644 --- a/pkg/registry/apis/dashboard/legacysearcher/search_client.go +++ b/pkg/registry/apis/dashboard/legacysearcher/search_client.go @@ -360,7 +360,17 @@ func (c *DashboardSearchClient) Search(ctx context.Context, req *resourcepb.Reso }) } - list.TotalHits = int64(len(list.Results.Rows)) + // the UI expects us to populate "TotalHits" with the total search hits, not however many we are returning. + // this is a dumb workaround due to the fact that legacy doesn't expose a way of "counting search hits" + // it fixes a bug that only happens in mode 1-2 that prevents pagination from working in the dashboard list view + // we only have a handful of instances running in this mode and moving towards 0 instances fast, so this is fine + query.Limit = 0 + query.Page = 1 + res, err = c.dashboardStore.FindDashboards(ctx, query) + if err != nil { + return nil, err + } + list.TotalHits = int64(len(res)) return list, nil } diff --git a/pkg/registry/apis/dashboard/legacysearcher/search_client_test.go b/pkg/registry/apis/dashboard/legacysearcher/search_client_test.go index cb7ead459f6..22907e24c8f 100644 --- a/pkg/registry/apis/dashboard/legacysearcher/search_client_test.go +++ b/pkg/registry/apis/dashboard/legacysearcher/search_client_test.go @@ -48,6 +48,18 @@ func TestDashboardSearchClient_Search(t *testing.T) { {ID: 2, UID: "uid2", Title: "Test Dashboard2", FolderUID: "folder2", Tags: []string{}}, }, nil).Once() + // Second call for total count with Page: 1, Limit: 0 + mockStore.On("FindDashboards", mock.Anything, &dashboards.FindPersistedDashboardsQuery{ + SignedInUser: user, + Type: "dash-db", + Sort: sorter, + Limit: 0, + Page: 1, + }).Return([]dashboards.DashboardSearchProjection{ + {ID: 1, UID: "uid", Title: "Test Dashboard", FolderUID: "folder1", Tags: []string{"term"}}, + {ID: 2, UID: "uid2", Title: "Test Dashboard2", FolderUID: "folder2", Tags: []string{}}, + }, nil).Once() + req := &resourcepb.ResourceSearchRequest{ Options: &resourcepb.ListOptions{ Key: dashboardKey, @@ -124,6 +136,17 @@ func TestDashboardSearchClient_Search(t *testing.T) { {ID: 1, UID: "uid", Title: "Test Dashboard", FolderUID: "folder", SortMeta: int64(50), Tags: []string{}}, }, nil).Once() + // Second call for total count with Page: 1, Limit: 0 + mockStore.On("FindDashboards", mock.Anything, &dashboards.FindPersistedDashboardsQuery{ + SignedInUser: user, + Type: "dash-db", + Sort: sortOptionAsc, + Limit: 0, + Page: 1, + }).Return([]dashboards.DashboardSearchProjection{ + {ID: 1, UID: "uid", Title: "Test Dashboard", FolderUID: "folder", SortMeta: int64(50), Tags: []string{}}, + }, nil).Once() + req := &resourcepb.ResourceSearchRequest{ Options: &resourcepb.ListOptions{ Key: dashboardKey, @@ -189,6 +212,17 @@ func TestDashboardSearchClient_Search(t *testing.T) { {ID: 1, UID: "uid", Title: "Test Dashboard", FolderUID: "folder", SortMeta: int64(2), Tags: []string{}}, }, nil).Once() + // Second call for total count with Page: 1, Limit: 0 + mockStore.On("FindDashboards", mock.Anything, &dashboards.FindPersistedDashboardsQuery{ + SignedInUser: user, + Type: "dash-db", + Sort: sortOptionAsc, + Limit: 0, + Page: 1, + }).Return([]dashboards.DashboardSearchProjection{ + {ID: 1, UID: "uid", Title: "Test Dashboard", FolderUID: "folder", SortMeta: int64(2), Tags: []string{}}, + }, nil).Once() + req := &resourcepb.ResourceSearchRequest{ Options: &resourcepb.ListOptions{ Key: dashboardKey, @@ -293,6 +327,17 @@ func TestDashboardSearchClient_Search(t *testing.T) { {UID: "uid", Title: "Test Dashboard", FolderUID: "folder1"}, }, nil).Once() + // Second call for total count with Page: 1, Limit: 0 + mockStore.On("FindDashboards", mock.Anything, &dashboards.FindPersistedDashboardsQuery{ + Title: "test", + SignedInUser: user, + Type: "dash-db", + Limit: 0, + Page: 1, + }).Return([]dashboards.DashboardSearchProjection{ + {UID: "uid", Title: "Test Dashboard", FolderUID: "folder1"}, + }, nil).Once() + req := &resourcepb.ResourceSearchRequest{ Options: &resourcepb.ListOptions{ Key: dashboardKey, @@ -319,6 +364,18 @@ func TestDashboardSearchClient_Search(t *testing.T) { {UID: "uid", Title: "Test Dashboard", FolderUID: "folder1"}, }, nil).Once() + // Second call for total count with Page: 1, Limit: 0 + mockStore.On("FindDashboards", mock.Anything, &dashboards.FindPersistedDashboardsQuery{ + Title: "test", + TitleExactMatch: true, + SignedInUser: user, + Type: "dash-db", + Limit: 0, + Page: 1, + }).Return([]dashboards.DashboardSearchProjection{ + {UID: "uid", Title: "Test Dashboard", FolderUID: "folder1"}, + }, nil).Once() + req := &resourcepb.ResourceSearchRequest{ Options: &resourcepb.ListOptions{ Key: dashboardKey, @@ -350,6 +407,17 @@ func TestDashboardSearchClient_Search(t *testing.T) { {UID: "uid", Title: "Test Dashboard", FolderUID: "folder1"}, }, nil).Once() + // Second call for total count with Page: 1, Limit: 0 + mockStore.On("FindDashboards", mock.Anything, &dashboards.FindPersistedDashboardsQuery{ + DashboardIds: []int64{1, 2}, + SignedInUser: user, + Type: "dash-db", + Limit: 0, + Page: 1, + }).Return([]dashboards.DashboardSearchProjection{ + {UID: "uid", Title: "Test Dashboard", FolderUID: "folder1"}, + }, nil).Once() + req := &resourcepb.ResourceSearchRequest{ Options: &resourcepb.ListOptions{ Key: dashboardKey, @@ -383,6 +451,19 @@ func TestDashboardSearchClient_Search(t *testing.T) { {UID: "uid", Title: "Test Dashboard", FolderUID: "folder1"}, }, nil).Once() + // Second call for total count with Page: 1, Limit: 0 + mockStore.On("FindDashboards", mock.Anything, &dashboards.FindPersistedDashboardsQuery{ + DashboardUIDs: []string{"uid1", "uid2"}, + Tags: []string{"tag1", "tag2"}, + FolderUIDs: []string{"general", "folder1"}, + SignedInUser: user, + Type: "dash-db", + Limit: 0, + Page: 1, + }).Return([]dashboards.DashboardSearchProjection{ + {UID: "uid", Title: "Test Dashboard", FolderUID: "folder1"}, + }, nil).Once() + req := &resourcepb.ResourceSearchRequest{ Options: &resourcepb.ListOptions{ Key: dashboardKey, @@ -532,6 +613,17 @@ func TestDashboardSearchClient_Search(t *testing.T) { {ID: 1, UID: "uid", Title: "Test Dashboard", FolderUID: "folder1"}, }, nil).Once() + // Second call for total count with Page: 1, Limit: 0 + mockStore.On("FindDashboards", mock.Anything, &dashboards.FindPersistedDashboardsQuery{ + SignedInUser: user, + Sort: sort.SortAlphaAsc, + Type: "dash-db", + Limit: 0, + Page: 1, + }).Return([]dashboards.DashboardSearchProjection{ + {ID: 1, UID: "uid", Title: "Test Dashboard", FolderUID: "folder1"}, + }, nil).Once() + req := &resourcepb.ResourceSearchRequest{ Options: &resourcepb.ListOptions{ Key: dashboardKey, @@ -552,7 +644,7 @@ func TestDashboardSearchClient_Search(t *testing.T) { t.Run("Should set correct sort field when sorting by views", func(t *testing.T) { mockStore.On("FindDashboards", mock.Anything, mock.Anything).Return([]dashboards.DashboardSearchProjection{ {ID: 1, UID: "uid", Title: "Test Dashboard", FolderUID: "folder1", SortMeta: 100}, - }, nil).Once() + }, nil).Twice() // Will be called twice due to the total count call req := &resourcepb.ResourceSearchRequest{ Options: &resourcepb.ListOptions{ @@ -584,7 +676,7 @@ func TestDashboardSearchClient_Search(t *testing.T) { mockStore.On("FindDashboards", mock.Anything, mock.Anything).Return([]dashboards.DashboardSearchProjection{ {UID: "dashboard1", FolderUID: "folder1", ID: 1}, {UID: "dashboard2", FolderUID: "folder2", ID: 2}, - }, nil).Once() + }, nil).Twice() // Will be called twice due to the total count call req := &resourcepb.ResourceSearchRequest{ Options: &resourcepb.ListOptions{ diff --git a/pkg/registry/apis/folders/register.go b/pkg/registry/apis/folders/register.go index 64e51c06312..7c39fbe22ae 100644 --- a/pkg/registry/apis/folders/register.go +++ b/pkg/registry/apis/folders/register.go @@ -356,7 +356,7 @@ func (b *FolderAPIBuilder) Validate(ctx context.Context, a admission.Attributes, if !ok { return fmt.Errorf("obj is not folders.Folder") } - return validateOnUpdate(ctx, f, old, b.storage, b.parents, folder.MaxNestedFolderDepth) + return validateOnUpdate(ctx, f, old, b.storage, b.parents, b.searcher, folder.MaxNestedFolderDepth) default: return nil } diff --git a/pkg/registry/apis/folders/register_test.go b/pkg/registry/apis/folders/register_test.go index 066f8793776..1eb00f0a7e5 100644 --- a/pkg/registry/apis/folders/register_test.go +++ b/pkg/registry/apis/folders/register_test.go @@ -376,6 +376,10 @@ func TestFolderAPIBuilder_Validate_Update(t *testing.T) { m.On("Get", mock.Anything, "new-parent", mock.Anything).Return( &folders.Folder{}, nil).Once() + // also retrieves old parent for depth difference calculation + m.On("Get", mock.Anything, "valid-parent", mock.Anything).Return( + &folders.Folder{}, + nil).Once() }, }, { diff --git a/pkg/registry/apis/folders/validate.go b/pkg/registry/apis/folders/validate.go index eb0c29b30a1..3c7c30a1aea 100644 --- a/pkg/registry/apis/folders/validate.go +++ b/pkg/registry/apis/folders/validate.go @@ -6,6 +6,7 @@ import ( "slices" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/selection" "k8s.io/apiserver/pkg/registry/rest" folders "github.com/grafana/grafana/apps/folder/pkg/apis/folder/v1beta1" @@ -13,6 +14,7 @@ import ( "github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/folder" + "github.com/grafana/grafana/pkg/storage/unified/resource" "github.com/grafana/grafana/pkg/storage/unified/resourcepb" "github.com/grafana/grafana/pkg/util" ) @@ -73,6 +75,7 @@ func validateOnUpdate(ctx context.Context, old *folders.Folder, getter rest.Getter, parents parentsGetter, + searcher resourcepb.ResourceIndexClient, maxDepth int, ) error { folderObj, err := utils.MetaAccessor(obj) @@ -95,7 +98,10 @@ func validateOnUpdate(ctx context.Context, // Validate the move operation newParent := folderObj.GetFolder() - // If we move to root, we don't need to validate the depth. + // If we move to root, we don't need to validate the depth, because the folder already existed + // before and wasn't too deep. This move will make it more shallow. + // + // We also don't need to validate circular references because the root folder cannot have a parent. if newParent == folder.RootFolderUID { return nil } @@ -113,9 +119,6 @@ func validateOnUpdate(ctx context.Context, if !ok { return fmt.Errorf("expected folder, found %T", parentObj) } - - //FIXME: until we have a way to represent the tree, we can only - // look at folder parents to check how deep the new folder tree will be info, err := parents(ctx, parent) if err != nil { return err @@ -129,13 +132,162 @@ func validateOnUpdate(ctx context.Context, } } - // if by moving a folder we exceed the max depth, return an error + // if by moving a folder we exceed the max depth just from its parents + itself, return an error if len(info.Items) > maxDepth+1 { return folder.ErrMaximumDepthReached.Errorf("maximum folder depth reached") } + // To try to save some computation, get the parents of the old parent (this is typically cheaper + // than looking at the children of the folder). If the old parent has more parents or the same + // number of parents as the new parent, we can return early, because we know the folder had to be + // safe from the creation validation. If we cannot access the older parent, we will continue to check the children. + if canSkipChildrenCheck(ctx, oldFolder, getter, parents, len(info.Items)) { + return nil + } + + // Now comes the more expensive part: we need to check if moving this folder will cause + // any descendant folders to exceed the max depth. + // + // Calculate the maximum allowed subtree depth after the move. + allowedDepth := (maxDepth + 1) - len(info.Items) + if allowedDepth <= 0 { + return nil + } + + return checkSubtreeDepth(ctx, searcher, obj.Namespace, obj.Name, allowedDepth, maxDepth) +} + +// canSkipChildrenCheck determines if we can skip the expensive children depth check. +// If the old parent depth is >= the new parent depth, the folder was already valid +// and this move won't make descendants exceed max depth. +func canSkipChildrenCheck(ctx context.Context, oldFolder utils.GrafanaMetaAccessor, getter rest.Getter, parents parentsGetter, newParentDepth int) bool { + if oldFolder.GetFolder() == folder.RootFolderUID { + return false + } + + oldParentObj, err := getter.Get(ctx, oldFolder.GetFolder(), &metav1.GetOptions{}) + if err != nil { + return false + } + + oldParent, ok := oldParentObj.(*folders.Folder) + if !ok { + return false + } + + oldInfo, err := parents(ctx, oldParent) + if err != nil { + return false + } + + oldParentDepth := len(oldInfo.Items) + levelDifference := newParentDepth - oldParentDepth + return levelDifference <= 0 +} + +// checkSubtreeDepth uses a hybrid DFS+batching approach: +// 1. fetches one page of children for the current folder(s) +// 2. batches all those children into one request to get their children +// 3. continues depth-first (batching still) until max depth or violation +// 4. only fetches more siblings after fully exploring current batch +func checkSubtreeDepth(ctx context.Context, searcher resourcepb.ResourceIndexClient, namespace string, folderUID string, remainingDepth int, maxDepth int) error { + if remainingDepth <= 0 { + return nil + } + + // Start with the folder being moved + return checkSubtreeDepthBatched(ctx, searcher, namespace, []string{folderUID}, remainingDepth, maxDepth) +} + +// checkSubtreeDepthBatched checks depth for a batch of folders at the same level +func checkSubtreeDepthBatched(ctx context.Context, searcher resourcepb.ResourceIndexClient, namespace string, parentUIDs []string, remainingDepth int, maxDepth int) error { + if remainingDepth <= 0 || len(parentUIDs) == 0 { + return nil + } + + const pageSize int64 = 1000 + var offset int64 + totalPages := 0 + hasMore := true + + // Using an upper limit to ensure no infinite loops can happen + for hasMore && totalPages < 1000 { + totalPages++ + + var err error + var children []string + children, hasMore, err = getChildrenBatch(ctx, searcher, namespace, parentUIDs, pageSize, offset) + if err != nil { + return fmt.Errorf("failed to get children: %w", err) + } + + if len(children) == 0 { + return nil + } + + // if we are at the last allowed depth and children exist, we will hit the max + if remainingDepth == 1 { + return folder.ErrMaximumDepthReached.Errorf("maximum folder depth %d would be exceeded after move", maxDepth) + } + + if err := checkSubtreeDepthBatched(ctx, searcher, namespace, children, remainingDepth-1, maxDepth); err != nil { + return err + } + + if !hasMore { + return nil + } + + offset += pageSize + } + return nil } +// getChildrenBatch fetches children for multiple parents +func getChildrenBatch(ctx context.Context, searcher resourcepb.ResourceIndexClient, namespace string, parentUIDs []string, limit int64, offset int64) ([]string, bool, error) { + if len(parentUIDs) == 0 { + return nil, false, nil + } + + resp, err := searcher.Search(ctx, &resourcepb.ResourceSearchRequest{ + Options: &resourcepb.ListOptions{ + Key: &resourcepb.ResourceKey{ + Namespace: namespace, + Group: folders.FolderResourceInfo.GroupVersionResource().Group, + Resource: folders.FolderResourceInfo.GroupVersionResource().Resource, + }, + Fields: []*resourcepb.Requirement{{ + Key: resource.SEARCH_FIELD_FOLDER, + Operator: string(selection.In), + Values: parentUIDs, + }}, + }, + Limit: limit, + Offset: offset, + }) + if err != nil { + return nil, false, fmt.Errorf("failed to search folders: %w", err) + } + + if resp.Error != nil { + return nil, false, fmt.Errorf("search error: %s", resp.Error.Message) + } + + if resp.Results == nil || len(resp.Results.Rows) == 0 { + return nil, false, nil + } + + children := make([]string, 0, len(resp.Results.Rows)) + for _, row := range resp.Results.Rows { + if row.Key != nil { + children = append(children, row.Key.Name) + } + } + + hasMore := resp.Results.NextPageToken != "" + return children, hasMore, nil +} + func validateOnDelete(ctx context.Context, f *folders.Folder, searcher resourcepb.ResourceIndexClient, diff --git a/pkg/registry/apis/folders/validate_test.go b/pkg/registry/apis/folders/validate_test.go index 7fdb3cfae12..b9f55571ce0 100644 --- a/pkg/registry/apis/folders/validate_test.go +++ b/pkg/registry/apis/folders/validate_test.go @@ -282,6 +282,7 @@ func TestValidateUpdate(t *testing.T) { old *folders.Folder parents *folders.FolderInfoList parentsError error + allFolders []folders.Folder expectedErr string maxDepth int // defaults to 5 unless set }{ @@ -454,6 +455,74 @@ func TestValidateUpdate(t *testing.T) { }, expectedErr: "cannot move folder under its own descendant", }, + { + name: "error when moving folder from root to level2 with children exceeds max depth", + folder: &folders.Folder{ + ObjectMeta: metav1.ObjectMeta{ + Name: "folderWithChildren", + Annotations: map[string]string{ + utils.AnnoKeyFolder: "level2", + }, + }, + Spec: folders.FolderSpec{ + Title: "folder with children", + }, + }, + old: &folders.Folder{ + ObjectMeta: metav1.ObjectMeta{ + Name: "folderWithChildren", + }, + Spec: folders.FolderSpec{ + Title: "folder with children", + }, + }, + parents: &folders.FolderInfoList{ + Items: []folders.FolderInfo{ + {Name: "level2", Parent: "level1"}, + {Name: "level1", Parent: folder.GeneralFolderUID}, + {Name: folder.GeneralFolderUID}, + }, + }, + allFolders: []folders.Folder{ + {ObjectMeta: metav1.ObjectMeta{Name: "child1", Annotations: map[string]string{utils.AnnoKeyFolder: "folderWithChildren"}}}, + {ObjectMeta: metav1.ObjectMeta{Name: "grandchild1", Annotations: map[string]string{utils.AnnoKeyFolder: "child1"}}}, + }, + maxDepth: 4, + expectedErr: "[folder.maximum-depth-reached]", + }, + { + name: "can move folder from root level to level1 with children when within max depth", + folder: &folders.Folder{ + ObjectMeta: metav1.ObjectMeta{ + Name: "folderWithChildren", + Annotations: map[string]string{ + utils.AnnoKeyFolder: "level1", + }, + }, + Spec: folders.FolderSpec{ + Title: "folder with children", + }, + }, + old: &folders.Folder{ + ObjectMeta: metav1.ObjectMeta{ + Name: "folderWithChildren", + }, + Spec: folders.FolderSpec{ + Title: "folder with children", + }, + }, + parents: &folders.FolderInfoList{ + Items: []folders.FolderInfo{ + {Name: "level1", Parent: folder.GeneralFolderUID}, + {Name: folder.GeneralFolderUID}, + }, + }, + allFolders: []folders.Folder{ + {ObjectMeta: metav1.ObjectMeta{Name: "child1", Annotations: map[string]string{utils.AnnoKeyFolder: "folderWithChildren"}}}, + {ObjectMeta: metav1.ObjectMeta{Name: "grandchild1", Annotations: map[string]string{utils.AnnoKeyFolder: "child1"}}}, + }, + maxDepth: 4, + }, } for _, tt := range tests { @@ -474,11 +543,17 @@ func TestValidateUpdate(t *testing.T) { }, nil).Maybe() } } + for i := range tt.allFolders { + f := tt.allFolders[i] + m.On("Get", context.Background(), f.Name, &metav1.GetOptions{}).Return(&f, nil).Maybe() + } err := validateOnUpdate(context.Background(), tt.folder, tt.old, m, func(ctx context.Context, folder *folders.Folder) (*folders.FolderInfoList, error) { return tt.parents, tt.parentsError - }, maxDepth) + }, + &mockSearchClient{folders: tt.allFolders}, + maxDepth) if tt.expectedErr == "" { require.NoError(t, err) @@ -693,8 +768,7 @@ type mockSearchClient struct { stats *resourcepb.ResourceStatsResponse statsErr error - search *resourcepb.ResourceSearchResponse - searchErr error + folders []folders.Folder } // GetStats implements resourcepb.ResourceIndexClient. @@ -703,8 +777,37 @@ func (m *mockSearchClient) GetStats(ctx context.Context, in *resourcepb.Resource } // Search implements resourcepb.ResourceIndexClient. -func (m *mockSearchClient) Search(ctx context.Context, in *resourcepb.ResourceSearchRequest, opts ...grpc.CallOption) (*resourcepb.ResourceSearchResponse, error) { - return m.search, m.searchErr +func (m *mockSearchClient) Search(ctx context.Context, req *resourcepb.ResourceSearchRequest, opts ...grpc.CallOption) (*resourcepb.ResourceSearchResponse, error) { + // get the list of parents from the search request + parentSet := make(map[string]bool) + if req.Options != nil && req.Options.Fields != nil { + for _, field := range req.Options.Fields { + if field.Key == "folder" && field.Operator == "in" { + for _, v := range field.Values { + parentSet[v] = true + } + } + } + } + + // find children that match the parent filter + var rows []*resourcepb.ResourceTableRow + for i := range m.folders { + meta, err := utils.MetaAccessor(&m.folders[i]) + if err != nil { + continue + } + parentUID := meta.GetFolder() + if parentSet[parentUID] { + rows = append(rows, &resourcepb.ResourceTableRow{ + Key: &resourcepb.ResourceKey{Name: m.folders[i].Name}, + }) + } + } + + return &resourcepb.ResourceSearchResponse{ + Results: &resourcepb.ResourceTable{Rows: rows}, + }, nil } // RebuildIndexes implements resourcepb.ResourceIndexClient. diff --git a/pkg/registry/apis/iam/api_installer.go b/pkg/registry/apis/iam/api_installer.go new file mode 100644 index 00000000000..1d456dd3777 --- /dev/null +++ b/pkg/registry/apis/iam/api_installer.go @@ -0,0 +1,79 @@ +package iam + +import ( + "context" + + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apiserver/pkg/authorization/authorizer" + "k8s.io/apiserver/pkg/registry/rest" + "k8s.io/apiserver/pkg/server" + + iamv0 "github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1" + "github.com/grafana/grafana/pkg/apimachinery/utils" + "github.com/grafana/grafana/pkg/registry/apis/iam/noopstorage" + "github.com/grafana/grafana/pkg/services/apiserver/builder" +) + +// ApiInstaller is a generic interface for installing API resources. +// This allows different implementations (OSS noop, Enterprise with features) +// to provide their own resource registration and validation logic. +type ApiInstaller[T runtime.Object] interface { + // GetAuthorizer returns the authorizer for the API group. + GetAuthorizer() authorizer.Authorizer + + // RegisterStorage registers storage and hooks with the API group. + RegisterStorage(apiGroupInfo *server.APIGroupInfo, opts *builder.APIGroupOptions, storage map[string]rest.Storage) error + + // ValidateOnCreate validates object creation. + ValidateOnCreate(ctx context.Context, obj T) error + + // ValidateOnUpdate validates object updates. + ValidateOnUpdate(ctx context.Context, oldObj, newObj T) error + + // ValidateOnDelete validates object deletion. + ValidateOnDelete(ctx context.Context, obj T) error +} + +// RoleApiInstaller provides Role-specific API registration and validation. +// This interface allows enterprise implementations to provide custom role handling +// while keeping the core IAM registration logic in OSS. +type RoleApiInstaller ApiInstaller[*iamv0.Role] + +// NoopApiInstaller is a no-op implementation for when roles are not available (OSS). +type NoopApiInstaller[T runtime.Object] struct { + ResourceInfo utils.ResourceInfo +} + +func (n *NoopApiInstaller[T]) GetAuthorizer() authorizer.Authorizer { + return authorizer.AuthorizerFunc(func(ctx context.Context, attr authorizer.Attributes) (authorizer.Decision, string, error) { + return authorizer.DecisionDeny, "Unavailable functionality", nil + }) +} + +func (n *NoopApiInstaller[T]) RegisterStorage(apiGroupInfo *server.APIGroupInfo, opts *builder.APIGroupOptions, storage map[string]rest.Storage) error { + storage[n.ResourceInfo.StoragePath()] = &noopstorage.NoopREST{ResourceInfo: n.ResourceInfo} + return nil +} + +func (n *NoopApiInstaller[T]) ValidateOnCreate(ctx context.Context, obj T) error { + // No validation needed in OSS + return nil +} + +func (n *NoopApiInstaller[T]) ValidateOnUpdate(ctx context.Context, oldObj, newObj T) error { + // No validation needed in OSS + return nil +} + +func (n *NoopApiInstaller[T]) ValidateOnDelete(ctx context.Context, obj T) error { + // No validation needed in OSS + return nil +} + +// ProvideNoopRoleApiInstaller provides a no-op role installer specifically for Role types. +// This is needed for Wire dependency injection which doesn't handle generic functions well. +func ProvideNoopRoleApiInstaller() RoleApiInstaller { + return &NoopApiInstaller[*iamv0.Role]{ + ResourceInfo: iamv0.RoleInfo, + } +} diff --git a/pkg/registry/apis/iam/authorizer.go b/pkg/registry/apis/iam/authorizer.go index 026254ebab6..8abc67bf885 100644 --- a/pkg/registry/apis/iam/authorizer.go +++ b/pkg/registry/apis/iam/authorizer.go @@ -19,7 +19,11 @@ type iamAuthorizer struct { resourceAuthorizer map[string]authorizer.Authorizer // Map resource to its authorizer } -func newIAMAuthorizer(accessClient authlib.AccessClient, legacyAccessClient authlib.AccessClient) authorizer.Authorizer { +func newIAMAuthorizer( + accessClient authlib.AccessClient, + legacyAccessClient authlib.AccessClient, + roleApiInstaller RoleApiInstaller, +) authorizer.Authorizer { resourceAuthorizer := make(map[string]authorizer.Authorizer) serviceAuthorizer := gfauthorizer.NewServiceAuthorizer() @@ -44,7 +48,7 @@ func newIAMAuthorizer(accessClient authlib.AccessClient, legacyAccessClient auth // Access specific resources authorizer := gfauthorizer.NewResourceAuthorizer(accessClient) resourceAuthorizer[iamv0.CoreRoleInfo.GetName()] = iamauthorizer.NewCoreRoleAuthorizer(accessClient) - resourceAuthorizer[iamv0.RoleInfo.GetName()] = authorizer + resourceAuthorizer[iamv0.RoleInfo.GetName()] = roleApiInstaller.GetAuthorizer() resourceAuthorizer[iamv0.ResourcePermissionInfo.GetName()] = allowAuthorizer // Handled by the backend wrapper resourceAuthorizer[iamv0.RoleBindingInfo.GetName()] = authorizer resourceAuthorizer[iamv0.ServiceAccountResourceInfo.GetName()] = authorizer diff --git a/pkg/registry/apis/iam/models.go b/pkg/registry/apis/iam/models.go index f8ae4219b65..9e4d8e484e4 100644 --- a/pkg/registry/apis/iam/models.go +++ b/pkg/registry/apis/iam/models.go @@ -56,7 +56,7 @@ type IdentityAccessManagementAPIBuilder struct { teamBindingLegacyStore *teambinding.LegacyBindingStore ssoLegacyStore *sso.LegacyStore coreRolesStorage CoreRoleStorageBackend - rolesStorage RoleStorageBackend + roleApiInstaller RoleApiInstaller resourcePermissionsStorage resource.StorageBackend roleBindingsStorage RoleBindingStorageBackend externalGroupMappingStorage ExternalGroupMappingStorageBackend diff --git a/pkg/registry/apis/iam/noopstorage/rest.go b/pkg/registry/apis/iam/noopstorage/rest.go new file mode 100644 index 00000000000..aa0214788ab --- /dev/null +++ b/pkg/registry/apis/iam/noopstorage/rest.go @@ -0,0 +1,74 @@ +package noopstorage + +import ( + "context" + + "k8s.io/apimachinery/pkg/apis/meta/internalversion" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/watch" + "k8s.io/apiserver/pkg/registry/rest" + + "github.com/grafana/grafana/pkg/apimachinery/utils" +) + +type NoopREST struct { + ResourceInfo utils.ResourceInfo +} + +var ( + _ rest.Storage = (*NoopREST)(nil) + _ rest.Scoper = (*NoopREST)(nil) + _ rest.SingularNameProvider = (*NoopREST)(nil) + _ rest.Getter = (*NoopREST)(nil) +) + +func (n *NoopREST) New() runtime.Object { + return n.ResourceInfo.NewFunc() +} + +func (n *NoopREST) NewList() runtime.Object { + return n.ResourceInfo.NewListFunc() +} + +func (n *NoopREST) NamespaceScoped() bool { + return true +} + +func (n *NoopREST) GetSingularName() string { + return n.ResourceInfo.GetSingularName() +} + +func (n *NoopREST) Destroy() {} + +func (n *NoopREST) Get(ctx context.Context, name string, options *metav1.GetOptions) (runtime.Object, error) { + return nil, errNoopStorage +} + +func (n *NoopREST) List(ctx context.Context, options *internalversion.ListOptions) (runtime.Object, error) { + return nil, errNoopStorage +} + +func (n *NoopREST) Create(ctx context.Context, obj runtime.Object, createValidation rest.ValidateObjectFunc, options *metav1.CreateOptions) (runtime.Object, error) { + return nil, errNoopStorage +} + +func (n *NoopREST) Update(ctx context.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc, forceAllowCreate bool, options *metav1.UpdateOptions) (runtime.Object, bool, error) { + return nil, false, errNoopStorage +} + +func (n *NoopREST) Delete(ctx context.Context, name string, deleteValidation rest.ValidateObjectFunc, options *metav1.DeleteOptions) (runtime.Object, bool, error) { + return nil, false, errNoopStorage +} + +func (n *NoopREST) DeleteCollection(ctx context.Context, deleteValidation rest.ValidateObjectFunc, options *metav1.DeleteOptions, listOptions *internalversion.ListOptions) (runtime.Object, error) { + return nil, errNoopStorage +} + +func (n *NoopREST) Watch(ctx context.Context, options *internalversion.ListOptions) (watch.Interface, error) { + return nil, errNoopStorage +} + +func (n *NoopREST) ConvertToTable(ctx context.Context, object runtime.Object, tableOptions runtime.Object) (*metav1.Table, error) { + return nil, errNoopStorage +} diff --git a/pkg/registry/apis/iam/register.go b/pkg/registry/apis/iam/register.go index a9a68e90d2c..8a3dcb9586b 100644 --- a/pkg/registry/apis/iam/register.go +++ b/pkg/registry/apis/iam/register.go @@ -72,7 +72,7 @@ func RegisterAPIService( zClient zanzana.Client, reg prometheus.Registerer, coreRolesStorage CoreRoleStorageBackend, - rolesStorage RoleStorageBackend, + roleApiInstaller RoleApiInstaller, tracing *tracing.TracingService, roleBindingsStorage RoleBindingStorageBackend, externalGroupMappingStorageBackend ExternalGroupMappingStorageBackend, @@ -87,7 +87,7 @@ func RegisterAPIService( dbProvider := legacysql.NewDatabaseProvider(sql) store := legacy.NewLegacySQLStores(dbProvider) legacyAccessClient := newLegacyAccessClient(ac, store) - authorizer := newIAMAuthorizer(accessClient, legacyAccessClient) + authorizer := newIAMAuthorizer(accessClient, legacyAccessClient, roleApiInstaller) registerMetrics(reg) //nolint:staticcheck // not yet migrated to OpenFeature @@ -106,7 +106,7 @@ func RegisterAPIService( teamBindingLegacyStore: teambinding.NewLegacyBindingStore(store, enableAuthnMutation, tracing), ssoLegacyStore: sso.NewLegacyStore(ssoService, tracing), coreRolesStorage: coreRolesStorage, - rolesStorage: rolesStorage, + roleApiInstaller: roleApiInstaller, resourcePermissionsStorage: resourcepermission.ProvideStorageBackend(dbProvider), roleBindingsStorage: roleBindingsStorage, externalGroupMappingStorage: externalGroupMappingStorageBackend, @@ -139,7 +139,7 @@ func NewAPIService( accessClient types.AccessClient, dbProvider legacysql.LegacyDatabaseProvider, coreRoleStorage CoreRoleStorageBackend, - roleStorage RoleStorageBackend, + roleApiInstaller RoleApiInstaller, features featuremgmt.FeatureToggles, zClient zanzana.Client, reg prometheus.Registerer, @@ -162,7 +162,6 @@ func NewAPIService( store: store, display: user.NewLegacyDisplayREST(store), resourcePermissionsStorage: resourcePermissionsStorage, - rolesStorage: roleStorage, coreRolesStorage: coreRoleStorage, roleBindingsStorage: noopstorage.ProvideStorageBackend(), // TODO: add a proper storage backend logger: log.New("iam.apis"), @@ -172,6 +171,7 @@ func NewAPIService( zClient: zClient, zTickets: make(chan bool, MaxConcurrentZanzanaWrites), reg: reg, + roleApiInstaller: roleApiInstaller, authorizer: authorizer.AuthorizerFunc( func(ctx context.Context, a authorizer.Attributes) (authorizer.Decision, string, error) { user, ok := types.AuthInfoFrom(ctx) @@ -377,23 +377,17 @@ func (b *IdentityAccessManagementAPIBuilder) UpdateAPIGroupInfo(apiGroupInfo *ge } if enableZanzanaSync { b.logger.Info("Enabling hooks for CoreRole to sync to Zanzana") - coreRoleStore.AfterCreate = b.AfterRoleCreate - coreRoleStore.AfterDelete = b.AfterRoleDelete - coreRoleStore.BeginUpdate = b.BeginRoleUpdate + h := NewRoleHooks(b.zClient, b.zTickets, b.logger) + coreRoleStore.AfterCreate = h.AfterRoleCreate + coreRoleStore.AfterDelete = h.AfterRoleDelete + coreRoleStore.BeginUpdate = h.BeginRoleUpdate } storage[iamv0.CoreRoleInfo.StoragePath()] = coreRoleStore - roleStore, err := NewLocalStore(iamv0.RoleInfo, apiGroupInfo.Scheme, opts.OptsGetter, b.reg, b.accessClient, b.rolesStorage) - if err != nil { + // Role registration is delegated to the RoleApiInstaller + if err := b.roleApiInstaller.RegisterStorage(apiGroupInfo, &opts, storage); err != nil { return err } - if enableZanzanaSync { - 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 roleBindingStore, err := NewLocalStore(iamv0.RoleBindingInfo, apiGroupInfo.Scheme, opts.OptsGetter, b.reg, b.accessClient, b.roleBindingsStorage) if err != nil { @@ -568,6 +562,8 @@ func (b *IdentityAccessManagementAPIBuilder) Validate(ctx context.Context, a adm return resourcepermission.ValidateCreateAndUpdateInput(ctx, typedObj) case *iamv0.ExternalGroupMapping: return externalgroupmapping.ValidateOnCreate(typedObj) + case *iamv0.Role: + return b.roleApiInstaller.ValidateOnCreate(ctx, typedObj) } return nil case admission.Update: @@ -592,9 +588,19 @@ func (b *IdentityAccessManagementAPIBuilder) Validate(ctx context.Context, a adm return fmt.Errorf("expected old object to be a TeamBinding, got %T", oldTeamBindingObj) } return teambinding.ValidateOnUpdate(ctx, typedObj, oldTeamBindingObj) + case *iamv0.Role: + oldRoleObj, ok := a.GetOldObject().(*iamv0.Role) + if !ok { + return fmt.Errorf("expected old object to be a Role, got %T", oldRoleObj) + } + return b.roleApiInstaller.ValidateOnUpdate(ctx, oldRoleObj, typedObj) } return nil case admission.Delete: + switch oldRoleObj := a.GetOldObject().(type) { + case *iamv0.Role: + return b.roleApiInstaller.ValidateOnDelete(ctx, oldRoleObj) + } return nil case admission.Connect: return nil diff --git a/pkg/registry/apis/iam/role_hooks.go b/pkg/registry/apis/iam/role_hooks.go index 831a2993fe5..8d86a35bd27 100644 --- a/pkg/registry/apis/iam/role_hooks.go +++ b/pkg/registry/apis/iam/role_hooks.go @@ -9,12 +9,23 @@ import ( "k8s.io/apiserver/pkg/registry/generic/registry" iamv0 "github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1" + "github.com/grafana/grafana/pkg/infra/log" "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" ) +type RoleHooks struct { + zClient zanzana.Client + zTickets chan bool + logger log.Logger +} + +func NewRoleHooks(zClient zanzana.Client, zTickets chan bool, logger log.Logger) *RoleHooks { + return &RoleHooks{zClient: zClient, zTickets: zTickets, logger: logger} +} + // 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) { @@ -44,8 +55,8 @@ func convertRolePermissionsToTuples(roleUID string, permissions []iamv0.CoreRole // 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 { +func (h *RoleHooks) AfterRoleCreate(obj runtime.Object, _ *metav1.CreateOptions) { + if h.zClient == nil { return } @@ -76,21 +87,21 @@ func (b *IdentityAccessManagementAPIBuilder) AfterRoleCreate(obj runtime.Object, } wait := time.Now() - b.zTickets <- true + h.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 + <-h.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", + h.logger.Error("failed to convert role permissions to tuples", "namespace", role.Namespace, "roleUID", role.Name, "roleType", roleType, @@ -103,7 +114,7 @@ func (b *IdentityAccessManagementAPIBuilder) AfterRoleCreate(obj runtime.Object, // Avoid writing if there are no valid tuples if len(tuples) == 0 { - b.logger.Debug("no valid tuples to write for role", + h.logger.Debug("no valid tuples to write for role", "namespace", role.Namespace, "roleUID", role.Name, "roleType", roleType, @@ -113,7 +124,7 @@ func (b *IdentityAccessManagementAPIBuilder) AfterRoleCreate(obj runtime.Object, return } - b.logger.Debug("writing role permissions to zanzana", + h.logger.Debug("writing role permissions to zanzana", "namespace", role.Namespace, "roleUID", role.Name, "roleType", roleType, @@ -124,14 +135,14 @@ func (b *IdentityAccessManagementAPIBuilder) AfterRoleCreate(obj runtime.Object, ctx, cancel := context.WithTimeout(context.Background(), defaultWriteTimeout) defer cancel() - err = b.zClient.Write(ctx, &v1.WriteRequest{ + err = h.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", + h.logger.Error("failed to write role permissions to zanzana", "err", err, "namespace", role.Namespace, "roleUID", role.Name, @@ -149,8 +160,8 @@ func (b *IdentityAccessManagementAPIBuilder) AfterRoleCreate(obj runtime.Object, // 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 { +func (h *RoleHooks) AfterRoleDelete(obj runtime.Object, _ *metav1.DeleteOptions) { + if h.zClient == nil { return } @@ -182,15 +193,15 @@ func (b *IdentityAccessManagementAPIBuilder) AfterRoleDelete(obj runtime.Object, } wait := time.Now() - b.zTickets <- true + h.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 + <-h.zTickets }() - b.logger.Debug("deleting role permissions from zanzana", + h.logger.Debug("deleting role permissions from zanzana", "namespace", role.Namespace, "roleUID", role.Name, "roleType", roleType, @@ -199,7 +210,7 @@ func (b *IdentityAccessManagementAPIBuilder) AfterRoleDelete(obj runtime.Object, tuples, err := convertRolePermissionsToTuples(role.Name, role.Spec.Permissions) if err != nil { - b.logger.Error("failed to convert role permissions to tuples for deletion", + h.logger.Error("failed to convert role permissions to tuples for deletion", "namespace", role.Namespace, "roleUID", role.Name, "roleType", roleType, @@ -211,7 +222,7 @@ func (b *IdentityAccessManagementAPIBuilder) AfterRoleDelete(obj runtime.Object, // Avoid deleting if there are no valid tuples if len(tuples) == 0 { - b.logger.Debug("no valid tuples to delete for role", + h.logger.Debug("no valid tuples to delete for role", "namespace", role.Namespace, "roleUID", role.Name, "roleType", roleType, @@ -223,7 +234,7 @@ func (b *IdentityAccessManagementAPIBuilder) AfterRoleDelete(obj runtime.Object, // Convert tuples to TupleKeyWithoutCondition for deletion deleteTuples := toTupleKeysWithoutCondition(tuples) - b.logger.Debug("deleting role permissions from zanzana", + h.logger.Debug("deleting role permissions from zanzana", "namespace", role.Namespace, "roleUID", role.Name, "roleType", roleType, @@ -234,14 +245,14 @@ func (b *IdentityAccessManagementAPIBuilder) AfterRoleDelete(obj runtime.Object, ctx, cancel := context.WithTimeout(context.Background(), defaultWriteTimeout) defer cancel() - err = b.zClient.Write(ctx, &v1.WriteRequest{ + err = h.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", + h.logger.Error("failed to delete role permissions from zanzana", "err", err, "namespace", role.Namespace, "roleUID", role.Name, @@ -255,8 +266,8 @@ func (b *IdentityAccessManagementAPIBuilder) AfterRoleDelete(obj runtime.Object, // 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 { +func (h *RoleHooks) BeginRoleUpdate(ctx context.Context, obj, oldObj runtime.Object, options *metav1.UpdateOptions) (registry.FinishFunc, error) { + if h.zClient == nil { return nil, nil } var oldRole, newRole *iamv0.CoreRole @@ -316,12 +327,12 @@ func (b *IdentityAccessManagementAPIBuilder) BeginRoleUpdate(ctx context.Context // Grab a ticket to write to Zanzana wait := time.Now() - b.zTickets <- true + h.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 + <-h.zTickets }() roleUID, namespace := old.Name, old.Namespace oldPermissions, newPermissions := old.Spec.Permissions, new.Spec.Permissions @@ -332,7 +343,7 @@ func (b *IdentityAccessManagementAPIBuilder) BeginRoleUpdate(ctx context.Context var err error oldTuples, err = convertRolePermissionsToTuples(roleUID, oldPermissions) if err != nil { - b.logger.Error("failed to convert old role permissions to tuples", + h.logger.Error("failed to convert old role permissions to tuples", "namespace", namespace, "roleUID", roleUID, "roleType", roleType, @@ -344,7 +355,7 @@ func (b *IdentityAccessManagementAPIBuilder) BeginRoleUpdate(ctx context.Context // 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", + h.logger.Error("failed to convert new role permissions to tuples", "namespace", namespace, "roleUID", roleUID, "roleType", roleType, @@ -353,7 +364,7 @@ func (b *IdentityAccessManagementAPIBuilder) BeginRoleUpdate(ctx context.Context return } - b.logger.Debug("updating role permissions in zanzana", + h.logger.Debug("updating role permissions in zanzana", "namespace", namespace, "roleUID", roleUID, "roleType", roleType, @@ -375,7 +386,7 @@ func (b *IdentityAccessManagementAPIBuilder) BeginRoleUpdate(ctx context.Context req.Deletes = &v1.WriteRequestDeletes{ TupleKeys: deleteTuples, } - b.logger.Debug("deleting existing role permissions from zanzana", + h.logger.Debug("deleting existing role permissions from zanzana", "namespace", namespace, "roleUID", roleUID, "roleType", roleType, @@ -388,7 +399,7 @@ func (b *IdentityAccessManagementAPIBuilder) BeginRoleUpdate(ctx context.Context req.Writes = &v1.WriteRequestWrites{ TupleKeys: newTuples, } - b.logger.Debug("writing new role permissions to zanzana", + h.logger.Debug("writing new role permissions to zanzana", "namespace", namespace, "roleUID", roleUID, "roleType", roleType, @@ -398,9 +409,9 @@ func (b *IdentityAccessManagementAPIBuilder) BeginRoleUpdate(ctx context.Context // Only make the request if there are deletes or writes if req.Deletes != nil || req.Writes != nil { - err = b.zClient.Write(ctx, req) + err = h.zClient.Write(ctx, req) if err != nil { - b.logger.Error("failed to update role permissions in zanzana", + h.logger.Error("failed to update role permissions in zanzana", "err", err, "namespace", namespace, "roleUID", roleUID, diff --git a/pkg/registry/apis/iam/role_hooks_test.go b/pkg/registry/apis/iam/role_hooks_test.go index 497150f1c61..847d0c7727a 100644 --- a/pkg/registry/apis/iam/role_hooks_test.go +++ b/pkg/registry/apis/iam/role_hooks_test.go @@ -53,7 +53,7 @@ func requireDeleteTuplesMatch(t *testing.T, actual []*v1.TupleKeyWithoutConditio func TestAfterCoreRoleCreate(t *testing.T) { var wg sync.WaitGroup - b := &IdentityAccessManagementAPIBuilder{ + h := &RoleHooks{ logger: log.NewNopLogger(), zTickets: make(chan bool, 1), } @@ -90,8 +90,8 @@ func TestAfterCoreRoleCreate(t *testing.T) { return nil } - b.zClient = &FakeZanzanaClient{writeCallback: testCoreRoleEntries} - b.AfterRoleCreate(&coreRole, nil) + h.zClient = &FakeZanzanaClient{writeCallback: testCoreRoleEntries} + h.AfterRoleCreate(&coreRole, nil) wg.Wait() }) @@ -129,8 +129,8 @@ func TestAfterCoreRoleCreate(t *testing.T) { return nil } - b.zClient = &FakeZanzanaClient{writeCallback: testDashboardRoleEntries} - b.AfterRoleCreate(&coreRole, nil) + h.zClient = &FakeZanzanaClient{writeCallback: testDashboardRoleEntries} + h.AfterRoleCreate(&coreRole, nil) wg.Wait() }) @@ -163,8 +163,8 @@ func TestAfterCoreRoleCreate(t *testing.T) { return nil } - b.zClient = &FakeZanzanaClient{writeCallback: testWildcardEntries} - b.AfterRoleCreate(&coreRole, nil) + h.zClient = &FakeZanzanaClient{writeCallback: testWildcardEntries} + h.AfterRoleCreate(&coreRole, nil) wg.Wait() }) @@ -198,15 +198,15 @@ func TestAfterCoreRoleCreate(t *testing.T) { return nil } - b.zClient = &FakeZanzanaClient{writeCallback: testMixedEntries} - b.AfterRoleCreate(&coreRole, nil) + h.zClient = &FakeZanzanaClient{writeCallback: testMixedEntries} + h.AfterRoleCreate(&coreRole, nil) wg.Wait() }) } func TestAfterRoleCreate(t *testing.T) { var wg sync.WaitGroup - b := &IdentityAccessManagementAPIBuilder{ + h := &RoleHooks{ logger: log.NewNopLogger(), zTickets: make(chan bool, 1), } @@ -243,8 +243,8 @@ func TestAfterRoleCreate(t *testing.T) { return nil } - b.zClient = &FakeZanzanaClient{writeCallback: testRoleEntries} - b.AfterRoleCreate(&role, nil) + h.zClient = &FakeZanzanaClient{writeCallback: testRoleEntries} + h.AfterRoleCreate(&role, nil) wg.Wait() }) @@ -281,8 +281,8 @@ func TestAfterRoleCreate(t *testing.T) { return nil } - b.zClient = &FakeZanzanaClient{writeCallback: testDashRoleEntries} - b.AfterRoleCreate(&role, nil) + h.zClient = &FakeZanzanaClient{writeCallback: testDashRoleEntries} + h.AfterRoleCreate(&role, nil) wg.Wait() }) @@ -317,15 +317,15 @@ func TestAfterRoleCreate(t *testing.T) { return nil } - b.zClient = &FakeZanzanaClient{writeCallback: testMergedEntries} - b.AfterRoleCreate(&role, nil) + h.zClient = &FakeZanzanaClient{writeCallback: testMergedEntries} + h.AfterRoleCreate(&role, nil) wg.Wait() }) } func TestBeginCoreRoleUpdate(t *testing.T) { var wg sync.WaitGroup - b := &IdentityAccessManagementAPIBuilder{ + h := &RoleHooks{ logger: log.NewNopLogger(), zTickets: make(chan bool, 1), } @@ -387,10 +387,10 @@ func TestBeginCoreRoleUpdate(t *testing.T) { return nil } - b.zClient = &FakeZanzanaClient{writeCallback: testUpdate} + h.zClient = &FakeZanzanaClient{writeCallback: testUpdate} // Call BeginUpdate which does all the work - finishFunc, err := b.BeginRoleUpdate(context.Background(), &newRole, &oldRole, nil) + finishFunc, err := h.BeginRoleUpdate(context.Background(), &newRole, &oldRole, nil) require.NoError(t, err) require.NotNil(t, finishFunc) @@ -445,10 +445,10 @@ func TestBeginCoreRoleUpdate(t *testing.T) { return nil } - b.zClient = &FakeZanzanaClient{writeCallback: testExpand} + h.zClient = &FakeZanzanaClient{writeCallback: testExpand} // Call BeginUpdate which does all the work - finishFunc, err := b.BeginRoleUpdate(context.Background(), &newRole, &oldRole, nil) + finishFunc, err := h.BeginRoleUpdate(context.Background(), &newRole, &oldRole, nil) require.NoError(t, err) require.NotNil(t, finishFunc) @@ -499,10 +499,10 @@ func TestBeginCoreRoleUpdate(t *testing.T) { return nil } - b.zClient = &FakeZanzanaClient{writeCallback: testClear} + h.zClient = &FakeZanzanaClient{writeCallback: testClear} // Call BeginUpdate which does all the work - finishFunc, err := b.BeginRoleUpdate(context.Background(), &newRole, &oldRole, nil) + finishFunc, err := h.BeginRoleUpdate(context.Background(), &newRole, &oldRole, nil) require.NoError(t, err) require.NotNil(t, finishFunc) @@ -514,7 +514,7 @@ func TestBeginCoreRoleUpdate(t *testing.T) { func TestBeginRoleUpdate(t *testing.T) { var wg sync.WaitGroup - b := &IdentityAccessManagementAPIBuilder{ + h := &RoleHooks{ logger: log.NewNopLogger(), zTickets: make(chan bool, 1), } @@ -577,10 +577,10 @@ func TestBeginRoleUpdate(t *testing.T) { return nil } - b.zClient = &FakeZanzanaClient{writeCallback: testUpdate} + h.zClient = &FakeZanzanaClient{writeCallback: testUpdate} // Call BeginUpdate which does all the work - finishFunc, err := b.BeginRoleUpdate(context.Background(), &newRole, &oldRole, nil) + finishFunc, err := h.BeginRoleUpdate(context.Background(), &newRole, &oldRole, nil) require.NoError(t, err) require.NotNil(t, finishFunc) @@ -640,10 +640,10 @@ func TestBeginRoleUpdate(t *testing.T) { return nil } - b.zClient = &FakeZanzanaClient{writeCallback: testSwap} + h.zClient = &FakeZanzanaClient{writeCallback: testSwap} // Call BeginUpdate which does all the work - finishFunc, err := b.BeginRoleUpdate(context.Background(), &newRole, &oldRole, nil) + finishFunc, err := h.BeginRoleUpdate(context.Background(), &newRole, &oldRole, nil) require.NoError(t, err) require.NotNil(t, finishFunc) @@ -695,10 +695,10 @@ func TestBeginRoleUpdate(t *testing.T) { return nil } - b.zClient = &FakeZanzanaClient{writeCallback: testAddToEmpty} + h.zClient = &FakeZanzanaClient{writeCallback: testAddToEmpty} // Call BeginUpdate which does all the work - finishFunc, err := b.BeginRoleUpdate(context.Background(), &newRole, &oldRole, nil) + finishFunc, err := h.BeginRoleUpdate(context.Background(), &newRole, &oldRole, nil) require.NoError(t, err) require.NotNil(t, finishFunc) @@ -710,7 +710,7 @@ func TestBeginRoleUpdate(t *testing.T) { func TestAfterCoreRoleDelete(t *testing.T) { var wg sync.WaitGroup - b := &IdentityAccessManagementAPIBuilder{ + h := &RoleHooks{ logger: log.NewNopLogger(), zTickets: make(chan bool, 1), } @@ -747,8 +747,8 @@ func TestAfterCoreRoleDelete(t *testing.T) { return nil } - b.zClient = &FakeZanzanaClient{writeCallback: testCoreRoleDeletes} - b.AfterRoleDelete(&coreRole, nil) + h.zClient = &FakeZanzanaClient{writeCallback: testCoreRoleDeletes} + h.AfterRoleDelete(&coreRole, nil) wg.Wait() }) @@ -785,8 +785,8 @@ func TestAfterCoreRoleDelete(t *testing.T) { return nil } - b.zClient = &FakeZanzanaClient{writeCallback: testDashboardRoleDeletes} - b.AfterRoleDelete(&coreRole, nil) + h.zClient = &FakeZanzanaClient{writeCallback: testDashboardRoleDeletes} + h.AfterRoleDelete(&coreRole, nil) wg.Wait() }) @@ -818,8 +818,8 @@ func TestAfterCoreRoleDelete(t *testing.T) { return nil } - b.zClient = &FakeZanzanaClient{writeCallback: testWildcardDeletes} - b.AfterRoleDelete(&coreRole, nil) + h.zClient = &FakeZanzanaClient{writeCallback: testWildcardDeletes} + h.AfterRoleDelete(&coreRole, nil) wg.Wait() }) @@ -853,15 +853,15 @@ func TestAfterCoreRoleDelete(t *testing.T) { return nil } - b.zClient = &FakeZanzanaClient{writeCallback: testMixedDeletes} - b.AfterRoleDelete(&coreRole, nil) + h.zClient = &FakeZanzanaClient{writeCallback: testMixedDeletes} + h.AfterRoleDelete(&coreRole, nil) wg.Wait() }) } func TestAfterRoleDelete(t *testing.T) { var wg sync.WaitGroup - b := &IdentityAccessManagementAPIBuilder{ + h := &RoleHooks{ logger: log.NewNopLogger(), zTickets: make(chan bool, 1), } @@ -898,8 +898,8 @@ func TestAfterRoleDelete(t *testing.T) { return nil } - b.zClient = &FakeZanzanaClient{writeCallback: testRoleDeletes} - b.AfterRoleDelete(&role, nil) + h.zClient = &FakeZanzanaClient{writeCallback: testRoleDeletes} + h.AfterRoleDelete(&role, nil) wg.Wait() }) @@ -936,8 +936,8 @@ func TestAfterRoleDelete(t *testing.T) { return nil } - b.zClient = &FakeZanzanaClient{writeCallback: testDashRoleDeletes} - b.AfterRoleDelete(&role, nil) + h.zClient = &FakeZanzanaClient{writeCallback: testDashRoleDeletes} + h.AfterRoleDelete(&role, nil) wg.Wait() }) @@ -982,8 +982,8 @@ func TestAfterRoleDelete(t *testing.T) { return nil } - b.zClient = &FakeZanzanaClient{writeCallback: testMultiDeletes} - b.AfterRoleDelete(&role, nil) + h.zClient = &FakeZanzanaClient{writeCallback: testMultiDeletes} + h.AfterRoleDelete(&role, nil) wg.Wait() }) } diff --git a/pkg/registry/apis/iam/team/legacy_search.go b/pkg/registry/apis/iam/team/legacy_search.go index 938062bd9e6..8f9594b96ac 100644 --- a/pkg/registry/apis/iam/team/legacy_search.go +++ b/pkg/registry/apis/iam/team/legacy_search.go @@ -6,6 +6,7 @@ import ( "log/slog" "math" "strconv" + "strings" "google.golang.org/grpc" @@ -102,7 +103,8 @@ func getColumns(fields []string) []*resourcepb.ResourceTableColumnDefinition { columns := getDefaultColumns() for _, field := range fields { - if col, ok := builders.TeamSearchTableColumnDefinitions[field]; ok { + fieldName := strings.TrimPrefix(field, res.SEARCH_FIELD_PREFIX) + if col, ok := builders.TeamSearchTableColumnDefinitions[fieldName]; ok { columns = append(columns, col) } } @@ -121,7 +123,8 @@ func getDefaultColumns() []*resourcepb.ResourceTableColumnDefinition { func createCells(t *team.TeamDTO, fields []string) [][]byte { cells := createDefaultCells(t) for _, field := range fields { - switch field { + fieldName := strings.TrimPrefix(field, res.SEARCH_FIELD_PREFIX) + switch fieldName { case builders.TEAM_SEARCH_EMAIL: cells = append(cells, []byte(t.Email)) case builders.TEAM_SEARCH_PROVISIONED: diff --git a/pkg/registry/apis/iam/team_search.go b/pkg/registry/apis/iam/team_search.go index 786bf9be834..2252263a708 100644 --- a/pkg/registry/apis/iam/team_search.go +++ b/pkg/registry/apis/iam/team_search.go @@ -2,6 +2,7 @@ package iam import ( "encoding/json" + "fmt" "net/http" "net/url" "strconv" @@ -12,6 +13,7 @@ import ( "k8s.io/kube-openapi/pkg/validation/spec" iamv0alpha1 "github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1" + "github.com/grafana/grafana/pkg/apimachinery/identity" "github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/services/apiserver/builder" "github.com/grafana/grafana/pkg/services/featuremgmt" @@ -137,6 +139,12 @@ func (s *TeamSearchHandler) DoTeamSearch(w http.ResponseWriter, r *http.Request) return } + requester, err := identity.GetRequester(ctx) + if err != nil { + errhttp.Write(ctx, fmt.Errorf("no identity found for request: %w", err), w) + return + } + limit := 50 offset := 0 page := 1 @@ -154,16 +162,23 @@ func (s *TeamSearchHandler) DoTeamSearch(w http.ResponseWriter, r *http.Request) } searchRequest := &resourcepb.ResourceSearchRequest{ - Options: &resourcepb.ListOptions{}, + Options: &resourcepb.ListOptions{ + Key: &resourcepb.ResourceKey{ + Group: iamv0alpha1.TeamResourceInfo.GroupResource().Group, + Resource: iamv0alpha1.TeamResourceInfo.GroupResource().Resource, + Namespace: requester.GetNamespace(), + }, + }, Query: queryParams.Get("query"), Limit: int64(limit), Offset: int64(offset), Page: int64(page), Explain: queryParams.Has("explain") && queryParams.Get("explain") != "false", Fields: []string{ - builders.TEAM_SEARCH_EMAIL, - builders.TEAM_SEARCH_PROVISIONED, - builders.TEAM_SEARCH_EXTERNAL_UID, + resource.SEARCH_FIELD_TITLE, + resource.SEARCH_FIELD_PREFIX + builders.TEAM_SEARCH_EMAIL, + resource.SEARCH_FIELD_PREFIX + builders.TEAM_SEARCH_PROVISIONED, + resource.SEARCH_FIELD_PREFIX + builders.TEAM_SEARCH_EXTERNAL_UID, }, } diff --git a/pkg/registry/apis/iam/team_search_test.go b/pkg/registry/apis/iam/team_search_test.go index 76efed1c067..2142ba4e505 100644 --- a/pkg/registry/apis/iam/team_search_test.go +++ b/pkg/registry/apis/iam/team_search_test.go @@ -89,7 +89,7 @@ func TestTeamSearchHandler(t *testing.T) { if mockClient.LastSearchRequest == nil { t.Fatalf("expected Search to be called, but it was not") } - expectedFields := []string{"email", "provisioned", "externalUID"} + expectedFields := []string{"title", "fields.email", "fields.provisioned", "fields.externalUID"} if fmt.Sprintf("%v", mockClient.LastSearchRequest.Fields) != fmt.Sprintf("%v", expectedFields) { t.Errorf("expected fields %v, got %v", expectedFields, mockClient.LastSearchRequest.Fields) } diff --git a/pkg/registry/apis/provisioning/accesscontrol.go b/pkg/registry/apis/provisioning/accesscontrol.go index e56ab7b06e2..755eabb60da 100644 --- a/pkg/registry/apis/provisioning/accesscontrol.go +++ b/pkg/registry/apis/provisioning/accesscontrol.go @@ -12,6 +12,12 @@ const ( ActionProvisioningRepositoriesRead = "provisioning.repositories:read" // GET + LIST. ActionProvisioningRepositoriesDelete = "provisioning.repositories:delete" // DELETE. + // Connections + ActionProvisioningConnectionsCreate = "provisioning.connections:create" // CREATE. + ActionProvisioningConnectionsWrite = "provisioning.connections:write" // UPDATE. + ActionProvisioningConnectionsRead = "provisioning.connections:read" // GET + LIST. + ActionProvisioningConnectionsDelete = "provisioning.connections:delete" // DELETE. + // Jobs ActionProvisioningJobsCreate = "provisioning.jobs:create" // CREATE. ActionProvisioningJobsWrite = "provisioning.jobs:write" // UPDATE. @@ -20,6 +26,12 @@ const ( // Historic Jobs ActionProvisioningHistoricJobsRead = "provisioning.historicjobs:read" // GET + LIST. + + // Settings (read-only, needed by multiple UI pages) + ActionProvisioningSettingsRead = "provisioning.settings:read" // GET + LIST. + + // Stats (read-only, admin-only) + ActionProvisioningStatsRead = "provisioning.stats:read" // GET + LIST. ) func registerAccessControlRoles(service accesscontrol.Service) error { @@ -63,6 +75,46 @@ func registerAccessControlRoles(service accesscontrol.Service) error { Grants: []string{string(org.RoleAdmin)}, } + // Connections + connectionsReader := accesscontrol.RoleRegistration{ + Role: accesscontrol.RoleDTO{ + Name: "fixed:provisioning.connections:reader", + DisplayName: "Connections Reader", + Description: "Read and list provisioning connections.", + Group: "Provisioning", + Permissions: []accesscontrol.Permission{ + { + Action: ActionProvisioningConnectionsRead, + }, + }, + }, + Grants: []string{string(org.RoleAdmin)}, + } + + connectionsWriter := accesscontrol.RoleRegistration{ + Role: accesscontrol.RoleDTO{ + Name: "fixed:provisioning.connections:writer", + DisplayName: "Connections Writer", + Description: "Create, update and delete provisioning connections.", + Group: "Provisioning", + Permissions: []accesscontrol.Permission{ + { + Action: ActionProvisioningConnectionsCreate, + }, + { + Action: ActionProvisioningConnectionsRead, + }, + { + Action: ActionProvisioningConnectionsWrite, + }, + { + Action: ActionProvisioningConnectionsDelete, + }, + }, + }, + Grants: []string{string(org.RoleAdmin)}, + } + // Jobs jobsReader := accesscontrol.RoleRegistration{ Role: accesscontrol.RoleDTO{ @@ -119,11 +171,47 @@ func registerAccessControlRoles(service accesscontrol.Service) error { Grants: []string{string(org.RoleAdmin)}, } + // Settings - granted to Viewer (accessible by all logged-in users) + settingsReader := accesscontrol.RoleRegistration{ + Role: accesscontrol.RoleDTO{ + Name: "fixed:provisioning.settings:reader", + DisplayName: "Settings Reader", + Description: "Read provisioning settings.", + Group: "Provisioning", + Permissions: []accesscontrol.Permission{ + { + Action: ActionProvisioningSettingsRead, + }, + }, + }, + Grants: []string{string(org.RoleViewer)}, + } + + // Stats - granted to Admin only + statsReader := accesscontrol.RoleRegistration{ + Role: accesscontrol.RoleDTO{ + Name: "fixed:provisioning.stats:reader", + DisplayName: "Stats Reader", + Description: "Read provisioning stats.", + Group: "Provisioning", + Permissions: []accesscontrol.Permission{ + { + Action: ActionProvisioningStatsRead, + }, + }, + }, + Grants: []string{string(org.RoleAdmin)}, + } + return service.DeclareFixedRoles( repositoriesReader, repositoriesWriter, + connectionsReader, + connectionsWriter, jobsReader, jobsWriter, historicJobsReader, + settingsReader, + statsReader, ) } diff --git a/pkg/registry/apis/provisioning/controller/repository.go b/pkg/registry/apis/provisioning/controller/repository.go index 00821db3655..b0e726135a4 100644 --- a/pkg/registry/apis/provisioning/controller/repository.go +++ b/pkg/registry/apis/provisioning/controller/repository.go @@ -26,7 +26,6 @@ import ( "github.com/grafana/grafana/pkg/infra/tracing" "github.com/grafana/grafana/pkg/registry/apis/provisioning/jobs" "github.com/grafana/grafana/pkg/registry/apis/provisioning/resources" - "github.com/grafana/grafana/pkg/storage/legacysql/dualwrite" "github.com/prometheus/client_golang/prometheus" ) @@ -53,7 +52,6 @@ type RepositoryController struct { repoLister listers.RepositoryLister repoSynced cache.InformerSynced logger logging.Logger - dualwrite dualwrite.Service jobs interface { jobs.Queue @@ -86,7 +84,6 @@ func NewRepositoryController( jobs.Queue jobs.Store }, - dualwrite dualwrite.Service, healthChecker *HealthChecker, statusPatcher StatusPatcher, registry prometheus.Registerer, @@ -114,11 +111,10 @@ func NewRepositoryController( metrics: &finalizerMetrics, maxWorkers: parallelOperations, }, - jobs: jobs, - logger: logging.DefaultLogger.With("logger", loggerName), - dualwrite: dualwrite, - registry: registry, - tracer: tracer, + jobs: jobs, + logger: logging.DefaultLogger.With("logger", loggerName), + registry: registry, + tracer: tracer, } _, err := repoInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{ @@ -356,9 +352,6 @@ func (rc *RepositoryController) determineSyncStrategy(ctx context.Context, obj * case !healthStatus.Healthy: logger.Info("skip sync for unhealthy repository") return nil - case rc.dualwrite != nil && dualwrite.IsReadingLegacyDashboardsAndFolders(ctx, rc.dualwrite): - logger.Info("skip sync as we are reading from legacy storage") - return nil case healthStatus.Healthy != obj.Status.Health.Healthy: logger.Info("repository became healthy, full resync") return &provisioning.SyncJobOptions{} diff --git a/pkg/registry/apis/provisioning/files.go b/pkg/registry/apis/provisioning/files.go index ad9bc4bc472..a418860caac 100644 --- a/pkg/registry/apis/provisioning/files.go +++ b/pkg/registry/apis/provisioning/files.go @@ -13,9 +13,10 @@ import ( authlib "github.com/grafana/authlib/types" "github.com/grafana/grafana-app-sdk/logging" provisioning "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1" + "github.com/grafana/grafana/apps/provisioning/pkg/auth" "github.com/grafana/grafana/apps/provisioning/pkg/repository" "github.com/grafana/grafana/apps/provisioning/pkg/safepath" - "github.com/grafana/grafana/pkg/apimachinery/identity" + "github.com/grafana/grafana/pkg/apimachinery/utils" "github.com/grafana/grafana/pkg/registry/apis/provisioning/resources" ) @@ -26,12 +27,12 @@ const ( type filesConnector struct { getter RepoGetter - access authlib.AccessChecker + access auth.AccessChecker parsers resources.ParserFactory clients resources.ClientFactory } -func NewFilesConnector(getter RepoGetter, parsers resources.ParserFactory, clients resources.ClientFactory, access authlib.AccessChecker) *filesConnector { +func NewFilesConnector(getter RepoGetter, parsers resources.ParserFactory, clients resources.ClientFactory, access auth.AccessChecker) *filesConnector { return &filesConnector{getter: getter, parsers: parsers, clients: clients, access: access} } @@ -74,179 +75,233 @@ func (c *filesConnector) Connect(ctx context.Context, name string, opts runtime. ctx = logging.Context(ctx, logger) return WithTimeout(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - repo, err := c.getRepo(ctx, r.Method, name) - if err != nil { - logger.Debug("failed to find repository", "error", err) - responder.Error(err) - return - } - - readWriter, ok := repo.(repository.ReaderWriter) - if !ok { - responder.Error(apierrors.NewBadRequest("repository does not support read-writing")) - return - } - - parser, err := c.parsers.GetParser(ctx, readWriter) - if err != nil { - responder.Error(fmt.Errorf("failed to get parser: %w", err)) - return - } - - clients, err := c.clients.Clients(ctx, repo.Config().Namespace) - if err != nil { - responder.Error(fmt.Errorf("failed to get clients: %w", err)) - return - } - - folderClient, err := clients.Folder(ctx) - if err != nil { - responder.Error(fmt.Errorf("failed to get folder client: %w", err)) - return - } - folders := resources.NewFolderManager(readWriter, folderClient, resources.NewEmptyFolderTree()) - dualReadWriter := resources.NewDualReadWriter(readWriter, parser, folders, c.access) - query := r.URL.Query() - opts := resources.DualWriteOptions{ - Ref: query.Get("ref"), - Message: query.Get("message"), - SkipDryRun: query.Get("skipDryRun") == "true", - OriginalPath: query.Get("originalPath"), - Branch: repo.Config().Branch(), - } - logger := logger.With("url", r.URL.Path, "ref", opts.Ref, "message", opts.Message) - ctx := logging.Context(r.Context(), logger) - - opts.Path, err = pathAfterPrefix(r.URL.Path, fmt.Sprintf("/%s/files", name)) - if err != nil { - responder.Error(apierrors.NewBadRequest(err.Error())) - return - } - - if err := resources.IsPathSupported(opts.Path); err != nil { - responder.Error(apierrors.NewBadRequest(err.Error())) - return - } - - isDir := safepath.IsDir(opts.Path) - if r.Method == http.MethodGet && isDir { - files, err := c.listFolderFiles(ctx, opts.Path, opts.Ref, readWriter) - if err != nil { - responder.Error(err) - return - } - - responder.Object(http.StatusOK, files) - return - } - - if opts.Path == "" { - responder.Error(apierrors.NewBadRequest("missing request path")) - return - } - - var obj *provisioning.ResourceWrapper - code := http.StatusOK - switch r.Method { - case http.MethodGet: - resource, err := dualReadWriter.Read(ctx, opts.Path, opts.Ref) - if err != nil { - respondWithError(responder, err) - return - } - obj = resource.AsResourceWrapper() - case http.MethodPost: - // Check if this is a move operation first (originalPath query parameter is present) - if opts.OriginalPath != "" { - // For move operations, only read body for file moves (not directory moves) - if !isDir { - opts.Data, err = readBody(r, filesMaxBodySize) - if err != nil { - responder.Error(err) - return - } - } - - resource, err := dualReadWriter.MoveResource(ctx, opts) - if err != nil { - respondWithError(responder, err) - return - } - obj = resource.AsResourceWrapper() - } else if isDir { - obj, err = dualReadWriter.CreateFolder(ctx, opts) - } else { - opts.Data, err = readBody(r, filesMaxBodySize) - if err != nil { - responder.Error(err) - return - } - - var resource *resources.ParsedResource - resource, err = dualReadWriter.CreateResource(ctx, opts) - if err != nil { - respondWithError(responder, err) - return - } - obj = resource.AsResourceWrapper() - } - case http.MethodPut: - // TODO: document in API specification - if isDir { - err = apierrors.NewMethodNotSupported(provisioning.RepositoryResourceInfo.GroupResource(), r.Method) - } else { - opts.Data, err = readBody(r, filesMaxBodySize) - if err != nil { - responder.Error(err) - return - } - - resource, err := dualReadWriter.UpdateResource(ctx, opts) - if err != nil { - respondWithError(responder, err) - return - } - obj = resource.AsResourceWrapper() - } - case http.MethodDelete: - resource, err := dualReadWriter.Delete(ctx, opts) - if err != nil { - respondWithError(responder, err) - return - } - obj = resource.AsResourceWrapper() - default: - err = apierrors.NewMethodNotSupported(provisioning.RepositoryResourceInfo.GroupResource(), r.Method) - } - - if err != nil { - logger.Debug("got an error after processing request", "error", err) - responder.Error(err) - return - } - - if len(obj.Errors) > 0 { - code = http.StatusPartialContent - } - - logger.Debug("request resulted in valid object", "object", obj) - responder.Object(code, obj) + c.handleRequest(ctx, name, r, responder, logger) }), 30*time.Second), nil } -// listFolderFiles returns a list of files in a folder -func (c *filesConnector) listFolderFiles(ctx context.Context, filePath string, ref string, readWriter repository.ReaderWriter) (*provisioning.FileList, error) { - id, err := identity.GetRequester(ctx) +// handleRequest processes the HTTP request for files operations. +func (c *filesConnector) handleRequest(ctx context.Context, name string, r *http.Request, responder rest.Responder, logger logging.Logger) { + repo, err := c.getRepo(ctx, r.Method, name) if err != nil { - return nil, fmt.Errorf("missing auth info in context") + logger.Debug("failed to find repository", "error", err) + responder.Error(err) + return } - // TODO: replace with access check on the repo itself - if !id.GetOrgRole().Includes(identity.RoleAdmin) { - return nil, apierrors.NewForbidden(resources.DashboardResource.GroupResource(), "", - fmt.Errorf("requires admin role")) + readWriter, ok := repo.(repository.ReaderWriter) + if !ok { + responder.Error(apierrors.NewBadRequest("repository does not support read-writing")) + return } + dualReadWriter, err := c.createDualReadWriter(ctx, repo, readWriter) + if err != nil { + responder.Error(err) + return + } + + opts, err := c.parseRequestOptions(r, name, repo) + if err != nil { + responder.Error(apierrors.NewBadRequest(err.Error())) + return + } + + logger = logger.With("url", r.URL.Path, "ref", opts.Ref, "message", opts.Message) + ctx = logging.Context(r.Context(), logger) + + // Handle directory listing separately + isDir := safepath.IsDir(opts.Path) + if r.Method == http.MethodGet && isDir { + c.handleDirectoryListing(ctx, name, opts, readWriter, responder) + return + } + + if opts.Path == "" { + responder.Error(apierrors.NewBadRequest("missing request path")) + return + } + + obj, err := c.handleMethodRequest(ctx, r, opts, isDir, dualReadWriter) + if err != nil { + logger.Debug("got an error after processing request", "error", err) + respondWithError(responder, err) + return + } + + code := http.StatusOK + if len(obj.Errors) > 0 { + code = http.StatusPartialContent + } + + logger.Debug("request resulted in valid object", "object", obj) + responder.Object(code, obj) +} + +// createDualReadWriter sets up the dual read writer with all required dependencies. +func (c *filesConnector) createDualReadWriter(ctx context.Context, repo repository.Repository, readWriter repository.ReaderWriter) (*resources.DualReadWriter, error) { + parser, err := c.parsers.GetParser(ctx, readWriter) + if err != nil { + return nil, fmt.Errorf("failed to get parser: %w", err) + } + + clients, err := c.clients.Clients(ctx, repo.Config().Namespace) + if err != nil { + return nil, fmt.Errorf("failed to get clients: %w", err) + } + + folderClient, err := clients.Folder(ctx) + if err != nil { + return nil, fmt.Errorf("failed to get folder client: %w", err) + } + + folders := resources.NewFolderManager(readWriter, folderClient, resources.NewEmptyFolderTree()) + return resources.NewDualReadWriter(readWriter, parser, folders, c.access), nil +} + +// parseRequestOptions extracts options from the HTTP request. +func (c *filesConnector) parseRequestOptions(r *http.Request, name string, repo repository.Repository) (resources.DualWriteOptions, error) { + query := r.URL.Query() + opts := resources.DualWriteOptions{ + Ref: query.Get("ref"), + Message: query.Get("message"), + SkipDryRun: query.Get("skipDryRun") == "true", + OriginalPath: query.Get("originalPath"), + Branch: repo.Config().Branch(), + } + + path, err := pathAfterPrefix(r.URL.Path, fmt.Sprintf("/%s/files", name)) + if err != nil { + return opts, err + } + opts.Path = path + + if err := resources.IsPathSupported(opts.Path); err != nil { + return opts, err + } + + return opts, nil +} + +// handleDirectoryListing handles GET requests for directory listing. +func (c *filesConnector) handleDirectoryListing(ctx context.Context, name string, opts resources.DualWriteOptions, readWriter repository.ReaderWriter, responder rest.Responder) { + if err := c.authorizeListFiles(ctx, name); err != nil { + responder.Error(err) + return + } + + files, err := c.listFolderFiles(ctx, opts.Path, opts.Ref, readWriter) + if err != nil { + responder.Error(err) + return + } + + responder.Object(http.StatusOK, files) +} + +// handleMethodRequest routes the request to the appropriate handler based on HTTP method. +func (c *filesConnector) handleMethodRequest(ctx context.Context, r *http.Request, opts resources.DualWriteOptions, isDir bool, dualReadWriter *resources.DualReadWriter) (*provisioning.ResourceWrapper, error) { + switch r.Method { + case http.MethodGet: + return c.handleGet(ctx, opts, dualReadWriter) + case http.MethodPost: + return c.handlePost(ctx, r, opts, isDir, dualReadWriter) + case http.MethodPut: + return c.handlePut(ctx, r, opts, isDir, dualReadWriter) + case http.MethodDelete: + return c.handleDelete(ctx, opts, dualReadWriter) + default: + return nil, apierrors.NewMethodNotSupported(provisioning.RepositoryResourceInfo.GroupResource(), r.Method) + } +} + +func (c *filesConnector) handleGet(ctx context.Context, opts resources.DualWriteOptions, dualReadWriter *resources.DualReadWriter) (*provisioning.ResourceWrapper, error) { + resource, err := dualReadWriter.Read(ctx, opts.Path, opts.Ref) + if err != nil { + return nil, err + } + return resource.AsResourceWrapper(), nil +} + +func (c *filesConnector) handlePost(ctx context.Context, r *http.Request, opts resources.DualWriteOptions, isDir bool, dualReadWriter *resources.DualReadWriter) (*provisioning.ResourceWrapper, error) { + // Check if this is a move operation (originalPath query parameter is present) + if opts.OriginalPath != "" { + return c.handleMove(ctx, r, opts, isDir, dualReadWriter) + } + + if isDir { + return dualReadWriter.CreateFolder(ctx, opts) + } + + data, err := readBody(r, filesMaxBodySize) + if err != nil { + return nil, err + } + opts.Data = data + + resource, err := dualReadWriter.CreateResource(ctx, opts) + if err != nil { + return nil, err + } + return resource.AsResourceWrapper(), nil +} + +func (c *filesConnector) handleMove(ctx context.Context, r *http.Request, opts resources.DualWriteOptions, isDir bool, dualReadWriter *resources.DualReadWriter) (*provisioning.ResourceWrapper, error) { + // For move operations, only read body for file moves (not directory moves) + if !isDir { + data, err := readBody(r, filesMaxBodySize) + if err != nil { + return nil, err + } + opts.Data = data + } + + resource, err := dualReadWriter.MoveResource(ctx, opts) + if err != nil { + return nil, err + } + return resource.AsResourceWrapper(), nil +} + +func (c *filesConnector) handlePut(ctx context.Context, r *http.Request, opts resources.DualWriteOptions, isDir bool, dualReadWriter *resources.DualReadWriter) (*provisioning.ResourceWrapper, error) { + if isDir { + return nil, apierrors.NewMethodNotSupported(provisioning.RepositoryResourceInfo.GroupResource(), r.Method) + } + + data, err := readBody(r, filesMaxBodySize) + if err != nil { + return nil, err + } + opts.Data = data + + resource, err := dualReadWriter.UpdateResource(ctx, opts) + if err != nil { + return nil, err + } + return resource.AsResourceWrapper(), nil +} + +func (c *filesConnector) handleDelete(ctx context.Context, opts resources.DualWriteOptions, dualReadWriter *resources.DualReadWriter) (*provisioning.ResourceWrapper, error) { + resource, err := dualReadWriter.Delete(ctx, opts) + if err != nil { + return nil, err + } + return resource.AsResourceWrapper(), nil +} + +// authorizeListFiles checks if the user has repositories:read permission for listing files. +// The access checker handles AccessPolicy identities, namespace resolution, and role-based fallback internally. +func (c *filesConnector) authorizeListFiles(ctx context.Context, repoName string) error { + return c.access.Check(ctx, authlib.CheckRequest{ + Verb: utils.VerbGet, + Group: provisioning.GROUP, + Resource: provisioning.RepositoryResourceInfo.GetName(), + Name: repoName, + }, "") +} + +// listFolderFiles returns a list of files in a folder. +// Authorization is checked via authorizeListFiles before calling this function. +func (c *filesConnector) listFolderFiles(ctx context.Context, filePath string, ref string, readWriter repository.ReaderWriter) (*provisioning.FileList, error) { // TODO: Implement folder navigation if len(filePath) > 0 { return nil, apierrors.NewBadRequest("folder navigation not yet supported") diff --git a/pkg/registry/apis/provisioning/jobs/export/mock_export_fn.go b/pkg/registry/apis/provisioning/jobs/export/mock_export_fn.go index e748228da2b..74e2ca4a26e 100644 --- a/pkg/registry/apis/provisioning/jobs/export/mock_export_fn.go +++ b/pkg/registry/apis/provisioning/jobs/export/mock_export_fn.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.52.4. DO NOT EDIT. +// Code generated by mockery v2.53.4. DO NOT EDIT. package export diff --git a/pkg/registry/apis/provisioning/jobs/export/mock_wrap_with_stage_fn.go b/pkg/registry/apis/provisioning/jobs/export/mock_wrap_with_stage_fn.go index 99718fd4d88..a2582001c9a 100644 --- a/pkg/registry/apis/provisioning/jobs/export/mock_wrap_with_stage_fn.go +++ b/pkg/registry/apis/provisioning/jobs/export/mock_wrap_with_stage_fn.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.52.4. DO NOT EDIT. +// Code generated by mockery v2.53.4. DO NOT EDIT. package export diff --git a/pkg/registry/apis/provisioning/jobs/loki_history_test.go b/pkg/registry/apis/provisioning/jobs/loki_history_test.go index 26d7f01ab4f..1f41875662c 100644 --- a/pkg/registry/apis/provisioning/jobs/loki_history_test.go +++ b/pkg/registry/apis/provisioning/jobs/loki_history_test.go @@ -49,7 +49,6 @@ func TestLokiJobHistory_WriteJob(t *testing.T) { Path: "/exported", }, Migrate: &provisioning.MigrateJobOptions{ - History: true, Message: "Migration test", }, Delete: &provisioning.DeleteJobOptions{ @@ -101,7 +100,7 @@ func TestLokiJobHistory_WriteJob(t *testing.T) { } t.Run("jobToStream creates correct stream with all fields", func(t *testing.T) { - history := createTestLokiJobHistory(t) + history := createTestLokiJobHistory() // Clean job copy like WriteJob does jobCopy := job.DeepCopy() delete(jobCopy.Labels, LabelJobClaim) @@ -147,7 +146,6 @@ func TestLokiJobHistory_WriteJob(t *testing.T) { assert.Equal(t, "main", deserializedJob.Spec.Push.Branch) assert.Equal(t, "/exported", deserializedJob.Spec.Push.Path) require.NotNil(t, deserializedJob.Spec.Migrate) - assert.True(t, deserializedJob.Spec.Migrate.History) assert.Equal(t, "Migration test", deserializedJob.Spec.Migrate.Message) require.NotNil(t, deserializedJob.Spec.Delete) assert.Equal(t, "main", deserializedJob.Spec.Delete.Ref) @@ -190,7 +188,7 @@ func TestLokiJobHistory_WriteJob(t *testing.T) { }) t.Run("buildJobQuery creates correct LogQL", func(t *testing.T) { - history := createTestLokiJobHistory(t) + history := createTestLokiJobHistory() query := history.buildJobQuery("test-ns", "test-repo") @@ -199,7 +197,7 @@ func TestLokiJobHistory_WriteJob(t *testing.T) { }) t.Run("getJobTimestamp returns correct timestamp", func(t *testing.T) { - history := createTestLokiJobHistory(t) + history := createTestLokiJobHistory() // Test finished time priority jobWithFinished := &provisioning.Job{ @@ -584,7 +582,7 @@ func TestLokiJobHistory_GetJob(t *testing.T) { } // createTestLokiJobHistory creates a LokiJobHistory for testing -func createTestLokiJobHistory(t *testing.T) *LokiJobHistory { +func createTestLokiJobHistory() *LokiJobHistory { // Create test URLs readURL, _ := url.Parse("http://localhost:3100") writeURL, _ := url.Parse("http://localhost:3100") diff --git a/pkg/registry/apis/provisioning/jobs/migrate/legacy.go b/pkg/registry/apis/provisioning/jobs/migrate/legacy.go deleted file mode 100644 index 5b241c84775..00000000000 --- a/pkg/registry/apis/provisioning/jobs/migrate/legacy.go +++ /dev/null @@ -1,95 +0,0 @@ -package migrate - -import ( - "context" - "errors" - "fmt" - "time" - - "github.com/grafana/grafana-app-sdk/logging" - 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/jobs" -) - -type LegacyMigrator struct { - legacyMigrator LegacyResourcesMigrator - storageSwapper StorageSwapper - syncWorker jobs.Worker - wrapWithStageFn WrapWithStageFn -} - -func NewLegacyMigrator( - legacyMigrator LegacyResourcesMigrator, - storageSwapper StorageSwapper, - syncWorker jobs.Worker, - wrapWithStageFn WrapWithStageFn, -) *LegacyMigrator { - return &LegacyMigrator{ - legacyMigrator: legacyMigrator, - storageSwapper: storageSwapper, - syncWorker: syncWorker, - wrapWithStageFn: wrapWithStageFn, - } -} - -func (m *LegacyMigrator) Migrate(ctx context.Context, rw repository.ReaderWriter, options provisioning.MigrateJobOptions, progress jobs.JobProgressRecorder) error { - namespace := rw.Config().Namespace - var stageMode repository.StageMode - if options.History { - // When History is true, we want to commit and push each file (previous PushOnWrites: true) - stageMode = repository.StageModeCommitAndPushOnEach - } else { - // When History is false, we want to commit only once (previous CommitOnlyOnce: true) - stageMode = repository.StageModeCommitOnlyOnce - } - - stageOptions := repository.StageOptions{ - Mode: stageMode, - CommitOnlyOnceMessage: options.Message, - // TODO: make this configurable - Timeout: 10 * time.Minute, - } - - // Fail if migrating at least one - progress.StrictMaxErrors(1) - progress.SetMessage(ctx, "migrating legacy resources") - - if err := m.wrapWithStageFn(ctx, rw, stageOptions, func(repo repository.Repository, staged bool) error { - rw, ok := repo.(repository.ReaderWriter) - if !ok { - return errors.New("migration job submitted targeting repository that is not a ReaderWriter") - } - - return m.legacyMigrator.Migrate(ctx, rw, namespace, options, progress) - }); err != nil { - return fmt.Errorf("migrate from SQL: %w", err) - } - - progress.SetMessage(ctx, "resetting unified storage") - if err := m.storageSwapper.WipeUnifiedAndSetMigratedFlag(ctx, namespace); err != nil { - return fmt.Errorf("unable to reset unified storage %w", err) - } - - // Reset the results after the export as pull will operate on the same resources - progress.ResetResults() - - // Delegate the import to a sync (from the already checked out go-git repository!) - progress.SetMessage(ctx, "pulling resources") - if err := m.syncWorker.Process(ctx, rw, provisioning.Job{ - Spec: provisioning.JobSpec{ - Pull: &provisioning.SyncJobOptions{ - Incremental: false, - }, - }, - }, progress); err != nil { // this will have an error when too many errors exist - progress.SetMessage(ctx, "error importing resources, reverting") - if e2 := m.storageSwapper.StopReadingUnifiedStorage(ctx); e2 != nil { - logger := logging.FromContext(ctx) - logger.Warn("error trying to revert dual write settings after an error", "err", err) - } - return err - } - - return nil -} diff --git a/pkg/registry/apis/provisioning/jobs/migrate/legacy_resources.go b/pkg/registry/apis/provisioning/jobs/migrate/legacy_resources.go deleted file mode 100644 index 48add96ee16..00000000000 --- a/pkg/registry/apis/provisioning/jobs/migrate/legacy_resources.go +++ /dev/null @@ -1,265 +0,0 @@ -package migrate - -import ( - "context" - "fmt" - - "k8s.io/apimachinery/pkg/runtime/schema" - - provisioning "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1" - "github.com/grafana/grafana/apps/provisioning/pkg/repository" - "github.com/grafana/grafana/pkg/apimachinery/utils" - "github.com/grafana/grafana/pkg/registry/apis/dashboard/legacy" - "github.com/grafana/grafana/pkg/registry/apis/provisioning/jobs" - "github.com/grafana/grafana/pkg/registry/apis/provisioning/jobs/export" - "github.com/grafana/grafana/pkg/registry/apis/provisioning/resources" - "github.com/grafana/grafana/pkg/registry/apis/provisioning/resources/signature" - unifiedmigrations "github.com/grafana/grafana/pkg/storage/unified/migrations" - "github.com/grafana/grafana/pkg/storage/unified/parquet" - "github.com/grafana/grafana/pkg/storage/unified/resource" - "github.com/grafana/grafana/pkg/storage/unified/resourcepb" -) - -var _ resource.BulkResourceWriter = (*legacyResourceResourceMigrator)(nil) - -//go:generate mockery --name LegacyResourcesMigrator --structname MockLegacyResourcesMigrator --inpackage --filename mock_legacy_resources_migrator.go --with-expecter -type LegacyResourcesMigrator interface { - Migrate(ctx context.Context, rw repository.ReaderWriter, namespace string, opts provisioning.MigrateJobOptions, progress jobs.JobProgressRecorder) error -} - -type legacyResourcesMigrator struct { - repositoryResources resources.RepositoryResourcesFactory - parsers resources.ParserFactory - dashboardAccess legacy.MigrationDashboardAccessor - signerFactory signature.SignerFactory - clients resources.ClientFactory - exportFn export.ExportFn -} - -func NewLegacyResourcesMigrator( - repositoryResources resources.RepositoryResourcesFactory, - parsers resources.ParserFactory, - dashboardAccess legacy.MigrationDashboardAccessor, - signerFactory signature.SignerFactory, - clients resources.ClientFactory, - exportFn export.ExportFn, -) LegacyResourcesMigrator { - return &legacyResourcesMigrator{ - repositoryResources: repositoryResources, - parsers: parsers, - dashboardAccess: dashboardAccess, - signerFactory: signerFactory, - clients: clients, - exportFn: exportFn, - } -} - -func (m *legacyResourcesMigrator) Migrate(ctx context.Context, rw repository.ReaderWriter, namespace string, opts provisioning.MigrateJobOptions, progress jobs.JobProgressRecorder) error { - parser, err := m.parsers.GetParser(ctx, rw) - if err != nil { - return fmt.Errorf("get parser: %w", err) - } - - repositoryResources, err := m.repositoryResources.Client(ctx, rw) - if err != nil { - return fmt.Errorf("get repository resources: %w", err) - } - - // FIXME: signature is only relevant for repositories which support signature - // Not all repositories support history - signer, err := m.signerFactory.New(ctx, signature.SignOptions{ - Namespace: namespace, - History: opts.History, - }) - if err != nil { - return fmt.Errorf("get signer: %w", err) - } - - progress.SetMessage(ctx, "migrate folders from SQL") - clients, err := m.clients.Clients(ctx, namespace) - if err != nil { - return err - } - - // nothing special for the export for now - exportOpts := provisioning.ExportJobOptions{} - if err = m.exportFn(ctx, rw.Config().Name, exportOpts, clients, repositoryResources, progress); err != nil { - return fmt.Errorf("migrate folders from SQL: %w", err) - } - - progress.SetMessage(ctx, "migrate resources from SQL") - for _, kind := range resources.SupportedProvisioningResources { - if kind == resources.FolderResource { - continue // folders have special handling - } - - reader := newLegacyResourceMigrator( - rw, - m.dashboardAccess, - parser, - repositoryResources, - progress, - opts, - namespace, - kind.GroupResource(), - signer, - ) - - if err := reader.Migrate(ctx); err != nil { - return fmt.Errorf("migrate resource %s: %w", kind, err) - } - } - - return nil -} - -type legacyResourceResourceMigrator struct { - repo repository.ReaderWriter - dashboardAccess legacy.MigrationDashboardAccessor - parser resources.Parser - progress jobs.JobProgressRecorder - namespace string - kind schema.GroupResource - options provisioning.MigrateJobOptions - resources resources.RepositoryResources - signer signature.Signer - history map[string]string // UID >> file path -} - -func newLegacyResourceMigrator( - repo repository.ReaderWriter, - dashboardAccess legacy.MigrationDashboardAccessor, - parser resources.Parser, - resources resources.RepositoryResources, - progress jobs.JobProgressRecorder, - options provisioning.MigrateJobOptions, - namespace string, - kind schema.GroupResource, - signer signature.Signer, -) *legacyResourceResourceMigrator { - var history map[string]string - if options.History { - history = make(map[string]string) - } - return &legacyResourceResourceMigrator{ - repo: repo, - dashboardAccess: dashboardAccess, - parser: parser, - progress: progress, - options: options, - namespace: namespace, - kind: kind, - resources: resources, - signer: signer, - history: history, - } -} - -// Close implements resource.BulkResourceWriter. -func (r *legacyResourceResourceMigrator) Close() error { - return nil -} - -// CloseWithResults implements resource.BulkResourceWriter. -func (r *legacyResourceResourceMigrator) CloseWithResults() (*resourcepb.BulkResponse, error) { - return &resourcepb.BulkResponse{}, nil -} - -// Write implements resource.BulkResourceWriter. -func (r *legacyResourceResourceMigrator) Write(ctx context.Context, key *resourcepb.ResourceKey, value []byte) error { - // Reuse the same parse+cleanup logic - parsed, err := r.parser.Parse(ctx, &repository.FileInfo{ - Path: "", // empty path to ignore file system - Data: value, - }) - if err != nil { - return fmt.Errorf("unmarshal unstructured: %w", err) - } - - // clear anything so it will get written - parsed.Meta.SetManagerProperties(utils.ManagerProperties{}) - parsed.Meta.SetSourceProperties(utils.SourceProperties{}) - - // Add author signature to the context - ctx, err = r.signer.Sign(ctx, parsed.Meta) - if err != nil { - return fmt.Errorf("add author signature: %w", err) - } - - // TODO: this seems to be same logic as the export job - // TODO: we should use a kind safe manager here - fileName, err := r.resources.WriteResourceFileFromObject(ctx, parsed.Obj, resources.WriteOptions{ - Path: "", - Ref: "", - }) - - // When replaying history, the path to the file may change over time - // This happens when the title or folder change - if r.history != nil && err == nil { - name := parsed.Meta.GetName() - previous := r.history[name] - if previous != "" && previous != fileName { - err = r.repo.Delete(ctx, previous, "", fmt.Sprintf("moved to: %s", fileName)) - } - r.history[name] = fileName - } - - result := jobs.JobResourceResult{ - Name: parsed.Meta.GetName(), - Group: r.kind.Group, - Kind: parsed.GVK.Kind, - Action: repository.FileActionCreated, - Path: fileName, - } - - if err != nil { - result.Error = fmt.Errorf("writing resource %s/%s %s to file %s: %w", r.kind.Group, r.kind.Resource, parsed.Meta.GetName(), fileName, err) - } - - r.progress.Record(ctx, result) - if err := r.progress.TooManyErrors(); err != nil { - return err - } - - return nil -} - -func (r *legacyResourceResourceMigrator) Migrate(ctx context.Context) error { - r.progress.SetMessage(ctx, fmt.Sprintf("migrate %s resource", r.kind.Resource)) - - // Create a parquet migrator with this instance as the BulkResourceWriter - parquetClient := parquet.NewBulkResourceWriterClient(r) - migrator := unifiedmigrations.ProvideUnifiedMigratorParquet( - r.dashboardAccess, - parquetClient, - ) - - opts := legacy.MigrateOptions{ - Namespace: r.namespace, - WithHistory: r.options.History, - Resources: []schema.GroupResource{r.kind}, - OnlyCount: true, // first get the count - } - stats, err := migrator.Migrate(ctx, opts) - if err != nil { - return fmt.Errorf("unable to count legacy items %w", err) - } - - // FIXME: explain why we calculate it in this way - if len(stats.Summary) > 0 { - count := stats.Summary[0].Count // - history := stats.Summary[0].History - if history > count { - count = history // the number of items we will process - } - r.progress.SetTotal(ctx, int(count)) - } - - opts.OnlyCount = false // this time actually write - _, err = migrator.Migrate(ctx, opts) - if err != nil { - return fmt.Errorf("migrate legacy %s: %w", r.kind.Resource, err) - } - - return nil -} diff --git a/pkg/registry/apis/provisioning/jobs/migrate/legacy_resources_test.go b/pkg/registry/apis/provisioning/jobs/migrate/legacy_resources_test.go deleted file mode 100644 index 7f4318639c2..00000000000 --- a/pkg/registry/apis/provisioning/jobs/migrate/legacy_resources_test.go +++ /dev/null @@ -1,934 +0,0 @@ -package migrate - -import ( - "context" - "errors" - "fmt" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" - "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" - - provisioning "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1" - "github.com/grafana/grafana/apps/provisioning/pkg/repository" - "github.com/grafana/grafana/pkg/apimachinery/utils" - "github.com/grafana/grafana/pkg/registry/apis/dashboard/legacy" - "github.com/grafana/grafana/pkg/registry/apis/provisioning/jobs" - "github.com/grafana/grafana/pkg/registry/apis/provisioning/jobs/export" - "github.com/grafana/grafana/pkg/registry/apis/provisioning/resources" - "github.com/grafana/grafana/pkg/registry/apis/provisioning/resources/signature" - "github.com/grafana/grafana/pkg/storage/unified/resourcepb" -) - -func TestLegacyResourcesMigrator_Migrate(t *testing.T) { - t.Run("should fail when parser factory fails", func(t *testing.T) { - mockParserFactory := resources.NewMockParserFactory(t) - mockParserFactory.On("GetParser", mock.Anything, mock.Anything). - Return(nil, errors.New("parser factory error")) - - signerFactory := signature.NewMockSignerFactory(t) - mockClientFactory := resources.NewMockClientFactory(t) - mockExportFn := export.NewMockExportFn(t) - - migrator := NewLegacyResourcesMigrator( - nil, - mockParserFactory, - nil, - signerFactory, - mockClientFactory, - mockExportFn.Execute, - ) - - err := migrator.Migrate(context.Background(), nil, "test-namespace", provisioning.MigrateJobOptions{}, jobs.NewMockJobProgressRecorder(t)) - require.Error(t, err) - require.EqualError(t, err, "get parser: parser factory error") - - mockParserFactory.AssertExpectations(t) - mockExportFn.AssertExpectations(t) - mockClientFactory.AssertExpectations(t) - }) - - t.Run("should fail when repository resources factory fails", func(t *testing.T) { - mockParserFactory := resources.NewMockParserFactory(t) - mockParserFactory.On("GetParser", mock.Anything, mock.Anything). - Return(resources.NewMockParser(t), nil) - - mockRepoResourcesFactory := resources.NewMockRepositoryResourcesFactory(t) - mockRepoResourcesFactory.On("Client", mock.Anything, mock.Anything). - Return(nil, errors.New("repo resources factory error")) - signerFactory := signature.NewMockSignerFactory(t) - mockClientFactory := resources.NewMockClientFactory(t) - mockExportFn := export.NewMockExportFn(t) - - migrator := NewLegacyResourcesMigrator( - mockRepoResourcesFactory, - mockParserFactory, - nil, - signerFactory, - mockClientFactory, - mockExportFn.Execute, - ) - - err := migrator.Migrate(context.Background(), nil, "test-namespace", provisioning.MigrateJobOptions{}, jobs.NewMockJobProgressRecorder(t)) - require.Error(t, err) - require.EqualError(t, err, "get repository resources: repo resources factory error") - - mockParserFactory.AssertExpectations(t) - mockRepoResourcesFactory.AssertExpectations(t) - mockExportFn.AssertExpectations(t) - mockClientFactory.AssertExpectations(t) - }) - - t.Run("should fail when resource migration fails", func(t *testing.T) { - mockParserFactory := resources.NewMockParserFactory(t) - mockParserFactory.On("GetParser", mock.Anything, mock.Anything). - Return(resources.NewMockParser(t), nil) - - mockRepoResources := resources.NewMockRepositoryResources(t) - mockRepoResourcesFactory := resources.NewMockRepositoryResourcesFactory(t) - mockRepoResourcesFactory.On("Client", mock.Anything, mock.Anything). - Return(mockRepoResources, nil) - - mockDashboardAccess := legacy.NewMockMigrationDashboardAccessor(t) - mockDashboardAccess.On("CountResources", mock.Anything, mock.MatchedBy(func(opts legacy.MigrateOptions) bool { - return opts.OnlyCount && opts.Namespace == "test-namespace" - })).Return(&resourcepb.BulkResponse{}, errors.New("legacy migrator error")) - - progress := jobs.NewMockJobProgressRecorder(t) - progress.On("SetMessage", mock.Anything, mock.Anything).Return() - - signer := signature.NewMockSigner(t) - signerFactory := signature.NewMockSignerFactory(t) - signerFactory.On("New", mock.Anything, mock.Anything). - Return(signer, nil) - - mockClients := resources.NewMockResourceClients(t) - mockClientFactory := resources.NewMockClientFactory(t) - mockClientFactory.On("Clients", mock.Anything, "test-namespace"). - Return(mockClients, nil) - mockExportFn := export.NewMockExportFn(t) - - migrator := NewLegacyResourcesMigrator( - mockRepoResourcesFactory, - mockParserFactory, - mockDashboardAccess, - signerFactory, - mockClientFactory, - mockExportFn.Execute, - ) - repo := repository.NewMockRepository(t) - repo.On("Config").Return(&provisioning.Repository{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: "test-namespace", - Name: "test-repo", - }, - }) - mockExportFn.On("Execute", mock.Anything, mock.Anything, provisioning.ExportJobOptions{}, mockClients, mockRepoResources, mock.Anything). - Return(nil) - - err := migrator.Migrate(context.Background(), repo, "test-namespace", provisioning.MigrateJobOptions{}, progress) - require.Error(t, err) - require.Contains(t, err.Error(), "migrate resource") - - mockParserFactory.AssertExpectations(t) - mockRepoResourcesFactory.AssertExpectations(t) - mockDashboardAccess.AssertExpectations(t) - progress.AssertExpectations(t) - mockExportFn.AssertExpectations(t) - mockClientFactory.AssertExpectations(t) - mockClients.AssertExpectations(t) - repo.AssertExpectations(t) - }) - t.Run("should fail when client creation fails", func(t *testing.T) { - mockParserFactory := resources.NewMockParserFactory(t) - mockParserFactory.On("GetParser", mock.Anything, mock.Anything). - Return(resources.NewMockParser(t), nil) - - mockRepoResources := resources.NewMockRepositoryResources(t) - mockRepoResourcesFactory := resources.NewMockRepositoryResourcesFactory(t) - mockRepoResourcesFactory.On("Client", mock.Anything, mock.Anything). - Return(mockRepoResources, nil) - - mockSigner := signature.NewMockSigner(t) - mockSignerFactory := signature.NewMockSignerFactory(t) - mockSignerFactory.On("New", mock.Anything, mock.Anything). - Return(mockSigner, nil) - - mockClientFactory := resources.NewMockClientFactory(t) - mockClientFactory.On("Clients", mock.Anything, "test-namespace"). - Return(nil, errors.New("client creation error")) - - mockExportFn := export.NewMockExportFn(t) - - progress := jobs.NewMockJobProgressRecorder(t) - progress.On("SetMessage", mock.Anything, "migrate folders from SQL").Return() - - migrator := NewLegacyResourcesMigrator( - mockRepoResourcesFactory, - mockParserFactory, - nil, - mockSignerFactory, - mockClientFactory, - mockExportFn.Execute, - ) - - repo := repository.NewMockRepository(t) - err := migrator.Migrate(context.Background(), repo, "test-namespace", provisioning.MigrateJobOptions{}, progress) - require.Error(t, err) - require.EqualError(t, err, "client creation error") - - mockParserFactory.AssertExpectations(t) - mockRepoResourcesFactory.AssertExpectations(t) - mockSignerFactory.AssertExpectations(t) - mockClientFactory.AssertExpectations(t) - progress.AssertExpectations(t) - mockExportFn.AssertExpectations(t) - repo.AssertExpectations(t) - }) - - t.Run("should fail when signer factory fails", func(t *testing.T) { - mockParserFactory := resources.NewMockParserFactory(t) - mockParserFactory.On("GetParser", mock.Anything, mock.Anything). - Return(resources.NewMockParser(t), nil) - - mockRepoResources := resources.NewMockRepositoryResources(t) - mockRepoResourcesFactory := resources.NewMockRepositoryResourcesFactory(t) - mockRepoResourcesFactory.On("Client", mock.Anything, mock.Anything). - Return(mockRepoResources, nil) - - mockSignerFactory := signature.NewMockSignerFactory(t) - mockSignerFactory.On("New", mock.Anything, signature.SignOptions{ - Namespace: "test-namespace", - History: true, - }).Return(nil, fmt.Errorf("signer factory error")) - - mockClientFactory := resources.NewMockClientFactory(t) - mockExportFn := export.NewMockExportFn(t) - - progress := jobs.NewMockJobProgressRecorder(t) - migrator := NewLegacyResourcesMigrator( - mockRepoResourcesFactory, - mockParserFactory, - nil, - mockSignerFactory, - mockClientFactory, - mockExportFn.Execute, - ) - - err := migrator.Migrate(context.Background(), nil, "test-namespace", provisioning.MigrateJobOptions{ - History: true, - }, progress) - require.Error(t, err) - require.EqualError(t, err, "get signer: signer factory error") - - mockParserFactory.AssertExpectations(t) - mockRepoResourcesFactory.AssertExpectations(t) - mockSignerFactory.AssertExpectations(t) - mockClientFactory.AssertExpectations(t) - progress.AssertExpectations(t) - mockExportFn.AssertExpectations(t) - }) - t.Run("should fail when folder export fails", func(t *testing.T) { - mockParser := resources.NewMockParser(t) - mockParserFactory := resources.NewMockParserFactory(t) - mockParserFactory.On("GetParser", mock.Anything, mock.Anything). - Return(mockParser, nil) - - mockRepoResources := resources.NewMockRepositoryResources(t) - mockRepoResourcesFactory := resources.NewMockRepositoryResourcesFactory(t) - mockRepoResourcesFactory.On("Client", mock.Anything, mock.Anything). - Return(mockRepoResources, nil) - - mockSigner := signature.NewMockSigner(t) - mockSignerFactory := signature.NewMockSignerFactory(t) - mockSignerFactory.On("New", mock.Anything, signature.SignOptions{ - Namespace: "test-namespace", - History: false, - }).Return(mockSigner, nil) - - mockClients := resources.NewMockResourceClients(t) - mockClientFactory := resources.NewMockClientFactory(t) - mockClientFactory.On("Clients", mock.Anything, "test-namespace"). - Return(mockClients, nil) - - mockExportFn := export.NewMockExportFn(t) - mockExportFn.On("Execute", mock.Anything, mock.Anything, provisioning.ExportJobOptions{}, mockClients, mockRepoResources, mock.Anything). - Return(fmt.Errorf("export error")) - - progress := jobs.NewMockJobProgressRecorder(t) - progress.On("SetMessage", mock.Anything, "migrate folders from SQL").Return() - - migrator := NewLegacyResourcesMigrator( - mockRepoResourcesFactory, - mockParserFactory, - nil, - mockSignerFactory, - mockClientFactory, - mockExportFn.Execute, - ) - repo := repository.NewMockRepository(t) - repo.On("Config").Return(&provisioning.Repository{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: "test-namespace", - Name: "test-repo", - }, - }) - - err := migrator.Migrate(context.Background(), repo, "test-namespace", provisioning.MigrateJobOptions{}, progress) - require.Error(t, err) - require.Contains(t, err.Error(), "migrate folders from SQL: export error") - - mockParserFactory.AssertExpectations(t) - mockRepoResourcesFactory.AssertExpectations(t) - mockSignerFactory.AssertExpectations(t) - mockClientFactory.AssertExpectations(t) - mockExportFn.AssertExpectations(t) - progress.AssertExpectations(t) - }) - - t.Run("should successfully migrate all resources", func(t *testing.T) { - mockParser := resources.NewMockParser(t) - mockParserFactory := resources.NewMockParserFactory(t) - mockParserFactory.On("GetParser", mock.Anything, mock.Anything). - Return(mockParser, nil) - - mockRepoResources := resources.NewMockRepositoryResources(t) - mockRepoResourcesFactory := resources.NewMockRepositoryResourcesFactory(t) - mockRepoResourcesFactory.On("Client", mock.Anything, mock.Anything). - Return(mockRepoResources, nil) - - mockSigner := signature.NewMockSigner(t) - mockSignerFactory := signature.NewMockSignerFactory(t) - mockSignerFactory.On("New", mock.Anything, signature.SignOptions{ - Namespace: "test-namespace", - History: true, - }).Return(mockSigner, nil) - - mockDashboardAccess := legacy.NewMockMigrationDashboardAccessor(t) - // Mock CountResources for the count phase - mockDashboardAccess.On("CountResources", mock.Anything, mock.MatchedBy(func(opts legacy.MigrateOptions) bool { - return opts.OnlyCount && opts.Namespace == "test-namespace" - })).Return(&resourcepb.BulkResponse{}, nil).Once() - // Mock MigrateDashboards for the actual migration phase (dashboards resource) - mockDashboardAccess.On("MigrateDashboards", mock.Anything, mock.Anything, mock.MatchedBy(func(opts legacy.MigrateOptions) bool { - return !opts.OnlyCount && opts.Namespace == "test-namespace" - }), mock.Anything).Return(&legacy.BlobStoreInfo{ - Count: 10, - Size: 5, - }, nil).Once() - - mockClients := resources.NewMockResourceClients(t) - mockClientFactory := resources.NewMockClientFactory(t) - mockClientFactory.On("Clients", mock.Anything, "test-namespace"). - Return(mockClients, nil) - mockExportFn := export.NewMockExportFn(t) - - progress := jobs.NewMockJobProgressRecorder(t) - progress.On("SetMessage", mock.Anything, "migrate folders from SQL").Return() - progress.On("SetMessage", mock.Anything, "migrate resources from SQL").Return() - progress.On("SetMessage", mock.Anything, "migrate dashboards resource").Return() - - migrator := NewLegacyResourcesMigrator( - mockRepoResourcesFactory, - mockParserFactory, - mockDashboardAccess, - mockSignerFactory, - mockClientFactory, - mockExportFn.Execute, - ) - - repo := repository.NewMockRepository(t) - repo.On("Config").Return(&provisioning.Repository{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: "test-namespace", - Name: "test-repo", - }, - }) - mockExportFn.On("Execute", mock.Anything, mock.Anything, provisioning.ExportJobOptions{}, mockClients, mockRepoResources, mock.Anything). - Return(nil) - - err := migrator.Migrate(context.Background(), repo, "test-namespace", provisioning.MigrateJobOptions{ - History: true, - }, progress) - require.NoError(t, err) - - mockParserFactory.AssertExpectations(t) - mockRepoResourcesFactory.AssertExpectations(t) - mockDashboardAccess.AssertExpectations(t) - mockClientFactory.AssertExpectations(t) - mockExportFn.AssertExpectations(t) - progress.AssertExpectations(t) - mockClients.AssertExpectations(t) - }) -} - -func TestLegacyResourceResourceMigrator_Write(t *testing.T) { - t.Run("should fail when parser fails", func(t *testing.T) { - mockParser := resources.NewMockParser(t) - mockParser.On("Parse", mock.Anything, mock.Anything). - Return(nil, errors.New("parser error")) - - progress := jobs.NewMockJobProgressRecorder(t) - - migrator := newLegacyResourceMigrator( - nil, - nil, - mockParser, - nil, - progress, - provisioning.MigrateJobOptions{}, - "test-namespace", - schema.GroupResource{Group: "test.grafana.app", Resource: "tests"}, - signature.NewGrafanaSigner(), - ) - - err := migrator.Write(context.Background(), &resourcepb.ResourceKey{}, []byte("test")) - require.Error(t, err) - require.Contains(t, err.Error(), "unmarshal unstructured") - - mockParser.AssertExpectations(t) - }) - - t.Run("records error when create resource file fails", func(t *testing.T) { - mockParser := resources.NewMockParser(t) - obj := &unstructured.Unstructured{ - Object: map[string]any{ - "metadata": map[string]any{ - "name": "test", - }, - }, - } - meta, err := utils.MetaAccessor(obj) - require.NoError(t, err) - - mockParser.On("Parse", mock.Anything, mock.Anything). - Return(&resources.ParsedResource{ - Meta: meta, - Obj: obj, - }, nil) - - mockRepoResources := resources.NewMockRepositoryResources(t) - mockRepoResources.On("WriteResourceFileFromObject", mock.Anything, mock.Anything, mock.Anything). - Return("", errors.New("create file error")) - - progress := jobs.NewMockJobProgressRecorder(t) - progress.On("Record", mock.Anything, mock.MatchedBy(func(result jobs.JobResourceResult) bool { - return result.Action == repository.FileActionCreated && - result.Name == "test" && - result.Error != nil && - result.Error.Error() == "writing resource test.grafana.app/tests test to file : create file error" - })).Return() - progress.On("TooManyErrors").Return(nil) - - migrator := newLegacyResourceMigrator( - nil, - nil, - mockParser, - mockRepoResources, - progress, - provisioning.MigrateJobOptions{}, - "test-namespace", - schema.GroupResource{Group: "test.grafana.app", Resource: "tests"}, - signature.NewGrafanaSigner(), - ) - - err = migrator.Write(context.Background(), &resourcepb.ResourceKey{}, []byte("test")) - require.NoError(t, err) // Error is recorded but not returned - - mockParser.AssertExpectations(t) - mockRepoResources.AssertExpectations(t) - progress.AssertExpectations(t) - }) - - t.Run("should fail when signer fails", func(t *testing.T) { - mockParser := resources.NewMockParser(t) - obj := &unstructured.Unstructured{ - Object: map[string]any{ - "metadata": map[string]any{ - "name": "test", - }, - }, - } - meta, err := utils.MetaAccessor(obj) - require.NoError(t, err) - - mockParser.On("Parse", mock.Anything, mock.Anything). - Return(&resources.ParsedResource{ - Meta: meta, - Obj: obj, - }, nil) - - mockSigner := signature.NewMockSigner(t) - mockSigner.On("Sign", mock.Anything, meta). - Return(nil, errors.New("signing error")) - - progress := jobs.NewMockJobProgressRecorder(t) - migrator := newLegacyResourceMigrator( - nil, - nil, - mockParser, - nil, - progress, - provisioning.MigrateJobOptions{}, - "test-namespace", - schema.GroupResource{Group: "test.grafana.app", Resource: "tests"}, - mockSigner, - ) - - err = migrator.Write(context.Background(), &resourcepb.ResourceKey{}, []byte("test")) - require.Error(t, err) - require.EqualError(t, err, "add author signature: signing error") - - mockParser.AssertExpectations(t) - mockSigner.AssertExpectations(t) - progress.AssertExpectations(t) - }) - - t.Run("should successfully add author signature", func(t *testing.T) { - mockParser := resources.NewMockParser(t) - obj := &unstructured.Unstructured{ - Object: map[string]any{ - "metadata": map[string]any{ - "name": "test", - }, - }, - } - meta, err := utils.MetaAccessor(obj) - require.NoError(t, err) - - mockParser.On("Parse", mock.Anything, mock.Anything). - Return(&resources.ParsedResource{ - Meta: meta, - Obj: obj, - }, nil) - - mockSigner := signature.NewMockSigner(t) - signedCtx := repository.WithAuthorSignature(context.Background(), repository.CommitSignature{ - Name: "test-user", - Email: "test@example.com", - }) - mockSigner.On("Sign", mock.Anything, meta). - Return(signedCtx, nil) - - mockRepoResources := resources.NewMockRepositoryResources(t) - mockRepoResources.On("WriteResourceFileFromObject", signedCtx, mock.Anything, mock.Anything). - Return("test/path", nil) - - progress := jobs.NewMockJobProgressRecorder(t) - progress.On("Record", mock.Anything, mock.MatchedBy(func(result jobs.JobResourceResult) bool { - return result.Action == repository.FileActionCreated && - result.Name == "test" && - result.Error == nil && - result.Path == "test/path" - })).Return() - progress.On("TooManyErrors").Return(nil) - - migrator := newLegacyResourceMigrator( - nil, - nil, - mockParser, - mockRepoResources, - progress, - provisioning.MigrateJobOptions{}, - "test-namespace", - schema.GroupResource{Group: "test.grafana.app", Resource: "tests"}, - mockSigner, - ) - - err = migrator.Write(context.Background(), &resourcepb.ResourceKey{}, []byte("test")) - require.NoError(t, err) - - mockParser.AssertExpectations(t) - mockSigner.AssertExpectations(t) - mockRepoResources.AssertExpectations(t) - progress.AssertExpectations(t) - }) - - t.Run("should maintain history", func(t *testing.T) { - progress := jobs.NewMockJobProgressRecorder(t) - progress.On("Record", mock.Anything, mock.Anything).Return() - progress.On("TooManyErrors").Return(nil) - - mockParser := resources.NewMockParser(t) - obj := &unstructured.Unstructured{ - Object: map[string]any{ - "metadata": map[string]any{ - "name": "test", - }, - }, - } - meta, _ := utils.MetaAccessor(obj) - mockParser.On("Parse", mock.Anything, mock.Anything). - Return(&resources.ParsedResource{ - Meta: meta, - Obj: obj, - }, nil) - - mockRepo := repository.NewMockRepository(t) - - mockRepoResources := resources.NewMockRepositoryResources(t) - writeResourceFileFromObject := mockRepoResources.On("WriteResourceFileFromObject", mock.Anything, mock.Anything, mock.Anything) - - migrator := newLegacyResourceMigrator( - mockRepo, - nil, - mockParser, - mockRepoResources, - progress, - provisioning.MigrateJobOptions{ - History: true, - }, - "test-namespace", - schema.GroupResource{Group: "test.grafana.app", Resource: "tests"}, - signature.NewGrafanaSigner(), - ) - - writeResourceFileFromObject.Return("aaaa.json", nil) - err := migrator.Write(context.Background(), &resourcepb.ResourceKey{}, []byte("")) - require.NoError(t, err) - require.Equal(t, "aaaa.json", migrator.history["test"], "kept track of the old files") - - // Change the result file name - writeResourceFileFromObject.Return("bbbb.json", nil) - mockRepo.On("Delete", mock.Anything, "aaaa.json", "", "moved to: bbbb.json"). - Return(nil).Once() - - err = migrator.Write(context.Background(), &resourcepb.ResourceKey{}, []byte("")) - require.NoError(t, err) - require.Equal(t, "bbbb.json", migrator.history["test"], "kept track of the old files") - - mockParser.AssertExpectations(t) - mockRepoResources.AssertExpectations(t) - progress.AssertExpectations(t) - }) - - t.Run("should successfully write resource", func(t *testing.T) { - mockParser := resources.NewMockParser(t) - obj := &unstructured.Unstructured{ - Object: map[string]any{ - "metadata": map[string]any{ - "name": "test", - }, - }, - } - meta, err := utils.MetaAccessor(obj) - require.NoError(t, err) - meta.SetManagerProperties(utils.ManagerProperties{ - Kind: utils.ManagerKindRepo, - Identity: "test", - AllowsEdits: true, - Suspended: false, - }) - meta.SetSourceProperties(utils.SourceProperties{ - Path: "test", - Checksum: "test", - TimestampMillis: 1234567890, - }) - - mockParser.On("Parse", mock.Anything, mock.MatchedBy(func(info *repository.FileInfo) bool { - return info != nil && info.Path == "" && string(info.Data) == "test" - })). - Return(&resources.ParsedResource{ - Meta: meta, - Obj: obj, - }, nil) - - mockRepoResources := resources.NewMockRepositoryResources(t) - mockRepoResources.On("WriteResourceFileFromObject", mock.Anything, mock.MatchedBy(func(obj *unstructured.Unstructured) bool { - if obj == nil { - return false - } - if obj.GetName() != "test" { - return false - } - - meta, err := utils.MetaAccessor(obj) - require.NoError(t, err) - managerProps, _ := meta.GetManagerProperties() - sourceProps, _ := meta.GetSourceProperties() - - return assert.Zero(t, sourceProps) && assert.Zero(t, managerProps) - }), resources.WriteOptions{ - Path: "", - Ref: "", - }). - Return("test/path", nil) - - progress := jobs.NewMockJobProgressRecorder(t) - progress.On("Record", mock.Anything, mock.MatchedBy(func(result jobs.JobResourceResult) bool { - return result.Action == repository.FileActionCreated && - result.Name == "test" && - result.Error == nil && - result.Kind == "" && // empty kind - result.Group == "test.grafana.app" && - result.Path == "test/path" - })).Return() - progress.On("TooManyErrors").Return(nil) - - migrator := newLegacyResourceMigrator( - nil, - nil, - mockParser, - mockRepoResources, - progress, - provisioning.MigrateJobOptions{}, - "test-namespace", - schema.GroupResource{Group: "test.grafana.app", Resource: "tests"}, - signature.NewGrafanaSigner(), - ) - - err = migrator.Write(context.Background(), &resourcepb.ResourceKey{}, []byte("test")) - require.NoError(t, err) - - mockParser.AssertExpectations(t) - mockRepoResources.AssertExpectations(t) - progress.AssertExpectations(t) - }) - - t.Run("should fail when too many errors", func(t *testing.T) { - mockParser := resources.NewMockParser(t) - obj := &unstructured.Unstructured{ - Object: map[string]any{ - "metadata": map[string]any{ - "name": "test", - }, - }, - } - meta, err := utils.MetaAccessor(obj) - require.NoError(t, err) - - mockParser.On("Parse", mock.Anything, mock.Anything). - Return(&resources.ParsedResource{ - Meta: meta, - Obj: obj, - }, nil) - - mockRepoResources := resources.NewMockRepositoryResources(t) - mockRepoResources.On("WriteResourceFileFromObject", mock.Anything, mock.Anything, resources.WriteOptions{}). - Return("test/path", nil) - - progress := jobs.NewMockJobProgressRecorder(t) - progress.On("Record", mock.Anything, mock.Anything).Return() - progress.On("TooManyErrors").Return(errors.New("too many errors")) - - migrator := newLegacyResourceMigrator( - nil, - nil, - mockParser, - mockRepoResources, - progress, - provisioning.MigrateJobOptions{}, - "test-namespace", - schema.GroupResource{Group: "test.grafana.app", Resource: "tests"}, - signature.NewGrafanaSigner(), - ) - - err = migrator.Write(context.Background(), &resourcepb.ResourceKey{}, []byte("test")) - require.EqualError(t, err, "too many errors") - - mockParser.AssertExpectations(t) - mockRepoResources.AssertExpectations(t) - progress.AssertExpectations(t) - }) -} - -func TestLegacyResourceResourceMigrator_Migrate(t *testing.T) { - t.Run("should fail when legacy migrate count fails", func(t *testing.T) { - mockDashboardAccess := legacy.NewMockMigrationDashboardAccessor(t) - mockDashboardAccess.On("CountResources", mock.Anything, mock.MatchedBy(func(opts legacy.MigrateOptions) bool { - return opts.OnlyCount && opts.Namespace == "test-namespace" - })).Return(&resourcepb.BulkResponse{}, errors.New("count error")) - - progress := jobs.NewMockJobProgressRecorder(t) - progress.On("SetMessage", mock.Anything, mock.Anything).Return() - - migrator := newLegacyResourceMigrator( - nil, - mockDashboardAccess, - nil, - nil, - progress, - provisioning.MigrateJobOptions{}, - "test-namespace", - schema.GroupResource{Group: "test.grafana.app", Resource: "tests"}, - signature.NewGrafanaSigner(), - ) - - err := migrator.Migrate(context.Background()) - require.Error(t, err) - require.Contains(t, err.Error(), "unable to count legacy items") - - mockDashboardAccess.AssertExpectations(t) - progress.AssertExpectations(t) - }) - - t.Run("should fail when legacy migrate write fails", func(t *testing.T) { - mockDashboardAccess := legacy.NewMockMigrationDashboardAccessor(t) - mockDashboardAccess.On("CountResources", mock.Anything, mock.MatchedBy(func(opts legacy.MigrateOptions) bool { - return opts.OnlyCount && opts.Namespace == "test-namespace" - })).Return(&resourcepb.BulkResponse{}, nil).Once() // Count phase - // For test-resources GroupResource, we don't know which method it will call, but since it's not dashboards/folders/librarypanels, - // the Migrate will fail trying to map the resource type. Let's make it dashboards for this test. - mockDashboardAccess.On("MigrateDashboards", mock.Anything, mock.Anything, mock.MatchedBy(func(opts legacy.MigrateOptions) bool { - return !opts.OnlyCount && opts.Namespace == "test-namespace" - }), mock.Anything).Return(nil, errors.New("write error")).Once() // Write phase - - progress := jobs.NewMockJobProgressRecorder(t) - progress.On("SetMessage", mock.Anything, mock.Anything).Return() - - migrator := newLegacyResourceMigrator( - nil, - mockDashboardAccess, - nil, - nil, - progress, - provisioning.MigrateJobOptions{}, - "test-namespace", - schema.GroupResource{Group: "dashboard.grafana.app", Resource: "dashboards"}, - signature.NewGrafanaSigner(), - ) - - err := migrator.Migrate(context.Background()) - require.Error(t, err) - require.Contains(t, err.Error(), "migrate legacy dashboards: write error") - - mockDashboardAccess.AssertExpectations(t) - progress.AssertExpectations(t) - }) - - t.Run("should successfully migrate resource", func(t *testing.T) { - mockDashboardAccess := legacy.NewMockMigrationDashboardAccessor(t) - mockDashboardAccess.On("CountResources", mock.Anything, mock.MatchedBy(func(opts legacy.MigrateOptions) bool { - return opts.OnlyCount && opts.Namespace == "test-namespace" - })).Return(&resourcepb.BulkResponse{}, nil).Once() // Count phase - mockDashboardAccess.On("MigrateDashboards", mock.Anything, mock.Anything, mock.MatchedBy(func(opts legacy.MigrateOptions) bool { - return !opts.OnlyCount && opts.Namespace == "test-namespace" - }), mock.Anything).Return(&legacy.BlobStoreInfo{}, nil).Once() // Write phase - - progress := jobs.NewMockJobProgressRecorder(t) - progress.On("SetMessage", mock.Anything, mock.Anything).Return() - - migrator := newLegacyResourceMigrator( - nil, - mockDashboardAccess, - nil, - nil, - progress, - provisioning.MigrateJobOptions{}, - "test-namespace", - schema.GroupResource{Group: "dashboard.grafana.app", Resource: "dashboards"}, - signature.NewGrafanaSigner(), - ) - - err := migrator.Migrate(context.Background()) - require.NoError(t, err) - - mockDashboardAccess.AssertExpectations(t) - progress.AssertExpectations(t) - }) - t.Run("should set total to history if history is greater than count", func(t *testing.T) { - mockDashboardAccess := legacy.NewMockMigrationDashboardAccessor(t) - mockDashboardAccess.On("CountResources", mock.Anything, mock.MatchedBy(func(opts legacy.MigrateOptions) bool { - return opts.OnlyCount && opts.Namespace == "test-namespace" - })).Return(&resourcepb.BulkResponse{ - Summary: []*resourcepb.BulkResponse_Summary{ - { - Group: "dashboard.grafana.app", - Resource: "dashboards", - Count: 1, - History: 100, - }, - }, - }, nil).Once() // Count phase - mockDashboardAccess.On("MigrateDashboards", mock.Anything, mock.Anything, mock.MatchedBy(func(opts legacy.MigrateOptions) bool { - return !opts.OnlyCount && opts.Namespace == "test-namespace" - }), mock.Anything).Return(&legacy.BlobStoreInfo{}, nil).Once() // Write phase - - progress := jobs.NewMockJobProgressRecorder(t) - progress.On("SetMessage", mock.Anything, mock.Anything).Return() - progress.On("SetTotal", mock.Anything, 100).Return() - - migrator := newLegacyResourceMigrator( - nil, - mockDashboardAccess, - nil, - nil, - progress, - provisioning.MigrateJobOptions{}, - "test-namespace", - schema.GroupResource{Group: "dashboard.grafana.app", Resource: "dashboards"}, - signature.NewGrafanaSigner(), - ) - - err := migrator.Migrate(context.Background()) - require.NoError(t, err) - - mockDashboardAccess.AssertExpectations(t) - progress.AssertExpectations(t) - }) - t.Run("should set total to count if history is less than count", func(t *testing.T) { - mockDashboardAccess := legacy.NewMockMigrationDashboardAccessor(t) - mockDashboardAccess.On("CountResources", mock.Anything, mock.MatchedBy(func(opts legacy.MigrateOptions) bool { - return opts.OnlyCount && opts.Namespace == "test-namespace" - })).Return(&resourcepb.BulkResponse{ - Summary: []*resourcepb.BulkResponse_Summary{ - { - Group: "dashboard.grafana.app", - Resource: "dashboards", - Count: 200, - History: 1, - }, - }, - }, nil).Once() // Count phase - mockDashboardAccess.On("MigrateDashboards", mock.Anything, mock.Anything, mock.MatchedBy(func(opts legacy.MigrateOptions) bool { - return !opts.OnlyCount && opts.Namespace == "test-namespace" - }), mock.Anything).Return(&legacy.BlobStoreInfo{}, nil).Once() // Write phase - - progress := jobs.NewMockJobProgressRecorder(t) - progress.On("SetMessage", mock.Anything, mock.Anything).Return() - progress.On("SetTotal", mock.Anything, 200).Return() - signer := signature.NewMockSigner(t) - - migrator := newLegacyResourceMigrator( - nil, - mockDashboardAccess, - nil, - nil, - progress, - provisioning.MigrateJobOptions{}, - "test-namespace", - schema.GroupResource{Group: "dashboard.grafana.app", Resource: "dashboards"}, - signer, - ) - - err := migrator.Migrate(context.Background()) - require.NoError(t, err) - - mockDashboardAccess.AssertExpectations(t) - progress.AssertExpectations(t) - }) -} - -func TestLegacyResourceResourceMigrator_Close(t *testing.T) { - t.Run("should return nil error", func(t *testing.T) { - migrator := &legacyResourceResourceMigrator{} - err := migrator.Close() - require.NoError(t, err) - }) -} - -func TestLegacyResourceResourceMigrator_CloseWithResults(t *testing.T) { - t.Run("should return empty bulk response and nil error", func(t *testing.T) { - migrator := &legacyResourceResourceMigrator{} - response, err := migrator.CloseWithResults() - - require.NoError(t, err) - require.NotNil(t, response) - require.IsType(t, &resourcepb.BulkResponse{}, response) - require.Empty(t, response.Summary) - }) -} diff --git a/pkg/registry/apis/provisioning/jobs/migrate/legacy_test.go b/pkg/registry/apis/provisioning/jobs/migrate/legacy_test.go deleted file mode 100644 index 6b16fb3da7a..00000000000 --- a/pkg/registry/apis/provisioning/jobs/migrate/legacy_test.go +++ /dev/null @@ -1,440 +0,0 @@ -package migrate - -import ( - "context" - "errors" - "testing" - "time" - - mock "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - - 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/jobs" -) - -func TestWrapWithStageFn(t *testing.T) { - t.Run("should return error when repository is not a ReaderWriter", func(t *testing.T) { - // Setup - ctx := context.Background() - // Create the wrapper function that matches WrapWithCloneFn signature - wrapFn := func(ctx context.Context, rw repository.Repository, stageOpts repository.StageOptions, fn func(repository.Repository, bool) error) error { - // pass a reader to function call - repo := repository.NewMockReader(t) - return fn(repo, true) - } - - legacyFoldersMigrator := NewLegacyMigrator( - NewMockLegacyResourcesMigrator(t), - NewMockStorageSwapper(t), - jobs.NewMockWorker(t), - wrapFn, - ) - - progress := jobs.NewMockJobProgressRecorder(t) - progress.On("StrictMaxErrors", 1).Return() - progress.On("SetMessage", mock.Anything, "migrating legacy resources").Return() - - // Execute - repo := repository.NewMockRepository(t) - repo.On("Config").Return(&provisioning.Repository{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: "test-namespace", - }, - }) - err := legacyFoldersMigrator.Migrate(ctx, repo, provisioning.MigrateJobOptions{}, progress) - // Assert - require.Error(t, err) - require.Contains(t, err.Error(), "migration job submitted targeting repository that is not a ReaderWriter") - }) -} -func TestWrapWithCloneFn_Error(t *testing.T) { - t.Run("should return error when wrapFn fails", func(t *testing.T) { - // Setup - ctx := context.Background() - expectedErr := errors.New("clone failed") - - // Create the wrapper function that returns an error - wrapFn := func(ctx context.Context, rw repository.Repository, stageOpts repository.StageOptions, fn func(repository.Repository, bool) error) error { - return expectedErr - } - - legacyMigrator := NewLegacyMigrator( - NewMockLegacyResourcesMigrator(t), - NewMockStorageSwapper(t), - jobs.NewMockWorker(t), - wrapFn, - ) - - progress := jobs.NewMockJobProgressRecorder(t) - progress.On("StrictMaxErrors", 1).Return() - progress.On("SetMessage", mock.Anything, "migrating legacy resources").Return() - // Execute - repo := repository.NewMockRepository(t) - repo.On("Config").Return(&provisioning.Repository{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: "test-namespace", - }, - }) - - err := legacyMigrator.Migrate(ctx, repo, provisioning.MigrateJobOptions{}, progress) - - // Assert - require.Error(t, err) - require.Contains(t, err.Error(), "migrate from SQL: clone failed") - }) -} - -func TestLegacyMigrator_MigrateFails(t *testing.T) { - t.Run("should return error when legacyMigrator.Migrate fails", func(t *testing.T) { - // Setup - ctx := context.Background() - expectedErr := errors.New("migration failed") - - mockLegacyMigrator := NewMockLegacyResourcesMigrator(t) - mockLegacyMigrator.On("Migrate", mock.Anything, mock.Anything, "test-namespace", mock.Anything, mock.Anything). - Return(expectedErr) - - mockStorageSwapper := NewMockStorageSwapper(t) - mockWorker := jobs.NewMockWorker(t) - - // Create a wrapper function that calls the provided function - wrapFn := func(ctx context.Context, rw repository.Repository, stageOpts repository.StageOptions, fn func(repository.Repository, bool) error) error { - return fn(rw, true) - } - - legacyMigrator := NewLegacyMigrator( - mockLegacyMigrator, - mockStorageSwapper, - mockWorker, - wrapFn, - ) - - progress := jobs.NewMockJobProgressRecorder(t) - progress.On("StrictMaxErrors", 1).Return() - progress.On("SetMessage", mock.Anything, "migrating legacy resources").Return() - - // Execute - repo := repository.NewMockRepository(t) - repo.On("Config").Return(&provisioning.Repository{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: "test-namespace", - }, - }) - - err := legacyMigrator.Migrate(ctx, repo, provisioning.MigrateJobOptions{}, progress) - - // Assert - require.Error(t, err) - require.Contains(t, err.Error(), "migrate from SQL: migration failed") - - // Storage swapper should not be called when migration fails - mockStorageSwapper.AssertNotCalled(t, "WipeUnifiedAndSetMigratedFlag") - }) -} - -func TestLegacyMigrator_ResetUnifiedStorageFails(t *testing.T) { - t.Run("should return error when storage reset fails", func(t *testing.T) { - // Setup - ctx := context.Background() - expectedErr := errors.New("reset failed") - - mockLegacyMigrator := NewMockLegacyResourcesMigrator(t) - mockLegacyMigrator.On("Migrate", mock.Anything, mock.Anything, "test-namespace", mock.Anything, mock.Anything). - Return(nil) - - mockStorageSwapper := NewMockStorageSwapper(t) - mockStorageSwapper.On("WipeUnifiedAndSetMigratedFlag", mock.Anything, "test-namespace"). - Return(expectedErr) - - mockWorker := jobs.NewMockWorker(t) - - // Create a wrapper function that calls the provided function - wrapFn := func(ctx context.Context, rw repository.Repository, stageOpts repository.StageOptions, fn func(repository.Repository, bool) error) error { - return fn(rw, true) - } - - legacyMigrator := NewLegacyMigrator( - mockLegacyMigrator, - mockStorageSwapper, - mockWorker, - wrapFn, - ) - - progress := jobs.NewMockJobProgressRecorder(t) - progress.On("StrictMaxErrors", 1).Return() - progress.On("SetMessage", mock.Anything, "migrating legacy resources").Return() - progress.On("SetMessage", mock.Anything, "resetting unified storage").Return() - - // Execute - repo := repository.NewMockRepository(t) - repo.On("Config").Return(&provisioning.Repository{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: "test-namespace", - }, - }) - - err := legacyMigrator.Migrate(ctx, repo, provisioning.MigrateJobOptions{}, progress) - - // Assert - require.Error(t, err) - require.Contains(t, err.Error(), "unable to reset unified storage") - - // Sync worker should not be called when reset fails - mockWorker.AssertNotCalled(t, "Process") - }) -} - -func TestLegacyMigrator_SyncFails(t *testing.T) { - t.Run("should revert storage settings when sync fails", func(t *testing.T) { - // Setup - ctx := context.Background() - expectedErr := errors.New("sync failed") - - mockLegacyMigrator := NewMockLegacyResourcesMigrator(t) - mockLegacyMigrator.On("Migrate", mock.Anything, mock.Anything, "test-namespace", mock.Anything, mock.Anything). - Return(nil) - - mockStorageSwapper := NewMockStorageSwapper(t) - mockStorageSwapper.On("WipeUnifiedAndSetMigratedFlag", mock.Anything, "test-namespace"). - Return(nil) - mockStorageSwapper.On("StopReadingUnifiedStorage", mock.Anything). - Return(nil) - - mockWorker := jobs.NewMockWorker(t) - mockWorker.On("Process", mock.Anything, mock.Anything, mock.MatchedBy(func(job provisioning.Job) bool { - return job.Spec.Pull != nil && !job.Spec.Pull.Incremental - }), mock.Anything).Return(expectedErr) - - // Create a wrapper function that calls the provided function - wrapFn := func(ctx context.Context, rw repository.Repository, stageOpts repository.StageOptions, fn func(repository.Repository, bool) error) error { - return fn(rw, true) - } - - legacyMigrator := NewLegacyMigrator( - mockLegacyMigrator, - mockStorageSwapper, - mockWorker, - wrapFn, - ) - - progress := jobs.NewMockJobProgressRecorder(t) - progress.On("StrictMaxErrors", 1).Return() - progress.On("SetMessage", mock.Anything, "migrating legacy resources").Return() - progress.On("SetMessage", mock.Anything, "resetting unified storage").Return() - progress.On("ResetResults").Return() - progress.On("SetMessage", mock.Anything, "pulling resources").Return() - progress.On("SetMessage", mock.Anything, "error importing resources, reverting").Return() - - // Execute - repo := repository.NewMockRepository(t) - repo.On("Config").Return(&provisioning.Repository{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: "test-namespace", - }, - }) - - err := legacyMigrator.Migrate(ctx, repo, provisioning.MigrateJobOptions{}, progress) - - // Assert - require.Error(t, err) - require.Contains(t, err.Error(), "sync failed") - - // Verify storage settings were reverted - mockStorageSwapper.AssertCalled(t, "StopReadingUnifiedStorage", mock.Anything) - }) - - t.Run("should handle revert failure after sync failure", func(t *testing.T) { - // Setup - ctx := context.Background() - syncErr := errors.New("sync failed") - revertErr := errors.New("revert failed") - - mockLegacyMigrator := NewMockLegacyResourcesMigrator(t) - mockLegacyMigrator.On("Migrate", mock.Anything, mock.Anything, "test-namespace", mock.Anything, mock.Anything). - Return(nil) - - mockStorageSwapper := NewMockStorageSwapper(t) - mockStorageSwapper.On("WipeUnifiedAndSetMigratedFlag", mock.Anything, "test-namespace"). - Return(nil) - mockStorageSwapper.On("StopReadingUnifiedStorage", mock.Anything). - Return(revertErr) - - mockWorker := jobs.NewMockWorker(t) - mockWorker.On("Process", mock.Anything, mock.Anything, mock.MatchedBy(func(job provisioning.Job) bool { - return job.Spec.Pull != nil && !job.Spec.Pull.Incremental - }), mock.Anything).Return(syncErr) - - // Create a wrapper function that calls the provided function - wrapFn := func(ctx context.Context, rw repository.Repository, stageOpts repository.StageOptions, fn func(repository.Repository, bool) error) error { - return fn(rw, true) - } - - legacyMigrator := NewLegacyMigrator( - mockLegacyMigrator, - mockStorageSwapper, - mockWorker, - wrapFn, - ) - - progress := jobs.NewMockJobProgressRecorder(t) - progress.On("StrictMaxErrors", 1).Return() - progress.On("SetMessage", mock.Anything, "migrating legacy resources").Return() - progress.On("SetMessage", mock.Anything, "resetting unified storage").Return() - progress.On("ResetResults").Return() - progress.On("SetMessage", mock.Anything, "pulling resources").Return() - progress.On("SetMessage", mock.Anything, "error importing resources, reverting").Return() - - // Execute - repo := repository.NewMockRepository(t) - repo.On("Config").Return(&provisioning.Repository{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: "test-namespace", - }, - }) - - err := legacyMigrator.Migrate(ctx, repo, provisioning.MigrateJobOptions{}, progress) - - // Assert - require.Error(t, err) - require.Contains(t, err.Error(), "sync failed") - - // Verify both errors occurred - mockStorageSwapper.AssertCalled(t, "StopReadingUnifiedStorage", mock.Anything) - }) -} - -func TestLegacyMigrator_Success(t *testing.T) { - t.Run("should complete migration successfully", func(t *testing.T) { - // Setup - ctx := context.Background() - - mockLegacyMigrator := NewMockLegacyResourcesMigrator(t) - mockLegacyMigrator.On("Migrate", mock.Anything, mock.Anything, "test-namespace", mock.Anything, mock.Anything). - Return(nil) - - mockStorageSwapper := NewMockStorageSwapper(t) - mockStorageSwapper.On("WipeUnifiedAndSetMigratedFlag", mock.Anything, "test-namespace"). - Return(nil) - - mockWorker := jobs.NewMockWorker(t) - mockWorker.On("Process", mock.Anything, mock.Anything, mock.MatchedBy(func(job provisioning.Job) bool { - return job.Spec.Pull != nil && !job.Spec.Pull.Incremental - }), mock.Anything).Return(nil) - - // Create a wrapper function that calls the provided function - wrapFn := func(ctx context.Context, rw repository.Repository, stageOpts repository.StageOptions, fn func(repository.Repository, bool) error) error { - return fn(rw, true) - } - - legacyMigrator := NewLegacyMigrator( - mockLegacyMigrator, - mockStorageSwapper, - mockWorker, - wrapFn, - ) - - progress := jobs.NewMockJobProgressRecorder(t) - progress.On("StrictMaxErrors", 1).Return() - progress.On("SetMessage", mock.Anything, "migrating legacy resources").Return() - progress.On("SetMessage", mock.Anything, "resetting unified storage").Return() - progress.On("ResetResults").Return() - progress.On("SetMessage", mock.Anything, "pulling resources").Return() - - // Execute - repo := repository.NewMockRepository(t) - repo.On("Config").Return(&provisioning.Repository{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: "test-namespace", - }, - }) - - err := legacyMigrator.Migrate(ctx, repo, provisioning.MigrateJobOptions{}, progress) - - // Assert - require.NoError(t, err) - - // Verify all expected operations were called in order - mockLegacyMigrator.AssertCalled(t, "Migrate", mock.Anything, mock.Anything, "test-namespace", mock.Anything, mock.Anything) - mockStorageSwapper.AssertCalled(t, "WipeUnifiedAndSetMigratedFlag", mock.Anything, "test-namespace") - mockWorker.AssertCalled(t, "Process", mock.Anything, mock.Anything, mock.Anything, mock.Anything) - }) -} - -func TestLegacyMigrator_BeforeFnExecution(t *testing.T) { - t.Run("should execute beforeFn functions", func(t *testing.T) { - // Setup - mockLegacyMigrator := NewMockLegacyResourcesMigrator(t) - mockStorageSwapper := NewMockStorageSwapper(t) - mockWorker := jobs.NewMockWorker(t) - // Create a wrapper function that calls the provided function - wrapFn := func(ctx context.Context, rw repository.Repository, stageOpts repository.StageOptions, fn func(repository.Repository, bool) error) error { - return errors.New("abort test here") - } - - legacyMigrator := NewLegacyMigrator( - mockLegacyMigrator, - mockStorageSwapper, - mockWorker, - wrapFn, - ) - - progress := jobs.NewMockJobProgressRecorder(t) - // No progress messages expected in current staging implementation - progress.On("StrictMaxErrors", 1).Return() - progress.On("SetMessage", mock.Anything, "migrating legacy resources").Return() - - // Execute - repo := repository.NewMockRepository(t) - repo.On("Config").Return(&provisioning.Repository{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: "test-namespace", - }, - }) - - err := legacyMigrator.Migrate(context.Background(), repo, provisioning.MigrateJobOptions{}, progress) - require.EqualError(t, err, "migrate from SQL: abort test here") - }) -} - -func TestLegacyMigrator_ProgressScanner(t *testing.T) { - t.Run("should update progress with scanner", func(t *testing.T) { - mockLegacyMigrator := NewMockLegacyResourcesMigrator(t) - mockStorageSwapper := NewMockStorageSwapper(t) - mockWorker := jobs.NewMockWorker(t) - - // Create a wrapper function that calls the provided function - wrapFn := func(ctx context.Context, rw repository.Repository, stageOpts repository.StageOptions, fn func(repository.Repository, bool) error) error { - return errors.New("abort test here") - } - - legacyMigrator := NewLegacyMigrator( - mockLegacyMigrator, - mockStorageSwapper, - mockWorker, - wrapFn, - ) - - progress := jobs.NewMockJobProgressRecorder(t) - // No progress messages expected in current staging implementation - progress.On("StrictMaxErrors", 1).Return() - progress.On("SetMessage", mock.Anything, "migrating legacy resources").Return() - - repo := repository.NewMockRepository(t) - repo.On("Config").Return(&provisioning.Repository{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: "test-namespace", - }, - }) - - err := legacyMigrator.Migrate(context.Background(), repo, provisioning.MigrateJobOptions{}, progress) - require.EqualError(t, err, "migrate from SQL: abort test here") - - require.Eventually(t, func() bool { - // No progress message calls expected in current staging implementation - return progress.AssertExpectations(t) - }, time.Second, 10*time.Millisecond) - }) -} diff --git a/pkg/registry/apis/provisioning/jobs/migrate/mock_bulk_process_client.go b/pkg/registry/apis/provisioning/jobs/migrate/mock_bulk_process_client.go deleted file mode 100644 index e16d5695c0d..00000000000 --- a/pkg/registry/apis/provisioning/jobs/migrate/mock_bulk_process_client.go +++ /dev/null @@ -1,430 +0,0 @@ -// Code generated by mockery v2.52.4. DO NOT EDIT. - -package migrate - -import ( - context "context" - - mock "github.com/stretchr/testify/mock" - metadata "google.golang.org/grpc/metadata" - - "github.com/grafana/grafana/pkg/storage/unified/resourcepb" -) - -// BulkStore_BulkProcessClient is an autogenerated mock type for the BulkStore_BulkProcessClient type -type BulkStore_BulkProcessClient struct { - mock.Mock -} - -type BulkStore_BulkProcessClient_Expecter struct { - mock *mock.Mock -} - -func (_m *BulkStore_BulkProcessClient) EXPECT() *BulkStore_BulkProcessClient_Expecter { - return &BulkStore_BulkProcessClient_Expecter{mock: &_m.Mock} -} - -// CloseAndRecv provides a mock function with no fields -func (_m *BulkStore_BulkProcessClient) CloseAndRecv() (*resourcepb.BulkResponse, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for CloseAndRecv") - } - - var r0 *resourcepb.BulkResponse - var r1 error - if rf, ok := ret.Get(0).(func() (*resourcepb.BulkResponse, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() *resourcepb.BulkResponse); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*resourcepb.BulkResponse) - } - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// BulkStore_BulkProcessClient_CloseAndRecv_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CloseAndRecv' -type BulkStore_BulkProcessClient_CloseAndRecv_Call struct { - *mock.Call -} - -// CloseAndRecv is a helper method to define mock.On call -func (_e *BulkStore_BulkProcessClient_Expecter) CloseAndRecv() *BulkStore_BulkProcessClient_CloseAndRecv_Call { - return &BulkStore_BulkProcessClient_CloseAndRecv_Call{Call: _e.mock.On("CloseAndRecv")} -} - -func (_c *BulkStore_BulkProcessClient_CloseAndRecv_Call) Run(run func()) *BulkStore_BulkProcessClient_CloseAndRecv_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *BulkStore_BulkProcessClient_CloseAndRecv_Call) Return(_a0 *resourcepb.BulkResponse, _a1 error) *BulkStore_BulkProcessClient_CloseAndRecv_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *BulkStore_BulkProcessClient_CloseAndRecv_Call) RunAndReturn(run func() (*resourcepb.BulkResponse, error)) *BulkStore_BulkProcessClient_CloseAndRecv_Call { - _c.Call.Return(run) - return _c -} - -// CloseSend provides a mock function with no fields -func (_m *BulkStore_BulkProcessClient) CloseSend() error { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for CloseSend") - } - - var r0 error - if rf, ok := ret.Get(0).(func() error); ok { - r0 = rf() - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// BulkStore_BulkProcessClient_CloseSend_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CloseSend' -type BulkStore_BulkProcessClient_CloseSend_Call struct { - *mock.Call -} - -// CloseSend is a helper method to define mock.On call -func (_e *BulkStore_BulkProcessClient_Expecter) CloseSend() *BulkStore_BulkProcessClient_CloseSend_Call { - return &BulkStore_BulkProcessClient_CloseSend_Call{Call: _e.mock.On("CloseSend")} -} - -func (_c *BulkStore_BulkProcessClient_CloseSend_Call) Run(run func()) *BulkStore_BulkProcessClient_CloseSend_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *BulkStore_BulkProcessClient_CloseSend_Call) Return(_a0 error) *BulkStore_BulkProcessClient_CloseSend_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *BulkStore_BulkProcessClient_CloseSend_Call) RunAndReturn(run func() error) *BulkStore_BulkProcessClient_CloseSend_Call { - _c.Call.Return(run) - return _c -} - -// Context provides a mock function with no fields -func (_m *BulkStore_BulkProcessClient) Context() context.Context { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for Context") - } - - var r0 context.Context - if rf, ok := ret.Get(0).(func() context.Context); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(context.Context) - } - } - - return r0 -} - -// BulkStore_BulkProcessClient_Context_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Context' -type BulkStore_BulkProcessClient_Context_Call struct { - *mock.Call -} - -// Context is a helper method to define mock.On call -func (_e *BulkStore_BulkProcessClient_Expecter) Context() *BulkStore_BulkProcessClient_Context_Call { - return &BulkStore_BulkProcessClient_Context_Call{Call: _e.mock.On("Context")} -} - -func (_c *BulkStore_BulkProcessClient_Context_Call) Run(run func()) *BulkStore_BulkProcessClient_Context_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *BulkStore_BulkProcessClient_Context_Call) Return(_a0 context.Context) *BulkStore_BulkProcessClient_Context_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *BulkStore_BulkProcessClient_Context_Call) RunAndReturn(run func() context.Context) *BulkStore_BulkProcessClient_Context_Call { - _c.Call.Return(run) - return _c -} - -// Header provides a mock function with no fields -func (_m *BulkStore_BulkProcessClient) Header() (metadata.MD, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for Header") - } - - var r0 metadata.MD - var r1 error - if rf, ok := ret.Get(0).(func() (metadata.MD, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() metadata.MD); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(metadata.MD) - } - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// BulkStore_BulkProcessClient_Header_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Header' -type BulkStore_BulkProcessClient_Header_Call struct { - *mock.Call -} - -// Header is a helper method to define mock.On call -func (_e *BulkStore_BulkProcessClient_Expecter) Header() *BulkStore_BulkProcessClient_Header_Call { - return &BulkStore_BulkProcessClient_Header_Call{Call: _e.mock.On("Header")} -} - -func (_c *BulkStore_BulkProcessClient_Header_Call) Run(run func()) *BulkStore_BulkProcessClient_Header_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *BulkStore_BulkProcessClient_Header_Call) Return(_a0 metadata.MD, _a1 error) *BulkStore_BulkProcessClient_Header_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *BulkStore_BulkProcessClient_Header_Call) RunAndReturn(run func() (metadata.MD, error)) *BulkStore_BulkProcessClient_Header_Call { - _c.Call.Return(run) - return _c -} - -// RecvMsg provides a mock function with given fields: m -func (_m *BulkStore_BulkProcessClient) RecvMsg(m interface{}) error { - ret := _m.Called(m) - - if len(ret) == 0 { - panic("no return value specified for RecvMsg") - } - - var r0 error - if rf, ok := ret.Get(0).(func(interface{}) error); ok { - r0 = rf(m) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// BulkStore_BulkProcessClient_RecvMsg_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RecvMsg' -type BulkStore_BulkProcessClient_RecvMsg_Call struct { - *mock.Call -} - -// RecvMsg is a helper method to define mock.On call -// - m interface{} -func (_e *BulkStore_BulkProcessClient_Expecter) RecvMsg(m interface{}) *BulkStore_BulkProcessClient_RecvMsg_Call { - return &BulkStore_BulkProcessClient_RecvMsg_Call{Call: _e.mock.On("RecvMsg", m)} -} - -func (_c *BulkStore_BulkProcessClient_RecvMsg_Call) Run(run func(m interface{})) *BulkStore_BulkProcessClient_RecvMsg_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(interface{})) - }) - return _c -} - -func (_c *BulkStore_BulkProcessClient_RecvMsg_Call) Return(_a0 error) *BulkStore_BulkProcessClient_RecvMsg_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *BulkStore_BulkProcessClient_RecvMsg_Call) RunAndReturn(run func(interface{}) error) *BulkStore_BulkProcessClient_RecvMsg_Call { - _c.Call.Return(run) - return _c -} - -// Send provides a mock function with given fields: _a0 -func (_m *BulkStore_BulkProcessClient) Send(_a0 *resourcepb.BulkRequest) error { - ret := _m.Called(_a0) - - if len(ret) == 0 { - panic("no return value specified for Send") - } - - var r0 error - if rf, ok := ret.Get(0).(func(*resourcepb.BulkRequest) error); ok { - r0 = rf(_a0) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// BulkStore_BulkProcessClient_Send_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Send' -type BulkStore_BulkProcessClient_Send_Call struct { - *mock.Call -} - -// Send is a helper method to define mock.On call -// - _a0 *resource.BulkRequest -func (_e *BulkStore_BulkProcessClient_Expecter) Send(_a0 interface{}) *BulkStore_BulkProcessClient_Send_Call { - return &BulkStore_BulkProcessClient_Send_Call{Call: _e.mock.On("Send", _a0)} -} - -func (_c *BulkStore_BulkProcessClient_Send_Call) Run(run func(_a0 *resourcepb.BulkRequest)) *BulkStore_BulkProcessClient_Send_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*resourcepb.BulkRequest)) - }) - return _c -} - -func (_c *BulkStore_BulkProcessClient_Send_Call) Return(_a0 error) *BulkStore_BulkProcessClient_Send_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *BulkStore_BulkProcessClient_Send_Call) RunAndReturn(run func(*resourcepb.BulkRequest) error) *BulkStore_BulkProcessClient_Send_Call { - _c.Call.Return(run) - return _c -} - -// SendMsg provides a mock function with given fields: m -func (_m *BulkStore_BulkProcessClient) SendMsg(m interface{}) error { - ret := _m.Called(m) - - if len(ret) == 0 { - panic("no return value specified for SendMsg") - } - - var r0 error - if rf, ok := ret.Get(0).(func(interface{}) error); ok { - r0 = rf(m) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// BulkStore_BulkProcessClient_SendMsg_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SendMsg' -type BulkStore_BulkProcessClient_SendMsg_Call struct { - *mock.Call -} - -// SendMsg is a helper method to define mock.On call -// - m interface{} -func (_e *BulkStore_BulkProcessClient_Expecter) SendMsg(m interface{}) *BulkStore_BulkProcessClient_SendMsg_Call { - return &BulkStore_BulkProcessClient_SendMsg_Call{Call: _e.mock.On("SendMsg", m)} -} - -func (_c *BulkStore_BulkProcessClient_SendMsg_Call) Run(run func(m interface{})) *BulkStore_BulkProcessClient_SendMsg_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(interface{})) - }) - return _c -} - -func (_c *BulkStore_BulkProcessClient_SendMsg_Call) Return(_a0 error) *BulkStore_BulkProcessClient_SendMsg_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *BulkStore_BulkProcessClient_SendMsg_Call) RunAndReturn(run func(interface{}) error) *BulkStore_BulkProcessClient_SendMsg_Call { - _c.Call.Return(run) - return _c -} - -// Trailer provides a mock function with no fields -func (_m *BulkStore_BulkProcessClient) Trailer() metadata.MD { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for Trailer") - } - - var r0 metadata.MD - if rf, ok := ret.Get(0).(func() metadata.MD); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(metadata.MD) - } - } - - return r0 -} - -// BulkStore_BulkProcessClient_Trailer_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Trailer' -type BulkStore_BulkProcessClient_Trailer_Call struct { - *mock.Call -} - -// Trailer is a helper method to define mock.On call -func (_e *BulkStore_BulkProcessClient_Expecter) Trailer() *BulkStore_BulkProcessClient_Trailer_Call { - return &BulkStore_BulkProcessClient_Trailer_Call{Call: _e.mock.On("Trailer")} -} - -func (_c *BulkStore_BulkProcessClient_Trailer_Call) Run(run func()) *BulkStore_BulkProcessClient_Trailer_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *BulkStore_BulkProcessClient_Trailer_Call) Return(_a0 metadata.MD) *BulkStore_BulkProcessClient_Trailer_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *BulkStore_BulkProcessClient_Trailer_Call) RunAndReturn(run func() metadata.MD) *BulkStore_BulkProcessClient_Trailer_Call { - _c.Call.Return(run) - return _c -} - -// NewBulkStore_BulkProcessClient creates a new instance of BulkStore_BulkProcessClient. 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 NewBulkStore_BulkProcessClient(t interface { - mock.TestingT - Cleanup(func()) -}) *BulkStore_BulkProcessClient { - mock := &BulkStore_BulkProcessClient{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/pkg/registry/apis/provisioning/jobs/migrate/mock_bulk_store_client.go b/pkg/registry/apis/provisioning/jobs/migrate/mock_bulk_store_client.go deleted file mode 100644 index 9fa21e12ab0..00000000000 --- a/pkg/registry/apis/provisioning/jobs/migrate/mock_bulk_store_client.go +++ /dev/null @@ -1,113 +0,0 @@ -// Code generated by mockery v2.52.4. DO NOT EDIT. - -package migrate - -import ( - context "context" - - grpc "google.golang.org/grpc" - - mock "github.com/stretchr/testify/mock" - - resourcepb "github.com/grafana/grafana/pkg/storage/unified/resourcepb" -) - -// MockBulkStoreClient is an autogenerated mock type for the BulkStoreClient type -type MockBulkStoreClient struct { - mock.Mock -} - -type MockBulkStoreClient_Expecter struct { - mock *mock.Mock -} - -func (_m *MockBulkStoreClient) EXPECT() *MockBulkStoreClient_Expecter { - return &MockBulkStoreClient_Expecter{mock: &_m.Mock} -} - -// BulkProcess provides a mock function with given fields: ctx, opts -func (_m *MockBulkStoreClient) BulkProcess(ctx context.Context, opts ...grpc.CallOption) (resourcepb.BulkStore_BulkProcessClient, error) { - _va := make([]interface{}, len(opts)) - for _i := range opts { - _va[_i] = opts[_i] - } - var _ca []interface{} - _ca = append(_ca, ctx) - _ca = append(_ca, _va...) - ret := _m.Called(_ca...) - - if len(ret) == 0 { - panic("no return value specified for BulkProcess") - } - - var r0 resourcepb.BulkStore_BulkProcessClient - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, ...grpc.CallOption) (resourcepb.BulkStore_BulkProcessClient, error)); ok { - return rf(ctx, opts...) - } - if rf, ok := ret.Get(0).(func(context.Context, ...grpc.CallOption) resourcepb.BulkStore_BulkProcessClient); ok { - r0 = rf(ctx, opts...) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(resourcepb.BulkStore_BulkProcessClient) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, ...grpc.CallOption) error); ok { - r1 = rf(ctx, opts...) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockBulkStoreClient_BulkProcess_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'BulkProcess' -type MockBulkStoreClient_BulkProcess_Call struct { - *mock.Call -} - -// BulkProcess is a helper method to define mock.On call -// - ctx context.Context -// - opts ...grpc.CallOption -func (_e *MockBulkStoreClient_Expecter) BulkProcess(ctx interface{}, opts ...interface{}) *MockBulkStoreClient_BulkProcess_Call { - return &MockBulkStoreClient_BulkProcess_Call{Call: _e.mock.On("BulkProcess", - append([]interface{}{ctx}, opts...)...)} -} - -func (_c *MockBulkStoreClient_BulkProcess_Call) Run(run func(ctx context.Context, opts ...grpc.CallOption)) *MockBulkStoreClient_BulkProcess_Call { - _c.Call.Run(func(args mock.Arguments) { - variadicArgs := make([]grpc.CallOption, len(args)-1) - for i, a := range args[1:] { - if a != nil { - variadicArgs[i] = a.(grpc.CallOption) - } - } - run(args[0].(context.Context), variadicArgs...) - }) - return _c -} - -func (_c *MockBulkStoreClient_BulkProcess_Call) Return(_a0 resourcepb.BulkStore_BulkProcessClient, _a1 error) *MockBulkStoreClient_BulkProcess_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockBulkStoreClient_BulkProcess_Call) RunAndReturn(run func(context.Context, ...grpc.CallOption) (resourcepb.BulkStore_BulkProcessClient, error)) *MockBulkStoreClient_BulkProcess_Call { - _c.Call.Return(run) - return _c -} - -// NewMockBulkStoreClient creates a new instance of MockBulkStoreClient. 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 NewMockBulkStoreClient(t interface { - mock.TestingT - Cleanup(func()) -}) *MockBulkStoreClient { - mock := &MockBulkStoreClient{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/pkg/registry/apis/provisioning/jobs/migrate/mock_legacy_resources_migrator.go b/pkg/registry/apis/provisioning/jobs/migrate/mock_legacy_resources_migrator.go deleted file mode 100644 index c55c4e22508..00000000000 --- a/pkg/registry/apis/provisioning/jobs/migrate/mock_legacy_resources_migrator.go +++ /dev/null @@ -1,91 +0,0 @@ -// Code generated by mockery v2.52.4. DO NOT EDIT. - -package migrate - -import ( - context "context" - - jobs "github.com/grafana/grafana/pkg/registry/apis/provisioning/jobs" - mock "github.com/stretchr/testify/mock" - - repository "github.com/grafana/grafana/apps/provisioning/pkg/repository" - - v0alpha1 "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1" -) - -// MockLegacyResourcesMigrator is an autogenerated mock type for the LegacyResourcesMigrator type -type MockLegacyResourcesMigrator struct { - mock.Mock -} - -type MockLegacyResourcesMigrator_Expecter struct { - mock *mock.Mock -} - -func (_m *MockLegacyResourcesMigrator) EXPECT() *MockLegacyResourcesMigrator_Expecter { - return &MockLegacyResourcesMigrator_Expecter{mock: &_m.Mock} -} - -// Migrate provides a mock function with given fields: ctx, rw, namespace, opts, progress -func (_m *MockLegacyResourcesMigrator) Migrate(ctx context.Context, rw repository.ReaderWriter, namespace string, opts v0alpha1.MigrateJobOptions, progress jobs.JobProgressRecorder) error { - ret := _m.Called(ctx, rw, namespace, opts, progress) - - if len(ret) == 0 { - panic("no return value specified for Migrate") - } - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, repository.ReaderWriter, string, v0alpha1.MigrateJobOptions, jobs.JobProgressRecorder) error); ok { - r0 = rf(ctx, rw, namespace, opts, progress) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockLegacyResourcesMigrator_Migrate_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Migrate' -type MockLegacyResourcesMigrator_Migrate_Call struct { - *mock.Call -} - -// Migrate is a helper method to define mock.On call -// - ctx context.Context -// - rw repository.ReaderWriter -// - namespace string -// - opts v0alpha1.MigrateJobOptions -// - progress jobs.JobProgressRecorder -func (_e *MockLegacyResourcesMigrator_Expecter) Migrate(ctx interface{}, rw interface{}, namespace interface{}, opts interface{}, progress interface{}) *MockLegacyResourcesMigrator_Migrate_Call { - return &MockLegacyResourcesMigrator_Migrate_Call{Call: _e.mock.On("Migrate", ctx, rw, namespace, opts, progress)} -} - -func (_c *MockLegacyResourcesMigrator_Migrate_Call) Run(run func(ctx context.Context, rw repository.ReaderWriter, namespace string, opts v0alpha1.MigrateJobOptions, progress jobs.JobProgressRecorder)) *MockLegacyResourcesMigrator_Migrate_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(repository.ReaderWriter), args[2].(string), args[3].(v0alpha1.MigrateJobOptions), args[4].(jobs.JobProgressRecorder)) - }) - return _c -} - -func (_c *MockLegacyResourcesMigrator_Migrate_Call) Return(_a0 error) *MockLegacyResourcesMigrator_Migrate_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockLegacyResourcesMigrator_Migrate_Call) RunAndReturn(run func(context.Context, repository.ReaderWriter, string, v0alpha1.MigrateJobOptions, jobs.JobProgressRecorder) error) *MockLegacyResourcesMigrator_Migrate_Call { - _c.Call.Return(run) - return _c -} - -// NewMockLegacyResourcesMigrator creates a new instance of MockLegacyResourcesMigrator. 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 NewMockLegacyResourcesMigrator(t interface { - mock.TestingT - Cleanup(func()) -}) *MockLegacyResourcesMigrator { - mock := &MockLegacyResourcesMigrator{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/pkg/registry/apis/provisioning/jobs/migrate/mock_migrator.go b/pkg/registry/apis/provisioning/jobs/migrate/mock_migrator.go index f7bc66ca676..53050b99de1 100644 --- a/pkg/registry/apis/provisioning/jobs/migrate/mock_migrator.go +++ b/pkg/registry/apis/provisioning/jobs/migrate/mock_migrator.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.52.4. DO NOT EDIT. +// Code generated by mockery v2.53.4. DO NOT EDIT. package migrate diff --git a/pkg/registry/apis/provisioning/jobs/migrate/mock_namespace_cleaner.go b/pkg/registry/apis/provisioning/jobs/migrate/mock_namespace_cleaner.go index 2b168bfa202..1ae1afa8ccf 100644 --- a/pkg/registry/apis/provisioning/jobs/migrate/mock_namespace_cleaner.go +++ b/pkg/registry/apis/provisioning/jobs/migrate/mock_namespace_cleaner.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.52.4. DO NOT EDIT. +// Code generated by mockery v2.53.4. DO NOT EDIT. package migrate diff --git a/pkg/registry/apis/provisioning/jobs/migrate/mock_storage_swapper.go b/pkg/registry/apis/provisioning/jobs/migrate/mock_storage_swapper.go deleted file mode 100644 index d3073c2566b..00000000000 --- a/pkg/registry/apis/provisioning/jobs/migrate/mock_storage_swapper.go +++ /dev/null @@ -1,129 +0,0 @@ -// Code generated by mockery v2.52.4. DO NOT EDIT. - -package migrate - -import ( - context "context" - - mock "github.com/stretchr/testify/mock" -) - -// MockStorageSwapper is an autogenerated mock type for the StorageSwapper type -type MockStorageSwapper struct { - mock.Mock -} - -type MockStorageSwapper_Expecter struct { - mock *mock.Mock -} - -func (_m *MockStorageSwapper) EXPECT() *MockStorageSwapper_Expecter { - return &MockStorageSwapper_Expecter{mock: &_m.Mock} -} - -// StopReadingUnifiedStorage provides a mock function with given fields: ctx -func (_m *MockStorageSwapper) StopReadingUnifiedStorage(ctx context.Context) error { - ret := _m.Called(ctx) - - if len(ret) == 0 { - panic("no return value specified for StopReadingUnifiedStorage") - } - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context) error); ok { - r0 = rf(ctx) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockStorageSwapper_StopReadingUnifiedStorage_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'StopReadingUnifiedStorage' -type MockStorageSwapper_StopReadingUnifiedStorage_Call struct { - *mock.Call -} - -// StopReadingUnifiedStorage is a helper method to define mock.On call -// - ctx context.Context -func (_e *MockStorageSwapper_Expecter) StopReadingUnifiedStorage(ctx interface{}) *MockStorageSwapper_StopReadingUnifiedStorage_Call { - return &MockStorageSwapper_StopReadingUnifiedStorage_Call{Call: _e.mock.On("StopReadingUnifiedStorage", ctx)} -} - -func (_c *MockStorageSwapper_StopReadingUnifiedStorage_Call) Run(run func(ctx context.Context)) *MockStorageSwapper_StopReadingUnifiedStorage_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context)) - }) - return _c -} - -func (_c *MockStorageSwapper_StopReadingUnifiedStorage_Call) Return(_a0 error) *MockStorageSwapper_StopReadingUnifiedStorage_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockStorageSwapper_StopReadingUnifiedStorage_Call) RunAndReturn(run func(context.Context) error) *MockStorageSwapper_StopReadingUnifiedStorage_Call { - _c.Call.Return(run) - return _c -} - -// WipeUnifiedAndSetMigratedFlag provides a mock function with given fields: ctx, namespace -func (_m *MockStorageSwapper) WipeUnifiedAndSetMigratedFlag(ctx context.Context, namespace string) error { - ret := _m.Called(ctx, namespace) - - if len(ret) == 0 { - panic("no return value specified for WipeUnifiedAndSetMigratedFlag") - } - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, string) error); ok { - r0 = rf(ctx, namespace) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockStorageSwapper_WipeUnifiedAndSetMigratedFlag_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WipeUnifiedAndSetMigratedFlag' -type MockStorageSwapper_WipeUnifiedAndSetMigratedFlag_Call struct { - *mock.Call -} - -// WipeUnifiedAndSetMigratedFlag is a helper method to define mock.On call -// - ctx context.Context -// - namespace string -func (_e *MockStorageSwapper_Expecter) WipeUnifiedAndSetMigratedFlag(ctx interface{}, namespace interface{}) *MockStorageSwapper_WipeUnifiedAndSetMigratedFlag_Call { - return &MockStorageSwapper_WipeUnifiedAndSetMigratedFlag_Call{Call: _e.mock.On("WipeUnifiedAndSetMigratedFlag", ctx, namespace)} -} - -func (_c *MockStorageSwapper_WipeUnifiedAndSetMigratedFlag_Call) Run(run func(ctx context.Context, namespace string)) *MockStorageSwapper_WipeUnifiedAndSetMigratedFlag_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(string)) - }) - return _c -} - -func (_c *MockStorageSwapper_WipeUnifiedAndSetMigratedFlag_Call) Return(_a0 error) *MockStorageSwapper_WipeUnifiedAndSetMigratedFlag_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockStorageSwapper_WipeUnifiedAndSetMigratedFlag_Call) RunAndReturn(run func(context.Context, string) error) *MockStorageSwapper_WipeUnifiedAndSetMigratedFlag_Call { - _c.Call.Return(run) - return _c -} - -// NewMockStorageSwapper creates a new instance of MockStorageSwapper. 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 NewMockStorageSwapper(t interface { - mock.TestingT - Cleanup(func()) -}) *MockStorageSwapper { - mock := &MockStorageSwapper{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/pkg/registry/apis/provisioning/jobs/migrate/mock_wrap_with_stage_fn.go b/pkg/registry/apis/provisioning/jobs/migrate/mock_wrap_with_stage_fn.go new file mode 100644 index 00000000000..3281004d695 --- /dev/null +++ b/pkg/registry/apis/provisioning/jobs/migrate/mock_wrap_with_stage_fn.go @@ -0,0 +1,86 @@ +// Code generated by mockery v2.53.4. DO NOT EDIT. + +package migrate + +import ( + context "context" + + repository "github.com/grafana/grafana/apps/provisioning/pkg/repository" + mock "github.com/stretchr/testify/mock" +) + +// MockWrapWithStageFn is an autogenerated mock type for the WrapWithStageFn type +type MockWrapWithStageFn struct { + mock.Mock +} + +type MockWrapWithStageFn_Expecter struct { + mock *mock.Mock +} + +func (_m *MockWrapWithStageFn) EXPECT() *MockWrapWithStageFn_Expecter { + return &MockWrapWithStageFn_Expecter{mock: &_m.Mock} +} + +// Execute provides a mock function with given fields: ctx, repo, stageOptions, fn +func (_m *MockWrapWithStageFn) Execute(ctx context.Context, repo repository.Repository, stageOptions repository.StageOptions, fn func(repository.Repository, bool) error) error { + ret := _m.Called(ctx, repo, stageOptions, fn) + + if len(ret) == 0 { + panic("no return value specified for Execute") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, repository.Repository, repository.StageOptions, func(repository.Repository, bool) error) error); ok { + r0 = rf(ctx, repo, stageOptions, fn) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockWrapWithStageFn_Execute_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Execute' +type MockWrapWithStageFn_Execute_Call struct { + *mock.Call +} + +// Execute is a helper method to define mock.On call +// - ctx context.Context +// - repo repository.Repository +// - stageOptions repository.StageOptions +// - fn func(repository.Repository , bool) error +func (_e *MockWrapWithStageFn_Expecter) Execute(ctx interface{}, repo interface{}, stageOptions interface{}, fn interface{}) *MockWrapWithStageFn_Execute_Call { + return &MockWrapWithStageFn_Execute_Call{Call: _e.mock.On("Execute", ctx, repo, stageOptions, fn)} +} + +func (_c *MockWrapWithStageFn_Execute_Call) Run(run func(ctx context.Context, repo repository.Repository, stageOptions repository.StageOptions, fn func(repository.Repository, bool) error)) *MockWrapWithStageFn_Execute_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(repository.Repository), args[2].(repository.StageOptions), args[3].(func(repository.Repository, bool) error)) + }) + return _c +} + +func (_c *MockWrapWithStageFn_Execute_Call) Return(_a0 error) *MockWrapWithStageFn_Execute_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockWrapWithStageFn_Execute_Call) RunAndReturn(run func(context.Context, repository.Repository, repository.StageOptions, func(repository.Repository, bool) error) error) *MockWrapWithStageFn_Execute_Call { + _c.Call.Return(run) + return _c +} + +// NewMockWrapWithStageFn creates a new instance of MockWrapWithStageFn. 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 NewMockWrapWithStageFn(t interface { + mock.TestingT + Cleanup(func()) +}) *MockWrapWithStageFn { + mock := &MockWrapWithStageFn{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/registry/apis/provisioning/jobs/migrate/storage.go b/pkg/registry/apis/provisioning/jobs/migrate/storage.go deleted file mode 100644 index 6d04eaa8c88..00000000000 --- a/pkg/registry/apis/provisioning/jobs/migrate/storage.go +++ /dev/null @@ -1,102 +0,0 @@ -package migrate - -import ( - "context" - "fmt" - "time" - - "google.golang.org/grpc" - "google.golang.org/grpc/metadata" - - "github.com/grafana/grafana-app-sdk/logging" - - "github.com/grafana/grafana/pkg/registry/apis/provisioning/resources" - "github.com/grafana/grafana/pkg/storage/legacysql/dualwrite" - "github.com/grafana/grafana/pkg/storage/unified/resource" - "github.com/grafana/grafana/pkg/storage/unified/resourcepb" -) - -//go:generate mockery --name BulkStoreClient --structname MockBulkStoreClient --inpackage --filename mock_bulk_store_client.go --with-expecter -//go:generate mockery --name=BulkStore_BulkProcessClient --srcpkg=github.com/grafana/grafana/pkg/storage/unified/resource --output=. --outpkg=migrate --filename=mock_bulk_process_client.go --with-expecter -type BulkStoreClient interface { - BulkProcess(ctx context.Context, opts ...grpc.CallOption) (resourcepb.BulkStore_BulkProcessClient, error) -} - -//go:generate mockery --name StorageSwapper --structname MockStorageSwapper --inpackage --filename mock_storage_swapper.go --with-expecter -type StorageSwapper interface { - StopReadingUnifiedStorage(ctx context.Context) error - WipeUnifiedAndSetMigratedFlag(ctx context.Context, namespace string) error -} - -type storageSwapper struct { - // Direct access to unified storage... use carefully! - bulk BulkStoreClient - dual dualwrite.Service -} - -func NewStorageSwapper(bulk BulkStoreClient, dual dualwrite.Service) StorageSwapper { - return &storageSwapper{ - bulk: bulk, - dual: dual, - } -} - -func (s *storageSwapper) StopReadingUnifiedStorage(ctx context.Context) error { - // FIXME: dual writer is not namespaced which means that we would consider all namespaces migrated - // after one migrates - for _, gr := range resources.SupportedProvisioningResources { - status, _ := s.dual.Status(ctx, gr.GroupResource()) - status.ReadUnified = false - status.Migrated = 0 - status.Migrating = 0 - _, err := s.dual.Update(ctx, status) - if err != nil { - return err - } - } - - return nil -} - -func (s *storageSwapper) WipeUnifiedAndSetMigratedFlag(ctx context.Context, namespace string) error { - for _, gr := range resources.SupportedProvisioningResources { - status, _ := s.dual.Status(ctx, gr.GroupResource()) - if status.ReadUnified { - return fmt.Errorf("unexpected state - already using unified storage for: %s", gr) - } - if status.Migrating > 0 { - if time.Since(time.UnixMilli(status.Migrating)) < time.Second*30 { - return fmt.Errorf("another migration job is running for: %s", gr) - } - } - settings := resource.BulkSettings{ - RebuildCollection: true, // wipes everything in the collection - Collection: []*resourcepb.ResourceKey{{ - Namespace: namespace, - Group: gr.Group, - Resource: gr.Resource, - }}, - } - ctx = metadata.NewOutgoingContext(ctx, settings.ToMD()) - stream, err := s.bulk.BulkProcess(ctx) - if err != nil { - return fmt.Errorf("error clearing unified %s / %w", gr, err) - } - stats, err := stream.CloseAndRecv() - if err != nil { - return fmt.Errorf("error clearing unified %s / %w", gr, err) - } - logger := logging.FromContext(ctx) - logger.Error("cleared unified storage", "stats", stats) - - status.Migrated = time.Now().UnixMilli() // but not really... since the sync is starting - status.ReadUnified = true - status.WriteLegacy = false // keep legacy "clean" - _, err = s.dual.Update(ctx, status) - if err != nil { - return err - } - } - - return nil -} diff --git a/pkg/registry/apis/provisioning/jobs/migrate/storage_test.go b/pkg/registry/apis/provisioning/jobs/migrate/storage_test.go deleted file mode 100644 index 5e1adadcc2d..00000000000 --- a/pkg/registry/apis/provisioning/jobs/migrate/storage_test.go +++ /dev/null @@ -1,204 +0,0 @@ -package migrate - -import ( - "context" - "errors" - "testing" - "time" - - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" - - "github.com/grafana/grafana/pkg/registry/apis/provisioning/resources" - "github.com/grafana/grafana/pkg/storage/legacysql/dualwrite" - "github.com/grafana/grafana/pkg/storage/unified/resource" - "github.com/grafana/grafana/pkg/storage/unified/resourcepb" - - "google.golang.org/grpc/metadata" -) - -func TestStorageSwapper_StopReadingUnifiedStorage(t *testing.T) { - tests := []struct { - name string - setupMocks func(*MockBulkStoreClient, *dualwrite.MockService) - expectedError string - }{ - { - name: "should update status for all resources", - setupMocks: func(bulk *MockBulkStoreClient, dual *dualwrite.MockService) { - for _, gr := range resources.SupportedProvisioningResources { - status := dualwrite.StorageStatus{ - ReadUnified: true, - Migrated: 123, - Migrating: 456, - } - dual.On("Status", mock.Anything, gr.GroupResource()).Return(status, nil) - dual.On("Update", mock.Anything, mock.MatchedBy(func(status dualwrite.StorageStatus) bool { - return !status.ReadUnified && status.Migrated == 0 && status.Migrating == 0 - })).Return(dualwrite.StorageStatus{}, nil) - } - }, - }, - { - name: "should fail if status update fails", - setupMocks: func(bulk *MockBulkStoreClient, dual *dualwrite.MockService) { - gr := resources.SupportedProvisioningResources[0] - dual.On("Status", mock.Anything, gr.GroupResource()).Return(dualwrite.StorageStatus{}, nil) - dual.On("Update", mock.Anything, mock.Anything).Return(dualwrite.StorageStatus{}, errors.New("update failed")) - }, - expectedError: "update failed", - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - bulk := NewMockBulkStoreClient(t) - dual := dualwrite.NewMockService(t) - - if tt.setupMocks != nil { - tt.setupMocks(bulk, dual) - } - - swapper := NewStorageSwapper(bulk, dual) - err := swapper.StopReadingUnifiedStorage(context.Background()) - - if tt.expectedError != "" { - require.Error(t, err) - require.Contains(t, err.Error(), tt.expectedError) - } else { - require.NoError(t, err) - } - }) - } -} - -func TestStorageSwapper_WipeUnifiedAndSetMigratedFlag(t *testing.T) { - tests := []struct { - name string - setupMocks func(*MockBulkStoreClient, *dualwrite.MockService) - expectedError string - }{ - { - name: "should fail if already using unified storage", - setupMocks: func(bulk *MockBulkStoreClient, dual *dualwrite.MockService) { - gr := resources.SupportedProvisioningResources[0] - status := dualwrite.StorageStatus{ - ReadUnified: true, - } - dual.On("Status", mock.Anything, gr.GroupResource()).Return(status, nil) - }, - expectedError: "unexpected state - already using unified storage", - }, - { - name: "should fail if migration is in progress", - setupMocks: func(bulk *MockBulkStoreClient, dual *dualwrite.MockService) { - gr := resources.SupportedProvisioningResources[0] - status := dualwrite.StorageStatus{ - ReadUnified: false, - Migrating: time.Now().UnixMilli(), - } - dual.On("Status", mock.Anything, gr.GroupResource()).Return(status, nil) - }, - expectedError: "another migration job is running", - }, - { - name: "should fail if bulk process fails", - setupMocks: func(bulk *MockBulkStoreClient, dual *dualwrite.MockService) { - gr := resources.SupportedProvisioningResources[0] - dual.On("Status", mock.Anything, gr.GroupResource()).Return(dualwrite.StorageStatus{}, nil) - bulk.On("BulkProcess", mock.Anything, mock.Anything).Return(nil, errors.New("bulk process failed")) - }, - expectedError: "error clearing unified", - }, - { - name: "should fail if status update fails after bulk process", - setupMocks: func(bulk *MockBulkStoreClient, dual *dualwrite.MockService) { - gr := resources.SupportedProvisioningResources[0] - dual.On("Status", mock.Anything, gr.GroupResource()).Return(dualwrite.StorageStatus{}, nil) - - mockStream := NewBulkStore_BulkProcessClient(t) - mockStream.On("CloseAndRecv").Return(&resourcepb.BulkResponse{}, nil) - bulk.On("BulkProcess", mock.Anything, mock.Anything).Return(mockStream, nil) - - dual.On("Update", mock.Anything, mock.MatchedBy(func(status dualwrite.StorageStatus) bool { - return status.ReadUnified && !status.WriteLegacy && status.Migrated > 0 - })).Return(dualwrite.StorageStatus{}, errors.New("update failed")) - }, - expectedError: "update failed", - }, - { - name: "should fail if bulk process stream close fails", - setupMocks: func(bulk *MockBulkStoreClient, dual *dualwrite.MockService) { - gr := resources.SupportedProvisioningResources[0] - dual.On("Status", mock.Anything, gr.GroupResource()).Return(dualwrite.StorageStatus{}, nil) - - mockStream := NewBulkStore_BulkProcessClient(t) - mockStream.On("CloseAndRecv").Return(nil, errors.New("stream close failed")) - bulk.On("BulkProcess", mock.Anything, mock.Anything).Return(mockStream, nil) - }, - expectedError: "error clearing unified", - }, - { - name: "should succeed with complete workflow", - setupMocks: func(bulk *MockBulkStoreClient, dual *dualwrite.MockService) { - for _, gr := range resources.SupportedProvisioningResources { - dual.On("Status", mock.Anything, gr.GroupResource()).Return(dualwrite.StorageStatus{}, nil) - - mockStream := NewBulkStore_BulkProcessClient(t) - mockStream.On("CloseAndRecv").Return(&resourcepb.BulkResponse{}, nil) - bulk.On("BulkProcess", mock.MatchedBy(func(ctx context.Context) bool { - md, ok := metadata.FromOutgoingContext(ctx) - if !ok { - return false - } - - //nolint:errcheck // hits the err != nil gotcha - settings, _ := resource.NewBulkSettings(md) - if !settings.RebuildCollection { - return false - } - if len(settings.Collection) != 1 { - return false - } - if settings.Collection[0].Namespace != "test-namespace" { - return false - } - if settings.Collection[0].Group != gr.Group { - return false - } - if settings.Collection[0].Resource != gr.Resource { - return false - } - - return true - }), mock.Anything).Return(mockStream, nil) - - dual.On("Update", mock.Anything, mock.MatchedBy(func(status dualwrite.StorageStatus) bool { - return status.ReadUnified && !status.WriteLegacy && status.Migrated > 0 - })).Return(dualwrite.StorageStatus{}, nil) - } - }, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - bulk := NewMockBulkStoreClient(t) - dual := dualwrite.NewMockService(t) - - if tt.setupMocks != nil { - tt.setupMocks(bulk, dual) - } - - swapper := NewStorageSwapper(bulk, dual) - err := swapper.WipeUnifiedAndSetMigratedFlag(context.Background(), "test-namespace") - - if tt.expectedError != "" { - require.Error(t, err) - require.Contains(t, err.Error(), tt.expectedError) - } else { - require.NoError(t, err) - } - }) - } -} diff --git a/pkg/registry/apis/provisioning/jobs/migrate/unifiedstorage.go b/pkg/registry/apis/provisioning/jobs/migrate/unifiedstorage.go index edd3a72f1bd..35c4de298f2 100644 --- a/pkg/registry/apis/provisioning/jobs/migrate/unifiedstorage.go +++ b/pkg/registry/apis/provisioning/jobs/migrate/unifiedstorage.go @@ -33,23 +33,7 @@ func NewUnifiedStorageMigrator( func (m *UnifiedStorageMigrator) Migrate(ctx context.Context, repo repository.ReaderWriter, options provisioning.MigrateJobOptions, progress jobs.JobProgressRecorder) error { namespace := repo.Config().GetNamespace() - // For folder-type repositories, only run sync (skip export and cleaner) - if repo.Config().Spec.Sync.Target == provisioning.SyncTargetTypeFolder { - progress.SetMessage(ctx, "pull resources") - syncJob := provisioning.Job{ - Spec: provisioning.JobSpec{ - Pull: &provisioning.SyncJobOptions{ - Incremental: false, - }, - }, - } - if err := m.syncWorker.Process(ctx, repo, syncJob, progress); err != nil { - return fmt.Errorf("pull resources: %w", err) - } - return nil - } - - // For instance-type repositories, run the full workflow: export -> sync -> clean + // Export resources first (for both folder and instance sync) progress.SetMessage(ctx, "export resources") progress.StrictMaxErrors(1) // strict as we want the entire instance to be managed @@ -67,6 +51,7 @@ func (m *UnifiedStorageMigrator) Migrate(ctx context.Context, repo repository.Re // Reset the results after the export as pull will operate on the same resources progress.ResetResults() + // Pull resources from the repository progress.SetMessage(ctx, "pull resources") syncJob := provisioning.Job{ Spec: provisioning.JobSpec{ @@ -79,9 +64,12 @@ func (m *UnifiedStorageMigrator) Migrate(ctx context.Context, repo repository.Re return fmt.Errorf("pull resources: %w", err) } - progress.SetMessage(ctx, "clean namespace") - if err := m.namespaceCleaner.Clean(ctx, namespace, progress); err != nil { - return fmt.Errorf("clean namespace: %w", err) + // For instance-type repositories, also clean the namespace + if repo.Config().Spec.Sync.Target != provisioning.SyncTargetTypeFolder { + progress.SetMessage(ctx, "clean namespace") + if err := m.namespaceCleaner.Clean(ctx, namespace, progress); err != nil { + return fmt.Errorf("clean namespace: %w", err) + } } return nil diff --git a/pkg/registry/apis/provisioning/jobs/migrate/unifiedstorage_test.go b/pkg/registry/apis/provisioning/jobs/migrate/unifiedstorage_test.go index d509c1c2f81..d84e95fcebd 100644 --- a/pkg/registry/apis/provisioning/jobs/migrate/unifiedstorage_test.go +++ b/pkg/registry/apis/provisioning/jobs/migrate/unifiedstorage_test.go @@ -134,7 +134,7 @@ func TestUnifiedStorageMigrator_Migrate(t *testing.T) { expectedError: "", }, { - name: "should only run sync for folder-type repositories", + name: "should run export and sync for folder-type repositories", setupMocks: func(nc *MockNamespaceCleaner, ew *jobs.MockWorker, sw *jobs.MockWorker, pr *jobs.MockJobProgressRecorder, rw *repository.MockRepository) { rw.On("Config").Return(&provisioning.Repository{ ObjectMeta: metav1.ObjectMeta{ @@ -147,9 +147,15 @@ func TestUnifiedStorageMigrator_Migrate(t *testing.T) { }, }, }) - // Export should be skipped - no export-related mocks - // Cleaner should also be skipped - no cleaner-related mocks - // Only sync job should run + // Export should run for folder-type repositories + pr.On("SetMessage", mock.Anything, "export resources").Return() + pr.On("StrictMaxErrors", 1).Return() + ew.On("Process", mock.Anything, rw, mock.MatchedBy(func(job provisioning.Job) bool { + return job.Spec.Push != nil + }), pr).Return(nil) + pr.On("ResetResults").Return() + // Cleaner should be skipped - no cleaner-related mocks + // Sync job should run pr.On("SetMessage", mock.Anything, "pull resources").Return() sw.On("Process", mock.Anything, rw, mock.MatchedBy(func(job provisioning.Job) bool { return job.Spec.Pull != nil && !job.Spec.Pull.Incremental @@ -171,7 +177,14 @@ func TestUnifiedStorageMigrator_Migrate(t *testing.T) { }, }, }) - // Only sync job should run and fail + // Export should run first + pr.On("SetMessage", mock.Anything, "export resources").Return() + pr.On("StrictMaxErrors", 1).Return() + ew.On("Process", mock.Anything, rw, mock.MatchedBy(func(job provisioning.Job) bool { + return job.Spec.Push != nil + }), pr).Return(nil) + pr.On("ResetResults").Return() + // Sync job should run and fail pr.On("SetMessage", mock.Anything, "pull resources").Return() sw.On("Process", mock.Anything, rw, mock.MatchedBy(func(job provisioning.Job) bool { return job.Spec.Pull != nil && !job.Spec.Pull.Incremental diff --git a/pkg/registry/apis/provisioning/jobs/migrate/worker.go b/pkg/registry/apis/provisioning/jobs/migrate/worker.go index 9de5d4015e8..e1b4e916d10 100644 --- a/pkg/registry/apis/provisioning/jobs/migrate/worker.go +++ b/pkg/registry/apis/provisioning/jobs/migrate/worker.go @@ -7,7 +7,6 @@ import ( 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/jobs" - "github.com/grafana/grafana/pkg/storage/legacysql/dualwrite" ) //go:generate mockery --name Migrator --structname MockMigrator --inpackage --filename mock_migrator.go --with-expecter @@ -16,8 +15,6 @@ type Migrator interface { } type MigrationWorker struct { - storageStatus dualwrite.Service - legacyMigrator Migrator unifiedMigrator Migrator } @@ -27,16 +24,9 @@ func NewMigrationWorkerFromUnified(unifiedMigrator Migrator) *MigrationWorker { } } -// HACK: we should decouple the implementation of these two -func NewMigrationWorker( - legacyMigrator Migrator, - unifiedMigrator Migrator, - storageStatus dualwrite.Service, -) *MigrationWorker { +func NewMigrationWorker(unifiedMigrator Migrator) *MigrationWorker { return &MigrationWorker{ unifiedMigrator: unifiedMigrator, - legacyMigrator: legacyMigrator, - storageStatus: storageStatus, } } @@ -56,28 +46,5 @@ func (w *MigrationWorker) Process(ctx context.Context, repo repository.Repositor return errors.New("migration job submitted targeting repository that is not a ReaderWriter") } - if options.History { - if repo.Config().Spec.Type != provisioning.GitHubRepositoryType { - return errors.New("history is only supported for github repositories") - } - } - - // Block migrate for legacy resources if repository type is folder - if repo.Config().Spec.Sync.Target == provisioning.SyncTargetTypeFolder { - // HACK: we should not have to check for storage existence here - if w.storageStatus != nil && dualwrite.IsReadingLegacyDashboardsAndFolders(ctx, w.storageStatus) { - return errors.New("migration of legacy resources is not supported for folder-type repositories") - } - } - - // HACK: we should not have to check for storage existence here - if w.storageStatus != nil && dualwrite.IsReadingLegacyDashboardsAndFolders(ctx, w.storageStatus) { - return w.legacyMigrator.Migrate(ctx, rw, *options, progress) - } - - if options.History { - return errors.New("history is not yet supported in unified storage") - } - return w.unifiedMigrator.Migrate(ctx, rw, *options, progress) } diff --git a/pkg/registry/apis/provisioning/jobs/migrate/worker_test.go b/pkg/registry/apis/provisioning/jobs/migrate/worker_test.go index 962a69a8f54..b8171a2df9d 100644 --- a/pkg/registry/apis/provisioning/jobs/migrate/worker_test.go +++ b/pkg/registry/apis/provisioning/jobs/migrate/worker_test.go @@ -2,7 +2,6 @@ package migrate import ( "context" - "errors" "testing" "github.com/stretchr/testify/assert" @@ -11,9 +10,7 @@ import ( provisioning "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1" "github.com/grafana/grafana/apps/provisioning/pkg/repository" - "github.com/grafana/grafana/apps/provisioning/pkg/repository/local" "github.com/grafana/grafana/pkg/registry/apis/provisioning/jobs" - "github.com/grafana/grafana/pkg/storage/legacysql/dualwrite" ) func TestMigrationWorker_IsSupported(t *testing.T) { @@ -42,7 +39,7 @@ func TestMigrationWorker_IsSupported(t *testing.T) { }, } - worker := NewMigrationWorker(nil, nil, nil) + worker := NewMigrationWorker(nil) for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -53,7 +50,7 @@ func TestMigrationWorker_IsSupported(t *testing.T) { } func TestMigrationWorker_ProcessNotReaderWriter(t *testing.T) { - worker := NewMigrationWorker(nil, nil, nil) + worker := NewMigrationWorker(NewMockMigrator(t)) job := provisioning.Job{ Spec: provisioning.JobSpec{ Action: provisioning.JobActionMigrate, @@ -68,56 +65,13 @@ func TestMigrationWorker_ProcessNotReaderWriter(t *testing.T) { require.EqualError(t, err, "migration job submitted targeting repository that is not a ReaderWriter") } -func TestMigrationWorker_WithHistory(t *testing.T) { - fakeDualwrite := dualwrite.NewMockService(t) - fakeDualwrite.On("ReadFromUnified", mock.Anything, mock.Anything). - Maybe().Return(true, nil) // using unified storage - - worker := NewMigrationWorker(nil, nil, fakeDualwrite) - job := provisioning.Job{ - Spec: provisioning.JobSpec{ - Action: provisioning.JobActionMigrate, - Migrate: &provisioning.MigrateJobOptions{ - History: true, - }, - }, - } - - t.Run("fail local", func(t *testing.T) { - progressRecorder := jobs.NewMockJobProgressRecorder(t) - progressRecorder.On("SetTotal", mock.Anything, 10).Return() - - repo := local.NewRepository(&provisioning.Repository{}, nil) - err := worker.Process(context.Background(), repo, job, progressRecorder) - require.EqualError(t, err, "history is only supported for github repositories") - }) - - t.Run("fail unified", func(t *testing.T) { - progressRecorder := jobs.NewMockJobProgressRecorder(t) - progressRecorder.On("SetTotal", mock.Anything, 10).Return() - - repo := repository.NewMockRepository(t) - repo.On("Config").Return(&provisioning.Repository{ - Spec: provisioning.RepositorySpec{ - Type: provisioning.GitHubRepositoryType, - GitHub: &provisioning.GitHubRepositoryConfig{ - URL: "empty", // not valid - }, - }, - }) - err := worker.Process(context.Background(), repo, job, progressRecorder) - require.EqualError(t, err, "history is not yet supported in unified storage") - }) -} - func TestMigrationWorker_Process(t *testing.T) { tests := []struct { - name string - setupMocks func(*MockMigrator, *MockMigrator, *dualwrite.MockService, *jobs.MockJobProgressRecorder) - setupRepo func(*repository.MockRepository) - job provisioning.Job - expectedError string - isLegacyActive bool + name string + setupMocks func(*MockMigrator, *jobs.MockJobProgressRecorder) + setupRepo func(*repository.MockRepository) + job provisioning.Job + expectedError string }{ { name: "should fail when migrate settings are missing", @@ -127,7 +81,7 @@ func TestMigrationWorker_Process(t *testing.T) { Migrate: nil, }, }, - setupMocks: func(lm *MockMigrator, um *MockMigrator, ds *dualwrite.MockService, pr *jobs.MockJobProgressRecorder) { + setupMocks: func(um *MockMigrator, pr *jobs.MockJobProgressRecorder) { }, setupRepo: func(repo *repository.MockRepository) { // No Config() call expected since we fail before that @@ -135,150 +89,35 @@ func TestMigrationWorker_Process(t *testing.T) { expectedError: "missing migrate settings", }, { - name: "should use legacy migrator when legacy storage is active", + name: "should use unified storage migrator for instance-type repositories", job: provisioning.Job{ Spec: provisioning.JobSpec{ Action: provisioning.JobActionMigrate, Migrate: &provisioning.MigrateJobOptions{}, }, }, - isLegacyActive: true, - setupMocks: func(lm *MockMigrator, um *MockMigrator, ds *dualwrite.MockService, pr *jobs.MockJobProgressRecorder) { + setupMocks: func(um *MockMigrator, pr *jobs.MockJobProgressRecorder) { pr.On("SetTotal", mock.Anything, 10).Return() - ds.On("ReadFromUnified", mock.Anything, mock.Anything).Return(false, nil) - lm.On("Migrate", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil) - }, - setupRepo: func(repo *repository.MockRepository) { - repo.On("Config").Return(&provisioning.Repository{ - Spec: provisioning.RepositorySpec{ - Sync: provisioning.SyncOptions{ - Target: provisioning.SyncTargetTypeInstance, - }, - }, - }) - }, - }, - { - name: "should use unified storage migrator when legacy storage is not active", - job: provisioning.Job{ - Spec: provisioning.JobSpec{ - Action: provisioning.JobActionMigrate, - Migrate: &provisioning.MigrateJobOptions{}, - }, - }, - isLegacyActive: false, - setupMocks: func(lm *MockMigrator, um *MockMigrator, ds *dualwrite.MockService, pr *jobs.MockJobProgressRecorder) { - pr.On("SetTotal", mock.Anything, 10).Return() - ds.On("ReadFromUnified", mock.Anything, mock.Anything).Return(true, nil) um.On("Migrate", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil) }, setupRepo: func(repo *repository.MockRepository) { - repo.On("Config").Return(&provisioning.Repository{ - Spec: provisioning.RepositorySpec{ - Sync: provisioning.SyncOptions{ - Target: provisioning.SyncTargetTypeInstance, - }, - }, - }) + // No Config() call needed anymore }, }, { - name: "should propagate migrator errors", + name: "should allow migration for folder-type repositories", job: provisioning.Job{ Spec: provisioning.JobSpec{ Action: provisioning.JobActionMigrate, Migrate: &provisioning.MigrateJobOptions{}, }, }, - isLegacyActive: true, - setupMocks: func(lm *MockMigrator, um *MockMigrator, ds *dualwrite.MockService, pr *jobs.MockJobProgressRecorder) { + setupMocks: func(um *MockMigrator, pr *jobs.MockJobProgressRecorder) { pr.On("SetTotal", mock.Anything, 10).Return() - ds.On("ReadFromUnified", mock.Anything, mock.Anything).Return(false, nil) - lm.On("Migrate", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(errors.New("migration failed")) - }, - setupRepo: func(repo *repository.MockRepository) { - repo.On("Config").Return(&provisioning.Repository{ - Spec: provisioning.RepositorySpec{ - Sync: provisioning.SyncOptions{ - Target: provisioning.SyncTargetTypeInstance, - }, - }, - }) - }, - expectedError: "migration failed", - }, - { - name: "should block migration of legacy resources for folder-type repositories", - job: provisioning.Job{ - Spec: provisioning.JobSpec{ - Action: provisioning.JobActionMigrate, - Migrate: &provisioning.MigrateJobOptions{}, - }, - }, - isLegacyActive: true, - setupMocks: func(lm *MockMigrator, um *MockMigrator, ds *dualwrite.MockService, pr *jobs.MockJobProgressRecorder) { - pr.On("SetTotal", mock.Anything, 10).Return() - ds.On("ReadFromUnified", mock.Anything, mock.Anything).Return(false, nil) - // legacyMigrator should not be called as we block before reaching it - }, - setupRepo: func(repo *repository.MockRepository) { - repo.On("Config").Return(&provisioning.Repository{ - Spec: provisioning.RepositorySpec{ - Sync: provisioning.SyncOptions{ - Target: provisioning.SyncTargetTypeFolder, - }, - }, - }) - }, - expectedError: "migration of legacy resources is not supported for folder-type repositories", - }, - { - name: "should allow migration of legacy resources for instance-type repositories", - job: provisioning.Job{ - Spec: provisioning.JobSpec{ - Action: provisioning.JobActionMigrate, - Migrate: &provisioning.MigrateJobOptions{}, - }, - }, - isLegacyActive: true, - setupMocks: func(lm *MockMigrator, um *MockMigrator, ds *dualwrite.MockService, pr *jobs.MockJobProgressRecorder) { - pr.On("SetTotal", mock.Anything, 10).Return() - ds.On("ReadFromUnified", mock.Anything, mock.Anything).Return(false, nil) - lm.On("Migrate", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil) - }, - setupRepo: func(repo *repository.MockRepository) { - repo.On("Config").Return(&provisioning.Repository{ - Spec: provisioning.RepositorySpec{ - Sync: provisioning.SyncOptions{ - Target: provisioning.SyncTargetTypeInstance, - }, - }, - }) - }, - expectedError: "", - }, - { - name: "should allow migration for folder-type repositories when legacy storage is not active", - job: provisioning.Job{ - Spec: provisioning.JobSpec{ - Action: provisioning.JobActionMigrate, - Migrate: &provisioning.MigrateJobOptions{}, - }, - }, - isLegacyActive: false, - setupMocks: func(lm *MockMigrator, um *MockMigrator, ds *dualwrite.MockService, pr *jobs.MockJobProgressRecorder) { - pr.On("SetTotal", mock.Anything, 10).Return() - ds.On("ReadFromUnified", mock.Anything, mock.Anything).Return(true, nil) um.On("Migrate", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil) }, setupRepo: func(repo *repository.MockRepository) { - repo.On("Config").Return(&provisioning.Repository{ - Spec: provisioning.RepositorySpec{ - Sync: provisioning.SyncOptions{ - Target: provisioning.SyncTargetTypeFolder, - }, - }, - }) + // No Config() call needed anymore }, expectedError: "", }, @@ -286,15 +125,13 @@ func TestMigrationWorker_Process(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - legacyMigrator := NewMockMigrator(t) unifiedMigrator := NewMockMigrator(t) - dualWriteService := dualwrite.NewMockService(t) progressRecorder := jobs.NewMockJobProgressRecorder(t) - worker := NewMigrationWorker(legacyMigrator, unifiedMigrator, dualWriteService) + worker := NewMigrationWorker(unifiedMigrator) if tt.setupMocks != nil { - tt.setupMocks(legacyMigrator, unifiedMigrator, dualWriteService, progressRecorder) + tt.setupMocks(unifiedMigrator, progressRecorder) } rw := repository.NewMockRepository(t) @@ -310,7 +147,7 @@ func TestMigrationWorker_Process(t *testing.T) { require.NoError(t, err) } - mock.AssertExpectationsForObjects(t, legacyMigrator, unifiedMigrator, dualWriteService, progressRecorder, rw) + mock.AssertExpectationsForObjects(t, unifiedMigrator, progressRecorder, rw) }) } } diff --git a/pkg/registry/apis/provisioning/jobs/progress_fn_mock.go b/pkg/registry/apis/provisioning/jobs/progress_fn_mock.go index 8c68bec33f7..9fde7042601 100644 --- a/pkg/registry/apis/provisioning/jobs/progress_fn_mock.go +++ b/pkg/registry/apis/provisioning/jobs/progress_fn_mock.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.52.4. DO NOT EDIT. +// Code generated by mockery v2.53.4. DO NOT EDIT. package jobs diff --git a/pkg/registry/apis/provisioning/jobs/sync/sync.go b/pkg/registry/apis/provisioning/jobs/sync/sync.go index 7f677a8ce3b..6fec2783a6a 100644 --- a/pkg/registry/apis/provisioning/jobs/sync/sync.go +++ b/pkg/registry/apis/provisioning/jobs/sync/sync.go @@ -14,7 +14,7 @@ import ( //go:generate mockery --name FullSyncFn --structname MockFullSyncFn --inpackage --filename full_sync_fn_mock.go --with-expecter type FullSyncFn func(ctx context.Context, repo repository.Reader, compare CompareFn, clients resources.ResourceClients, currentRef string, repositoryResources resources.RepositoryResources, progress jobs.JobProgressRecorder, tracer tracing.Tracer, maxSyncWorkers int, metrics jobs.JobMetrics) error -//go:generate mockery --name CompareFn --structname MockCompareFn --inpackage --filename compare_fn_mock.go --with-expecter +//go:generate mockery -name CompareFn --structname MockCompareFn --inpackage --filename compare_fn_mock.go --with-expecter type CompareFn func(ctx context.Context, repo repository.Reader, repositoryResources resources.RepositoryResources, ref string) ([]ResourceFileChange, error) //go:generate mockery --name IncrementalSyncFn --structname MockIncrementalSyncFn --inpackage --filename incremental_sync_fn_mock.go --with-expecter diff --git a/pkg/registry/apis/provisioning/jobs/sync/worker.go b/pkg/registry/apis/provisioning/jobs/sync/worker.go index 05e6340b193..367ed672bd2 100644 --- a/pkg/registry/apis/provisioning/jobs/sync/worker.go +++ b/pkg/registry/apis/provisioning/jobs/sync/worker.go @@ -12,7 +12,6 @@ import ( "github.com/grafana/grafana/pkg/registry/apis/provisioning/jobs" "github.com/grafana/grafana/pkg/registry/apis/provisioning/resources" "github.com/grafana/grafana/pkg/registry/apis/provisioning/utils" - "github.com/grafana/grafana/pkg/storage/legacysql/dualwrite" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/trace" ) @@ -29,9 +28,6 @@ type SyncWorker struct { // ResourceClients for the repository repositoryResources resources.RepositoryResourcesFactory - // Check if the system is using unified storage - storageStatus dualwrite.Service - // Patch status for the repository patchStatus RepositoryPatchFn @@ -48,7 +44,6 @@ type SyncWorker struct { func NewSyncWorker( clients resources.ClientFactory, repositoryResources resources.RepositoryResourcesFactory, - storageStatus dualwrite.Service, patchStatus RepositoryPatchFn, syncer Syncer, metrics jobs.JobMetrics, @@ -59,7 +54,6 @@ func NewSyncWorker( clients: clients, repositoryResources: repositoryResources, patchStatus: patchStatus, - storageStatus: storageStatus, syncer: syncer, metrics: metrics, tracer: tracer, @@ -96,13 +90,6 @@ func (r *SyncWorker) Process(ctx context.Context, repo repository.Repository, jo ) }() - // Check if we are onboarding from legacy storage - // HACK -- this should be handled outside of this worker - if r.storageStatus != nil && dualwrite.IsReadingLegacyDashboardsAndFolders(ctx, r.storageStatus) { - err := fmt.Errorf("sync not supported until storage has migrated") - return tracing.Error(span, err) - } - rw, ok := repo.(repository.ReaderWriter) if !ok { err := fmt.Errorf("sync job submitted for repository that does not support read-write") diff --git a/pkg/registry/apis/provisioning/jobs/sync/worker_test.go b/pkg/registry/apis/provisioning/jobs/sync/worker_test.go index a5013539957..34d32372936 100644 --- a/pkg/registry/apis/provisioning/jobs/sync/worker_test.go +++ b/pkg/registry/apis/provisioning/jobs/sync/worker_test.go @@ -10,7 +10,6 @@ import ( "github.com/grafana/grafana/pkg/infra/tracing" "github.com/grafana/grafana/pkg/registry/apis/provisioning/jobs" "github.com/grafana/grafana/pkg/registry/apis/provisioning/resources" - "github.com/grafana/grafana/pkg/storage/legacysql/dualwrite" "github.com/prometheus/client_golang/prometheus" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" @@ -46,7 +45,7 @@ func TestSyncWorker_IsSupported(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - worker := NewSyncWorker(nil, nil, nil, nil, nil, metrics, tracing.NewNoopTracerService(), 10) + worker := NewSyncWorker(nil, nil, nil, nil, metrics, tracing.NewNoopTracerService(), 10) result := worker.IsSupported(context.Background(), tt.job) require.Equal(t, tt.expected, result) }) @@ -63,9 +62,7 @@ func TestSyncWorker_ProcessNotReaderWriter(t *testing.T) { Title: "test-repo", }, }) - fakeDualwrite := dualwrite.NewMockService(t) - fakeDualwrite.On("ReadFromUnified", mock.Anything, mock.Anything).Return(true, nil).Twice() - worker := NewSyncWorker(nil, nil, fakeDualwrite, nil, nil, jobs.RegisterJobMetrics(prometheus.NewPedanticRegistry()), tracing.NewNoopTracerService(), 10) + worker := NewSyncWorker(nil, nil, nil, nil, jobs.RegisterJobMetrics(prometheus.NewPedanticRegistry()), tracing.NewNoopTracerService(), 10) err := worker.Process(context.Background(), repo, provisioning.Job{}, jobs.NewMockJobProgressRecorder(t)) require.EqualError(t, err, "sync job submitted for repository that does not support read-write") } @@ -73,31 +70,13 @@ func TestSyncWorker_ProcessNotReaderWriter(t *testing.T) { func TestSyncWorker_Process(t *testing.T) { tests := []struct { name string - setupMocks func(*resources.MockClientFactory, *resources.MockRepositoryResourcesFactory, *dualwrite.MockService, *MockRepositoryPatchFn, *MockSyncer, *mockReaderWriter, *jobs.MockJobProgressRecorder) + setupMocks func(*resources.MockClientFactory, *resources.MockRepositoryResourcesFactory, *MockRepositoryPatchFn, *MockSyncer, *mockReaderWriter, *jobs.MockJobProgressRecorder) expectedError string expectedStatus *provisioning.SyncStatus }{ - { - name: "legacy storage not migrated", - setupMocks: func(cf *resources.MockClientFactory, rrf *resources.MockRepositoryResourcesFactory, ds *dualwrite.MockService, rpf *MockRepositoryPatchFn, s *MockSyncer, rw *mockReaderWriter, pr *jobs.MockJobProgressRecorder) { - rw.MockRepository.On("Config").Return(&provisioning.Repository{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-repo", - }, - Spec: provisioning.RepositorySpec{ - Title: "test-repo", - }, - }) - - ds.On("ReadFromUnified", mock.Anything, mock.Anything).Return(false, nil).Twice() - }, - expectedError: "sync not supported until storage has migrated", - }, { name: "failed initial status patching", - setupMocks: func(cf *resources.MockClientFactory, rrf *resources.MockRepositoryResourcesFactory, ds *dualwrite.MockService, rpf *MockRepositoryPatchFn, s *MockSyncer, rw *mockReaderWriter, pr *jobs.MockJobProgressRecorder) { - ds.On("ReadFromUnified", mock.Anything, mock.Anything).Return(true, nil).Twice() - + setupMocks: func(cf *resources.MockClientFactory, rrf *resources.MockRepositoryResourcesFactory, rpf *MockRepositoryPatchFn, s *MockSyncer, rw *mockReaderWriter, pr *jobs.MockJobProgressRecorder) { // Setup repository config with existing LastRef repoConfig := &provisioning.Repository{ ObjectMeta: metav1.ObjectMeta{ @@ -132,7 +111,7 @@ func TestSyncWorker_Process(t *testing.T) { }, { name: "failed getting repository resources", - setupMocks: func(cf *resources.MockClientFactory, rrf *resources.MockRepositoryResourcesFactory, ds *dualwrite.MockService, rpf *MockRepositoryPatchFn, s *MockSyncer, rw *mockReaderWriter, pr *jobs.MockJobProgressRecorder) { + setupMocks: func(cf *resources.MockClientFactory, rrf *resources.MockRepositoryResourcesFactory, rpf *MockRepositoryPatchFn, s *MockSyncer, rw *mockReaderWriter, pr *jobs.MockJobProgressRecorder) { // Setup repository config repoConfig := &provisioning.Repository{ ObjectMeta: metav1.ObjectMeta{ @@ -149,9 +128,6 @@ func TestSyncWorker_Process(t *testing.T) { } rw.MockRepository.On("Config").Return(repoConfig) - // Storage is migrated - ds.On("ReadFromUnified", mock.Anything, mock.Anything).Return(true, nil).Twice() - // Initial status update succeeds - expect granular patches pr.On("SetMessage", mock.Anything, "update sync status at start").Return() rpf.On("Execute", mock.Anything, repoConfig, mock.Anything, mock.Anything, mock.Anything).Return(nil).Once() @@ -168,7 +144,7 @@ func TestSyncWorker_Process(t *testing.T) { }, { name: "failed getting clients for namespace", - setupMocks: func(cf *resources.MockClientFactory, rrf *resources.MockRepositoryResourcesFactory, ds *dualwrite.MockService, rpf *MockRepositoryPatchFn, s *MockSyncer, rw *mockReaderWriter, pr *jobs.MockJobProgressRecorder) { + setupMocks: func(cf *resources.MockClientFactory, rrf *resources.MockRepositoryResourcesFactory, rpf *MockRepositoryPatchFn, s *MockSyncer, rw *mockReaderWriter, pr *jobs.MockJobProgressRecorder) { // Setup repository config repoConfig := &provisioning.Repository{ ObjectMeta: metav1.ObjectMeta{ @@ -186,9 +162,6 @@ func TestSyncWorker_Process(t *testing.T) { } rw.MockRepository.On("Config").Return(repoConfig) - // Storage is migrated - ds.On("ReadFromUnified", mock.Anything, mock.Anything).Return(true, nil).Twice() - // Initial status update succeeds - expect granular patches pr.On("SetMessage", mock.Anything, "update sync status at start").Return() rpf.On("Execute", mock.Anything, repoConfig, mock.Anything, mock.Anything, mock.Anything).Return(nil).Once() @@ -208,7 +181,7 @@ func TestSyncWorker_Process(t *testing.T) { }, { name: "successful sync", - setupMocks: func(cf *resources.MockClientFactory, rrf *resources.MockRepositoryResourcesFactory, ds *dualwrite.MockService, rpf *MockRepositoryPatchFn, s *MockSyncer, rw *mockReaderWriter, pr *jobs.MockJobProgressRecorder) { + setupMocks: func(cf *resources.MockClientFactory, rrf *resources.MockRepositoryResourcesFactory, rpf *MockRepositoryPatchFn, s *MockSyncer, rw *mockReaderWriter, pr *jobs.MockJobProgressRecorder) { repoConfig := &provisioning.Repository{ ObjectMeta: metav1.ObjectMeta{ Name: "test-repo", @@ -222,9 +195,6 @@ func TestSyncWorker_Process(t *testing.T) { } rw.MockRepository.On("Config").Return(repoConfig) - // Storage is migrated - ds.On("ReadFromUnified", mock.Anything, mock.Anything).Return(true, nil).Twice() - // Initial status update - expect granular patches pr.On("SetMessage", mock.Anything, "update sync status at start").Return() rpf.On("Execute", mock.Anything, repoConfig, mock.Anything, mock.Anything, mock.Anything).Return(nil).Once() @@ -261,7 +231,7 @@ func TestSyncWorker_Process(t *testing.T) { }, { name: "failed sync", - setupMocks: func(cf *resources.MockClientFactory, rrf *resources.MockRepositoryResourcesFactory, ds *dualwrite.MockService, rpf *MockRepositoryPatchFn, s *MockSyncer, rw *mockReaderWriter, pr *jobs.MockJobProgressRecorder) { + setupMocks: func(cf *resources.MockClientFactory, rrf *resources.MockRepositoryResourcesFactory, rpf *MockRepositoryPatchFn, s *MockSyncer, rw *mockReaderWriter, pr *jobs.MockJobProgressRecorder) { repoConfig := &provisioning.Repository{ ObjectMeta: metav1.ObjectMeta{ Name: "test-repo", @@ -275,9 +245,6 @@ func TestSyncWorker_Process(t *testing.T) { } rw.MockRepository.On("Config").Return(repoConfig) - // Storage is migrated - ds.On("ReadFromUnified", mock.Anything, mock.Anything).Return(true, nil).Twice() - // Initial status update - expect granular patches pr.On("SetMessage", mock.Anything, "update sync status at start").Return() rpf.On("Execute", mock.Anything, repoConfig, mock.Anything, mock.Anything, mock.Anything).Return(nil).Once() @@ -315,7 +282,7 @@ func TestSyncWorker_Process(t *testing.T) { }, { name: "stats call fails", - setupMocks: func(cf *resources.MockClientFactory, rrf *resources.MockRepositoryResourcesFactory, ds *dualwrite.MockService, rpf *MockRepositoryPatchFn, s *MockSyncer, rw *mockReaderWriter, pr *jobs.MockJobProgressRecorder) { + setupMocks: func(cf *resources.MockClientFactory, rrf *resources.MockRepositoryResourcesFactory, rpf *MockRepositoryPatchFn, s *MockSyncer, rw *mockReaderWriter, pr *jobs.MockJobProgressRecorder) { repoConfig := &provisioning.Repository{ ObjectMeta: metav1.ObjectMeta{ Name: "test-repo", @@ -323,7 +290,6 @@ func TestSyncWorker_Process(t *testing.T) { }, } rw.MockRepository.On("Config").Return(repoConfig) - ds.On("ReadFromUnified", mock.Anything, mock.Anything).Return(true, nil).Twice() mockRepoResources := resources.NewMockRepositoryResources(t) mockRepoResources.On("Stats", mock.Anything).Return(nil, errors.New("stats error")) @@ -344,7 +310,7 @@ func TestSyncWorker_Process(t *testing.T) { }, { name: "stats returns nil stats and nil error", - setupMocks: func(cf *resources.MockClientFactory, rrf *resources.MockRepositoryResourcesFactory, ds *dualwrite.MockService, rpf *MockRepositoryPatchFn, s *MockSyncer, rw *mockReaderWriter, pr *jobs.MockJobProgressRecorder) { + setupMocks: func(cf *resources.MockClientFactory, rrf *resources.MockRepositoryResourcesFactory, rpf *MockRepositoryPatchFn, s *MockSyncer, rw *mockReaderWriter, pr *jobs.MockJobProgressRecorder) { repoConfig := &provisioning.Repository{ ObjectMeta: metav1.ObjectMeta{ Name: "test-repo", @@ -352,7 +318,6 @@ func TestSyncWorker_Process(t *testing.T) { }, } rw.MockRepository.On("Config").Return(repoConfig) - ds.On("ReadFromUnified", mock.Anything, mock.Anything).Return(true, nil).Twice() mockRepoResources := resources.NewMockRepositoryResources(t) mockRepoResources.On("Stats", mock.Anything).Return(nil, nil) @@ -378,7 +343,7 @@ func TestSyncWorker_Process(t *testing.T) { }, { name: "stats returns one managed stats", - setupMocks: func(cf *resources.MockClientFactory, rrf *resources.MockRepositoryResourcesFactory, ds *dualwrite.MockService, rpf *MockRepositoryPatchFn, s *MockSyncer, rw *mockReaderWriter, pr *jobs.MockJobProgressRecorder) { + setupMocks: func(cf *resources.MockClientFactory, rrf *resources.MockRepositoryResourcesFactory, rpf *MockRepositoryPatchFn, s *MockSyncer, rw *mockReaderWriter, pr *jobs.MockJobProgressRecorder) { repoConfig := &provisioning.Repository{ ObjectMeta: metav1.ObjectMeta{ Name: "test-repo", @@ -386,7 +351,6 @@ func TestSyncWorker_Process(t *testing.T) { }, } rw.MockRepository.On("Config").Return(repoConfig) - ds.On("ReadFromUnified", mock.Anything, mock.Anything).Return(true, nil).Twice() // Initial patch with granular updates rpf.On("Execute", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil).Once() @@ -439,7 +403,7 @@ func TestSyncWorker_Process(t *testing.T) { }, { name: "stats returns multiple managed stats", - setupMocks: func(cf *resources.MockClientFactory, rrf *resources.MockRepositoryResourcesFactory, ds *dualwrite.MockService, rpf *MockRepositoryPatchFn, s *MockSyncer, rw *mockReaderWriter, pr *jobs.MockJobProgressRecorder) { + setupMocks: func(cf *resources.MockClientFactory, rrf *resources.MockRepositoryResourcesFactory, rpf *MockRepositoryPatchFn, s *MockSyncer, rw *mockReaderWriter, pr *jobs.MockJobProgressRecorder) { repoConfig := &provisioning.Repository{ ObjectMeta: metav1.ObjectMeta{ Name: "test-repo", @@ -447,7 +411,6 @@ func TestSyncWorker_Process(t *testing.T) { }, } rw.MockRepository.On("Config").Return(repoConfig) - ds.On("ReadFromUnified", mock.Anything, mock.Anything).Return(true, nil).Twice() mockRepoResources := resources.NewMockRepositoryResources(t) stats := &provisioning.ResourceStats{ @@ -495,7 +458,7 @@ func TestSyncWorker_Process(t *testing.T) { }, { name: "failed final status patch", - setupMocks: func(cf *resources.MockClientFactory, rrf *resources.MockRepositoryResourcesFactory, ds *dualwrite.MockService, rpf *MockRepositoryPatchFn, s *MockSyncer, rw *mockReaderWriter, pr *jobs.MockJobProgressRecorder) { + setupMocks: func(cf *resources.MockClientFactory, rrf *resources.MockRepositoryResourcesFactory, rpf *MockRepositoryPatchFn, s *MockSyncer, rw *mockReaderWriter, pr *jobs.MockJobProgressRecorder) { repoConfig := &provisioning.Repository{ ObjectMeta: metav1.ObjectMeta{ Name: "test-repo", @@ -503,7 +466,6 @@ func TestSyncWorker_Process(t *testing.T) { }, } rw.MockRepository.On("Config").Return(repoConfig) - ds.On("ReadFromUnified", mock.Anything, mock.Anything).Return(true, nil).Twice() // Initial status patch succeeds - expect granular patches rpf.On("Execute", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil).Once() @@ -534,7 +496,6 @@ func TestSyncWorker_Process(t *testing.T) { // Create mocks clientFactory := resources.NewMockClientFactory(t) repoResourcesFactory := resources.NewMockRepositoryResourcesFactory(t) - dualwriteService := dualwrite.NewMockService(t) repositoryPatchFn := NewMockRepositoryPatchFn(t) syncer := NewMockSyncer(t) readerWriter := &mockReaderWriter{ @@ -544,13 +505,12 @@ func TestSyncWorker_Process(t *testing.T) { progressRecorder := jobs.NewMockJobProgressRecorder(t) // Setup mocks - tt.setupMocks(clientFactory, repoResourcesFactory, dualwriteService, repositoryPatchFn, syncer, readerWriter, progressRecorder) + tt.setupMocks(clientFactory, repoResourcesFactory, repositoryPatchFn, syncer, readerWriter, progressRecorder) // Create worker worker := NewSyncWorker( clientFactory, repoResourcesFactory, - dualwriteService, repositoryPatchFn.Execute, syncer, jobs.RegisterJobMetrics(prometheus.NewPedanticRegistry()), diff --git a/pkg/registry/apis/provisioning/jobs/worker_mock.go b/pkg/registry/apis/provisioning/jobs/worker_mock.go index 52f0683fdd8..d669193c166 100644 --- a/pkg/registry/apis/provisioning/jobs/worker_mock.go +++ b/pkg/registry/apis/provisioning/jobs/worker_mock.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.52.4. DO NOT EDIT. +// Code generated by mockery v2.53.4. DO NOT EDIT. package jobs diff --git a/pkg/registry/apis/provisioning/register.go b/pkg/registry/apis/provisioning/register.go index b479dc3f8c8..26e97f56b3c 100644 --- a/pkg/registry/apis/provisioning/register.go +++ b/pkg/registry/apis/provisioning/register.go @@ -28,9 +28,8 @@ import ( authlib "github.com/grafana/authlib/types" "github.com/grafana/grafana-app-sdk/logging" - dashboard "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v0alpha1" - 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/auth" connectionvalidation "github.com/grafana/grafana/apps/provisioning/pkg/connection" appcontroller "github.com/grafana/grafana/apps/provisioning/pkg/controller" clientset "github.com/grafana/grafana/apps/provisioning/pkg/generated/clientset/versioned" @@ -54,14 +53,12 @@ import ( movepkg "github.com/grafana/grafana/pkg/registry/apis/provisioning/jobs/move" "github.com/grafana/grafana/pkg/registry/apis/provisioning/jobs/sync" "github.com/grafana/grafana/pkg/registry/apis/provisioning/resources" - "github.com/grafana/grafana/pkg/registry/apis/provisioning/resources/signature" "github.com/grafana/grafana/pkg/registry/apis/provisioning/usage" "github.com/grafana/grafana/pkg/services/apiserver" "github.com/grafana/grafana/pkg/services/apiserver/builder" "github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/storage/legacysql/dualwrite" - "github.com/grafana/grafana/pkg/storage/unified/migrations" "github.com/grafana/grafana/pkg/storage/unified/resource" ) @@ -112,11 +109,13 @@ type APIBuilder struct { jobHistoryLoki *jobs.LokiJobHistory resourceLister resources.ResourceLister dashboardAccess legacy.MigrationDashboardAccessor - storageStatus dualwrite.Service unified resource.ResourceClient repoFactory repository.Factory client client.ProvisioningV0alpha1Interface - access authlib.AccessChecker + access auth.AccessChecker + accessWithAdmin auth.AccessChecker + accessWithEditor auth.AccessChecker + accessWithViewer auth.AccessChecker statusPatcher *appcontroller.RepositoryStatusPatcher healthChecker *controller.HealthChecker validator repository.RepositoryValidator @@ -159,9 +158,17 @@ func NewAPIBuilder( } else { clients = resources.NewClientFactory(configProvider) } + parsers := resources.NewParserFactory(clients) - legacyMigrator := migrations.ProvideUnifiedMigrator(dashboardAccess, unified) - resourceLister := resources.NewResourceListerForMigrations(unified, legacyMigrator, storageStatus) + resourceLister := resources.NewResourceListerForMigrations(unified) + + // Create access checker based on mode + var accessChecker auth.AccessChecker + if useExclusivelyAccessCheckerForAuthz { + accessChecker = auth.NewTokenAccessChecker(access) + } else { + accessChecker = auth.NewSessionAccessChecker(access) + } b := &APIBuilder{ onlyApiServer: onlyApiServer, @@ -174,9 +181,11 @@ func NewAPIBuilder( repositoryResources: resources.NewRepositoryResourcesFactory(parsers, clients, resourceLister), resourceLister: resourceLister, dashboardAccess: dashboardAccess, - storageStatus: storageStatus, unified: unified, - access: access, + access: accessChecker, + accessWithAdmin: accessChecker.WithFallbackRole(identity.RoleAdmin), + accessWithEditor: accessChecker.WithFallbackRole(identity.RoleEditor), + accessWithViewer: accessChecker.WithFallbackRole(identity.RoleViewer), jobHistoryConfig: jobHistoryConfig, extraWorkers: extraWorkers, restConfigGetter: restConfigGetter, @@ -250,6 +259,10 @@ func RegisterAPIService( return nil, nil } + if dualwrite.IsReadingLegacyDashboardsAndFolders(context.Background(), storageStatus) { + return nil, fmt.Errorf("resources are stored in an incompatible data format to use provisioning. Please enable data migration in settings for folders and dashboards by adding the following configuration:\n[unified_storage.folders.folder.grafana.app]\nenableMigration = true\n\n[unified_storage.dashboards.dashboard.grafana.app]\nenableMigration = true\n\nAlternatively, disable provisioning") + } + allowedTargets := []provisioning.SyncTargetType{} for _, target := range cfg.ProvisioningAllowedTargets { allowedTargets = append(allowedTargets, provisioning.SyncTargetType(target)) @@ -300,161 +313,142 @@ func (b *APIBuilder) GetAuthorizer() authorizer.Authorizer { } } - info, ok := authlib.AuthInfoFrom(ctx) - // when running as standalone API server, the identity type may not always match TypeAccessPolicy - // so we allow it to use the access checker if there is any auth info available - if ok && (authlib.IsIdentityType(info.GetIdentityType(), authlib.TypeAccessPolicy) || b.useExclusivelyAccessCheckerForAuthz) { - res, err := b.access.Check(ctx, info, authlib.CheckRequest{ - Verb: a.GetVerb(), - Group: a.GetAPIGroup(), - Resource: a.GetResource(), - Name: a.GetName(), - Namespace: a.GetNamespace(), - Subresource: a.GetSubresource(), - Path: a.GetPath(), - }, "") - if err != nil { - return authorizer.DecisionDeny, "failed to perform authorization", err - } - - if !res.Allowed { - return authorizer.DecisionDeny, "permission denied", nil - } - - return authorizer.DecisionAllow, "", nil - } - - id, err := identity.GetRequester(ctx) - if err != nil { - return authorizer.DecisionDeny, "failed to find requester", err - } - - return b.authorizeResource(ctx, a, id) + return b.authorizeResource(ctx, a) }) } // authorizeResource handles authorization for different resources. -// Different routes may need different permissions. -// * Reading and modifying a repository's configuration requires administrator privileges. -// * Reading a repository's limited configuration (/stats & /settings) requires viewer privileges. -// * Reading a repository's files requires viewer privileges. -// * Reading a repository's refs requires viewer privileges. -// * Editing a repository's files requires editor privileges. -// * Syncing a repository requires editor privileges. -// * Exporting a repository requires administrator privileges. -// * Migrating a repository requires administrator privileges. -// * Testing a repository configuration requires administrator privileges. -// * Viewing a repository's history requires editor privileges. -func (b *APIBuilder) authorizeResource(ctx context.Context, a authorizer.Attributes, id identity.Requester) (authorizer.Decision, string, error) { +// Uses fine-grained permissions defined in accesscontrol.go: +// +// Repositories: +// - CRUD: repositories:create/read/write/delete +// - Subresources: files (any auth), refs (editor), resources/history/status (admin) +// - Test: repositories:write +// - Jobs subresource: jobs:create/read +// +// Connections: +// - CRUD: connections:create/read/write/delete +// - Status: connections:read +// +// Jobs: +// - CRUD: jobs:create/read/write/delete +// +// Historic Jobs: +// - Read-only: historicjobs:read +// +// Settings: +// - settings:read - granted to Viewer (all logged-in users) +// +// Stats: +// - stats:read - granted to Admin only +func (b *APIBuilder) authorizeResource(ctx context.Context, a authorizer.Attributes) (authorizer.Decision, string, error) { switch a.GetResource() { case provisioning.RepositoryResourceInfo.GetName(): - return b.authorizeRepositorySubresource(a, id) - case "stats": - return b.authorizeStats(id) - case "settings": - return b.authorizeSettings(id) - case provisioning.JobResourceInfo.GetName(), provisioning.HistoricJobResourceInfo.GetName(): - return b.authorizeJobs(id) + return b.authorizeRepositorySubresource(ctx, a) case provisioning.ConnectionResourceInfo.GetName(): - return b.authorizeConnectionSubresource(a, id) + return b.authorizeConnectionSubresource(ctx, a) + case provisioning.JobResourceInfo.GetName(): + return toAuthorizerDecision(b.accessWithEditor.Check(ctx, authlib.CheckRequest{ + Verb: a.GetVerb(), + Group: provisioning.GROUP, + Resource: provisioning.JobResourceInfo.GetName(), + Name: a.GetName(), + Namespace: a.GetNamespace(), + }, "")) + case provisioning.HistoricJobResourceInfo.GetName(): + // Historic jobs are read-only and admin-only (not editor) + return toAuthorizerDecision(b.accessWithAdmin.Check(ctx, authlib.CheckRequest{ + Verb: a.GetVerb(), + Group: provisioning.GROUP, + Resource: provisioning.HistoricJobResourceInfo.GetName(), + Name: a.GetName(), + Namespace: a.GetNamespace(), + }, "")) + case "settings": + // Settings are read-only and accessible by all logged-in users (Viewer role) + return toAuthorizerDecision(b.accessWithViewer.Check(ctx, authlib.CheckRequest{ + Verb: a.GetVerb(), + Group: provisioning.GROUP, + Resource: "settings", + Namespace: a.GetNamespace(), + }, "")) + case "stats": + // Stats are read-only and admin-only + return toAuthorizerDecision(b.accessWithAdmin.Check(ctx, authlib.CheckRequest{ + Verb: a.GetVerb(), + Group: provisioning.GROUP, + Resource: "stats", + Namespace: a.GetNamespace(), + }, "")) default: - return b.authorizeDefault(id) + return b.authorizeDefault(ctx) } } // authorizeRepositorySubresource handles authorization for repository subresources. -func (b *APIBuilder) authorizeRepositorySubresource(a authorizer.Attributes, id identity.Requester) (authorizer.Decision, string, error) { - // TODO: Support more fine-grained permissions than the basic roles. Especially on Enterprise. - switch a.GetSubresource() { - case "", "test": - // Doing something with the repository itself. - if id.GetOrgRole().Includes(identity.RoleAdmin) { - return authorizer.DecisionAllow, "", nil - } - return authorizer.DecisionDeny, "admin role is required", nil - - case "jobs": - // Posting jobs requires editor privileges (for syncing). - if id.GetOrgRole().Includes(identity.RoleAdmin) || id.GetOrgRole().Includes(identity.RoleEditor) { - return authorizer.DecisionAllow, "", nil - } - return authorizer.DecisionDeny, "editor role is required", nil - - case "refs": - // This is strictly a read operation. It is handy on the frontend for viewers. - if id.GetOrgRole().Includes(identity.RoleViewer) { - return authorizer.DecisionAllow, "", nil - } - return authorizer.DecisionDeny, "viewer role is required", nil - - case "files": - // Access to files is controlled by the AccessClient - return authorizer.DecisionAllow, "", nil - - case "resources", "sync", "history": - // These are strictly read operations. - // Sync can also be somewhat destructive, but it's expected to be fine to import changes. - if id.GetOrgRole().Includes(identity.RoleEditor) { - return authorizer.DecisionAllow, "", nil - } - return authorizer.DecisionDeny, "editor role is required", nil - - case "status": - if id.GetOrgRole().Includes(identity.RoleViewer) && a.GetVerb() == apiutils.VerbGet { - return authorizer.DecisionAllow, "", nil - } - return authorizer.DecisionDeny, "users cannot update the status of a repository", nil - - default: - if id.GetIsGrafanaAdmin() { - return authorizer.DecisionAllow, "", nil - } - return authorizer.DecisionDeny, "unmapped subresource defaults to no access", nil - } -} - -// authorizeStats handles authorization for stats resource. -func (b *APIBuilder) authorizeStats(id identity.Requester) (authorizer.Decision, string, error) { - // This can leak information one shouldn't necessarily have access to. - if id.GetOrgRole().Includes(identity.RoleAdmin) { - return authorizer.DecisionAllow, "", nil - } - return authorizer.DecisionDeny, "admin role is required", nil -} - -// authorizeSettings handles authorization for settings resource. -func (b *APIBuilder) authorizeSettings(id identity.Requester) (authorizer.Decision, string, error) { - // This is strictly a read operation. It is handy on the frontend for viewers. - if id.GetOrgRole().Includes(identity.RoleViewer) { - return authorizer.DecisionAllow, "", nil - } - return authorizer.DecisionDeny, "viewer role is required", nil -} - -// authorizeJobs handles authorization for job resources. -func (b *APIBuilder) authorizeJobs(id identity.Requester) (authorizer.Decision, string, error) { - // Jobs are shown on the configuration page. - if id.GetOrgRole().Includes(identity.RoleAdmin) { - return authorizer.DecisionAllow, "", nil - } - return authorizer.DecisionDeny, "admin role is required", nil -} - -// authorizeRepositorySubresource handles authorization for connections subresources. -func (b *APIBuilder) authorizeConnectionSubresource(a authorizer.Attributes, id identity.Requester) (authorizer.Decision, string, error) { +// Uses the access checker with verb-based authorization. +func (b *APIBuilder) authorizeRepositorySubresource(ctx context.Context, a authorizer.Attributes) (authorizer.Decision, string, error) { switch a.GetSubresource() { + // Repository CRUD - use access checker with the actual verb case "": - // Doing something with the connection itself. - if id.GetOrgRole().Includes(identity.RoleAdmin) { - return authorizer.DecisionAllow, "", nil - } - return authorizer.DecisionDeny, "admin role is required", nil - case "status": - if id.GetOrgRole().Includes(identity.RoleViewer) && a.GetVerb() == apiutils.VerbGet { - return authorizer.DecisionAllow, "", nil - } - return authorizer.DecisionDeny, "users cannot update the status of a connection", nil + return toAuthorizerDecision(b.accessWithAdmin.Check(ctx, authlib.CheckRequest{ + Verb: a.GetVerb(), + Group: provisioning.GROUP, + Resource: provisioning.RepositoryResourceInfo.GetName(), + Name: a.GetName(), + Namespace: a.GetNamespace(), + }, "")) + + // Test requires write permission (testing before save) + case "test": + return toAuthorizerDecision(b.accessWithAdmin.Check(ctx, authlib.CheckRequest{ + Verb: apiutils.VerbUpdate, + Group: provisioning.GROUP, + Resource: provisioning.RepositoryResourceInfo.GetName(), + Name: a.GetName(), + Namespace: a.GetNamespace(), + }, "")) + + // Files subresource: allow any authenticated user at route level. + // Directory listing checks repositories:read in the connector. + // Individual file operations are authorized by DualReadWriter based on the actual resource. + case "files": + return authorizer.DecisionAllow, "", nil + + // refs subresource - editors need to see branches to push changes + case "refs": + return toAuthorizerDecision(b.accessWithEditor.Check(ctx, authlib.CheckRequest{ + Verb: apiutils.VerbGet, + Group: provisioning.GROUP, + Resource: provisioning.RepositoryResourceInfo.GetName(), + Name: a.GetName(), + Namespace: a.GetNamespace(), + }, "")) + + // Read-only subresources: resources, history, status (admin only) + case "resources", "history", "status": + return toAuthorizerDecision(b.accessWithAdmin.Check(ctx, authlib.CheckRequest{ + Verb: apiutils.VerbGet, + Group: provisioning.GROUP, + Resource: provisioning.RepositoryResourceInfo.GetName(), + Name: a.GetName(), + Namespace: a.GetNamespace(), + }, "")) + + // Jobs subresource - check jobs permissions with the verb (editors can manage jobs) + case "jobs": + return toAuthorizerDecision(b.accessWithEditor.Check(ctx, authlib.CheckRequest{ + Verb: a.GetVerb(), + Group: provisioning.GROUP, + Resource: provisioning.JobResourceInfo.GetName(), + Namespace: a.GetNamespace(), + }, "")) + default: + id, err := identity.GetRequester(ctx) + if err != nil { + return authorizer.DecisionDeny, "failed to find requester", err + } if id.GetIsGrafanaAdmin() { return authorizer.DecisionAllow, "", nil } @@ -462,8 +456,60 @@ func (b *APIBuilder) authorizeConnectionSubresource(a authorizer.Attributes, id } } +// authorizeConnectionSubresource handles authorization for connection subresources. +// Uses the access checker with verb-based authorization. +func (b *APIBuilder) authorizeConnectionSubresource(ctx context.Context, a authorizer.Attributes) (authorizer.Decision, string, error) { + switch a.GetSubresource() { + // Connection CRUD - use access checker with the actual verb + case "": + return toAuthorizerDecision(b.accessWithAdmin.Check(ctx, authlib.CheckRequest{ + Verb: a.GetVerb(), + Group: provisioning.GROUP, + Resource: provisioning.ConnectionResourceInfo.GetName(), + Name: a.GetName(), + Namespace: a.GetNamespace(), + }, "")) + + // Status is read-only + case "status": + return toAuthorizerDecision(b.accessWithAdmin.Check(ctx, authlib.CheckRequest{ + Verb: apiutils.VerbGet, + Group: provisioning.GROUP, + Resource: provisioning.ConnectionResourceInfo.GetName(), + Name: a.GetName(), + Namespace: a.GetNamespace(), + }, "")) + + default: + id, err := identity.GetRequester(ctx) + if err != nil { + return authorizer.DecisionDeny, "failed to find requester", err + } + if id.GetIsGrafanaAdmin() { + return authorizer.DecisionAllow, "", nil + } + return authorizer.DecisionDeny, "unmapped subresource defaults to no access", nil + } +} + +// ---------------------------------------------------------------------------- +// Authorization helpers +// ---------------------------------------------------------------------------- + +// toAuthorizerDecision converts an access check error to an authorizer decision tuple. +func toAuthorizerDecision(err error) (authorizer.Decision, string, error) { + if err != nil { + return authorizer.DecisionDeny, err.Error(), nil + } + return authorizer.DecisionAllow, "", nil +} + // authorizeDefault handles authorization for unmapped resources. -func (b *APIBuilder) authorizeDefault(id identity.Requester) (authorizer.Decision, string, error) { +func (b *APIBuilder) authorizeDefault(ctx context.Context) (authorizer.Decision, string, error) { + id, err := identity.GetRequester(ctx) + if err != nil { + return authorizer.DecisionDeny, "failed to find requester", err + } // We haven't bothered with this kind yet. if id.GetIsGrafanaAdmin() { return authorizer.DecisionAllow, "", nil @@ -560,7 +606,7 @@ func (b *APIBuilder) UpdateAPIGroupInfo(apiGroupInfo *genericapiserver.APIGroupI // TODO: Add some logic so that the connectors can registered themselves and we don't have logic all over the place storage[provisioning.RepositoryResourceInfo.StoragePath("test")] = NewTestConnector(b, repository.NewRepositoryTesterWithExistingChecker(repository.NewSimpleRepositoryTester(b.validator), b.VerifyAgainstExistingRepositories)) - storage[provisioning.RepositoryResourceInfo.StoragePath("files")] = NewFilesConnector(b, b.parsers, b.clients, b.access) + storage[provisioning.RepositoryResourceInfo.StoragePath("files")] = NewFilesConnector(b, b.parsers, b.clients, b.accessWithAdmin) storage[provisioning.RepositoryResourceInfo.StoragePath("refs")] = NewRefsConnector(b) storage[provisioning.RepositoryResourceInfo.StoragePath("resources")] = &listConnector{ getter: b, @@ -675,7 +721,8 @@ func (b *APIBuilder) Validate(ctx context.Context, a admission.Attributes, o adm // // the only time to add configuration checks here is if you need to compare // the incoming change to the current configuration - list := b.validator.ValidateRepository(repo) + isCreate := a.GetOperation() == admission.Create + list := b.validator.ValidateRepository(repo, isCreate) cfg := repo.Config() if a.GetOperation() == admission.Update { @@ -762,12 +809,6 @@ func (b *APIBuilder) GetPostStartHooks() (map[string]genericapiserver.PostStartH go repoInformer.Informer().Run(postStartHookCtx.Done()) go jobInformer.Informer().Run(postStartHookCtx.Done()) - // When starting with an empty instance -- swith to "mode 4+" - err = b.tryRunningOnlyUnifiedStorage() - if err != nil { - return err - } - // Create the repository resources factory repositoryListerWrapper := func(ctx context.Context) ([]provisioning.Repository, error) { return GetRepositoriesInNamespace(ctx, b.store) @@ -790,29 +831,12 @@ func (b *APIBuilder) GetPostStartHooks() (map[string]genericapiserver.PostStartH syncWorker := sync.NewSyncWorker( b.clients, b.repositoryResources, - b.storageStatus, b.statusPatcher.Patch, syncer, metrics, b.tracer, 10, ) - signerFactory := signature.NewSignerFactory(b.clients) - legacyResources := migrate.NewLegacyResourcesMigrator( - b.repositoryResources, - b.parsers, - b.dashboardAccess, - signerFactory, - b.clients, - export.ExportAll, - ) - storageSwapper := migrate.NewStorageSwapper(b.unified, b.storageStatus) - legacyMigrator := migrate.NewLegacyMigrator( - legacyResources, - storageSwapper, - syncWorker, - stageIfPossible, - ) cleaner := migrate.NewNamespaceCleaner(b.clients) unifiedStorageMigrator := migrate.NewUnifiedStorageMigrator( @@ -820,12 +844,7 @@ func (b *APIBuilder) GetPostStartHooks() (map[string]genericapiserver.PostStartH exportWorker, syncWorker, ) - - migrationWorker := migrate.NewMigrationWorker( - legacyMigrator, - unifiedStorageMigrator, - b.storageStatus, - ) + migrationWorker := migrate.NewMigrationWorker(unifiedStorageMigrator) deleteWorker := deletepkg.NewWorker(syncWorker, stageIfPossible, b.repositoryResources, metrics) moveWorker := movepkg.NewWorker(syncWorker, stageIfPossible, b.repositoryResources, metrics) @@ -897,7 +916,6 @@ func (b *APIBuilder) GetPostStartHooks() (map[string]genericapiserver.PostStartH b.resourceLister, b.clients, b.jobs, - b.storageStatus, b.GetHealthChecker(), b.statusPatcher, b.registry, @@ -1306,65 +1324,6 @@ spec: return oas, nil } -// FIXME: This logic does not belong in provisioning! (but required for now) -// When starting an empty instance, we shift so that we never reference legacy storage -// This should run somewhere else at startup by default (dual writer? dashboards?) -func (b *APIBuilder) tryRunningOnlyUnifiedStorage() error { - ctx := context.Background() - - if !b.storageStatus.ShouldManage(dashboard.DashboardResourceInfo.GroupResource()) { - return nil // not enabled - } - - if !dualwrite.IsReadingLegacyDashboardsAndFolders(ctx, b.storageStatus) { - return nil - } - - // Count how many things exist - create a migrator on-demand for this - legacyMigrator := migrations.ProvideUnifiedMigrator(b.dashboardAccess, b.unified) - rsp, err := legacyMigrator.Migrate(ctx, legacy.MigrateOptions{ - Namespace: "default", // FIXME! this works for single org, but need to check multi-org - Resources: []schema.GroupResource{{ - Group: dashboard.GROUP, Resource: dashboard.DASHBOARD_RESOURCE, - }, { - Group: folders.GROUP, Resource: folders.RESOURCE, - }}, - OnlyCount: true, - }) - if err != nil { - return fmt.Errorf("error getting legacy count %w", err) - } - for _, stats := range rsp.Summary { - if stats.Count > 0 { - return nil // something exists we can not just switch - } - } - - logger := logging.DefaultLogger.With("logger", "provisioning startup") - mode5 := func(gr schema.GroupResource) error { - status, _ := b.storageStatus.Status(ctx, gr) - if !status.ReadUnified { - status.ReadUnified = true - status.WriteLegacy = false - status.WriteUnified = true - status.Runtime = false - status.Migrated = time.Now().UnixMilli() - _, err = b.storageStatus.Update(ctx, status) - logger.Info("set unified storage access", "group", gr.Group, "resource", gr.Resource) - return err - } - return nil // already reading unified - } - - if err = mode5(dashboard.DashboardResourceInfo.GroupResource()); err != nil { - return err - } - if err = mode5(folders.FolderResourceInfo.GroupResource()); err != nil { - return err - } - return nil -} - // Helpers for fetching valid Repository objects // TODO: where should the helpers live? diff --git a/pkg/registry/apis/provisioning/resources/dualwriter.go b/pkg/registry/apis/provisioning/resources/dualwriter.go index 8ffcee696e8..e8a7ee83dd0 100644 --- a/pkg/registry/apis/provisioning/resources/dualwriter.go +++ b/pkg/registry/apis/provisioning/resources/dualwriter.go @@ -12,6 +12,7 @@ import ( authlib "github.com/grafana/authlib/types" "github.com/grafana/grafana-app-sdk/logging" provisioning "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1" + "github.com/grafana/grafana/apps/provisioning/pkg/auth" "github.com/grafana/grafana/apps/provisioning/pkg/repository" "github.com/grafana/grafana/apps/provisioning/pkg/safepath" "github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1" @@ -32,7 +33,7 @@ type DualReadWriter struct { repo repository.ReaderWriter parser Parser folders *FolderManager - access authlib.AccessChecker + access auth.AccessChecker } type DualWriteOptions struct { @@ -48,7 +49,7 @@ type DualWriteOptions struct { Branch string // Configured default branch } -func NewDualReadWriter(repo repository.ReaderWriter, parser Parser, folders *FolderManager, access authlib.AccessChecker) *DualReadWriter { +func NewDualReadWriter(repo repository.ReaderWriter, parser Parser, folders *FolderManager, access auth.AccessChecker) *DualReadWriter { return &DualReadWriter{repo: repo, parser: parser, folders: folders, access: access} } @@ -277,6 +278,16 @@ func (r *DualReadWriter) createOrUpdate(ctx context.Context, create bool, opts D // FIXME: to make sure if behaves in the same way as in sync, we should // we should refactor the code to use the same function. if r.shouldUpdateGrafanaDB(opts, parsed) { + // HACK: Get the has from repository -- this will avoid an additional RV increment + // we should change the signature of Create and Update to return FileInfo instead + info, _ = r.repo.Read(ctx, opts.Path, opts.Ref) + if info != nil { + parsed.Meta.SetSourceProperties(utils.SourceProperties{ + Path: opts.Path, + Checksum: info.Hash, + }) + } + if _, err := r.folders.EnsureFolderPathExist(ctx, opts.Path); err != nil { return nil, fmt.Errorf("ensure folder path exists: %w", err) } @@ -482,11 +493,6 @@ func (r *DualReadWriter) moveFile(ctx context.Context, opts DualWriteOptions) (* } func (r *DualReadWriter) authorize(ctx context.Context, parsed *ParsedResource, verb string) error { - id, err := identity.GetRequester(ctx) - if err != nil { - return apierrors.NewUnauthorized(err.Error()) - } - var name string if parsed.Existing != nil { name = parsed.Existing.GetName() @@ -494,44 +500,33 @@ func (r *DualReadWriter) authorize(ctx context.Context, parsed *ParsedResource, name = parsed.Obj.GetName() } - rsp, err := r.access.Check(ctx, id, authlib.CheckRequest{ - Group: parsed.GVR.Group, - Resource: parsed.GVR.Resource, - Namespace: id.GetNamespace(), - Name: name, - Verb: verb, + return r.access.Check(ctx, authlib.CheckRequest{ + Group: parsed.GVR.Group, + Resource: parsed.GVR.Resource, + Name: name, + Verb: verb, }, parsed.Meta.GetFolder()) - if err != nil || !rsp.Allowed { - return apierrors.NewForbidden(parsed.GVR.GroupResource(), parsed.Obj.GetName(), - fmt.Errorf("no access to read the embedded file")) - } - - idType, _, err := authlib.ParseTypeID(id.GetID()) - if err != nil { - return apierrors.NewForbidden(parsed.GVR.GroupResource(), parsed.Obj.GetName(), fmt.Errorf("could not determine identity type to check access")) - } - // only apply role based access if identity is not of type access policy - if idType == authlib.TypeAccessPolicy || id.GetOrgRole().Includes(identity.RoleEditor) { - return nil - } - - return apierrors.NewForbidden(parsed.GVR.GroupResource(), parsed.Obj.GetName(), - fmt.Errorf("must be admin or editor to access files from provisioning")) } -func (r *DualReadWriter) authorizeCreateFolder(ctx context.Context, _ string) error { - id, err := identity.GetRequester(ctx) - if err != nil { - return apierrors.NewUnauthorized(err.Error()) +func (r *DualReadWriter) authorizeCreateFolder(ctx context.Context, path string) error { + // Determine parent folder from path + parentFolder := "" + if path != "" { + parentPath := safepath.Dir(path) + if parentPath != "" { + parentFolder = ParseFolder(parentPath, r.repo.Config().Name).ID + } else { + parentFolder = RootFolder(r.repo.Config()) + } } - // Simple role based access for now - if id.GetOrgRole().Includes(identity.RoleEditor) { - return nil - } - - return apierrors.NewForbidden(FolderResource.GroupResource(), "", - fmt.Errorf("must be admin or editor to access folders with provisioning")) + // For folder create operations, use empty name to check parent folder permissions + return r.access.Check(ctx, authlib.CheckRequest{ + Group: FolderResource.Group, + Resource: FolderResource.Resource, + Name: "", // Empty name for create operations + Verb: utils.VerbCreate, + }, parentFolder) } func (r *DualReadWriter) deleteFolder(ctx context.Context, opts DualWriteOptions) (*ParsedResource, error) { diff --git a/pkg/registry/apis/provisioning/resources/folders.go b/pkg/registry/apis/provisioning/resources/folders.go index b74ab67976a..8b8f4201745 100644 --- a/pkg/registry/apis/provisioning/resources/folders.go +++ b/pkg/registry/apis/provisioning/resources/folders.go @@ -197,6 +197,8 @@ func (fm *FolderManager) EnsureFolderTreeExists(ctx context.Context, ref, path s if err != nil && (!errors.Is(err, repository.ErrFileNotFound) && !apierrors.IsNotFound(err)) { return fn(folder, false, fmt.Errorf("check if folder exists before writing: %w", err)) } else if err == nil { + // Folder already exists in repository, add it to tree so resources can find it + fm.tree.Add(folder, parent) return fn(folder, false, nil) } diff --git a/pkg/registry/apis/provisioning/resources/object.go b/pkg/registry/apis/provisioning/resources/object.go index 0a016786410..a51217d08af 100644 --- a/pkg/registry/apis/provisioning/resources/object.go +++ b/pkg/registry/apis/provisioning/resources/object.go @@ -4,15 +4,9 @@ import ( "context" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime/schema" - dashboard "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v0alpha1" - 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/pkg/apimachinery/utils" - "github.com/grafana/grafana/pkg/registry/apis/dashboard/legacy" - "github.com/grafana/grafana/pkg/storage/legacysql/dualwrite" - "github.com/grafana/grafana/pkg/storage/unified/migrations" "github.com/grafana/grafana/pkg/storage/unified/resource" "github.com/grafana/grafana/pkg/storage/unified/resourcepb" ) @@ -31,25 +25,16 @@ type ResourceStore interface { } type ResourceListerFromSearch struct { - store ResourceStore - migrator migrations.UnifiedMigrator - storageStatus dualwrite.Service + store ResourceStore } func NewResourceLister(store ResourceStore) ResourceLister { return &ResourceListerFromSearch{store: store} } -// FIXME: the logic about migration and storage should probably be separated from this -func NewResourceListerForMigrations( - store ResourceStore, - migrator migrations.UnifiedMigrator, - storageStatus dualwrite.Service, -) ResourceLister { +func NewResourceListerForMigrations(store ResourceStore) ResourceLister { return &ResourceListerFromSearch{ - store: store, - migrator: migrator, - storageStatus: storageStatus, + store: store, } } @@ -133,37 +118,6 @@ func (o *ResourceListerFromSearch) Stats(ctx context.Context, namespace, reposit return stats, nil } - // Get the stats based on what a migration could support - if o.storageStatus != nil && o.migrator != nil && dualwrite.IsReadingLegacyDashboardsAndFolders(ctx, o.storageStatus) { - rsp, err := o.migrator.Migrate(ctx, legacy.MigrateOptions{ - Namespace: namespace, - Resources: []schema.GroupResource{{ - Group: dashboard.GROUP, Resource: dashboard.DASHBOARD_RESOURCE, - }, { - Group: folders.GROUP, Resource: folders.RESOURCE, - }}, - WithHistory: false, - OnlyCount: true, - }) - if err != nil { - return nil, err - } - for _, v := range rsp.Summary { - stats.Instance = append(stats.Instance, provisioning.ResourceCount{ - Group: v.Group, - Resource: v.Resource, - Count: v.Count, - }) - // Everything is unmanaged in legacy storage - stats.Unmanaged = append(stats.Unmanaged, provisioning.ResourceCount{ - Group: v.Group, - Resource: v.Resource, - Count: v.Count, - }) - } - return stats, nil - } - // Get full instance stats info, err := o.store.GetStats(ctx, &resourcepb.ResourceStatsRequest{ Namespace: namespace, diff --git a/pkg/registry/apis/provisioning/resources/resources.go b/pkg/registry/apis/provisioning/resources/resources.go index 4954e6b51b6..8e12c7556cd 100644 --- a/pkg/registry/apis/provisioning/resources/resources.go +++ b/pkg/registry/apis/provisioning/resources/resources.go @@ -180,7 +180,12 @@ func (r *ResourcesManager) WriteResourceFileFromObject(ctx context.Context, obj var ok bool fid, ok = r.folders.Tree().DirPath(folder, rootFolder) if !ok { - return "", fmt.Errorf("folder %s NOT found in tree with root: %s", folder, rootFolder) + // HACK: this is a hack to get the folder path without the root folder + // TODO: should we build the tree in a different way? + fid, ok = r.folders.Tree().DirPath(folder, "") + if !ok { + return "", fmt.Errorf("folder %s NOT found in tree", folder) + } } } diff --git a/pkg/registry/apis/provisioning/resources/signature/grafana.go b/pkg/registry/apis/provisioning/resources/signature/grafana.go deleted file mode 100644 index e91497c1245..00000000000 --- a/pkg/registry/apis/provisioning/resources/signature/grafana.go +++ /dev/null @@ -1,33 +0,0 @@ -package signature - -import ( - "context" - - "github.com/grafana/grafana/apps/provisioning/pkg/repository" - "github.com/grafana/grafana/pkg/apimachinery/utils" -) - -type grafanaSigner struct{} - -// FIXME: where should we use this default signature? -// NewGrafanaSigner returns a Signer that uses the grafana user as the author -func NewGrafanaSigner() Signer { - return &grafanaSigner{} -} - -func (s *grafanaSigner) Sign(ctx context.Context, item utils.GrafanaMetaAccessor) (context.Context, error) { - sig := repository.CommitSignature{ - Name: "grafana", - // TODO: should we add email? - // Email: "grafana@grafana.com", - } - - t, err := item.GetUpdatedTimestamp() - if err == nil && t != nil { - sig.When = *t - } else { - sig.When = item.GetCreationTimestamp().Time - } - - return repository.WithAuthorSignature(ctx, sig), nil -} diff --git a/pkg/registry/apis/provisioning/resources/signature/grafana_test.go b/pkg/registry/apis/provisioning/resources/signature/grafana_test.go deleted file mode 100644 index cae5fbf4ebb..00000000000 --- a/pkg/registry/apis/provisioning/resources/signature/grafana_test.go +++ /dev/null @@ -1,90 +0,0 @@ -package signature - -import ( - "context" - "errors" - "testing" - "time" - - "github.com/stretchr/testify/require" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - - "github.com/grafana/grafana/apps/provisioning/pkg/repository" - "github.com/grafana/grafana/pkg/apimachinery/utils" -) - -func TestNewGrafanaSigner(t *testing.T) { - signer := NewGrafanaSigner() - require.NotNil(t, signer, "signer should not be nil") - require.IsType(t, &grafanaSigner{}, signer, "signer should be of type *grafanaSigner") -} - -func TestGrafanaSigner_Sign(t *testing.T) { - tests := []struct { - name string - creationTimestamp time.Time - updateTimestampErr error - updatedTimestamp *time.Time - expectedTime time.Time - setupMocks func(meta *utils.MockGrafanaMetaAccessor) - }{ - { - name: "should use creation timestamp when no update timestamp", - creationTimestamp: time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC), - updatedTimestamp: ptr(time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC)), - updateTimestampErr: errors.New("failed"), - expectedTime: time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC), - setupMocks: func(meta *utils.MockGrafanaMetaAccessor) { - meta.On("GetCreationTimestamp").Return(metav1.Time{Time: time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC)}) - }, - }, - { - name: "should use creation timestamp when update timestamp is nil", - creationTimestamp: time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC), - updatedTimestamp: nil, - expectedTime: time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC), - setupMocks: func(meta *utils.MockGrafanaMetaAccessor) { - meta.On("GetCreationTimestamp").Return(metav1.Time{Time: time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC)}) - }, - }, - { - name: "should use update timestamp when available", - creationTimestamp: time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC), - updatedTimestamp: ptr(time.Date(2024, 1, 2, 0, 0, 0, 0, time.UTC)), - expectedTime: time.Date(2024, 1, 2, 0, 0, 0, 0, time.UTC), - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - meta := utils.NewMockGrafanaMetaAccessor(t) - var updatedTime *time.Time - if tt.updatedTimestamp != nil { - updatedTime = tt.updatedTimestamp - } - meta.On("GetUpdatedTimestamp").Return(updatedTime, tt.updateTimestampErr) - - if tt.setupMocks != nil { - tt.setupMocks(meta) - } - - signer := NewGrafanaSigner() - ctx := context.Background() - - signedCtx, err := signer.Sign(ctx, meta) - require.NoError(t, err) - - // Verify the signature in the context - sig := repository.GetAuthorSignature(signedCtx) - require.NotNil(t, sig, "signature should be present in context") - require.Equal(t, "grafana", sig.Name) - require.Equal(t, tt.expectedTime, sig.When) - - meta.AssertExpectations(t) - }) - } -} - -func ptr[T any](v T) *T { - return &v -} diff --git a/pkg/registry/apis/provisioning/resources/signature/signature.go b/pkg/registry/apis/provisioning/resources/signature/signature.go deleted file mode 100644 index c0b39f7b325..00000000000 --- a/pkg/registry/apis/provisioning/resources/signature/signature.go +++ /dev/null @@ -1,52 +0,0 @@ -package signature - -import ( - "context" - "fmt" - - "github.com/grafana/grafana/pkg/apimachinery/utils" - "github.com/grafana/grafana/pkg/registry/apis/provisioning/resources" -) - -//go:generate mockery --name Signer --structname MockSigner --inpackage --filename signer_mock.go --with-expecter -type Signer interface { - Sign(ctx context.Context, item utils.GrafanaMetaAccessor) (context.Context, error) -} - -type SignOptions struct { - Namespace string - History bool -} - -// SignerFactory is a factory for creating Signers -// -//go:generate mockery --name SignerFactory --structname MockSignerFactory --inpackage --filename signature_factory_mock.go --with-expecter -type SignerFactory interface { - New(ctx context.Context, opts SignOptions) (Signer, error) -} - -type signerFactory struct { - clients resources.ClientFactory -} - -func NewSignerFactory(clients resources.ClientFactory) SignerFactory { - return &signerFactory{clients} -} - -func (f *signerFactory) New(ctx context.Context, opts SignOptions) (Signer, error) { - if !opts.History { - return NewGrafanaSigner(), nil - } - - clients, err := f.clients.Clients(ctx, opts.Namespace) - if err != nil { - return nil, fmt.Errorf("get clients: %w", err) - } - - userClient, err := clients.User(ctx) - if err != nil { - return nil, fmt.Errorf("get user client: %w", err) - } - - return NewLoadUsersOnceSigner(userClient), nil -} diff --git a/pkg/registry/apis/provisioning/resources/signature/signature_factory_mock.go b/pkg/registry/apis/provisioning/resources/signature/signature_factory_mock.go deleted file mode 100644 index 80647e0129c..00000000000 --- a/pkg/registry/apis/provisioning/resources/signature/signature_factory_mock.go +++ /dev/null @@ -1,95 +0,0 @@ -// Code generated by mockery v2.53.4. DO NOT EDIT. - -package signature - -import ( - context "context" - - mock "github.com/stretchr/testify/mock" -) - -// MockSignerFactory is an autogenerated mock type for the SignerFactory type -type MockSignerFactory struct { - mock.Mock -} - -type MockSignerFactory_Expecter struct { - mock *mock.Mock -} - -func (_m *MockSignerFactory) EXPECT() *MockSignerFactory_Expecter { - return &MockSignerFactory_Expecter{mock: &_m.Mock} -} - -// New provides a mock function with given fields: ctx, opts -func (_m *MockSignerFactory) New(ctx context.Context, opts SignOptions) (Signer, error) { - ret := _m.Called(ctx, opts) - - if len(ret) == 0 { - panic("no return value specified for New") - } - - var r0 Signer - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, SignOptions) (Signer, error)); ok { - return rf(ctx, opts) - } - if rf, ok := ret.Get(0).(func(context.Context, SignOptions) Signer); ok { - r0 = rf(ctx, opts) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(Signer) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, SignOptions) error); ok { - r1 = rf(ctx, opts) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockSignerFactory_New_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'New' -type MockSignerFactory_New_Call struct { - *mock.Call -} - -// New is a helper method to define mock.On call -// - ctx context.Context -// - opts SignOptions -func (_e *MockSignerFactory_Expecter) New(ctx interface{}, opts interface{}) *MockSignerFactory_New_Call { - return &MockSignerFactory_New_Call{Call: _e.mock.On("New", ctx, opts)} -} - -func (_c *MockSignerFactory_New_Call) Run(run func(ctx context.Context, opts SignOptions)) *MockSignerFactory_New_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(SignOptions)) - }) - return _c -} - -func (_c *MockSignerFactory_New_Call) Return(_a0 Signer, _a1 error) *MockSignerFactory_New_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockSignerFactory_New_Call) RunAndReturn(run func(context.Context, SignOptions) (Signer, error)) *MockSignerFactory_New_Call { - _c.Call.Return(run) - return _c -} - -// NewMockSignerFactory creates a new instance of MockSignerFactory. 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 NewMockSignerFactory(t interface { - mock.TestingT - Cleanup(func()) -}) *MockSignerFactory { - mock := &MockSignerFactory{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/pkg/registry/apis/provisioning/resources/signature/signature_test.go b/pkg/registry/apis/provisioning/resources/signature/signature_test.go deleted file mode 100644 index b339865ca5f..00000000000 --- a/pkg/registry/apis/provisioning/resources/signature/signature_test.go +++ /dev/null @@ -1,92 +0,0 @@ -package signature - -import ( - "context" - "fmt" - "testing" - - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" - - "github.com/grafana/grafana/pkg/registry/apis/provisioning/resources" -) - -func TestSignerFactory_New(t *testing.T) { - tests := []struct { - name string - opts SignOptions - setupMocks func(t *testing.T, clients *resources.MockClientFactory) - expectedType interface{} - expectedError string - }{ - { - name: "should return grafana signer when history is false", - opts: SignOptions{ - History: false, - }, - setupMocks: func(t *testing.T, clients *resources.MockClientFactory) { - // No mocks needed as we shouldn't call any clients - }, - expectedType: &grafanaSigner{}, - }, - { - name: "should return load users once signer when history is true", - opts: SignOptions{ - History: true, - Namespace: "test-ns", - }, - setupMocks: func(t *testing.T, clients *resources.MockClientFactory) { - mockResourceClients := resources.NewMockResourceClients(t) - clients.On("Clients", context.Background(), "test-ns").Return(mockResourceClients, nil) - mockResourceClients.On("User", mock.Anything).Return(nil, nil) - }, - expectedType: &loadUsersOnceSigner{}, - }, - { - name: "should return error when clients factory fails", - opts: SignOptions{ - History: true, - Namespace: "test-ns", - }, - setupMocks: func(t *testing.T, clients *resources.MockClientFactory) { - clients.On("Clients", context.Background(), "test-ns").Return(nil, fmt.Errorf("clients error")) - }, - expectedError: "get clients: clients error", - }, - { - name: "should return error when user client fails", - opts: SignOptions{ - History: true, - Namespace: "test-ns", - }, - setupMocks: func(t *testing.T, clients *resources.MockClientFactory) { - mockResourceClients := resources.NewMockResourceClients(t) - clients.On("Clients", context.Background(), "test-ns").Return(mockResourceClients, nil) - mockResourceClients.On("User", mock.Anything).Return(nil, fmt.Errorf("user client error")) - }, - expectedError: "get user client: user client error", - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - mockClients := resources.NewMockClientFactory(t) - tt.setupMocks(t, mockClients) - - factory := NewSignerFactory(mockClients) - signer, err := factory.New(context.Background(), tt.opts) - - if tt.expectedError != "" { - require.Error(t, err) - require.EqualError(t, err, tt.expectedError) - require.Nil(t, signer) - } else { - require.NoError(t, err) - require.NotNil(t, signer) - require.IsType(t, tt.expectedType, signer, "signer should be of expected type") - } - - mockClients.AssertExpectations(t) - }) - } -} diff --git a/pkg/registry/apis/provisioning/resources/signature/signer_mock.go b/pkg/registry/apis/provisioning/resources/signature/signer_mock.go deleted file mode 100644 index 46cd71dab55..00000000000 --- a/pkg/registry/apis/provisioning/resources/signature/signer_mock.go +++ /dev/null @@ -1,96 +0,0 @@ -// Code generated by mockery v2.53.4. DO NOT EDIT. - -package signature - -import ( - context "context" - - utils "github.com/grafana/grafana/pkg/apimachinery/utils" - mock "github.com/stretchr/testify/mock" -) - -// MockSigner is an autogenerated mock type for the Signer type -type MockSigner struct { - mock.Mock -} - -type MockSigner_Expecter struct { - mock *mock.Mock -} - -func (_m *MockSigner) EXPECT() *MockSigner_Expecter { - return &MockSigner_Expecter{mock: &_m.Mock} -} - -// Sign provides a mock function with given fields: ctx, item -func (_m *MockSigner) Sign(ctx context.Context, item utils.GrafanaMetaAccessor) (context.Context, error) { - ret := _m.Called(ctx, item) - - if len(ret) == 0 { - panic("no return value specified for Sign") - } - - var r0 context.Context - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, utils.GrafanaMetaAccessor) (context.Context, error)); ok { - return rf(ctx, item) - } - if rf, ok := ret.Get(0).(func(context.Context, utils.GrafanaMetaAccessor) context.Context); ok { - r0 = rf(ctx, item) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(context.Context) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, utils.GrafanaMetaAccessor) error); ok { - r1 = rf(ctx, item) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockSigner_Sign_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Sign' -type MockSigner_Sign_Call struct { - *mock.Call -} - -// Sign is a helper method to define mock.On call -// - ctx context.Context -// - item utils.GrafanaMetaAccessor -func (_e *MockSigner_Expecter) Sign(ctx interface{}, item interface{}) *MockSigner_Sign_Call { - return &MockSigner_Sign_Call{Call: _e.mock.On("Sign", ctx, item)} -} - -func (_c *MockSigner_Sign_Call) Run(run func(ctx context.Context, item utils.GrafanaMetaAccessor)) *MockSigner_Sign_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(utils.GrafanaMetaAccessor)) - }) - return _c -} - -func (_c *MockSigner_Sign_Call) Return(_a0 context.Context, _a1 error) *MockSigner_Sign_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockSigner_Sign_Call) RunAndReturn(run func(context.Context, utils.GrafanaMetaAccessor) (context.Context, error)) *MockSigner_Sign_Call { - _c.Call.Return(run) - return _c -} - -// NewMockSigner creates a new instance of MockSigner. 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 NewMockSigner(t interface { - mock.TestingT - Cleanup(func()) -}) *MockSigner { - mock := &MockSigner{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/pkg/registry/apis/provisioning/resources/signature/users.go b/pkg/registry/apis/provisioning/resources/signature/users.go deleted file mode 100644 index 1cf4171ed63..00000000000 --- a/pkg/registry/apis/provisioning/resources/signature/users.go +++ /dev/null @@ -1,115 +0,0 @@ -package signature - -import ( - "context" - "errors" - "fmt" - "strings" - "sync" - - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/client-go/dynamic" - - "github.com/grafana/grafana/apps/provisioning/pkg/repository" - "github.com/grafana/grafana/pkg/apimachinery/utils" - "github.com/grafana/grafana/pkg/registry/apis/provisioning/resources" -) - -const maxUsers = 10000 - -type loadUsersOnceSigner struct { - signatures map[string]repository.CommitSignature - client dynamic.ResourceInterface - once sync.Once - onceErr error -} - -// NewLoadUsersOnceSigner returns a Signer that loads the signatures from users -// it will only load the signatures once and cache them -// if the user is not found, it will use the grafana user as the author -func NewLoadUsersOnceSigner(client dynamic.ResourceInterface) Signer { - return &loadUsersOnceSigner{ - client: client, - once: sync.Once{}, - signatures: map[string]repository.CommitSignature{}, - } -} - -func (s *loadUsersOnceSigner) Sign(ctx context.Context, item utils.GrafanaMetaAccessor) (context.Context, error) { - if s.onceErr != nil { - return ctx, fmt.Errorf("load signatures: %w", s.onceErr) - } - - var err error - s.once.Do(func() { - s.signatures, err = s.load(ctx, s.client) - s.onceErr = err - }) - if err != nil { - return ctx, fmt.Errorf("load signatures: %w", err) - } - - id := item.GetUpdatedBy() - if id == "" { - id = item.GetCreatedBy() - } - if id == "" { - id = "grafana" - } - - sig := s.signatures[id] // lookup - if sig.Name == "" && sig.Email == "" { - sig.Name = id - } - t, err := item.GetUpdatedTimestamp() - if err == nil && t != nil { - sig.When = *t - } else { - sig.When = item.GetCreationTimestamp().Time - } - - return repository.WithAuthorSignature(ctx, sig), nil -} - -func (s *loadUsersOnceSigner) load(ctx context.Context, client dynamic.ResourceInterface) (map[string]repository.CommitSignature, error) { - userInfo := make(map[string]repository.CommitSignature) - var count int - err := resources.ForEach(ctx, client, func(item *unstructured.Unstructured) error { - count++ - if count > maxUsers { - return errors.New("too many users") - } - - sig := repository.CommitSignature{} - // FIXME: should we improve logging here? - var ( - ok bool - err error - ) - - sig.Name, ok, err = unstructured.NestedString(item.Object, "spec", "login") - if !ok || err != nil { - return nil - } - sig.Email, ok, err = unstructured.NestedString(item.Object, "spec", "email") - if !ok || err != nil { - return nil - } - - if sig.Name == sig.Email { - if sig.Name == "" { - sig.Name = item.GetName() - } else if strings.Contains(sig.Email, "@") { - sig.Email = "" // don't use the same value for name+email - } - } - - userInfo["user:"+item.GetName()] = sig - return nil - }) - if err != nil { - return nil, err - } - - return userInfo, nil -} diff --git a/pkg/registry/apis/provisioning/resources/signature/users_test.go b/pkg/registry/apis/provisioning/resources/signature/users_test.go deleted file mode 100644 index ccd63014a76..00000000000 --- a/pkg/registry/apis/provisioning/resources/signature/users_test.go +++ /dev/null @@ -1,357 +0,0 @@ -package signature - -import ( - "context" - "errors" - "fmt" - "testing" - "time" - - "github.com/stretchr/testify/require" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/client-go/dynamic" - - "github.com/grafana/grafana/apps/provisioning/pkg/repository" - "github.com/grafana/grafana/pkg/apimachinery/utils" -) - -// mockDynamicInterface implements a simplified version of the dynamic.ResourceInterface -type mockDynamicInterface struct { - dynamic.ResourceInterface - items []unstructured.Unstructured - err error -} - -func (m *mockDynamicInterface) List(ctx context.Context, opts metav1.ListOptions) (*unstructured.UnstructuredList, error) { - if m.err != nil { - return nil, m.err - } - return &unstructured.UnstructuredList{ - Items: m.items, - }, nil -} - -type mockGrafanaMetaAccessor struct { - utils.GrafanaMetaAccessor - createdBy string - updatedBy string - creationTimestamp time.Time - updatedTimestamp *time.Time - updatedTimestampErr error -} - -func (m *mockGrafanaMetaAccessor) GetCreatedBy() string { - return m.createdBy -} - -func (m *mockGrafanaMetaAccessor) GetUpdatedBy() string { - return m.updatedBy -} - -func (m *mockGrafanaMetaAccessor) GetCreationTimestamp() metav1.Time { - return metav1.Time{Time: m.creationTimestamp} -} - -func (m *mockGrafanaMetaAccessor) GetUpdatedTimestamp() (*time.Time, error) { - if m.updatedTimestampErr != nil { - return nil, m.updatedTimestampErr - } - return m.updatedTimestamp, nil -} - -func TestLoadUsersOnceSigner_Sign(t *testing.T) { - baseTime := time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC) - updateTime := time.Date(2024, 1, 2, 0, 0, 0, 0, time.UTC) - - tests := []struct { - name string - items []unstructured.Unstructured - meta *mockGrafanaMetaAccessor - clientErr error - expectedSig repository.CommitSignature - expectedError string - }{ - { - name: "should sign with user info when user exists", - items: []unstructured.Unstructured{ - { - Object: map[string]interface{}{ - "metadata": map[string]interface{}{ - "name": "user1", - }, - "spec": map[string]interface{}{ - "login": "johndoe", - "email": "john@example.com", - }, - }, - }, - }, - meta: &mockGrafanaMetaAccessor{ - updatedBy: "user:user1", - creationTimestamp: baseTime, - updatedTimestamp: &updateTime, - }, - expectedSig: repository.CommitSignature{ - Name: "johndoe", - Email: "john@example.com", - When: updateTime, - }, - }, - { - name: "should fallback to created by when updated by is empty", - items: []unstructured.Unstructured{ - { - Object: map[string]interface{}{ - "metadata": map[string]interface{}{ - "name": "user1", - }, - "spec": map[string]interface{}{ - "login": "johndoe", - "email": "john@example.com", - }, - }, - }, - }, - meta: &mockGrafanaMetaAccessor{ - createdBy: "user:user1", - creationTimestamp: baseTime, - }, - expectedSig: repository.CommitSignature{ - Name: "johndoe", - Email: "john@example.com", - When: baseTime, - }, - }, - { - name: "should use grafana when no user info available", - meta: &mockGrafanaMetaAccessor{ - creationTimestamp: baseTime, - }, - expectedSig: repository.CommitSignature{ - Name: "grafana", - When: baseTime, - }, - }, - { - name: "should handle user with same login and email", - items: []unstructured.Unstructured{ - { - Object: map[string]interface{}{ - "metadata": map[string]interface{}{ - "name": "user1", - }, - "spec": map[string]interface{}{ - "login": "john@example.com", - "email": "john@example.com", - }, - }, - }, - }, - meta: &mockGrafanaMetaAccessor{ - updatedBy: "user:user1", - creationTimestamp: baseTime, - updatedTimestamp: &updateTime, - }, - expectedSig: repository.CommitSignature{ - Name: "john@example.com", - Email: "", - When: updateTime, - }, - }, - { - name: "should handle empty login and email", - items: []unstructured.Unstructured{ - { - Object: map[string]interface{}{ - "metadata": map[string]interface{}{ - "name": "user1", - }, - "spec": map[string]interface{}{ - "login": "", - "email": "", - }, - }, - }, - }, - meta: &mockGrafanaMetaAccessor{ - updatedBy: "user:user1", - creationTimestamp: baseTime, - updatedTimestamp: &updateTime, - }, - expectedSig: repository.CommitSignature{ - Name: "user1", - Email: "", - When: updateTime, - }, - }, - { - name: "should handle empty email", - items: []unstructured.Unstructured{ - { - Object: map[string]interface{}{ - "metadata": map[string]interface{}{ - "name": "user1", - }, - "spec": map[string]interface{}{ - "login": "johndoe", - "email": "", - }, - }, - }, - }, - meta: &mockGrafanaMetaAccessor{ - updatedBy: "user:user1", - creationTimestamp: baseTime, - updatedTimestamp: &updateTime, - }, - expectedSig: repository.CommitSignature{ - Name: "johndoe", - Email: "", - When: updateTime, - }, - }, - { - name: "should fail when too many users", - items: func() []unstructured.Unstructured { - items := make([]unstructured.Unstructured, maxUsers+1) - for i := 0; i < maxUsers+1; i++ { - items[i] = unstructured.Unstructured{ - Object: map[string]interface{}{ - "metadata": map[string]interface{}{ - "name": "user1", - }, - "spec": map[string]interface{}{ - "login": "johndoe", - "email": "john@example.com", - }, - }, - } - } - return items - }(), - meta: &mockGrafanaMetaAccessor{ - updatedBy: "user:user1", - creationTimestamp: baseTime, - }, - expectedError: "load signatures: too many users", - }, - { - name: "should handle missing user fields gracefully", - items: []unstructured.Unstructured{ - { - Object: map[string]interface{}{ - "metadata": map[string]interface{}{ - "name": "user1", - }, - "spec": map[string]interface{}{ - // missing login and email - }, - }, - }, - }, - meta: &mockGrafanaMetaAccessor{ - updatedBy: "user:user1", - creationTimestamp: baseTime, - }, - expectedSig: repository.CommitSignature{ - Name: "user:user1", - When: baseTime, - }, - }, - { - name: "should use creation timestamp when update timestamp has error", - items: []unstructured.Unstructured{ - { - Object: map[string]interface{}{ - "metadata": map[string]interface{}{ - "name": "user1", - }, - "spec": map[string]interface{}{ - "login": "johndoe", - "email": "john@example.com", - }, - }, - }, - }, - meta: &mockGrafanaMetaAccessor{ - updatedBy: "user:user1", - creationTimestamp: baseTime, - updatedTimestampErr: errors.New("update timestamp error"), - }, - expectedSig: repository.CommitSignature{ - Name: "johndoe", - Email: "john@example.com", - When: baseTime, - }, - }, - { - name: "should fail when listing users fails", - meta: &mockGrafanaMetaAccessor{ - updatedBy: "user:user1", - creationTimestamp: baseTime, - }, - clientErr: fmt.Errorf("failed to list users"), - expectedError: "load signatures: error executing list: failed to list users", - }, - { - name: "should handle empty user list", - meta: &mockGrafanaMetaAccessor{ - updatedBy: "user:user1", - creationTimestamp: baseTime, - }, - items: []unstructured.Unstructured{}, - expectedSig: repository.CommitSignature{ - Name: "user:user1", - When: baseTime, - }, - }, - { - name: "should handle multiple calls with error", - meta: &mockGrafanaMetaAccessor{ - updatedBy: "user:user1", - creationTimestamp: baseTime, - }, - clientErr: fmt.Errorf("failed to list users"), - expectedError: "load signatures: error executing list: failed to list users", - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - client := &mockDynamicInterface{ - items: tt.items, - err: tt.clientErr, - } - - signer := NewLoadUsersOnceSigner(client) - ctx := context.Background() - - signedCtx, err := signer.Sign(ctx, tt.meta) - - if tt.expectedError != "" { - require.Error(t, err) - require.Contains(t, err.Error(), tt.expectedError) - - // Test that subsequent calls also fail with the same error - _, err2 := signer.Sign(ctx, tt.meta) - require.Error(t, err2) - require.Contains(t, err2.Error(), tt.expectedError) - return - } - - require.NoError(t, err) - sig := repository.GetAuthorSignature(signedCtx) - require.NotNil(t, sig) - require.Equal(t, tt.expectedSig.Name, sig.Name) - require.Equal(t, tt.expectedSig.Email, sig.Email) - require.Equal(t, tt.expectedSig.When, sig.When) - - // Test that subsequent calls use cached data - signedCtx2, err := signer.Sign(ctx, tt.meta) - require.NoError(t, err) - sig2 := repository.GetAuthorSignature(signedCtx2) - require.Equal(t, sig, sig2) - }) - } -} diff --git a/pkg/registry/apis/provisioning/routes.go b/pkg/registry/apis/provisioning/routes.go index 494d47d16e7..c818a76812b 100644 --- a/pkg/registry/apis/provisioning/routes.go +++ b/pkg/registry/apis/provisioning/routes.go @@ -14,7 +14,6 @@ import ( authlib "github.com/grafana/authlib/types" provisioning "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1" "github.com/grafana/grafana/pkg/services/apiserver/builder" - "github.com/grafana/grafana/pkg/storage/legacysql/dualwrite" "github.com/grafana/grafana/pkg/util/errhttp" ) @@ -156,16 +155,9 @@ func (b *APIBuilder) handleSettings(w http.ResponseWriter, r *http.Request) { return } - legacyStorage := false - if b.storageStatus != nil { - legacyStorage = dualwrite.IsReadingLegacyDashboardsAndFolders(ctx, b.storageStatus) - } - settings := provisioning.RepositoryViewList{ - Items: make([]provisioning.RepositoryView, len(all)), - AllowedTargets: b.allowedTargets, - // FIXME: this shouldn't be here in provisioning but at the dual writer or something about the storage - LegacyStorage: legacyStorage, + Items: make([]provisioning.RepositoryView, len(all)), + AllowedTargets: b.allowedTargets, AvailableRepositoryTypes: b.repoFactory.Types(), AllowImageRendering: b.allowImageRendering, } diff --git a/pkg/registry/apis/provisioning/webhooks/pullrequest/changes.go b/pkg/registry/apis/provisioning/webhooks/pullrequest/changes.go index f8e485e8fe5..d6fec09bc96 100644 --- a/pkg/registry/apis/provisioning/webhooks/pullrequest/changes.go +++ b/pkg/registry/apis/provisioning/webhooks/pullrequest/changes.go @@ -4,7 +4,6 @@ import ( "context" "fmt" "net/url" - "path" "strings" "time" @@ -141,14 +140,20 @@ func (e *evaluator) evaluateFile(ctx context.Context, repo repository.Reader, ba if info.Parsed.GVK.Kind == dashboardKind { // FIXME: extract the logic out of a dashboard URL builder/injector or similar // for testability and decoupling + urlBuilder, err := url.Parse(baseURL) + if err != nil { + info.Error = err.Error() + return info + } + if info.Parsed.Existing != nil { - info.GrafanaURL = fmt.Sprintf("%sd/%s/%s", baseURL, obj.GetName(), - slugify.Slugify(info.Title)) + grafanaURL := urlBuilder.JoinPath("d", obj.GetName(), slugify.Slugify(info.Title)) + info.GrafanaURL = grafanaURL.String() } // Load this file directly - info.PreviewURL = baseURL + path.Join("admin/provisioning", - info.Parsed.Repo.Name, "dashboard/preview", info.Parsed.Info.Path) + previewURL := urlBuilder.JoinPath("admin/provisioning", info.Parsed.Repo.Name, "dashboard/preview", info.Parsed.Info.Path) + info.PreviewURL = previewURL.String() query := url.Values{} query.Set("ref", info.Parsed.Info.Ref) diff --git a/pkg/registry/apis/provisioning/webhooks/pullrequest/changes_test.go b/pkg/registry/apis/provisioning/webhooks/pullrequest/changes_test.go index c8f0c33e92a..6c513830d29 100644 --- a/pkg/registry/apis/provisioning/webhooks/pullrequest/changes_test.go +++ b/pkg/registry/apis/provisioning/webhooks/pullrequest/changes_test.go @@ -737,8 +737,78 @@ func TestCalculateChanges(t *testing.T) { Path: "path/to/file.json", Ref: "ref", }, - GrafanaURL: "ht tp://bad url/d/the-uid/hello-world", // Malformed URL - PreviewURL: "ht tp://bad url/admin/provisioning/y/dashboard/preview/path/to/file.json?pull_request_url=http%253A%252F%252Fgithub.com%252Fpr%252F&ref=ref", + Error: "parse \"ht tp://bad url/\": first path segment in URL cannot contain colon", + }}, + }, + }, + { + name: "path with spaces", + setupMocks: func(parser *resources.MockParser, reader *repository.MockReader, progress *jobs.MockJobProgressRecorder, renderer *MockScreenshotRenderer, parserFactory *resources.MockParserFactory) { + finfo := &repository.FileInfo{ + Path: "path/to/file with spaces.json", + Ref: "ref", + Data: []byte("xxxx"), + } + obj := &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": resources.DashboardResource.GroupVersion().String(), + "kind": dashboardKind, + "metadata": map[string]interface{}{ + "name": "the-uid", + }, + "spec": map[string]interface{}{ + "title": "hello world", + }, + }, + } + meta, _ := utils.MetaAccessor(obj) + + progress.On("SetMessage", mock.Anything, "process path/to/file with spaces.json").Return() + reader.On("Read", mock.Anything, "path/to/file with spaces.json", "ref").Return(finfo, nil) + reader.On("Config").Return(&provisioning.Repository{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-repo", + Namespace: "x", + }, + Spec: provisioning.RepositorySpec{ + GitHub: &provisioning.GitHubRepositoryConfig{ + GenerateDashboardPreviews: true, + }, + }, + }) + parser.On("Parse", mock.Anything, finfo).Return(&resources.ParsedResource{ + Info: finfo, + Repo: provisioning.ResourceRepositoryInfo{ + Namespace: "x", + Name: "y", + }, + GVK: schema.GroupVersionKind{ + Kind: dashboardKind, + }, + Obj: obj, + Existing: obj, + Meta: meta, + DryRunResponse: obj, + }, nil) + renderer.On("IsAvailable", mock.Anything, mock.Anything).Return(false) + parserFactory.On("GetParser", mock.Anything, mock.Anything).Return(parser, nil) + }, + changes: []repository.VersionedFileChange{{ + Action: repository.FileActionCreated, + Path: "path/to/file with spaces.json", + Ref: "ref", + }}, + expectedInfo: changeInfo{ + Changes: []fileChangeInfo{{ + Change: repository.VersionedFileChange{ + Action: repository.FileActionCreated, + Path: "path/to/file with spaces.json", + Ref: "ref", + }, + GrafanaURL: "http://host/d/the-uid/hello-world", + PreviewURL: "http://host/admin/provisioning/y/dashboard/preview/path/to/file%20with%20spaces.json?pull_request_url=http%253A%252F%252Fgithub.com%252Fpr%252F&ref=ref", + GrafanaScreenshotURL: "", + PreviewScreenshotURL: "", }}, }, }, diff --git a/pkg/registry/apis/secret/decrypt/grpc_client.go b/pkg/registry/apis/secret/decrypt/grpc_client.go index f892de5ebe5..0612455c3d8 100644 --- a/pkg/registry/apis/secret/decrypt/grpc_client.go +++ b/pkg/registry/apis/secret/decrypt/grpc_client.go @@ -9,10 +9,13 @@ import ( "maps" "os" "slices" + "time" "github.com/fullstorydev/grpchan" + grpc_retry "github.com/grpc-ecosystem/go-grpc-middleware/retry" "go.opentelemetry.io/otel/trace" "google.golang.org/grpc" + "google.golang.org/grpc/codes" "google.golang.org/grpc/credentials" "google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/metadata" @@ -72,6 +75,15 @@ func NewGRPCDecryptClientWithTLS( opts = append(opts, grpc.WithDisableServiceConfig()) } + // Add retry interceptor to retry on transient connection issues. + // Retries on ResourceExhausted (per-RPC limits reached) and Unavailable (system unavailable). + retryInterceptor := grpc_retry.UnaryClientInterceptor( + grpc_retry.WithMax(3), + grpc_retry.WithBackoff(grpc_retry.BackoffExponentialWithJitter(time.Second, 0.5)), + grpc_retry.WithCodes(codes.ResourceExhausted, codes.Unavailable), + ) + opts = append(opts, grpc.WithUnaryInterceptor(retryInterceptor)) + conn, err := grpc.NewClient(address, opts...) if err != nil { return nil, fmt.Errorf("failed to connect to grpc decrypt server at %s: %w", address, err) diff --git a/pkg/registry/apis/wireset.go b/pkg/registry/apis/wireset.go index df38965759b..d95f01bef36 100644 --- a/pkg/registry/apis/wireset.go +++ b/pkg/registry/apis/wireset.go @@ -28,7 +28,7 @@ import ( var WireSetExts = wire.NewSet( noopstorage.ProvideStorageBackend, wire.Bind(new(iam.CoreRoleStorageBackend), new(*noopstorage.StorageBackendImpl)), - wire.Bind(new(iam.RoleStorageBackend), new(*noopstorage.StorageBackendImpl)), + iam.ProvideNoopRoleApiInstaller, wire.Bind(new(iam.RoleBindingStorageBackend), new(*noopstorage.StorageBackendImpl)), wire.Bind(new(iam.ExternalGroupMappingStorageBackend), new(*noopstorage.StorageBackendImpl)), diff --git a/pkg/registry/apps/alerting/notifications/receiver/conversions.go b/pkg/registry/apps/alerting/notifications/receiver/conversions.go index b0d79121912..993c63a46fd 100644 --- a/pkg/registry/apps/alerting/notifications/receiver/conversions.go +++ b/pkg/registry/apps/alerting/notifications/receiver/conversions.go @@ -110,10 +110,11 @@ func convertToK8sResource( } var permissionMapper = map[ngmodels.ReceiverPermission]string{ - ngmodels.ReceiverPermissionReadSecret: "canReadSecrets", - ngmodels.ReceiverPermissionAdmin: "canAdmin", - ngmodels.ReceiverPermissionWrite: "canWrite", - ngmodels.ReceiverPermissionDelete: "canDelete", + ngmodels.ReceiverPermissionReadSecret: "canReadSecrets", + ngmodels.ReceiverPermissionAdmin: "canAdmin", + ngmodels.ReceiverPermissionWrite: "canWrite", + ngmodels.ReceiverPermissionDelete: "canDelete", + ngmodels.ReceiverPermissionModifyProtected: "canModifyProtected", } func convertToDomainModel(receiver *model.Receiver) (*ngmodels.Receiver, map[string][]string, error) { diff --git a/pkg/registry/apps/alerting/notifications/register.go b/pkg/registry/apps/alerting/notifications/register.go index fbf75d44bb5..c96fa1759b7 100644 --- a/pkg/registry/apps/alerting/notifications/register.go +++ b/pkg/registry/apps/alerting/notifications/register.go @@ -20,6 +20,7 @@ import ( "github.com/grafana/grafana/pkg/registry/apps/alerting/notifications/timeinterval" "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/services/ngalert" ac "github.com/grafana/grafana/pkg/services/ngalert/accesscontrol" ngmodels "github.com/grafana/grafana/pkg/services/ngalert/models" @@ -97,7 +98,12 @@ func (a AlertingNotificationsAppInstaller) GetLegacyStorage(gvr schema.GroupVers } else if gvr == timeinterval.ResourceInfo.GroupVersionResource() { return timeinterval.NewStorage(api.MuteTimings, namespacer) } else if gvr == templategroup.ResourceInfo.GroupVersionResource() { - return templategroup.NewStorage(api.Templates, namespacer) + srv := api.Templates + //nolint:staticcheck // not yet migrated to OpenFeature + if a.ng.FeatureToggles.IsEnabledGlobally(featuremgmt.FlagAlertingImportAlertmanagerAPI) { + srv = srv.WithIncludeImported() + } + return templategroup.NewStorage(srv, namespacer) } else if gvr == routingtree.ResourceInfo.GroupVersionResource() { return routingtree.NewStorage(api.Policies, namespacer) } diff --git a/pkg/registry/apps/alerting/notifications/templategroup/conversions.go b/pkg/registry/apps/alerting/notifications/templategroup/conversions.go index 95cd2399816..f009a0d3329 100644 --- a/pkg/registry/apps/alerting/notifications/templategroup/conversions.go +++ b/pkg/registry/apps/alerting/notifications/templategroup/conversions.go @@ -1,6 +1,7 @@ package templategroup import ( + "github.com/grafana/alerting/definition" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/fields" "k8s.io/apimachinery/pkg/types" @@ -36,6 +37,7 @@ func convertToK8sResource(orgID int64, template definitions.NotificationTemplate Spec: model.TemplateGroupSpec{ Title: template.Name, Content: template.Template, + Kind: model.TemplateGroupTemplateKind(template.Kind), }, } result.SetProvenanceStatus(string(template.Provenance)) @@ -50,5 +52,6 @@ func convertToDomainModel(template *model.TemplateGroup) definitions.Notificatio Template: template.Spec.Content, ResourceVersion: template.ResourceVersion, Provenance: definitions.Provenance(ngmodels.ProvenanceNone), + Kind: definition.TemplateKind(template.Spec.Kind), } } diff --git a/pkg/registry/apps/alerting/notifications/templategroup/legacy_storage.go b/pkg/registry/apps/alerting/notifications/templategroup/legacy_storage.go index caf2558da96..2b1ff3e6638 100644 --- a/pkg/registry/apps/alerting/notifications/templategroup/legacy_storage.go +++ b/pkg/registry/apps/alerting/notifications/templategroup/legacy_storage.go @@ -4,6 +4,7 @@ import ( "context" "fmt" + "github.com/grafana/alerting/definition" "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/apis/meta/internalversion" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -211,6 +212,7 @@ func (s *legacyStorage) defaultTemplate() (definitions.NotificationTemplate, err UID: defaultTemplate.Name, Provenance: definitions.Provenance("system"), Template: defaultTemplate.Template, + Kind: definition.GrafanaTemplateKind, } return dto, nil diff --git a/pkg/registry/apps/logsdrilldown/authorizer.go b/pkg/registry/apps/logsdrilldown/authorizer.go index f485937121d..b9ba63a3cd2 100644 --- a/pkg/registry/apps/logsdrilldown/authorizer.go +++ b/pkg/registry/apps/logsdrilldown/authorizer.go @@ -24,26 +24,38 @@ func GetAuthorizer() authorizer.Authorizer { return authorizer.DecisionDeny, "valid user is required", err } + // check if is admin + if u.GetIsGrafanaAdmin() { + return authorizer.DecisionAllow, "isGrafanaAdmin", nil + } + // Auth handling for LogsDrilldownDefaults resource if attr.GetResource() == "logsdrilldowndefaults" { // Allow list and get for everyone if attr.GetVerb() == "list" || attr.GetVerb() == "get" { return authorizer.DecisionAllow, "", nil } - // Only allow admins to update (create, update, patch, delete) - if u.GetIsGrafanaAdmin() { - return authorizer.DecisionAllow, "", nil - } // Deny all other operations for non-admins return authorizer.DecisionDeny, "admin access required", nil } - // check if is admin - if u.GetIsGrafanaAdmin() { - return authorizer.DecisionAllow, "", nil + p := u.GetPermissions() + + // Auth handling for Logs Drilldown default columns + if attr.GetResource() == "logsdrilldowndefaultcolumns" { + // Allow get for all users + if attr.GetVerb() == "get" { + return authorizer.DecisionAllow, "", nil + } + // require plugins:write permissions for other operations + _, ok := p[accesscontrol.PluginRolePrefix+"write"] + if ok { + return authorizer.DecisionAllow, "user has plugins:write", nil + } else { + return authorizer.DecisionDeny, "user missing plugins:write", nil + } } - p := u.GetPermissions() if len(p) == 0 { return authorizer.DecisionDeny, "no permissions", nil } diff --git a/pkg/registry/apps/plugins/register.go b/pkg/registry/apps/plugins/register.go index 9113d927a29..68082f59713 100644 --- a/pkg/registry/apps/plugins/register.go +++ b/pkg/registry/apps/plugins/register.go @@ -2,16 +2,19 @@ package plugins import ( "fmt" - "os" authlib "github.com/grafana/authlib/types" appsdkapiserver "github.com/grafana/grafana-app-sdk/k8s/apiserver" pluginsapp "github.com/grafana/grafana/apps/plugins/pkg/app" "github.com/grafana/grafana/apps/plugins/pkg/app/meta" + "github.com/grafana/grafana/pkg/configprovider" "github.com/grafana/grafana/pkg/services/accesscontrol" + "github.com/grafana/grafana/pkg/services/apiserver" "github.com/grafana/grafana/pkg/services/apiserver/appinstaller" grafanaauthorizer "github.com/grafana/grafana/pkg/services/apiserver/auth/authorizer" + "github.com/grafana/grafana/pkg/services/pluginsintegration/pluginassets" + "github.com/grafana/grafana/pkg/services/pluginsintegration/pluginstore" ) var ( @@ -20,23 +23,26 @@ var ( ) type AppInstaller struct { + metaManager *meta.ProviderManager + cfgProvider configprovider.ConfigProvider + restConfigProvider apiserver.RestConfigProvider + *pluginsapp.PluginAppInstaller } -func ProvideAppInstaller(accessControlService accesscontrol.Service, accessClient authlib.AccessClient) (*AppInstaller, error) { +func ProvideAppInstaller( + cfgProvider configprovider.ConfigProvider, + restConfigProvider apiserver.RestConfigProvider, + pluginStore pluginstore.Store, + pluginAssetsService *pluginassets.Service, + accessControlService accesscontrol.Service, accessClient authlib.AccessClient, +) (*AppInstaller, error) { if err := registerAccessControlRoles(accessControlService); err != nil { return nil, fmt.Errorf("registering access control roles: %w", err) } - grafanaComAPIURL := os.Getenv("GRAFANA_COM_API_URL") - if grafanaComAPIURL == "" { - grafanaComAPIURL = "https://grafana.com/api/plugins" - } - - coreProvider := meta.NewCoreProvider() - cloudProvider := meta.NewCatalogProvider(grafanaComAPIURL) - metaProviderManager := meta.NewProviderManager(coreProvider, cloudProvider) - + localProvider := meta.NewLocalProvider(pluginStore, pluginAssetsService) + metaProviderManager := meta.NewProviderManager(localProvider) authorizer := grafanaauthorizer.NewResourceAuthorizer(accessClient) i, err := pluginsapp.ProvideAppInstaller(authorizer, metaProviderManager) if err != nil { @@ -44,6 +50,9 @@ func ProvideAppInstaller(accessControlService accesscontrol.Service, accessClien } return &AppInstaller{ + metaManager: metaProviderManager, + cfgProvider: cfgProvider, + restConfigProvider: restConfigProvider, PluginAppInstaller: i, }, nil } diff --git a/pkg/registry/apps/wireset.go b/pkg/registry/apps/wireset.go index a91fa138309..a2cef7b2d55 100644 --- a/pkg/registry/apps/wireset.go +++ b/pkg/registry/apps/wireset.go @@ -2,7 +2,6 @@ package appregistry import ( "github.com/google/wire" - "github.com/grafana/grafana/pkg/registry/apps/quotas" "github.com/grafana/grafana/pkg/registry/apps/alerting/historian" "github.com/grafana/grafana/pkg/registry/apps/alerting/notifications" @@ -14,6 +13,7 @@ import ( "github.com/grafana/grafana/pkg/registry/apps/logsdrilldown" "github.com/grafana/grafana/pkg/registry/apps/playlist" "github.com/grafana/grafana/pkg/registry/apps/plugins" + "github.com/grafana/grafana/pkg/registry/apps/quotas" "github.com/grafana/grafana/pkg/registry/apps/shorturl" ) diff --git a/pkg/semconv/Makefile b/pkg/semconv/Makefile index 6544e6ad79e..13058b4d235 100644 --- a/pkg/semconv/Makefile +++ b/pkg/semconv/Makefile @@ -3,7 +3,7 @@ all: go markdown .PHONY: go go: - @docker run --rm -u 1000:1000 -v./model:/tmp/grafana/model -v./:/tmp/grafana/output -v./templates:/tmp/grafana/templates \ + @docker run --rm --platform linux/amd64 -u 1000:1000 -v./model:/tmp/grafana/model -v./:/tmp/grafana/output -v./templates:/tmp/grafana/templates \ otel/semconvgen --yaml-root "/tmp/grafana/model/" \ code --template "/tmp/grafana/templates/template.j2" \ --output "/tmp/grafana/output/attributes.go" @@ -11,7 +11,7 @@ go: .PHONY: markdown markdown: - @docker run --rm -u 1000:1000 -v./model:/tmp/grafana/model -v./:/tmp/grafana/output -v./templates:/tmp/grafana/templates \ + @docker run --rm --platform linux/amd64 -u 1000:1000 -v./model:/tmp/grafana/model -v./:/tmp/grafana/output -v./templates:/tmp/grafana/templates \ otel/semconvgen --yaml-root "/tmp/grafana/model/" \ markdown --markdown-root "/tmp/grafana/output/" @npx --yes -- markdown-toc --bullets "-" --no-first-h1 --no-stripHeadingTags -i README.md || exit 1 diff --git a/pkg/semconv/README.md b/pkg/semconv/README.md index 585034221e0..b80a64ad1c9 100644 --- a/pkg/semconv/README.md +++ b/pkg/semconv/README.md @@ -55,6 +55,7 @@ For more information: | Attribute | Type | Description | Examples | [Requirement Level](https://opentelemetry.io/docs/specs/semconv/general/attribute-requirement-level/) | Stability | |---|---|---|---|---|---| | `grafana.plugin.id` | string | The plugin ID. | `prometheus`; `loki`; `grafana-github-datasource` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | +| `grafana.plugin.source.class` | string | The plugin source class. | `core` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | | `grafana.plugin.type` | string | The plugin type. | `datasource` | `Recommended` | ![Stable](https://img.shields.io/badge/-stable-lightgreen) | diff --git a/pkg/semconv/attributes.go b/pkg/semconv/attributes.go index c759ab2e9c0..dbc19ead8e5 100644 --- a/pkg/semconv/attributes.go +++ b/pkg/semconv/attributes.go @@ -140,6 +140,27 @@ func GrafanaPluginId(val string) attribute.KeyValue { return grafanaPluginIdKey.String(val) } +// Describes Grafana plugin source attributes. +const ( + // GrafanaPluginSourceClassKey is the attribute Key conforming to the + // "grafana.plugin.source.class" semantic conventions. It represents the + // plugin source class. + // + // Type: Enum + // RequirementLevel: Optional + // Stability: stable + grafanaPluginSourceClassKey = attribute.Key("grafana.plugin.source.class") +) + +var ( + // Core Plugin + GrafanaPluginSourceClassCore = grafanaPluginSourceClassKey.String("core") + // External Plugin + GrafanaPluginSourceClassExternal = grafanaPluginSourceClassKey.String("external") + // Unknown Plugin Source + GrafanaPluginSourceClassUnknown = grafanaPluginSourceClassKey.String("unknown") +) + // Describes Grafana service attributes. const ( // GrafanaServiceNameKey is the attribute Key conforming to the diff --git a/pkg/semconv/go.mod b/pkg/semconv/go.mod index 9998d716e35..30fc157eb75 100644 --- a/pkg/semconv/go.mod +++ b/pkg/semconv/go.mod @@ -2,9 +2,10 @@ module github.com/grafana/grafana/pkg/semconv go 1.25.5 -require go.opentelemetry.io/otel v1.38.0 +require go.opentelemetry.io/otel v1.39.0 require ( + github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect ) diff --git a/pkg/semconv/go.sum b/pkg/semconv/go.sum index ee3256f1e7a..290db815506 100644 --- a/pkg/semconv/go.sum +++ b/pkg/semconv/go.sum @@ -1,3 +1,5 @@ +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.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/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= @@ -6,7 +8,7 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= -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 v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48= +go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/pkg/semconv/model/registry/plugin.yml b/pkg/semconv/model/registry/plugin.yml index 431794bcd34..1dc2123b2a3 100644 --- a/pkg/semconv/model/registry/plugin.yml +++ b/pkg/semconv/model/registry/plugin.yml @@ -34,3 +34,26 @@ groups: brief: The plugin type. examples: datasource stability: stable + + - id: registry.grafana.plugin.source + type: attribute_group + display_name: Grafana Plugin Source Attributes + brief: "Describes Grafana plugin source attributes." + attributes: + - id: grafana.plugin.source.class + type: + members: + - id: core + value: "core" + brief: 'Core Plugin' + stability: stable + - id: external + value: "external" + brief: 'External Plugin' + stability: stable + - id: unknown + value: "unknown" + brief: 'Unknown Plugin Source' + stability: stable + brief: The plugin source class. + stability: stable diff --git a/pkg/semconv/model/trace/plugin.yaml b/pkg/semconv/model/trace/plugin.yaml index f25e894efbc..b25e1428454 100644 --- a/pkg/semconv/model/trace/plugin.yaml +++ b/pkg/semconv/model/trace/plugin.yaml @@ -5,4 +5,5 @@ groups: stability: stable attributes: - ref: grafana.plugin.id - - ref: grafana.plugin.type \ No newline at end of file + - ref: grafana.plugin.type + - ref: grafana.plugin.source.class \ No newline at end of file diff --git a/pkg/semconv/plugins.go b/pkg/semconv/plugins.go new file mode 100644 index 00000000000..b9e2b90fd08 --- /dev/null +++ b/pkg/semconv/plugins.go @@ -0,0 +1,19 @@ +package semconv + +import ( + "fmt" + + "go.opentelemetry.io/otel/attribute" +) + +// PluginSourceClass converts a plugin source class to the corresponding semantic convention attribute. +func PluginSourceClass(class fmt.Stringer) attribute.KeyValue { + switch class.String() { + case "core": + return GrafanaPluginSourceClassCore + case "external": + return GrafanaPluginSourceClassExternal + default: + return GrafanaPluginSourceClassUnknown + } +} diff --git a/pkg/server/wire_gen.go b/pkg/server/wire_gen.go index 5ed04adf12b..676b0605e83 100644 --- a/pkg/server/wire_gen.go +++ b/pkg/server/wire_gen.go @@ -786,7 +786,7 @@ func Initialize(ctx context.Context, cfg *setting.Cfg, opts Options, apiOpts api if err != nil { return nil, err } - appInstaller, err := plugins.ProvideAppInstaller(acimplService, accessClient) + appInstaller, err := plugins.ProvideAppInstaller(configProvider, eventualRestConfigProvider, pluginstoreService, pluginassetsService, acimplService, accessClient) if err != nil { return nil, err } @@ -882,8 +882,9 @@ func Initialize(ctx context.Context, cfg *setting.Cfg, opts Options, apiOpts api } folderAPIBuilder := folders.RegisterAPIService(cfg, featureToggles, apiserverService, folderimplService, folderPermissionsService, accessControl, acimplService, accessClient, registerer, resourceClient, zanzanaClient) storageBackendImpl := noopstorage.ProvideStorageBackend() + roleApiInstaller := iam.ProvideNoopRoleApiInstaller() noopTeamGroupsREST := externalgroupmapping.ProvideNoopTeamGroupsREST() - identityAccessManagementAPIBuilder, err := iam.RegisterAPIService(cfg, featureToggles, apiserverService, ssosettingsimplService, sqlStore, accessControl, accessClient, zanzanaClient, registerer, storageBackendImpl, storageBackendImpl, tracingService, storageBackendImpl, storageBackendImpl, noopTeamGroupsREST, dualwriteService, resourceClient, orgService, userService, teamService, eventualRestConfigProvider) + identityAccessManagementAPIBuilder, err := iam.RegisterAPIService(cfg, featureToggles, apiserverService, ssosettingsimplService, sqlStore, accessControl, accessClient, zanzanaClient, registerer, storageBackendImpl, roleApiInstaller, tracingService, storageBackendImpl, storageBackendImpl, noopTeamGroupsREST, dualwriteService, resourceClient, orgService, userService, teamService, eventualRestConfigProvider) if err != nil { return nil, err } @@ -1447,7 +1448,7 @@ func InitializeForTest(ctx context.Context, t sqlutil.ITestDB, testingT interfac if err != nil { return nil, err } - appInstaller, err := plugins.ProvideAppInstaller(acimplService, accessClient) + appInstaller, err := plugins.ProvideAppInstaller(configProvider, eventualRestConfigProvider, pluginstoreService, pluginassetsService, acimplService, accessClient) if err != nil { return nil, err } @@ -1543,8 +1544,9 @@ func InitializeForTest(ctx context.Context, t sqlutil.ITestDB, testingT interfac } folderAPIBuilder := folders.RegisterAPIService(cfg, featureToggles, apiserverService, folderimplService, folderPermissionsService, accessControl, acimplService, accessClient, registerer, resourceClient, zanzanaClient) storageBackendImpl := noopstorage.ProvideStorageBackend() + roleApiInstaller := iam.ProvideNoopRoleApiInstaller() noopTeamGroupsREST := externalgroupmapping.ProvideNoopTeamGroupsREST() - identityAccessManagementAPIBuilder, err := iam.RegisterAPIService(cfg, featureToggles, apiserverService, ssosettingsimplService, sqlStore, accessControl, accessClient, zanzanaClient, registerer, storageBackendImpl, storageBackendImpl, tracingService, storageBackendImpl, storageBackendImpl, noopTeamGroupsREST, dualwriteService, resourceClient, orgService, userService, teamService, eventualRestConfigProvider) + identityAccessManagementAPIBuilder, err := iam.RegisterAPIService(cfg, featureToggles, apiserverService, ssosettingsimplService, sqlStore, accessControl, accessClient, zanzanaClient, registerer, storageBackendImpl, roleApiInstaller, tracingService, storageBackendImpl, storageBackendImpl, noopTeamGroupsREST, dualwriteService, resourceClient, orgService, userService, teamService, eventualRestConfigProvider) if err != nil { return nil, err } diff --git a/pkg/services/accesscontrol/models.go b/pkg/services/accesscontrol/models.go index ec67cd03c64..b18fb4134f3 100644 --- a/pkg/services/accesscontrol/models.go +++ b/pkg/services/accesscontrol/models.go @@ -460,6 +460,7 @@ const ( ActionAlertingReceiversReadSecrets = "alert.notifications.receivers.secrets:read" ActionAlertingReceiversCreate = "alert.notifications.receivers:create" ActionAlertingReceiversUpdate = "alert.notifications.receivers:write" + ActionAlertingReceiversUpdateProtected = "alert.notifications.receivers.protected:write" ActionAlertingReceiversDelete = "alert.notifications.receivers:delete" ActionAlertingReceiversTest = "alert.notifications.receivers:test" ActionAlertingReceiversPermissionsRead = "receivers.permissions:read" diff --git a/pkg/services/accesscontrol/ossaccesscontrol/receivers.go b/pkg/services/accesscontrol/ossaccesscontrol/receivers.go index 49ca4a0b3e8..9dd4def1db3 100644 --- a/pkg/services/accesscontrol/ossaccesscontrol/receivers.go +++ b/pkg/services/accesscontrol/ossaccesscontrol/receivers.go @@ -23,7 +23,7 @@ import ( var ReceiversViewActions = []string{accesscontrol.ActionAlertingReceiversRead} var ReceiversEditActions = append(ReceiversViewActions, []string{accesscontrol.ActionAlertingReceiversUpdate, accesscontrol.ActionAlertingReceiversDelete}...) -var ReceiversAdminActions = append(ReceiversEditActions, []string{accesscontrol.ActionAlertingReceiversReadSecrets, accesscontrol.ActionAlertingReceiversPermissionsRead, accesscontrol.ActionAlertingReceiversPermissionsWrite}...) +var ReceiversAdminActions = append(ReceiversEditActions, []string{accesscontrol.ActionAlertingReceiversReadSecrets, accesscontrol.ActionAlertingReceiversPermissionsRead, accesscontrol.ActionAlertingReceiversPermissionsWrite, accesscontrol.ActionAlertingReceiversUpdateProtected}...) // defaultPermissions returns the default permissions for a newly created receiver. func defaultPermissions() []accesscontrol.SetResourcePermissionCommand { diff --git a/pkg/services/accesscontrol/resourcepermissions/api.go b/pkg/services/accesscontrol/resourcepermissions/api.go index 981a99f5189..3c6d1da2038 100644 --- a/pkg/services/accesscontrol/resourcepermissions/api.go +++ b/pkg/services/accesscontrol/resourcepermissions/api.go @@ -33,6 +33,7 @@ type api struct { permissions []string features featuremgmt.FeatureToggles restConfigProvider apiserver.RestConfigProvider + logger log.Logger } func newApi(cfg *setting.Cfg, ac accesscontrol.AccessControl, router routing.RouteRegister, manager *Service, features featuremgmt.FeatureToggles, restConfigProvider apiserver.RestConfigProvider) *api { @@ -41,7 +42,23 @@ func newApi(cfg *setting.Cfg, ac accesscontrol.AccessControl, router routing.Rou for i := len(manager.permissions) - 1; i >= 0; i-- { permissions = append(permissions, manager.permissions[i]) } - return &api{cfg, ac, router, manager, permissions, features, restConfigProvider} + return &api{ + cfg: cfg, + ac: ac, + router: router, + service: manager, + permissions: permissions, + features: features, + restConfigProvider: restConfigProvider, + logger: log.New("resource-permissions-api"), + } +} + +// shouldUseK8sAPIs returns true if both feature flags for K8s API redirect are enabled +func (a *api) shouldUseK8sAPIs() bool { + //nolint:staticcheck // not yet migrated to OpenFeature + return a.features.IsEnabledGlobally(featuremgmt.FlagKubernetesAuthZHandlerRedirect) && + a.features.IsEnabledGlobally(featuremgmt.FlagKubernetesAuthzResourcePermissionApis) } func (a *api) registerEndpoints() { @@ -189,11 +206,10 @@ func (a *api) getPermissions(c *contextmodel.ReqContext) response.Response { return response.JSON(http.StatusOK, k8sPermissions) } span.RecordError(err) - logger := log.New("resource-permissions-api") if errors.Is(err, ErrRestConfigNotAvailable) { - logger.Debug("k8s API not available for resource permissions, falling back to legacy", "error", err, "resourceID", resourceID, "resource", a.service.options.Resource) + a.logger.Debug("k8s API not available for resource permissions, falling back to legacy", "error", err, "resourceID", resourceID, "resource", a.service.options.Resource) } else { - logger.Warn("Failed to get resource permissions from k8s API, falling back to legacy", "error", err, "resourceID", resourceID, "resource", a.service.options.Resource) + a.logger.Warn("Failed to get resource permissions from k8s API, falling back to legacy", "error", err, "resourceID", resourceID, "resource", a.service.options.Resource) } } @@ -304,6 +320,19 @@ func (a *api) setUserPermission(c *contextmodel.ReqContext) response.Response { return response.Error(http.StatusBadRequest, "bad request data", err) } + if a.shouldUseK8sAPIs() { + err := a.setUserPermissionToK8s(c.Req.Context(), c.Namespace, resourceID, userID, cmd.Permission) + if err == nil { + return permissionSetResponse(cmd) + } + span.RecordError(err) + if errors.Is(err, ErrRestConfigNotAvailable) { + a.logger.Debug("k8s API not available for resource permissions, falling back to legacy", "error", err, "resourceID", resourceID, "resource", a.service.options.Resource) + } else { + a.logger.Warn("Failed to set user permission in k8s API, falling back to legacy", "error", err, "resourceID", resourceID, "resource", a.service.options.Resource) + } + } + _, err = a.service.SetUserPermission(c.Req.Context(), c.GetOrgID(), accesscontrol.User{ID: userID}, resourceID, cmd.Permission) if err != nil { return response.Err(err) @@ -361,6 +390,19 @@ func (a *api) setTeamPermission(c *contextmodel.ReqContext) response.Response { return response.Error(http.StatusBadRequest, "bad request data", err) } + if a.shouldUseK8sAPIs() { + err := a.setTeamPermissionToK8s(c.Req.Context(), c.Namespace, resourceID, teamID, cmd.Permission) + if err == nil { + return permissionSetResponse(cmd) + } + span.RecordError(err) + if errors.Is(err, ErrRestConfigNotAvailable) { + a.logger.Debug("k8s API not available for resource permissions, falling back to legacy", "error", err, "resourceID", resourceID, "resource", a.service.options.Resource) + } else { + a.logger.Warn("Failed to set team permission in k8s API, falling back to legacy", "error", err, "resourceID", resourceID, "resource", a.service.options.Resource) + } + } + _, err = a.service.SetTeamPermission(c.Req.Context(), c.GetOrgID(), teamID, resourceID, cmd.Permission) if err != nil { return response.Err(err) @@ -415,6 +457,17 @@ func (a *api) setBuiltinRolePermission(c *contextmodel.ReqContext) response.Resp return response.Error(http.StatusBadRequest, "bad request data", err) } + if a.shouldUseK8sAPIs() { + err := a.setBuiltInRolePermissionToK8s(c.Req.Context(), c.Namespace, resourceID, builtInRole, cmd.Permission) + if err == nil { + return permissionSetResponse(cmd) + } + span.RecordError(err) + if errors.Is(err, ErrRestConfigNotAvailable) { + a.logger.Debug("k8s API not available for resource permissions, falling back to legacy", "error", err, "resourceID", resourceID, "resource", a.service.options.Resource) + } + } + _, err := a.service.SetBuiltInRolePermission(c.Req.Context(), c.GetOrgID(), builtInRole, resourceID, cmd.Permission) if err != nil { return response.Err(err) @@ -463,6 +516,17 @@ func (a *api) setPermissions(c *contextmodel.ReqContext) response.Response { return response.Error(http.StatusBadRequest, "Bad request data: "+err.Error(), err) } + if a.shouldUseK8sAPIs() { + err := a.setResourcePermissionsToK8s(c.Req.Context(), c.Namespace, resourceID, cmd.Permissions) + if err == nil { + return response.Success("Permissions updated") + } + span.RecordError(err) + if errors.Is(err, ErrRestConfigNotAvailable) { + a.logger.Debug("k8s API not available for resource permissions, falling back to legacy", "error", err, "resourceID", resourceID, "resource", a.service.options.Resource) + } + } + _, err := a.service.SetPermissions(ctx, c.GetOrgID(), resourceID, cmd.Permissions...) if err != nil { return response.Err(err) diff --git a/pkg/services/accesscontrol/resourcepermissions/api_adapter.go b/pkg/services/accesscontrol/resourcepermissions/api_adapter.go index 868ae1a32b5..578111368e5 100644 --- a/pkg/services/accesscontrol/resourcepermissions/api_adapter.go +++ b/pkg/services/accesscontrol/resourcepermissions/api_adapter.go @@ -13,9 +13,12 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/client-go/dynamic" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + iamv0 "github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1" "github.com/grafana/grafana/pkg/api/dtos" "github.com/grafana/grafana/pkg/infra/log" + "github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/team" "github.com/grafana/grafana/pkg/services/user" ) @@ -162,3 +165,231 @@ func getMapKeys(m map[string][]string) []string { func (a *api) buildResourcePermissionName(resourceID string) string { return fmt.Sprintf("%s-%s-%s", a.getAPIGroup(), a.service.options.Resource, resourceID) } + +// Write operations + +func (a *api) setResourcePermissionsToK8s(ctx context.Context, namespace string, resourceID string, permissions []accesscontrol.SetResourcePermissionCommand) error { + dynamicClient, err := a.getDynamicClient(ctx) + if err != nil { + return err + } + + resourcePermName := a.buildResourcePermissionName(resourceID) + resourcePermResource := dynamicClient.Resource(iamv0.ResourcePermissionInfo.GroupVersionResource()).Namespace(namespace) + + _, existingResourceVersion, err := a.getExistingResourcePermission(ctx, resourcePermResource, resourcePermName) + if err != nil { + return err + } + + k8sPermissions := make([]iamv0.ResourcePermissionspecPermission, 0, len(permissions)) + for _, perm := range permissions { + if perm.Permission == "" { + continue + } + + kind := a.getPermissionKind(perm) + name, err := a.getPermissionName(ctx, perm) + if err != nil { + return fmt.Errorf("failed to get permission name: %w", err) + } + + k8sPermissions = append(k8sPermissions, iamv0.ResourcePermissionspecPermission{ + Kind: iamv0.ResourcePermissionSpecPermissionKind(kind), + Name: name, + Verb: cases.Lower(language.Und).String(perm.Permission), + }) + } + + if len(k8sPermissions) == 0 { + if existingResourceVersion != "" { + err = resourcePermResource.Delete(ctx, resourcePermName, metav1.DeleteOptions{}) + if err != nil && !k8serrors.IsNotFound(err) { + return fmt.Errorf("failed to delete resource permission in k8s: %w", err) + } + } + return nil + } + + resourcePerm := &iamv0.ResourcePermission{ + TypeMeta: metav1.TypeMeta{ + APIVersion: iamv0.ResourcePermissionInfo.GroupVersion().String(), + Kind: iamv0.ResourcePermissionInfo.TypeMeta().Kind, + }, + ObjectMeta: metav1.ObjectMeta{ + Name: resourcePermName, + Namespace: namespace, + ResourceVersion: existingResourceVersion, + }, + Spec: iamv0.ResourcePermissionSpec{ + Resource: iamv0.ResourcePermissionspecResource{ + ApiGroup: a.getAPIGroup(), + Resource: a.service.options.Resource, + Name: resourceID, + }, + Permissions: k8sPermissions, + }, + } + + return a.createOrUpdateResourcePermission(ctx, resourcePermResource, resourcePerm, existingResourceVersion != "") +} + +func (a *api) setUserPermissionToK8s(ctx context.Context, namespace string, resourceID string, userID int64, permission string) error { + userDetails, err := a.service.userService.GetByID(ctx, &user.GetUserByIDQuery{ID: userID}) + if err != nil { + return fmt.Errorf("failed to get user details: %w", err) + } + + return a.setSinglePermissionToK8s(ctx, namespace, resourceID, string(iamv0.ResourcePermissionSpecPermissionKindUser), userDetails.UID, permission) +} + +func (a *api) setTeamPermissionToK8s(ctx context.Context, namespace string, resourceID string, teamID int64, permission string) error { + teamDetails, err := a.service.teamService.GetTeamByID(ctx, &team.GetTeamByIDQuery{ID: teamID}) + if err != nil { + return fmt.Errorf("failed to get team details: %w", err) + } + + return a.setSinglePermissionToK8s(ctx, namespace, resourceID, string(iamv0.ResourcePermissionSpecPermissionKindTeam), teamDetails.UID, permission) +} + +func (a *api) setBuiltInRolePermissionToK8s(ctx context.Context, namespace string, resourceID string, builtInRole string, permission string) error { + return a.setSinglePermissionToK8s(ctx, namespace, resourceID, string(iamv0.ResourcePermissionSpecPermissionKindBasicRole), builtInRole, permission) +} + +func (a *api) setSinglePermissionToK8s(ctx context.Context, namespace string, resourceID string, kind string, name string, permission string) error { + dynamicClient, err := a.getDynamicClient(ctx) + if err != nil { + return err + } + + resourcePermName := a.buildResourcePermissionName(resourceID) + resourcePermResource := dynamicClient.Resource(iamv0.ResourcePermissionInfo.GroupVersionResource()).Namespace(namespace) + + existingResourcePerm, existingResourceVersion, err := a.getExistingResourcePermission(ctx, resourcePermResource, resourcePermName) + if err != nil { + return err + } + + newPermissions := make([]iamv0.ResourcePermissionspecPermission, 0) + for _, perm := range existingResourcePerm.Spec.Permissions { + if string(perm.Kind) == kind && perm.Name == name { + continue + } + newPermissions = append(newPermissions, perm) + } + + if permission != "" { + newPermissions = append(newPermissions, iamv0.ResourcePermissionspecPermission{ + Kind: iamv0.ResourcePermissionSpecPermissionKind(kind), + Name: name, + Verb: cases.Lower(language.Und).String(permission), + }) + } + + if len(newPermissions) == 0 { + if existingResourceVersion != "" { + err = resourcePermResource.Delete(ctx, resourcePermName, metav1.DeleteOptions{}) + if err != nil && !k8serrors.IsNotFound(err) { + return fmt.Errorf("failed to delete resource permission in k8s: %w", err) + } + } + return nil + } + + resourcePerm := &iamv0.ResourcePermission{ + TypeMeta: metav1.TypeMeta{ + APIVersion: iamv0.ResourcePermissionInfo.GroupVersion().String(), + Kind: iamv0.ResourcePermissionInfo.TypeMeta().Kind, + }, + ObjectMeta: metav1.ObjectMeta{ + Name: resourcePermName, + Namespace: namespace, + ResourceVersion: existingResourceVersion, + }, + Spec: iamv0.ResourcePermissionSpec{ + Resource: iamv0.ResourcePermissionspecResource{ + ApiGroup: a.getAPIGroup(), + Resource: a.service.options.Resource, + Name: resourceID, + }, + Permissions: newPermissions, + }, + } + + return a.createOrUpdateResourcePermission(ctx, resourcePermResource, resourcePerm, existingResourceVersion != "") +} + +func (a *api) getPermissionKind(perm accesscontrol.SetResourcePermissionCommand) string { + if perm.UserID != 0 { + return string(iamv0.ResourcePermissionSpecPermissionKindUser) + } + if perm.TeamID != 0 { + return string(iamv0.ResourcePermissionSpecPermissionKindTeam) + } + if perm.BuiltinRole != "" { + return string(iamv0.ResourcePermissionSpecPermissionKindBasicRole) + } + return "" +} + +func (a *api) getExistingResourcePermission(ctx context.Context, resourcePermResource dynamic.ResourceInterface, resourcePermName string) (*iamv0.ResourcePermission, string, error) { + unstructuredObj, err := resourcePermResource.Get(ctx, resourcePermName, metav1.GetOptions{}) + if err != nil { + if k8serrors.IsNotFound(err) { + return &iamv0.ResourcePermission{}, "", nil + } + return nil, "", fmt.Errorf("failed to get existing resource permission: %w", err) + } + + var resourcePerm iamv0.ResourcePermission + if err := runtime.DefaultUnstructuredConverter.FromUnstructured(unstructuredObj.Object, &resourcePerm); err != nil { + return nil, "", fmt.Errorf("failed to convert existing resource permission: %w", err) + } + + return &resourcePerm, unstructuredObj.GetResourceVersion(), nil +} + +func (a *api) createOrUpdateResourcePermission(ctx context.Context, resourcePermResource dynamic.ResourceInterface, resourcePerm *iamv0.ResourcePermission, isUpdate bool) error { + unstructuredObj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(resourcePerm) + if err != nil { + return fmt.Errorf("failed to convert resource permission to unstructured: %w", err) + } + unstructuredPerm := &unstructured.Unstructured{Object: unstructuredObj} + + if isUpdate { + _, err = resourcePermResource.Update(ctx, unstructuredPerm, metav1.UpdateOptions{}) + if err != nil { + return fmt.Errorf("failed to update resource permission in k8s: %w", err) + } + } else { + _, err = resourcePermResource.Create(ctx, unstructuredPerm, metav1.CreateOptions{}) + if err != nil { + return fmt.Errorf("failed to create resource permission in k8s: %w", err) + } + } + + return nil +} + +func (a *api) getPermissionName(ctx context.Context, perm accesscontrol.SetResourcePermissionCommand) (string, error) { + if perm.UserID != 0 { + userDetails, err := a.service.userService.GetByID(ctx, &user.GetUserByIDQuery{ID: perm.UserID}) + if err != nil { + return "", fmt.Errorf("failed to get user details for user ID %d: %w", perm.UserID, err) + } + return userDetails.UID, nil + } + if perm.TeamID != 0 { + teamDetails, err := a.service.teamService.GetTeamByID(ctx, &team.GetTeamByIDQuery{ + ID: perm.TeamID, + }) + if err != nil { + return "", fmt.Errorf("failed to get team details for team ID %d: %w", perm.TeamID, err) + } + return teamDetails.UID, nil + } + if perm.BuiltinRole != "" { + return perm.BuiltinRole, nil + } + return "", fmt.Errorf("no valid permission subject found") +} diff --git a/pkg/services/accesscontrol/resourcepermissions/api_adapter_test.go b/pkg/services/accesscontrol/resourcepermissions/api_adapter_test.go new file mode 100644 index 00000000000..ca0ca214c9a --- /dev/null +++ b/pkg/services/accesscontrol/resourcepermissions/api_adapter_test.go @@ -0,0 +1,200 @@ +package resourcepermissions + +import ( + "context" + "testing" + + "github.com/stretchr/testify/assert" + + iamv0 "github.com/grafana/grafana/apps/iam/pkg/apis/iam/v0alpha1" + "github.com/grafana/grafana/pkg/services/accesscontrol" +) + +// TestGetPermissionKind tests the permission kind mapping logic +func TestGetPermissionKind(t *testing.T) { + api := &api{ + service: &Service{ + options: Options{ + Resource: "dashboards", + ResourceAttribute: "uid", + }, + }, + } + + tests := []struct { + name string + perm accesscontrol.SetResourcePermissionCommand + expected string + }{ + { + name: "user permission", + perm: accesscontrol.SetResourcePermissionCommand{UserID: 123}, + expected: string(iamv0.ResourcePermissionSpecPermissionKindUser), + }, + { + name: "team permission", + perm: accesscontrol.SetResourcePermissionCommand{TeamID: 456}, + expected: string(iamv0.ResourcePermissionSpecPermissionKindTeam), + }, + { + name: "builtin role permission", + perm: accesscontrol.SetResourcePermissionCommand{BuiltinRole: "Editor"}, + expected: string(iamv0.ResourcePermissionSpecPermissionKindBasicRole), + }, + { + name: "empty permission returns empty kind", + perm: accesscontrol.SetResourcePermissionCommand{}, + expected: "", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + kind := api.getPermissionKind(tt.perm) + assert.Equal(t, tt.expected, kind) + }) + } +} + +// TestGetDynamicClient_RestConfigNotAvailable tests error handling when rest config is not available +func TestGetDynamicClient_RestConfigNotAvailable(t *testing.T) { + ctx := context.Background() + + api := &api{ + service: &Service{ + options: Options{ + Resource: "dashboards", + }, + }, + restConfigProvider: nil, + } + + client, err := api.getDynamicClient(ctx) + + assert.Error(t, err) + assert.Nil(t, client) + assert.Equal(t, ErrRestConfigNotAvailable, err) +} + +// TestBuildResourcePermissionName tests resource permission name building +func TestBuildResourcePermissionName(t *testing.T) { + tests := []struct { + name string + apiGroup string + resource string + resourceID string + expectedName string + }{ + { + name: "with custom API group", + apiGroup: "dashboard.grafana.app", + resource: "dashboards", + resourceID: "dashboard-uid-123", + expectedName: "dashboard.grafana.app-dashboards-dashboard-uid-123", + }, + { + name: "with default API group", + apiGroup: "", + resource: "folders", + resourceID: "folder-uid-456", + expectedName: "folders.grafana.app-folders-folder-uid-456", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + api := &api{ + service: &Service{ + options: Options{ + Resource: tt.resource, + APIGroup: tt.apiGroup, + }, + }, + } + + name := api.buildResourcePermissionName(tt.resourceID) + assert.Equal(t, tt.expectedName, name) + }) + } +} + +// TestGetAPIGroup tests API group resolution +func TestGetAPIGroup(t *testing.T) { + t.Run("returns custom API group when set", func(t *testing.T) { + api := &api{ + service: &Service{ + options: Options{ + Resource: "dashboards", + APIGroup: "custom.grafana.app", + }, + }, + } + + group := api.getAPIGroup() + assert.Equal(t, "custom.grafana.app", group) + }) + + t.Run("returns default API group when not set", func(t *testing.T) { + api := &api{ + service: &Service{ + options: Options{ + Resource: "dashboards", + APIGroup: "", + }, + }, + } + + group := api.getAPIGroup() + assert.Equal(t, "dashboards.grafana.app", group) + }) + + t.Run("default group for folders", func(t *testing.T) { + api := &api{ + service: &Service{ + options: Options{ + Resource: "folders", + APIGroup: "", + }, + }, + } + + group := api.getAPIGroup() + assert.Equal(t, "folders.grafana.app", group) + }) +} + +// TestResourcePermissionKindConstants verifies the kind constants match expected values +func TestResourcePermissionKindConstants(t *testing.T) { + tests := []struct { + name string + kind iamv0.ResourcePermissionSpecPermissionKind + expected string + }{ + { + name: "User kind", + kind: iamv0.ResourcePermissionSpecPermissionKindUser, + expected: "User", + }, + { + name: "Team kind", + kind: iamv0.ResourcePermissionSpecPermissionKindTeam, + expected: "Team", + }, + { + name: "ServiceAccount kind", + kind: iamv0.ResourcePermissionSpecPermissionKindServiceAccount, + expected: "ServiceAccount", + }, + { + name: "BasicRole kind", + kind: iamv0.ResourcePermissionSpecPermissionKindBasicRole, + expected: "BasicRole", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.expected, string(tt.kind)) + }) + } +} diff --git a/pkg/services/authn/clients/ext_jwt.go b/pkg/services/authn/clients/ext_jwt.go index b479f314c76..be9efa9ce76 100644 --- a/pkg/services/authn/clients/ext_jwt.go +++ b/pkg/services/authn/clients/ext_jwt.go @@ -131,7 +131,8 @@ func (s *ExtendedJWT) authenticateAsUser( return nil, errExtJWTInvalid.Errorf("failed to parse id token subject: %w", err) } - if !claims.IsIdentityType(t, claims.TypeUser) { + // TODO: How to support other identity types like render and anonymous here? + if !claims.IsIdentityType(t, claims.TypeUser, claims.TypeServiceAccount) { return nil, errExtJWTInvalidSubject.Errorf("unexpected identity: %s", idTokenClaims.Subject) } diff --git a/pkg/services/authn/clients/ext_jwt_test.go b/pkg/services/authn/clients/ext_jwt_test.go index 88cf11fb83a..3c7203844b1 100644 --- a/pkg/services/authn/clients/ext_jwt_test.go +++ b/pkg/services/authn/clients/ext_jwt_test.go @@ -53,6 +53,17 @@ var ( Namespace: "default", // org ID of 1 is special and translates to default }, } + validIDTokenClaimsWithServiceAccount = idTokenClaims{ + Claims: jwt.Claims{ + Subject: "service-account:3", + Expiry: jwt.NewNumericDate(time.Date(2023, 5, 3, 0, 0, 0, 0, time.UTC)), + IssuedAt: jwt.NewNumericDate(time.Date(2023, 5, 2, 0, 0, 0, 0, time.UTC)), + }, + Rest: authnlib.IDTokenClaims{ + AuthenticatedBy: "extended_jwt", + Namespace: "default", // org ID of 1 is special and translates to default + }, + } validIDTokenClaimsWithStackSet = idTokenClaims{ Claims: jwt.Claims{ Subject: "user:2", @@ -118,7 +129,7 @@ var ( } invalidSubjectIDTokenClaims = idTokenClaims{ Claims: jwt.Claims{ - Subject: "service-account:2", + Subject: "anonymous:2", Expiry: jwt.NewNumericDate(time.Date(2023, 5, 3, 0, 0, 0, 0, time.UTC)), IssuedAt: jwt.NewNumericDate(time.Date(2023, 5, 2, 0, 0, 0, 0, time.UTC)), }, @@ -286,6 +297,29 @@ func TestExtendedJWT_Authenticate(t *testing.T) { }, }, }, + { + name: "should authenticate as service account", + accessToken: &validAccessTokenClaims, + idToken: &validIDTokenClaimsWithServiceAccount, + orgID: 1, + want: &authn.Identity{ + ID: "3", + Type: claims.TypeServiceAccount, + OrgID: 1, + AccessTokenClaims: &validAccessTokenClaims, + IDTokenClaims: &validIDTokenClaimsWithServiceAccount, + Namespace: "default", + AuthenticatedBy: "extendedjwt", + AuthID: "access-policy:this-uid", + ClientParams: authn.ClientParams{ + FetchSyncedUser: true, + SyncPermissions: true, + FetchPermissionsParams: authn.FetchPermissionsParams{ + RestrictedActions: []string{"dashboards:create", "folders:read", "datasources:explore", "datasources.insights:read"}, + }, + }, + }, + }, { name: "should authenticate as user in the user namespace", accessToken: &validAccessTokenClaimsWildcard, diff --git a/pkg/services/authz/rbac/mapper.go b/pkg/services/authz/rbac/mapper.go index 9444d35d0ae..dcf2432fb2c 100644 --- a/pkg/services/authz/rbac/mapper.go +++ b/pkg/services/authz/rbac/mapper.go @@ -279,8 +279,11 @@ func NewMapperRegistry() MapperRegistry { }, "provisioning.grafana.app": { "repositories": newResourceTranslation("provisioning.repositories", "uid", false, skipScopeOnAllVerbs), + "connections": newResourceTranslation("provisioning.connections", "uid", false, skipScopeOnAllVerbs), "jobs": newResourceTranslation("provisioning.jobs", "uid", false, skipScopeOnAllVerbs), "historicjobs": newResourceTranslation("provisioning.historicjobs", "uid", false, skipScopeOnAllVerbs), + "settings": newResourceTranslation("provisioning.settings", "", false, skipScopeOnAllVerbs), + "stats": newResourceTranslation("provisioning.stats", "", false, skipScopeOnAllVerbs), }, "secret.grafana.app": { "securevalues": newResourceTranslation("secret.securevalues", "uid", false, nil), diff --git a/pkg/services/featuremgmt/models.go b/pkg/services/featuremgmt/models.go index 304d17ee075..d59dff63c37 100644 --- a/pkg/services/featuremgmt/models.go +++ b/pkg/services/featuremgmt/models.go @@ -23,9 +23,7 @@ type FeatureToggles interface { // a full server restart for a change to take place. // // Deprecated: FeatureToggles.IsEnabledGlobally is deprecated and will be removed in a future release. - // Toggles that must be reliably evaluated at the service startup should be - // changed to settings (see setting.StartupSettings), and/or removed entirely. - // For app registration please use `grafana-apiserver.runtime_config` in settings.ini + // Toggles that must be reliably evaluated at the service startup should be changed to settings and/or removed entirely. IsEnabledGlobally(flag string) bool // Get the enabled flags -- this *may* also include disabled flags (with value false) diff --git a/pkg/services/featuremgmt/registry.go b/pkg/services/featuremgmt/registry.go index d898492e918..d6f2bcbec2e 100644 --- a/pkg/services/featuremgmt/registry.go +++ b/pkg/services/featuremgmt/registry.go @@ -185,13 +185,6 @@ var ( Stage: FeatureStageExperimental, Owner: grafanaDatasourcesCoreServicesSquad, }, - { - Name: "unifiedRequestLog", - Description: "Writes error logs to the request logger", - Stage: FeatureStageGeneralAvailability, - Owner: grafanaBackendGroup, - Expression: "true", - }, { Name: "renderAuthJWT", Description: "Uses JWT-based auth for rendering instead of relying on remote cache", @@ -494,13 +487,6 @@ var ( Owner: grafanaDatasourcesCoreServicesSquad, FrontendOnly: true, // and can change at startup }, - { - Name: "queryServiceFromExplore", - Description: "Routes explore requests to the new query service", - Stage: FeatureStageExperimental, - Owner: grafanaDatasourcesCoreServicesSquad, - FrontendOnly: true, - }, { Name: "cloudWatchBatchQueries", Description: "Runs CloudWatch metrics queries as separate batches", @@ -607,6 +593,13 @@ var ( FrontendOnly: true, Owner: grafanaDashboardsSquad, }, + { + Name: "drilldownRecommendations", + Description: "Enables showing recently used drilldowns or recommendations given by the datasource in the AdHocFilters and GroupBy variables", + Stage: FeatureStageExperimental, + FrontendOnly: true, + Owner: grafanaDashboardsSquad, + }, { Name: "perPanelNonApplicableDrilldowns", Description: "Enables viewing non-applicable drilldowns on a panel level", @@ -820,6 +813,13 @@ var ( Owner: grafanaDashboardsSquad, HideFromDocs: true, }, + { + Name: "dashboardAdHocAndGroupByWrapper", + Description: "Wraps the ad hoc and group by variables in a single wrapper, with all other variables below it", + Stage: FeatureStageExperimental, + Owner: grafanaDashboardsSquad, + HideFromDocs: true, + }, { Name: "cloudWatchNewLabelParsing", Description: "Updates CloudWatch label parsing to be more accurate", @@ -885,6 +885,13 @@ var ( Owner: grafanaAlertingSquad, FrontendOnly: true, }, + { + Name: "alertingSavedSearches", + Description: "Enables saved searches for alert rules list", + Stage: FeatureStageExperimental, + Owner: grafanaAlertingSquad, + FrontendOnly: true, + }, { Name: "alertingDisableSendAlertsExternal", Description: "Disables the ability to send alerts to an external Alertmanager datasource.", @@ -1360,6 +1367,13 @@ var ( Owner: grafanaAlertingSquad, HideFromDocs: true, }, + { + Name: "fetchRulesInCompactMode", + Description: "Add compact=true when fetching rules", + Stage: FeatureStageExperimental, + Owner: grafanaAlertingSquad, + HideFromDocs: true, + }, { Name: "newLogsPanel", Description: "Enables the new logs panel", @@ -1914,6 +1928,14 @@ var ( Owner: grafanaDatavizSquad, Expression: "false", }, + { + Name: "heatmapRowsAxisOptions", + Description: "Enable Y-axis scale configuration options for pre-bucketed heatmap data (heatmap-rows)", + Stage: FeatureStageExperimental, + FrontendOnly: true, + Owner: grafanaDatavizSquad, + Expression: "false", + }, { Name: "preventPanelChromeOverflow", Description: "Restrict PanelChrome contents with overflow: hidden;", diff --git a/pkg/services/featuremgmt/toggles_gen.csv b/pkg/services/featuremgmt/toggles_gen.csv index 51bb242f1d9..179568aa0c4 100644 --- a/pkg/services/featuremgmt/toggles_gen.csv +++ b/pkg/services/featuremgmt/toggles_gen.csv @@ -24,7 +24,6 @@ influxqlStreamingParser,experimental,@grafana/partner-datasources,false,false,fa influxdbRunQueriesInParallel,privatePreview,@grafana/partner-datasources,false,false,false lokiLogsDataplane,experimental,@grafana/observability-logs,false,false,false disableSSEDataplane,experimental,@grafana/grafana-datasources-core-services,false,false,false -unifiedRequestLog,GA,@grafana/grafana-backend-group,false,false,false renderAuthJWT,preview,@grafana/grafana-operator-experience-squad,false,false,false refactorVariablesTimeRange,preview,@grafana/dashboards-squad,false,false,false faroDatasourceSelector,preview,@grafana/app-o11y,false,false,true @@ -68,7 +67,6 @@ queryService,experimental,@grafana/grafana-datasources-core-services,false,true, queryServiceWithConnections,experimental,@grafana/grafana-datasources-core-services,false,true,false queryServiceRewrite,experimental,@grafana/grafana-datasources-core-services,false,true,false queryServiceFromUI,experimental,@grafana/grafana-datasources-core-services,false,false,true -queryServiceFromExplore,experimental,@grafana/grafana-datasources-core-services,false,false,true cloudWatchBatchQueries,preview,@grafana/aws-datasources,false,false,false cachingOptimizeSerializationMemoryUsage,experimental,@grafana/grafana-operator-experience-squad,false,false,false alertmanagerRemoteSecondary,experimental,@grafana/alerting-squad,false,false,false @@ -84,6 +82,7 @@ dashboardNewLayouts,experimental,@grafana/dashboards-squad,false,false,false kubernetesDashboardsV2,experimental,@grafana/dashboards-squad,false,false,false dashboardUndoRedo,experimental,@grafana/dashboards-squad,false,false,true unlimitedLayoutsNesting,experimental,@grafana/dashboards-squad,false,false,true +drilldownRecommendations,experimental,@grafana/dashboards-squad,false,false,true perPanelNonApplicableDrilldowns,experimental,@grafana/dashboards-squad,false,false,true panelGroupBy,experimental,@grafana/dashboards-squad,false,false,true perPanelFiltering,experimental,@grafana/dashboards-squad,false,false,true @@ -113,6 +112,7 @@ scopeFilters,experimental,@grafana/dashboards-squad,false,false,false oauthRequireSubClaim,experimental,@grafana/identity-access-team,false,false,false refreshTokenRequired,experimental,@grafana/identity-access-team,false,false,false newDashboardWithFiltersAndGroupBy,experimental,@grafana/dashboards-squad,false,false,false +dashboardAdHocAndGroupByWrapper,experimental,@grafana/dashboards-squad,false,false,false cloudWatchNewLabelParsing,GA,@grafana/aws-datasources,false,false,false disableNumericMetricsSortingInExpressions,experimental,@grafana/oss-big-tent,false,true,false grafanaManagedRecordingRules,experimental,@grafana/alerting-squad,false,false,false @@ -122,6 +122,7 @@ suggestedDashboards,experimental,@grafana/sharing-squad,false,false,false dashboardTemplates,preview,@grafana/sharing-squad,false,false,false logsExploreTableDefaultVisualization,experimental,@grafana/observability-logs,false,false,true alertingListViewV2,privatePreview,@grafana/alerting-squad,false,false,true +alertingSavedSearches,experimental,@grafana/alerting-squad,false,false,true alertingDisableSendAlertsExternal,experimental,@grafana/alerting-squad,false,false,false preserveDashboardStateWhenNavigating,experimental,@grafana/dashboards-squad,false,false,false alertingCentralAlertHistory,experimental,@grafana/alerting-squad,false,false,false @@ -188,6 +189,7 @@ grafanaAdvisor,privatePreview,@grafana/plugins-platform-backend,false,false,fals elasticsearchImprovedParsing,experimental,@grafana/partner-datasources,false,false,false datasourceConnectionsTab,privatePreview,@grafana/plugins-platform-backend,false,false,true fetchRulesUsingPost,experimental,@grafana/alerting-squad,false,false,false +fetchRulesInCompactMode,experimental,@grafana/alerting-squad,false,false,false newLogsPanel,GA,@grafana/observability-logs,false,false,true grafanaconThemes,GA,@grafana/grafana-frontend-platform,false,true,false alertingJiraIntegration,experimental,@grafana/alerting-squad,false,false,true @@ -260,6 +262,7 @@ pluginInstallAPISync,experimental,@grafana/plugins-platform-backend,false,false, newGauge,experimental,@grafana/dataviz-squad,false,false,true newVizSuggestions,preview,@grafana/dataviz-squad,false,false,true externalVizSuggestions,experimental,@grafana/dataviz-squad,false,false,true +heatmapRowsAxisOptions,experimental,@grafana/dataviz-squad,false,false,true preventPanelChromeOverflow,preview,@grafana/grafana-frontend-platform,false,false,true jaegerEnableGrpcEndpoint,experimental,@grafana/oss-big-tent,false,false,false pluginStoreServiceLoading,experimental,@grafana/plugins-platform-backend,false,false,false diff --git a/pkg/services/featuremgmt/toggles_gen.go b/pkg/services/featuremgmt/toggles_gen.go index fc7b8043dec..2797b046d57 100644 --- a/pkg/services/featuremgmt/toggles_gen.go +++ b/pkg/services/featuremgmt/toggles_gen.go @@ -79,10 +79,6 @@ const ( // Disables dataplane specific processing in server side expressions. FlagDisableSSEDataplane = "disableSSEDataplane" - // FlagUnifiedRequestLog - // Writes error logs to the request logger - FlagUnifiedRequestLog = "unifiedRequestLog" - // FlagRenderAuthJWT // Uses JWT-based auth for rendering instead of relying on remote cache FlagRenderAuthJWT = "renderAuthJWT" @@ -339,6 +335,10 @@ const ( // Enables filters and group by variables on all new dashboards. Variables are added only if default data source supports filtering. FlagNewDashboardWithFiltersAndGroupBy = "newDashboardWithFiltersAndGroupBy" + // FlagDashboardAdHocAndGroupByWrapper + // Wraps the ad hoc and group by variables in a single wrapper, with all other variables below it + FlagDashboardAdHocAndGroupByWrapper = "dashboardAdHocAndGroupByWrapper" + // FlagCloudWatchNewLabelParsing // Updates CloudWatch label parsing to be more accurate FlagCloudWatchNewLabelParsing = "cloudWatchNewLabelParsing" @@ -571,6 +571,10 @@ const ( // Use a POST request to list rules by passing down the namespaces user has access to FlagFetchRulesUsingPost = "fetchRulesUsingPost" + // FlagFetchRulesInCompactMode + // Add compact=true when fetching rules + FlagFetchRulesInCompactMode = "fetchRulesInCompactMode" + // FlagGrafanaconThemes // Enables the temporary themes for GrafanaCon FlagGrafanaconThemes = "grafanaconThemes" diff --git a/pkg/services/featuremgmt/toggles_gen.json b/pkg/services/featuremgmt/toggles_gen.json index b768dc2f761..42922ecf82d 100644 --- a/pkg/services/featuremgmt/toggles_gen.json +++ b/pkg/services/featuremgmt/toggles_gen.json @@ -498,6 +498,19 @@ "codeowner": "@grafana/alerting-squad" } }, + { + "metadata": { + "name": "alertingSavedSearches", + "resourceVersion": "1765453147546", + "creationTimestamp": "2025-12-11T11:39:07Z" + }, + "spec": { + "description": "Enables saved searches for alert rules list", + "stage": "experimental", + "codeowner": "@grafana/alerting-squad", + "frontend": true + } + }, { "metadata": { "name": "alertingTriage", @@ -922,6 +935,19 @@ "frontend": true } }, + { + "metadata": { + "name": "dashboardAdHocAndGroupByWrapper", + "resourceVersion": "1765841806645", + "creationTimestamp": "2025-12-15T23:36:46Z" + }, + "spec": { + "description": "Wraps the ad hoc and group by variables in a single wrapper, with all other variables below it", + "stage": "experimental", + "codeowner": "@grafana/dashboards-squad", + "hideFromDocs": true + } + }, { "metadata": { "name": "dashboardDisableSchemaValidationV1", @@ -1181,6 +1207,19 @@ "codeowner": "@grafana/grafana-datasources-core-services" } }, + { + "metadata": { + "name": "drilldownRecommendations", + "resourceVersion": "1764855550769", + "creationTimestamp": "2025-12-04T13:39:10Z" + }, + "spec": { + "description": "Enables showing recently used drilldowns or recommendations given by the datasource in the AdHocFilters and GroupBy variables", + "stage": "experimental", + "codeowner": "@grafana/dashboards-squad", + "frontend": true + } + }, { "metadata": { "name": "elasticsearchCrossClusterSearch", @@ -1444,6 +1483,19 @@ "expression": "false" } }, + { + "metadata": { + "name": "fetchRulesInCompactMode", + "resourceVersion": "1766045288124", + "creationTimestamp": "2025-12-18T08:08:08Z" + }, + "spec": { + "description": "Add compact=true when fetching rules", + "stage": "experimental", + "codeowner": "@grafana/alerting-squad", + "hideFromDocs": true + } + }, { "metadata": { "name": "fetchRulesUsingPost", @@ -1608,6 +1660,20 @@ "codeowner": "@grafana/search-and-storage" } }, + { + "metadata": { + "name": "heatmapRowsAxisOptions", + "resourceVersion": "1765353244400", + "creationTimestamp": "2025-12-10T07:54:04Z" + }, + "spec": { + "description": "Enable Y-axis scale configuration options for pre-bucketed heatmap data (heatmap-rows)", + "stage": "experimental", + "codeowner": "@grafana/dataviz-squad", + "frontend": true, + "expression": "false" + } + }, { "metadata": { "name": "improvedExternalSessionHandling", @@ -2911,7 +2977,8 @@ "metadata": { "name": "queryServiceFromExplore", "resourceVersion": "1764664939750", - "creationTimestamp": "2025-04-02T10:00:33Z" + "creationTimestamp": "2025-04-02T10:00:33Z", + "deletionTimestamp": "2025-12-10T20:33:21Z" }, "spec": { "description": "Routes explore requests to the new query service", @@ -3475,7 +3542,8 @@ "metadata": { "name": "unifiedRequestLog", "resourceVersion": "1764664939750", - "creationTimestamp": "2023-03-31T13:38:09Z" + "creationTimestamp": "2023-03-31T13:38:09Z", + "deletionTimestamp": "2025-12-18T14:21:02Z" }, "spec": { "description": "Writes error logs to the request logger", diff --git a/pkg/services/folder/folderimpl/folder_unifiedstorage.go b/pkg/services/folder/folderimpl/folder_unifiedstorage.go index 9b238b769fe..69b8cb59311 100644 --- a/pkg/services/folder/folderimpl/folder_unifiedstorage.go +++ b/pkg/services/folder/folderimpl/folder_unifiedstorage.go @@ -726,19 +726,6 @@ func (s *Service) moveOnApiServer(ctx context.Context, cmd *folder.MoveFolderCom return nil, folder.ErrBadRequest.Errorf("k6 project may not be moved") } - f, err := s.unifiedStore.Get(ctx, folder.GetFolderQuery{ - UID: &cmd.UID, - OrgID: cmd.OrgID, - SignedInUser: cmd.SignedInUser, - }) - if err != nil { - return nil, err - } - - if f != nil && f.ParentUID == accesscontrol.K6FolderUID { - return nil, folder.ErrBadRequest.Errorf("k6 project may not be moved") - } - // Check that the user is allowed to move the folder to the destination folder hasAccess, evalErr := s.canMoveViaApiServer(ctx, cmd) if evalErr != nil { @@ -748,30 +735,7 @@ func (s *Service) moveOnApiServer(ctx context.Context, cmd *folder.MoveFolderCom return nil, dashboards.ErrFolderAccessDenied } - // here we get the folder, we need to get the height of current folder - // and the depth of the new parent folder, the sum can't bypass 8 - folderHeight, err := s.unifiedStore.GetHeight(ctx, cmd.UID, cmd.OrgID, &cmd.NewParentUID) - if err != nil { - return nil, err - } - parents, err := s.unifiedStore.GetParents(ctx, folder.GetParentsQuery{UID: cmd.NewParentUID, OrgID: cmd.OrgID}) - if err != nil { - return nil, err - } - - // height of the folder that is being moved + this current folder itself + depth of the NewParent folder should be less than or equal MaxNestedFolderDepth - if folderHeight+len(parents)+1 > folder.MaxNestedFolderDepth { - return nil, folder.ErrMaximumDepthReached.Errorf("failed to move folder") - } - - for _, parent := range parents { - // if the current folder is already a parent of newparent, we should return error - if parent.UID == cmd.UID { - return nil, folder.ErrCircularReference.Errorf("failed to move folder") - } - } - - f, err = s.unifiedStore.Update(ctx, folder.UpdateFolderCommand{ + f, err := s.unifiedStore.Update(ctx, folder.UpdateFolderCommand{ UID: cmd.UID, OrgID: cmd.OrgID, NewParentUID: &cmd.NewParentUID, diff --git a/pkg/services/folder/folderimpl/folder_unifiedstorage_test.go b/pkg/services/folder/folderimpl/folder_unifiedstorage_test.go index 0ff7a25b0e9..3a47c41fffb 100644 --- a/pkg/services/folder/folderimpl/folder_unifiedstorage_test.go +++ b/pkg/services/folder/folderimpl/folder_unifiedstorage_test.go @@ -439,7 +439,7 @@ func TestIntegrationFolderServiceViaUnifiedStorage(t *testing.T) { ID: fooFolder.ID, // nolint:staticcheck UID: fooFolder.UID, }, - }, nil).Once() + }, nil).Twice() // Called twice due to total count call id := int64(123) emptyString := "" query := &folder.GetFolderQuery{ @@ -455,7 +455,7 @@ func TestIntegrationFolderServiceViaUnifiedStorage(t *testing.T) { }) t.Run("When get folder by non existing ID should return not found error", func(t *testing.T) { - dashboardStore.On("FindDashboards", mock.Anything, mock.Anything).Return([]dashboards.DashboardSearchProjection{}, nil).Once() + dashboardStore.On("FindDashboards", mock.Anything, mock.Anything).Return([]dashboards.DashboardSearchProjection{}, nil).Twice() // Called twice due to total count call id := int64(111111) query := &folder.GetFolderQuery{ ID: &id, @@ -475,7 +475,7 @@ func TestIntegrationFolderServiceViaUnifiedStorage(t *testing.T) { ID: fooFolder.ID, // nolint:staticcheck UID: fooFolder.UID, }, - }, nil).Once() + }, nil).Twice() // Called twice due to total count call title := "foo" query := &folder.GetFolderQuery{ Title: &title, @@ -489,7 +489,7 @@ func TestIntegrationFolderServiceViaUnifiedStorage(t *testing.T) { }) t.Run("When get folder by non existing Title should return not found error", func(t *testing.T) { - dashboardStore.On("FindDashboards", mock.Anything, mock.Anything).Return([]dashboards.DashboardSearchProjection{}, nil).Once() + dashboardStore.On("FindDashboards", mock.Anything, mock.Anything).Return([]dashboards.DashboardSearchProjection{}, nil).Twice() // Called twice due to total count call title := "does not exists" query := &folder.GetFolderQuery{ Title: &title, diff --git a/pkg/services/frontend/frontend_settings.go b/pkg/services/frontend/frontend_settings.go index f6cf9855b2d..d9476c8ff40 100644 --- a/pkg/services/frontend/frontend_settings.go +++ b/pkg/services/frontend/frontend_settings.go @@ -32,6 +32,7 @@ type FSFrontendSettings struct { RudderstackWriteKey string `json:"rudderstackWriteKey,omitempty"` RudderstackDataPlaneUrl string `json:"rudderstackDataPlaneUrl,omitempty"` RudderstackSdkUrl string `json:"rudderstackSdkUrl,omitempty"` + RudderstackV3SdkUrl string `json:"rudderstackV3SdkUrl,omitempty"` RudderstackConfigUrl string `json:"rudderstackConfigUrl,omitempty"` RudderstackIntegrationsUrl string `json:"rudderstackIntegrationsUrl,omitempty"` diff --git a/pkg/services/frontend/index.go b/pkg/services/frontend/index.go index e87ca894d20..25704f1ab6d 100644 --- a/pkg/services/frontend/index.go +++ b/pkg/services/frontend/index.go @@ -94,6 +94,7 @@ func NewIndexProvider(cfg *setting.Cfg, assetsManifest dtos.EntryPointAssets, li RudderstackDataPlaneUrl: cfg.RudderstackDataPlaneURL, RudderstackIntegrationsUrl: cfg.RudderstackIntegrationsURL, RudderstackSdkUrl: cfg.RudderstackSDKURL, + RudderstackV3SdkUrl: cfg.RudderstackV3SDKURL, RudderstackWriteKey: cfg.RudderstackWriteKey, TrustedTypesDefaultPolicyEnabled: (cfg.CSPEnabled && strings.Contains(cfg.CSPTemplate, "require-trusted-types-for")) || (cfg.CSPReportOnlyEnabled && strings.Contains(cfg.CSPReportOnlyTemplate, "require-trusted-types-for")), VerifyEmailEnabled: cfg.VerifyEmailEnabled, diff --git a/pkg/services/live/features/dashboard.go b/pkg/services/live/features/dashboard.go index 537042d2da0..bb51635ef3d 100644 --- a/pkg/services/live/features/dashboard.go +++ b/pkg/services/live/features/dashboard.go @@ -26,9 +26,10 @@ const ( // DashboardEvent events related to dashboards type dashboardEvent struct { - UID string `json:"uid"` - Action actionType `json:"action"` // saved, editing, deleted - SessionID string `json:"sessionId,omitempty"` + UID string `json:"uid"` + Action actionType `json:"action"` // saved, editing, deleted + SessionID string `json:"sessionId,omitempty"` + ResourceVersion string `json:"rv,omitempty"` } // DashboardHandler manages all the `grafana/dashboard/*` channels @@ -105,10 +106,11 @@ func (h *DashboardHandler) publish(orgID int64, event dashboardEvent) error { } // DashboardSaved will broadcast to all connected dashboards -func (h *DashboardHandler) DashboardSaved(orgID int64, uid string) error { +func (h *DashboardHandler) DashboardSaved(orgID int64, uid string, rv string) error { return h.publish(orgID, dashboardEvent{ - UID: uid, - Action: ActionSaved, + UID: uid, + Action: ActionSaved, + ResourceVersion: rv, }) } diff --git a/pkg/services/live/live.go b/pkg/services/live/live.go index 7dbca506e2c..fe1dffba1b8 100644 --- a/pkg/services/live/live.go +++ b/pkg/services/live/live.go @@ -482,7 +482,7 @@ type GrafanaLive struct { // DashboardActivityChannel is a service to advertise dashboard activity type DashboardActivityChannel interface { // Called when a dashboard is saved - DashboardSaved(orgID int64, uid string) error + DashboardSaved(orgID int64, uid string, rv string) error // Called when a dashboard is deleted DashboardDeleted(orgID int64, uid string) error diff --git a/pkg/services/ngalert/accesscontrol.go b/pkg/services/ngalert/accesscontrol.go index 15e3212de03..6754b3c0680 100644 --- a/pkg/services/ngalert/accesscontrol.go +++ b/pkg/services/ngalert/accesscontrol.go @@ -289,12 +289,13 @@ var ( Role: accesscontrol.RoleDTO{ Name: accesscontrol.FixedRolePrefix + "alerting:admin", DisplayName: "Full admin access", - Description: "Full write access in Grafana and all external providers, including their permissions and secrets", + Description: "Full write access in Grafana and all external providers, including their permissions, protected fields and secrets", Group: models.AlertRolesGroup, Permissions: accesscontrol.ConcatPermissions(alertingWriterRole.Role.Permissions, []accesscontrol.Permission{ {Action: accesscontrol.ActionAlertingReceiversPermissionsRead, Scope: models.ScopeReceiversAll}, {Action: accesscontrol.ActionAlertingReceiversPermissionsWrite, Scope: models.ScopeReceiversAll}, {Action: accesscontrol.ActionAlertingReceiversReadSecrets, Scope: models.ScopeReceiversAll}, + {Action: accesscontrol.ActionAlertingReceiversUpdateProtected, Scope: models.ScopeReceiversAll}, }), }, Grants: []string{string(org.RoleAdmin)}, diff --git a/pkg/services/ngalert/accesscontrol/receivers.go b/pkg/services/ngalert/accesscontrol/receivers.go index eb2904854bf..f12a9114912 100644 --- a/pkg/services/ngalert/accesscontrol/receivers.go +++ b/pkg/services/ngalert/accesscontrol/receivers.go @@ -95,6 +95,26 @@ var ( ) } + // Asserts pre-conditions for access to modify protected fields of receivers. If this evaluates to false, the user cannot modify protected fields of any receivers. + updateReceiversProtectedPreConditionsEval = ac.EvalAll( + updateReceiversPreConditionsEval, + ac.EvalPermission(ac.ActionAlertingReceiversUpdateProtected), // Action for receivers. UID scope. + ) + + // Asserts access to modify protected fields of a specific receiver. + updateReceiverProtectedEval = func(uid string) ac.Evaluator { + return ac.EvalAll( + updateReceiverEval(uid), + ac.EvalPermission(ac.ActionAlertingReceiversUpdateProtected, models.ScopeReceiversProvider.GetResourceScopeUID(uid)), + ) + } + + // Asserts access to modify protected fields of all receivers. + updateAllReceiverProtectedEval = ac.EvalAll( + updateAllReceiversEval, + ac.EvalPermission(ac.ActionAlertingReceiversUpdateProtected, models.ScopeReceiversAll), + ) + // Delete // Asserts pre-conditions for delete access to receivers. If this evaluates to false, the user cannot delete any receivers. @@ -141,12 +161,13 @@ var ( ) type ReceiverAccess[T models.Identified] struct { - read actionAccess[T] - readDecrypted actionAccess[T] - create actionAccess[T] - update actionAccess[T] - delete actionAccess[T] - permissions actionAccess[T] + read actionAccess[T] + readDecrypted actionAccess[T] + create actionAccess[T] + update actionAccess[T] + updateProtected actionAccess[T] + delete actionAccess[T] + permissions actionAccess[T] } // NewReceiverAccess creates a new ReceiverAccess service. If includeProvisioningActions is true, the service will include @@ -201,6 +222,18 @@ func NewReceiverAccess[T models.Identified](a ac.AccessControl, includeProvision }, authorizeAll: updateAllReceiversEval, }, + updateProtected: actionAccess[T]{ + genericService: genericService{ + ac: a, + }, + resource: "receiver", + action: "update protected fields of", // this produces message "user is not authorized to update protected fields of X receiver" + authorizeSome: updateReceiversProtectedPreConditionsEval, + authorizeOne: func(receiver models.Identified) ac.Evaluator { + return updateReceiverProtectedEval(receiver.GetUID()) + }, + authorizeAll: updateAllReceiverProtectedEval, + }, delete: actionAccess[T]{ genericService: genericService{ ac: a, @@ -311,6 +344,14 @@ func (s ReceiverAccess[T]) AuthorizeUpdate(ctx context.Context, user identity.Re return s.update.Authorize(ctx, user, receiver) } +func (s ReceiverAccess[T]) HasUpdateProtected(ctx context.Context, user identity.Requester, receiver T) (bool, error) { + return s.updateProtected.Has(ctx, user, receiver) +} + +func (s ReceiverAccess[T]) AuthorizeUpdateProtected(ctx context.Context, user identity.Requester, receiver T) error { + return s.updateProtected.Authorize(ctx, user, receiver) +} + // Global // AuthorizeCreate checks if user has access to create receivers. Returns an error if user does not have access. @@ -380,6 +421,12 @@ func (s ReceiverAccess[T]) Access(ctx context.Context, user identity.Requester, basePerms.Set(models.ReceiverPermissionDelete, true) // Has access to all receivers. } + if err := s.updateProtected.AuthorizePreConditions(ctx, user); err != nil { + basePerms.Set(models.ReceiverPermissionModifyProtected, false) + } else if err := s.updateProtected.AuthorizeAll(ctx, user); err == nil { + basePerms.Set(models.ReceiverPermissionModifyProtected, true) + } + if basePerms.AllSet() { // Shortcut for the case when all permissions are known based on preconditions. result := make(map[string]models.ReceiverPermissionSet, len(receivers)) @@ -412,6 +459,11 @@ func (s ReceiverAccess[T]) Access(ctx context.Context, user identity.Requester, permSet.Set(models.ReceiverPermissionDelete, err == nil) } + if _, ok := permSet.Has(models.ReceiverPermissionModifyProtected); !ok { + err := s.updateProtected.authorize(ctx, user, rcv) + permSet.Set(models.ReceiverPermissionModifyProtected, err == nil) + } + result[rcv.GetUID()] = permSet } return result, nil diff --git a/pkg/services/ngalert/accesscontrol/receivers_test.go b/pkg/services/ngalert/accesscontrol/receivers_test.go index 7be1e9498e2..316fa3a98a6 100644 --- a/pkg/services/ngalert/accesscontrol/receivers_test.go +++ b/pkg/services/ngalert/accesscontrol/receivers_test.go @@ -204,6 +204,33 @@ func TestReceiverAccess(t *testing.T) { recv3.UID: permissions(), }, }, + { + name: "update protected cannot update receivers", + user: newEmptyUser( + ac.Permission{Action: ac.ActionAlertingReceiversRead, Scope: models.ScopeReceiversAll}, + ac.Permission{Action: ac.ActionAlertingReceiversUpdateProtected, Scope: models.ScopeReceiversAll}, + ), + expected: map[string]models.ReceiverPermissionSet{ + recv1.UID: permissions(), + recv2.UID: permissions(), + recv3.UID: permissions(), + }, + }, + { + name: "update protected receivers", + user: newEmptyUser( + ac.Permission{Action: ac.ActionAlertingReceiversRead, Scope: models.ScopeReceiversAll}, + ac.Permission{Action: ac.ActionAlertingReceiversUpdateProtected, Scope: models.ScopeReceiversProvider.GetResourceScopeUID(recv1.UID)}, + ac.Permission{Action: ac.ActionAlertingReceiversUpdate, Scope: models.ScopeReceiversProvider.GetResourceScopeUID(recv1.UID)}, + ac.Permission{Action: ac.ActionAlertingReceiversUpdate, Scope: models.ScopeReceiversProvider.GetResourceScopeUID(recv2.UID)}, + ac.Permission{Action: ac.ActionAlertingReceiversUpdateProtected, Scope: models.ScopeReceiversProvider.GetResourceScopeUID(recv3.UID)}, + ), + expected: map[string]models.ReceiverPermissionSet{ + recv1.UID: permissions(models.ReceiverPermissionWrite, models.ReceiverPermissionModifyProtected), + recv2.UID: permissions(models.ReceiverPermissionWrite), + recv3.UID: permissions(), + }, + }, // Receiver delete. { name: "global receiver delete should have delete but no write", diff --git a/pkg/services/ngalert/api/api_alertmanager.go b/pkg/services/ngalert/api/api_alertmanager.go index 90dcb26fc74..f8b7216bcdb 100644 --- a/pkg/services/ngalert/api/api_alertmanager.go +++ b/pkg/services/ngalert/api/api_alertmanager.go @@ -10,8 +10,10 @@ import ( "time" alertingNotify "github.com/grafana/alerting/notify" + "github.com/grafana/alerting/receivers/schema" "github.com/grafana/grafana/pkg/api/response" + "github.com/grafana/grafana/pkg/apimachinery/errutil" "github.com/grafana/grafana/pkg/apimachinery/identity" "github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/services/accesscontrol" @@ -32,6 +34,7 @@ const ( type receiversAuthz interface { FilterRead(ctx context.Context, user identity.Requester, receivers ...ReceiverStatus) ([]ReceiverStatus, error) + AuthorizeUpdateProtected(context.Context, identity.Requester, ReceiverStatus) error } type AlertmanagerSrv struct { @@ -210,11 +213,16 @@ func (srv AlertmanagerSrv) RouteGetReceivers(c *contextmodel.ReqContext) respons } func (srv AlertmanagerSrv) RoutePostTestReceivers(c *contextmodel.ReqContext, body apimodels.TestReceiversConfigBodyParams) response.Response { - if err := srv.crypto.ProcessSecureSettings(c.Req.Context(), c.GetOrgID(), body.Receivers); err != nil { + if err := srv.crypto.ProcessSecureSettings(c.Req.Context(), c.GetOrgID(), body.Receivers, func(receiverName string, paths []schema.IntegrationFieldPath) error { + return srv.receiverAuthz.AuthorizeUpdateProtected(c.Req.Context(), c.SignedInUser, ReceiverStatus{Name: receiverName}) + }); err != nil { var unknownReceiverError UnknownReceiverError if errors.As(err, &unknownReceiverError) { return ErrResp(http.StatusBadRequest, err, "") } + if errors.As(err, &errutil.Error{}) { + return response.Err(err) + } return ErrResp(http.StatusInternalServerError, err, "failed to post process Alertmanager configuration") } diff --git a/pkg/services/ngalert/api/api_prometheus_test.go b/pkg/services/ngalert/api/api_prometheus_test.go index 71e25d4c963..75ec6c901fd 100644 --- a/pkg/services/ngalert/api/api_prometheus_test.go +++ b/pkg/services/ngalert/api/api_prometheus_test.go @@ -2169,6 +2169,57 @@ func TestRouteGetRuleStatuses(t *testing.T) { }) }) + t.Run("compact mode with receiver_name filter returns only matching rules", func(t *testing.T) { + fakeStore, _, api := setupAPI(t) + + ruleA := gen.With( + gen.WithGroupKey(ngmodels.AlertRuleGroupKey{ + NamespaceUID: "folder-1", + RuleGroup: "group-1", + OrgID: orgID, + }), + gen.WithNotificationSettings( + ngmodels.NotificationSettings{ + Receiver: "receiver-a", + GroupBy: []string{"alertname"}, + }, + ), + ).GenerateRef() + fakeStore.PutRule(context.Background(), ruleA) + + ruleB := gen.With( + gen.WithGroupKey(ngmodels.AlertRuleGroupKey{ + NamespaceUID: "folder-2", + RuleGroup: "group-2", + OrgID: orgID, + }), + gen.WithNotificationSettings( + ngmodels.NotificationSettings{ + Receiver: "receiver-b", + GroupBy: []string{"alertname"}, + }, + ), + ).GenerateRef() + fakeStore.PutRule(context.Background(), ruleB) + r, err := http.NewRequest("GET", "/api/v1/rules?compact=true&receiver_name=receiver-a", nil) + require.NoError(t, err) + c := &contextmodel.ReqContext{ + Context: &web.Context{Req: r}, + SignedInUser: &user.SignedInUser{ + OrgID: orgID, + Permissions: queryPermissions, + }, + } + resp := api.RouteGetRuleStatuses(c) + require.Equal(t, http.StatusOK, resp.Status()) + var res apimodels.RuleResponse + require.NoError(t, json.Unmarshal(resp.Body(), &res)) + + require.Len(t, res.Data.RuleGroups, 1) + require.Equal(t, "group-1", res.Data.RuleGroups[0].Name) + require.Empty(t, res.Data.RuleGroups[0].Rules[0].Query, "Query should be empty in compact mode") + }) + t.Run("provenance as expected", func(t *testing.T) { fakeStore, fakeAIM, api, provStore := setupAPIFull(t) // Rule without provenance diff --git a/pkg/services/ngalert/api/prometheus/api_prometheus.go b/pkg/services/ngalert/api/prometheus/api_prometheus.go index 934805d74f4..b4e14a66cfe 100644 --- a/pkg/services/ngalert/api/prometheus/api_prometheus.go +++ b/pkg/services/ngalert/api/prometheus/api_prometheus.go @@ -357,7 +357,7 @@ func (srv PrometheusSrv) RouteGetRuleStatuses(c *contextmodel.ReqContext) respon type RuleStatusMutator func(source *ngmodels.AlertRule, toMutate *apimodels.AlertingRule) // mutator function used to attach alert states to the rule and returns the totals and filtered totals -type RuleAlertStateMutator func(source *ngmodels.AlertRule, toMutate *apimodels.AlertingRule, stateFilterSet map[eval.State]struct{}, matchers labels.Matchers, labelOptions []ngmodels.LabelOption) (total map[string]int64, filteredTotal map[string]int64) +type RuleAlertStateMutator func(source *ngmodels.AlertRule, toMutate *apimodels.AlertingRule, stateFilterSet map[eval.State]struct{}, matchers labels.Matchers, labelOptions []ngmodels.LabelOption, limitAlerts int64) (total map[string]int64, filteredTotal map[string]int64) func RuleStatusMutatorGenerator(statusReader StatusReader) RuleStatusMutator { return func(source *ngmodels.AlertRule, toMutate *apimodels.AlertingRule) { @@ -377,32 +377,18 @@ func RuleStatusMutatorGenerator(statusReader StatusReader) RuleStatusMutator { } func RuleAlertStateMutatorGenerator(manager state.AlertInstanceManager) RuleAlertStateMutator { - return func(source *ngmodels.AlertRule, toMutate *apimodels.AlertingRule, stateFilterSet map[eval.State]struct{}, matchers labels.Matchers, labelOptions []ngmodels.LabelOption) (map[string]int64, map[string]int64) { + return func(source *ngmodels.AlertRule, toMutate *apimodels.AlertingRule, stateFilterSet map[eval.State]struct{}, matchers labels.Matchers, labelOptions []ngmodels.LabelOption, limitAlerts int64) (map[string]int64, map[string]int64) { states := manager.GetStatesForRuleUID(source.OrgID, source.UID) totals := make(map[string]int64) totalsFiltered := make(map[string]int64) for _, alertState := range states { activeAt := alertState.StartsAt - valString := "" - if alertState.State == eval.Alerting || alertState.State == eval.Pending || alertState.State == eval.Recovering { - valString = FormatValues(alertState) - } stateKey := strings.ToLower(alertState.State.String()) totals[stateKey] += 1 // Do not add error twice when execution error state is Error if alertState.Error != nil && source.ExecErrState != ngmodels.ErrorErrState { totals["error"] += 1 } - alert := apimodels.Alert{ - Labels: apimodels.LabelsFromMap(alertState.GetLabels(labelOptions...)), - Annotations: apimodels.LabelsFromMap(alertState.Annotations), - - // TODO: or should we make this two fields? Using one field lets the - // frontend use the same logic for parsing text on annotations and this. - State: state.FormatStateAndReason(alertState.State, alertState.StateReason), - ActiveAt: &activeAt, - Value: valString, - } // Set the state of the rule based on the state of its alerts. // Only update the rule state with 'pending' or 'recovering' if the current state is 'inactive'. @@ -442,7 +428,23 @@ func RuleAlertStateMutatorGenerator(manager state.AlertInstanceManager) RuleAler totalsFiltered["error"] += 1 } - toMutate.Alerts = append(toMutate.Alerts, alert) + if limitAlerts != 0 { + valString := "" + if alertState.State == eval.Alerting || alertState.State == eval.Pending || alertState.State == eval.Recovering { + valString = FormatValues(alertState) + } + + toMutate.Alerts = append(toMutate.Alerts, apimodels.Alert{ + Labels: apimodels.LabelsFromMap(alertState.GetLabels(labelOptions...)), + Annotations: apimodels.LabelsFromMap(alertState.Annotations), + + // TODO: or should we make this two fields? Using one field lets the + // frontend use the same logic for parsing text on annotations and this. + State: state.FormatStateAndReason(alertState.State, alertState.StateReason), + ActiveAt: &activeAt, + Value: valString, + }) + } } return totals, totalsFiltered } @@ -1227,7 +1229,7 @@ func toRuleGroup(log log.Logger, groupKey ngmodels.AlertRuleGroupKey, folderFull } // mutate rule for alert states - totals, totalsFiltered := ruleAlertStateMutator(rule, &alertingRule, stateFilterSet, matchers, labelOptions) + totals, totalsFiltered := ruleAlertStateMutator(rule, &alertingRule, stateFilterSet, matchers, labelOptions, limitAlerts) if alertingRule.State != "" { rulesTotals[alertingRule.State] += 1 diff --git a/pkg/services/ngalert/api/tooling/definitions/alertmanager_validation.go b/pkg/services/ngalert/api/tooling/definitions/alertmanager_validation.go index c3fce7cb1b4..c0bc3685638 100644 --- a/pkg/services/ngalert/api/tooling/definitions/alertmanager_validation.go +++ b/pkg/services/ngalert/api/tooling/definitions/alertmanager_validation.go @@ -5,7 +5,8 @@ import ( "regexp" "strings" - "github.com/grafana/alerting/templates" + "github.com/grafana/alerting/definition" + "github.com/grafana/alerting/notify" "go.yaml.in/yaml/v3" ) @@ -31,11 +32,18 @@ func (t *NotificationTemplate) Validate() error { content = fmt.Sprintf("{{ define \"%s\" }}\n%s\n{{ end }}", t.Name, content) } t.Template = content - def := templates.TemplateDefinition{ - Name: t.Name, - Template: t.Template, - Kind: templates.GrafanaKind, + if t.Kind == "" { + t.Kind = definition.GrafanaTemplateKind } + postable := definition.PostableApiTemplate{ + Name: t.Name, + Content: t.Template, + Kind: t.Kind, + } + if err := postable.Validate(); err != nil { + return err + } + def := notify.PostableAPITemplateToTemplateDefinition(postable) return def.Validate() } diff --git a/pkg/services/ngalert/api/tooling/definitions/alertmanager_validation_test.go b/pkg/services/ngalert/api/tooling/definitions/alertmanager_validation_test.go index 74f186003d7..2b5139a4960 100644 --- a/pkg/services/ngalert/api/tooling/definitions/alertmanager_validation_test.go +++ b/pkg/services/ngalert/api/tooling/definitions/alertmanager_validation_test.go @@ -462,6 +462,16 @@ func TestValidateNotificationTemplates(t *testing.T) { }, expContent: `{{ define "Alert Instance Template" }}\nFiring: {{ .Labels.alertname }}\nSilence: {{ .SilenceURL }}\n{{ end }}[what is this?]`, }, + { + name: "unknown template kind", + template: NotificationTemplate{ + Name: "Alert Instance Template", + Template: `{{ define "Same name as definition" }}\nFiring: {{ .Labels.alertname }}\nSilence: {{ .SilenceURL }}\n{{ end }}`, + Provenance: "test", + Kind: "unknown", + }, + expError: errors.New("unknown template kind: unknown"), + }, } for _, tt := range tc { diff --git a/pkg/services/ngalert/api/tooling/definitions/provisioning_templates.go b/pkg/services/ngalert/api/tooling/definitions/provisioning_templates.go index 1633a903822..3c64573a812 100644 --- a/pkg/services/ngalert/api/tooling/definitions/provisioning_templates.go +++ b/pkg/services/ngalert/api/tooling/definitions/provisioning_templates.go @@ -1,5 +1,7 @@ package definitions +import "github.com/grafana/alerting/definition" + // swagger:route GET /v1/provisioning/templates provisioning stable RouteGetTemplates // // Get all notification template groups. @@ -55,11 +57,12 @@ type RouteDeleteTemplateParam struct { // swagger:model type NotificationTemplate struct { - UID string `json:"-" yaml:"-"` - Name string `json:"name"` - Template string `json:"template"` - Provenance Provenance `json:"provenance,omitempty"` - ResourceVersion string `json:"version,omitempty"` + UID string `json:"-" yaml:"-"` + Name string `json:"name"` + Template string `json:"template"` + Provenance Provenance `json:"provenance,omitempty"` + ResourceVersion string `json:"version,omitempty"` + Kind definition.TemplateKind `json:"-" yaml:"-"` } // swagger:model diff --git a/pkg/services/ngalert/models/permissions.go b/pkg/services/ngalert/models/permissions.go index a34e184fc99..ce52755eac8 100644 --- a/pkg/services/ngalert/models/permissions.go +++ b/pkg/services/ngalert/models/permissions.go @@ -9,10 +9,11 @@ import ( type ReceiverPermission string const ( - ReceiverPermissionReadSecret ReceiverPermission = "secrets" - ReceiverPermissionAdmin ReceiverPermission = "admin" - ReceiverPermissionWrite ReceiverPermission = "write" - ReceiverPermissionDelete ReceiverPermission = "delete" + ReceiverPermissionReadSecret ReceiverPermission = "secrets" + ReceiverPermissionAdmin ReceiverPermission = "admin" + ReceiverPermissionWrite ReceiverPermission = "write" + ReceiverPermissionDelete ReceiverPermission = "delete" + ReceiverPermissionModifyProtected ReceiverPermission = "modify-protected" ) // ReceiverPermissions returns all possible silence permissions. @@ -22,6 +23,7 @@ func ReceiverPermissions() []ReceiverPermission { ReceiverPermissionAdmin, ReceiverPermissionWrite, ReceiverPermissionDelete, + ReceiverPermissionModifyProtected, } } diff --git a/pkg/services/ngalert/models/receivers_diff.go b/pkg/services/ngalert/models/receivers_diff.go new file mode 100644 index 00000000000..bfe9328542f --- /dev/null +++ b/pkg/services/ngalert/models/receivers_diff.go @@ -0,0 +1,230 @@ +package models + +import ( + "fmt" + "reflect" + "strings" + + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + "github.com/grafana/alerting/receivers/schema" + + "github.com/grafana/grafana/pkg/util/cmputil" +) + +type IntegrationDiffReport struct { + cmputil.DiffReport +} + +// expandPaths recursively collects all sub-paths for keys in the provided map value +func (r IntegrationDiffReport) expandPaths(basePath schema.IntegrationFieldPath, mapVal reflect.Value) []schema.IntegrationFieldPath { + result := make([]schema.IntegrationFieldPath, 0) + iter := mapVal.MapRange() + for iter.Next() { + keyStr := fmt.Sprintf("%v", iter.Key()) // Assume string keys + p := basePath.With(keyStr) + // Recurse if the sub-value is another map + if m, ok := r.getMap(iter.Value()); ok { + result = append(result, r.expandPaths(p, m)...) + continue + } + result = append(result, p) + } + return result +} + +func (r IntegrationDiffReport) getMap(v reflect.Value) (reflect.Value, bool) { + if v.Kind() == reflect.Map { + return v, true + } + if v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface { + return r.getMap(v.Elem()) + } + return reflect.Value{}, false +} + +func (r IntegrationDiffReport) needExpand(diff cmputil.Diff) (reflect.Value, bool) { + ml, lok := r.getMap(diff.Left) + mr, rok := r.getMap(diff.Right) + if lok == rok { + return reflect.Value{}, false + } + if lok { + return ml, true + } + return mr, true +} + +func (r IntegrationDiffReport) GetSettingsPaths() []schema.IntegrationFieldPath { + diffs := r.GetDiffsForField("Settings") + paths := make([]schema.IntegrationFieldPath, 0, len(diffs)) + for _, diff := range diffs { + // diff.Path has format like Settings[url] or Settings[sub-form][field] + p := diff.Path + var path schema.IntegrationFieldPath + for { + start := strings.Index(p, "[") + if start == -1 { + break + } + p = p[start+1:] + end := strings.Index(p, "]") + if end == -1 { + break + } + fieldName := p[:end] + p = p[end+1:] + path = append(path, fieldName) + } + if m, ok := r.needExpand(diff); ok { + paths = append(paths, r.expandPaths(path, m)...) + continue + } + if len(path) > 0 { + paths = append(paths, path) + } + } + return paths +} + +func (r IntegrationDiffReport) GetSecureSettingsPaths() []schema.IntegrationFieldPath { + diffs := r.GetDiffsForField("SecureSettings") + paths := make([]schema.IntegrationFieldPath, 0, len(diffs)) + for _, diff := range diffs { + if diff.Path == "SecureSettings" { + if m, ok := r.needExpand(diff); ok { + paths = append(paths, r.expandPaths(nil, m)...) + } + continue + } + // diff.Path has format like SecureSettings[field.sub-field.sub] + p := schema.ParseIntegrationPath(diff.Path[len("SecureSettings[") : len(diff.Path)-1]) + paths = append(paths, p) + } + return paths +} + +func (integration *Integration) Diff(incoming Integration) IntegrationDiffReport { + var reporter cmputil.DiffReporter + var settingsCmp = cmpopts.AcyclicTransformer("settingsMap", func(in map[string]any) map[string]any { + if in == nil { + return map[string]any{} + } + return in + }) + var secureCmp = cmpopts.AcyclicTransformer("secureMap", func(in map[string]string) map[string]string { + if in == nil { + return map[string]string{} + } + return in + }) + schemaCmp := cmp.Comparer(func(a, b schema.IntegrationSchemaVersion) bool { + isAZero := reflect.ValueOf(a).IsZero() + isBZero := reflect.ValueOf(b).IsZero() + if isAZero && isBZero { + return true + } + if isAZero || isBZero { + return false + } + return a.Type() == b.Type() && a.Version == b.Version + }) + var cur Integration + if integration != nil { + cur = *integration + } + cmp.Equal(cur, incoming, cmp.Reporter(&reporter), settingsCmp, secureCmp, schemaCmp) + return IntegrationDiffReport{DiffReport: reporter.Diffs} +} + +// HasReceiversDifferentProtectedFields returns true if the receiver has any protected fields that are different from the incoming receiver. +func HasReceiversDifferentProtectedFields(existing, incoming *Receiver) map[string][]schema.IntegrationFieldPath { + existingIntegrations := make(map[string]*Integration, len(existing.Integrations)) + for _, integration := range existing.Integrations { + existingIntegrations[integration.UID] = integration + } + + var result = make(map[string][]schema.IntegrationFieldPath) + for _, in := range incoming.Integrations { + if in.UID == "" { + continue + } + ex, ok := existingIntegrations[in.UID] + if !ok { + continue + } + paths := HasIntegrationsDifferentProtectedFields(ex, in) + if len(paths) > 0 { + result[in.UID] = paths + } + } + return result +} + +// HasIntegrationsDifferentProtectedFields returns list of paths to protected fields that are different between two integrations. +func HasIntegrationsDifferentProtectedFields(existing, incoming *Integration) []schema.IntegrationFieldPath { + diff := existing.Diff(*incoming) + // The incoming receiver always has both secret and non-secret fields in Settings. + // So, if it's specified and happens to be sensitive, we consider it changed + var result []schema.IntegrationFieldPath + settingsDiff := diff.GetSettingsPaths() + for _, path := range settingsDiff { + if IsProtectedField(incoming.Config.Type(), path) { + result = append(result, path) + } + } + return result +} + +// IsProtectedField returns true if the field at the given path is existing protected one. +// This includes: +// 1. URL fields marked as secure in the schema (e.g., webhook URLs with credentials) +// 2. URL fields NOT marked as secure but could contain credentials (e.g., API endpoints) +func IsProtectedField(integrationType schema.IntegrationType, path schema.IntegrationFieldPath) bool { + str := strings.ToLower(string(integrationType)) + pathStr := path.String() + + switch str { + case "prometheus-alertmanager": + return pathStr == "url" + case "dingding": + return pathStr == "url" // marked as secure + case "discord": + return pathStr == "url" // marked as secure (webhook URL) + case "googlechat": + return pathStr == "url" // marked as secure + case "jira": + return pathStr == "api_url" + case "kafka": + return pathStr == "kafkaRestProxy" + case "line": + return false + case "mqtt": + return pathStr == "brokerUrl" + case "oncall": + return pathStr == "url" + case "opsgenie": + return pathStr == "apiUrl" + case "pagerduty": + return pathStr == "url" + case "sensugo": + return pathStr == "url" + case "slack": + return pathStr == "url" || pathStr == "endpointUrl" + case "teams": + return pathStr == "url" + case "victorops": + return pathStr == "url" // marked as secure + case "webex": + return pathStr == "api_url" + case "webhook": + return pathStr == "url" || + pathStr == "http_config.oauth2.token_url" || + pathStr == "http_config.oauth2.proxy_config.proxy_url" + case "wecom": + return pathStr == "url" || // marked as secure + pathStr == "endpointUrl" + default: + return false + } +} diff --git a/pkg/services/ngalert/models/receivers_diff_test.go b/pkg/services/ngalert/models/receivers_diff_test.go new file mode 100644 index 00000000000..dffeaee1dc2 --- /dev/null +++ b/pkg/services/ngalert/models/receivers_diff_test.go @@ -0,0 +1,262 @@ +package models + +import ( + "slices" + "testing" + + alertingNotify "github.com/grafana/alerting/notify" + "github.com/grafana/alerting/receivers/schema" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestIntegrationDiff(t *testing.T) { + s, _ := alertingNotify.GetSchemaVersionForIntegration("webhook", schema.V1) + a := Integration{ + UID: "test-uid", + Name: "test-name", + Config: s, + DisableResolveMessage: false, + Settings: map[string]any{ + "url": "http://localhost", + "name": 123, + "flag": true, + "child": map[string]any{ + "sub-form-field": "test", + }, + }, + SecureSettings: map[string]string{ + "password": "12345", + "token": "token-12345", + }, + } + + t.Run("no diff if equal", func(t *testing.T) { + result := a.Diff(a) + assert.Empty(t, result) + }) + + t.Run("should deep compare settings", func(t *testing.T) { + b := a + b.Settings = map[string]any{ + "url": "http://localhost:123", + "flag": false, + "child": map[string]any{ + "sub-form-field": "test123", + "sub-child": map[string]any{ + "test": "test", + }, + }, + } + + result := a.Diff(b) + assert.ElementsMatch(t, + []string{"Settings[url]", "Settings[name]", "Settings[flag]", "Settings[child][sub-form-field]", "Settings[child][sub-child]"}, + result.Paths()) + }) + + t.Run("should shallow compare schemas", func(t *testing.T) { + b := a + b.Config, _ = alertingNotify.GetSchemaVersionForIntegration("slack", schema.V1) + result := a.Diff(b) + assert.ElementsMatch(t, + []string{"Config"}, + result.Paths()) + }) + + t.Run("should compare with zero objects", func(t *testing.T) { + result := a.Diff(Integration{}) + assert.ElementsMatch(t, + []string{ + "UID", + "Name", + "Config", + "Settings[child]", + "Settings[flag]", + "Settings[name]", + "Settings[url]", + "SecureSettings[password]", + "SecureSettings[token]", + }, + result.Paths()) + }) +} + +func TestIntegrationDiffReport_GetSettingsPaths(t *testing.T) { + a := Integration{ + UID: "test-uid", + Name: "test-name", + Config: schema.IntegrationSchemaVersion{}, + DisableResolveMessage: false, + Settings: map[string]any{ + "url": "http://localhost", + "child": map[string]any{ + "field": "test", + "sub-child": map[string]any{ + "test": "test", + }, + }, + }, + } + + testCases := []struct { + name string + left map[string]any + right map[string]any + paths []string + }{ + { + name: "empty", + left: map[string]any{}, + right: map[string]any{}, + }, + { + name: "left is empty", + left: map[string]any{}, + right: map[string]any{ + "field": "test", + }, + paths: []string{"field"}, + }, + { + name: "right is empty", + left: map[string]any{ + "field": "test", + }, + right: map[string]any{}, + paths: []string{"field"}, + }, + { + name: "expands nested", + left: map[string]any{ + "field": map[string]any{ + "sub-field": map[string]any{ + "test": "test", + }, + }, + }, + right: map[string]any{ + "another": map[string]any{ + "sub-field": map[string]any{ + "test": "test", + }, + }, + }, + paths: []string{ + "field.sub-field.test", + "another.sub-field.test", + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + b := a + b.Settings = tc.right + a.Settings = tc.left + diff := a.Diff(b) + + actual := diff.GetSettingsPaths() + actualStrings := make([]string, 0, len(actual)) + for _, f := range actual { + actualStrings = append(actualStrings, f.String()) + } + assert.ElementsMatch(t, tc.paths, actualStrings) + }) + } +} + +func TestHasDifferentProtectedFields(t *testing.T) { + m := IntegrationMuts + + testCase := []struct { + name string + existing Integration + incoming Integration + expected map[string][]string + }{ + { + name: "different UID do not match", + existing: IntegrationGen(m.WithUID("existing"), m.WithValidConfig("webhook"))(), + incoming: IntegrationGen( + m.WithValidConfig("webhook"), + m.AddSetting("url", "http://some-other-url"), + m.WithUID("incoming"), + )(), + expected: nil, + }, + { + name: "find url protected", + existing: IntegrationGen(m.WithUID("1"), m.WithValidConfig("webhook"))(), + incoming: IntegrationGen( + m.WithValidConfig("webhook"), + m.AddSetting("url", "http://some-other-url"), + m.AddSetting("http_config", map[string]any{ + "oauth2": map[string]any{ + "proxy_config": map[string]any{ + "proxy_url": "http://some-other-url-proxy", + }, + "token_url": "http://some-other-url-token", + }, + }), + m.WithUID("1"), + )(), + expected: map[string][]string{ + "1": { + "http_config.oauth2.proxy_config.proxy_url", + "http_config.oauth2.token_url", + "url", + }, + }, + }, + { + name: "secure and protected", // simulate the situation when protected secured field is in secure settings but the incoming one has it in settings + existing: IntegrationGen( + m.WithUID("1"), + m.WithValidConfig("discord"), + m.RemoveSetting("url"), + m.WithSecureSettings(map[string]string{ + "url": "", + }))(), + incoming: IntegrationGen( + m.WithValidConfig("discord"), + m.AddSetting("url", "http://some-other-url"), + m.WithSecureSettings(nil), + m.WithUID("1"), + )(), + expected: map[string][]string{ + "1": { + "url", + }, + }, + }, + } + + for _, tc := range testCase { + t.Run(tc.name, func(t *testing.T) { + existing := &Receiver{ + Integrations: []*Integration{ + &tc.existing, + }, + } + incoming := &Receiver{ + Integrations: []*Integration{ + &tc.incoming, + }, + } + actual := HasReceiversDifferentProtectedFields(existing, incoming) + if len(tc.expected) == 0 { + require.Empty(t, actual) + return + } + actualStrings := make(map[string][]string, len(actual)) + for uid, paths := range actual { + for _, path := range paths { + actualStrings[uid] = append(actualStrings[uid], path.String()) + } + slices.Sort(actualStrings[uid]) + } + assert.EqualValues(t, tc.expected, actualStrings) + }) + } +} diff --git a/pkg/services/ngalert/models/testing.go b/pkg/services/ngalert/models/testing.go index 886f13d029a..8180afb0012 100644 --- a/pkg/services/ngalert/models/testing.go +++ b/pkg/services/ngalert/models/testing.go @@ -973,6 +973,12 @@ func (a AlertInstanceMutators) WithAnnotations(annotations InstanceAnnotations) } } +func (a AlertInstanceMutators) WithResultFingerprint(fp string) AlertInstanceMutator { + return func(i *AlertInstance) { + i.ResultFingerprint = fp + } +} + type Mutator[T any] func(*T) // CopyNotificationSettings creates a deep copy of NotificationSettings. @@ -1451,6 +1457,12 @@ func (n IntegrationMutators) AddSecureSetting(key, val string) Mutator[Integrati } } +func (n IntegrationMutators) RemoveSetting(key string) Mutator[Integration] { + return func(c *Integration) { + delete(c.Settings, key) + } +} + func randomMapKey[K comparable, V any](m map[K]V) (K, V) { randIdx := rand.Intn(len(m)) i := 0 diff --git a/pkg/services/ngalert/notifier/alertmanager_config.go b/pkg/services/ngalert/notifier/alertmanager_config.go index 87d573124e7..7e755903791 100644 --- a/pkg/services/ngalert/notifier/alertmanager_config.go +++ b/pkg/services/ngalert/notifier/alertmanager_config.go @@ -333,7 +333,7 @@ func (moa *MultiOrgAlertmanager) SaveAndApplyAlertmanagerConfiguration(ctx conte config.ExtraConfigs = extraConfigs } - if err := moa.Crypto.ProcessSecureSettings(ctx, org, config.AlertmanagerConfig.Receivers); err != nil { + if err := moa.Crypto.ProcessSecureSettings(ctx, org, config.AlertmanagerConfig.Receivers, nil); err != nil { return fmt.Errorf("failed to post process Alertmanager configuration: %w", err) } diff --git a/pkg/services/ngalert/notifier/crypto.go b/pkg/services/ngalert/notifier/crypto.go index ab5d5f03096..246cd03d64d 100644 --- a/pkg/services/ngalert/notifier/crypto.go +++ b/pkg/services/ngalert/notifier/crypto.go @@ -29,16 +29,18 @@ const ( cryptoPrefix = "crypto_" ) +type AuthorizeProtectedFn func(uid string, paths []schema.IntegrationFieldPath) error + // Crypto allows decryption of Alertmanager Configuration and encryption of arbitrary payloads. type Crypto interface { - LoadSecureSettings(ctx context.Context, orgId int64, receivers []*definitions.PostableApiReceiver) error + LoadSecureSettings(ctx context.Context, orgId int64, receivers []*definitions.PostableApiReceiver, fn AuthorizeProtectedFn) error Encrypt(ctx context.Context, payload []byte, opt secrets.EncryptionOptions) ([]byte, error) Decrypt(ctx context.Context, payload []byte) ([]byte, error) EncryptExtraConfigs(ctx context.Context, config *definitions.PostableUserConfig) error DecryptExtraConfigs(ctx context.Context, config *definitions.PostableUserConfig) error getDecryptedSecret(r *definitions.PostableGrafanaReceiver, key string) (string, error) - ProcessSecureSettings(ctx context.Context, orgId int64, recvs []*definitions.PostableApiReceiver) error + ProcessSecureSettings(ctx context.Context, orgId int64, recvs []*definitions.PostableApiReceiver, fn AuthorizeProtectedFn) error } // alertmanagerCrypto implements decryption of Alertmanager configuration and encryption of arbitrary payloads based on Grafana's encryptions. @@ -57,7 +59,7 @@ func NewCrypto(secrets secrets.Service, configs configurationStore, log log.Logg } // ProcessSecureSettings encrypts new secure settings and loads existing secure settings from the database. -func (c *alertmanagerCrypto) ProcessSecureSettings(ctx context.Context, orgId int64, recvs []*definitions.PostableApiReceiver) error { +func (c *alertmanagerCrypto) ProcessSecureSettings(ctx context.Context, orgId int64, recvs []*definitions.PostableApiReceiver, authorizeProtected AuthorizeProtectedFn) error { // First, we encrypt the new or updated secure settings. Then, we load the existing secure settings from the database // and add back any that weren't updated. // We perform these steps in this order to ensure the hash of the secure settings remains stable when no secure @@ -68,7 +70,7 @@ func (c *alertmanagerCrypto) ProcessSecureSettings(ctx context.Context, orgId in return fmt.Errorf("failed to encrypt receivers: %w", err) } - if err := c.LoadSecureSettings(ctx, orgId, recvs); err != nil { + if err := c.LoadSecureSettings(ctx, orgId, recvs, authorizeProtected); err != nil { return err } @@ -167,7 +169,7 @@ func encryptReceiverConfigs(c []*definitions.PostableApiReceiver, encrypt defini } // LoadSecureSettings adds the corresponding unencrypted secrets stored to the list of input receivers. -func (c *alertmanagerCrypto) LoadSecureSettings(ctx context.Context, orgId int64, receivers []*definitions.PostableApiReceiver) error { +func (c *alertmanagerCrypto) LoadSecureSettings(ctx context.Context, orgId int64, receivers []*definitions.PostableApiReceiver, authorizeProtected AuthorizeProtectedFn) error { // Get the last known working configuration. amConfig, err := c.configs.GetLatestAlertmanagerConfiguration(ctx, orgId) if err != nil { @@ -176,10 +178,10 @@ func (c *alertmanagerCrypto) LoadSecureSettings(ctx context.Context, orgId int64 return fmt.Errorf("failed to get latest configuration: %w", err) } } - + var currentConfig *definitions.PostableUserConfig currentReceiverMap := make(map[string]*definitions.PostableGrafanaReceiver) if amConfig != nil { - currentConfig, err := Load([]byte(amConfig.AlertmanagerConfiguration)) + currentConfig, err = Load([]byte(amConfig.AlertmanagerConfiguration)) // If the current config is un-loadable, treat it as if it never existed. Providing a new, valid config should be able to "fix" this state. if err != nil { c.log.Warn("Last known alertmanager configuration was invalid. Overwriting...") @@ -209,6 +211,33 @@ func (c *alertmanagerCrypto) LoadSecureSettings(ctx context.Context, orgId int64 return UnknownReceiverError{UID: gr.UID} } + if authorizeProtected != nil { + incoming, errIn := legacy_storage.PostableGrafanaReceiverToIntegration(gr) + existing, errEx := legacy_storage.PostableGrafanaReceiverToIntegration(cgmr) + var secure []schema.IntegrationFieldPath + authz := true + if errIn == nil && errEx == nil { + secure = models.HasIntegrationsDifferentProtectedFields(existing, incoming) + authz = len(secure) > 0 + } + // if conversion failed, consider there are changes and authorize + if authz && currentConfig != nil { + var receiverName string + NAME: + for _, rcv := range currentConfig.AlertmanagerConfig.Receivers { + for _, intg := range rcv.GrafanaManagedReceivers { + if intg.UID == cgmr.UID { + receiverName = rcv.Name + break NAME + } + } + } + if err := authorizeProtected(receiverName, secure); err != nil { + return err + } + } + } + // Frontend sends only the secure settings that have to be updated // Therefore we have to copy from the last configuration only those secure settings not included in the request for key, encryptedValue := range cgmr.SecureSettings { diff --git a/pkg/services/ngalert/notifier/receiver_svc.go b/pkg/services/ngalert/notifier/receiver_svc.go index 56a68fb3e55..e05b12a2920 100644 --- a/pkg/services/ngalert/notifier/receiver_svc.go +++ b/pkg/services/ngalert/notifier/receiver_svc.go @@ -80,6 +80,9 @@ type receiverAccessControlService interface { AuthorizeUpdate(context.Context, identity.Requester, *models.Receiver) error AuthorizeDeleteByUID(context.Context, identity.Requester, string) error + HasUpdateProtected(context.Context, identity.Requester, *models.Receiver) (bool, error) + AuthorizeUpdateProtected(context.Context, identity.Requester, *models.Receiver) error + Access(ctx context.Context, user identity.Requester, receivers ...*models.Receiver) (map[string]models.ReceiverPermissionSet, error) } @@ -474,6 +477,18 @@ func (rs *ReceiverService) UpdateReceiver(ctx context.Context, r *models.Receive return nil, err } + // if user does not have permissions to update protected, check the diff and return error if there is a change in protected fields + canUpdateProtected, _ := rs.authz.HasUpdateProtected(ctx, user, r) + if !canUpdateProtected { + diff := models.HasReceiversDifferentProtectedFields(existing, r) + if len(diff) > 0 { + err = rs.authz.AuthorizeUpdateProtected(ctx, user, r) + if err != nil { + return nil, makeProtectedFieldsAuthzError(err, diff) + } + } + } + // We need to perform two important steps to process settings on an updated integration: // 1. Encrypt new or updated secret fields as they will arrive in plain text. // 2. For updates, callers do not re-send unchanged secure settings and instead mark them in SecureFields. We need diff --git a/pkg/services/ngalert/notifier/receiver_svc_err.go b/pkg/services/ngalert/notifier/receiver_svc_err.go new file mode 100644 index 00000000000..06b27602f75 --- /dev/null +++ b/pkg/services/ngalert/notifier/receiver_svc_err.go @@ -0,0 +1,30 @@ +package notifier + +import ( + "errors" + "slices" + + "github.com/grafana/alerting/receivers/schema" + + "github.com/grafana/grafana/pkg/apimachinery/errutil" +) + +func makeProtectedFieldsAuthzError(err error, diff map[string][]schema.IntegrationFieldPath) error { + var authzErr errutil.Error + if !errors.As(err, &authzErr) { + return err + } + if authzErr.PublicPayload == nil { + authzErr.PublicPayload = map[string]interface{}{} + } + fields := make(map[string][]string, len(diff)) + for field, paths := range diff { + fields[field] = make([]string, len(paths)) + for i, path := range paths { + fields[field][i] = path.String() + } + slices.Sort(fields[field]) + } + authzErr.PublicPayload["changed_protected_fields"] = fields + return authzErr +} diff --git a/pkg/services/ngalert/notifier/receiver_svc_test.go b/pkg/services/ngalert/notifier/receiver_svc_test.go index 8d4b7630436..10e84f33b62 100644 --- a/pkg/services/ngalert/notifier/receiver_svc_test.go +++ b/pkg/services/ngalert/notifier/receiver_svc_test.go @@ -659,8 +659,9 @@ func TestReceiverService_Update(t *testing.T) { writer := &user.SignedInUser{OrgID: 1, Permissions: map[int64]map[string][]string{ 1: { - accesscontrol.ActionAlertingNotificationsWrite: nil, - accesscontrol.ActionAlertingNotificationsRead: nil, + accesscontrol.ActionAlertingNotificationsWrite: nil, + accesscontrol.ActionAlertingNotificationsRead: nil, + accesscontrol.ActionAlertingReceiversUpdateProtected: {models.ScopeReceiversAll}, }, }} decryptUser := &user.SignedInUser{OrgID: 1, Permissions: map[int64]map[string][]string{ @@ -1310,7 +1311,7 @@ func TestReceiverServiceAC_Update(t *testing.T) { }, }} - slackIntegration := models.IntegrationGen(models.IntegrationMuts.WithName("test receiver"), models.IntegrationMuts.WithValidConfig("slack")) + slackIntegration := models.IntegrationGen(models.IntegrationMuts.WithName("test receiver"), models.IntegrationMuts.WithValidConfig("webhook")) emailIntegration := models.IntegrationGen(models.IntegrationMuts.WithName("test receiver"), models.IntegrationMuts.WithValidConfig("email")) recv1 := models.ReceiverGen(models.ReceiverMuts.WithName("receiver1"), models.ReceiverMuts.WithIntegrations(slackIntegration(), emailIntegration()))() recv2 := models.ReceiverGen(models.ReceiverMuts.WithName("receiver2"), models.ReceiverMuts.WithIntegrations(slackIntegration(), emailIntegration()))() @@ -1322,8 +1323,8 @@ func TestReceiverServiceAC_Update(t *testing.T) { name string permissions map[string][]string existing []models.Receiver - - hasAccess []models.Receiver + incoming []models.Receiver + hasAccess []models.Receiver }{ { name: "not authorized without permissions", @@ -1411,6 +1412,43 @@ func TestReceiverServiceAC_Update(t *testing.T) { existing: allReceivers(), hasAccess: []models.Receiver{recv1, recv3}, }, + { + name: "protected fields modified without permission", + permissions: map[string][]string{ + accesscontrol.ActionAlertingReceiversUpdate: {models.ScopeReceiversAll}, + accesscontrol.ActionAlertingReceiversRead: {models.ScopeReceiversAll}, + }, + existing: []models.Receiver{ + recv1, + }, + incoming: []models.Receiver{ + func() models.Receiver { + f := recv1.Clone() + f.Integrations[0].Settings["url"] = "https://example.com/new" + return f + }(), + }, + hasAccess: nil, + }, + { + name: "protected fields modified with permission", + permissions: map[string][]string{ + accesscontrol.ActionAlertingReceiversUpdate: {models.ScopeReceiversAll}, + accesscontrol.ActionAlertingReceiversRead: {models.ScopeReceiversAll}, + accesscontrol.ActionAlertingReceiversUpdateProtected: {models.ScopeReceiversAll}, + }, + existing: []models.Receiver{ + recv1, + }, + incoming: []models.Receiver{ + func() models.Receiver { + f := recv1.Clone() + f.Integrations[0].Settings["url"] = "https://example.com/new" + return f + }(), + }, + hasAccess: []models.Receiver{recv1}, + }, } for _, tc := range testCases { @@ -1436,7 +1474,11 @@ func TestReceiverServiceAC_Update(t *testing.T) { } return false } - for _, recv := range allReceivers() { + incoming := allReceivers() + if tc.incoming != nil { + incoming = tc.incoming + } + for _, recv := range incoming { clone := recv.Clone() clone.Version = versions[recv.UID] response, err := sut.UpdateReceiver(context.Background(), &clone, nil, orgId, usr) @@ -1734,6 +1776,7 @@ func TestReceiverService_AccessControlMetadata(t *testing.T) { expectedPermissions.Set(models.ReceiverPermissionAdmin, false) expectedPermissions.Set(models.ReceiverPermissionWrite, false) expectedPermissions.Set(models.ReceiverPermissionDelete, false) + expectedPermissions.Set(models.ReceiverPermissionModifyProtected, false) expectedPermissions.Set(models.ReceiverPermissionReadSecret, true) expected := map[string]models.ReceiverPermissionSet{ diff --git a/pkg/services/ngalert/provisioning/errors.go b/pkg/services/ngalert/provisioning/errors.go index 407f45efed6..df3683751b3 100644 --- a/pkg/services/ngalert/provisioning/errors.go +++ b/pkg/services/ngalert/provisioning/errors.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/grafana/grafana/pkg/apimachinery/errutil" + "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions" "github.com/grafana/grafana/pkg/services/ngalert/models" ) @@ -25,6 +26,10 @@ var ( ErrTemplateNotFound = errutil.NotFound("alerting.notifications.templates.notFound") ErrTemplateInvalid = errutil.BadRequest("alerting.notifications.templates.invalidFormat").MustTemplate("Invalid format of the submitted template", errutil.WithPublic("Template is in invalid format. Correct the payload and try again.")) ErrTemplateExists = errutil.BadRequest("alerting.notifications.templates.nameExists", errutil.WithPublicMessage("Template file with this name already exists. Use a different name or update existing one.")) + ErrTemplateOrigin = errutil.BadRequest("alerting.notifications.templates.originInvalid").MustTemplate( + "Template '{{ .Public.Name }}' cannot be {{ .Public.Action }}d because it belongs to an imported configuration.", + errutil.WithPublic("Template '{{ .Public.Name }}' cannot be {{ .Public.Action }}d because it belongs to an imported configuration. Finish the import of the configuration first."), + ) ErrContactPointReferenced = errutil.Conflict("alerting.notifications.contact-points.referenced", errutil.WithPublicMessage("Contact point is currently referenced by a notification policy.")) ErrContactPointUsedInRule = errutil.Conflict("alerting.notifications.contact-points.used-by-rule", errutil.WithPublicMessage("Contact point is currently used in the notification settings of one or many alert rules.")) @@ -129,3 +134,7 @@ func MakeErrContactPointUidExists(uid, name string) error { }, }) } + +func makeErrTemplateOrigin(t definitions.NotificationTemplate, action string) error { + return ErrTemplateOrigin.Build(errutil.TemplateData{Public: map[string]interface{}{"Action": action, "Name": t.Name}}) +} diff --git a/pkg/services/ngalert/provisioning/templates.go b/pkg/services/ngalert/provisioning/templates.go index 9d4db1ed140..65cecfb506b 100644 --- a/pkg/services/ngalert/provisioning/templates.go +++ b/pkg/services/ngalert/provisioning/templates.go @@ -10,6 +10,8 @@ import ( "sort" "unsafe" + "github.com/grafana/alerting/definition" + "github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions" "github.com/grafana/grafana/pkg/services/ngalert/models" @@ -23,6 +25,7 @@ type TemplateService struct { xact TransactionManager log log.Logger validator validation.ProvenanceStatusTransitionValidator + includeImported bool } func NewTemplateService(config alertmanagerConfigStore, prov ProvisioningStore, xact TransactionManager, log log.Logger) *TemplateService { @@ -32,6 +35,18 @@ func NewTemplateService(config alertmanagerConfigStore, prov ProvisioningStore, xact: xact, validator: validation.ValidateProvenanceRelaxed, log: log, + includeImported: false, + } +} + +func (t *TemplateService) WithIncludeImported() *TemplateService { + return &TemplateService{ + configStore: t.configStore, + provenanceStore: t.provenanceStore, + xact: t.xact, + validator: t.validator, + log: t.log, + includeImported: true, } } @@ -41,35 +56,38 @@ func (t *TemplateService) GetTemplates(ctx context.Context, orgID int64) ([]defi return nil, err } - if len(revision.Config.TemplateFiles) == 0 { - return nil, nil - } + var templates []definitions.NotificationTemplate - provenances, err := t.provenanceStore.GetProvenances(ctx, orgID, (&definitions.NotificationTemplate{}).ResourceType()) - if err != nil { - return nil, err - } - - templates := make([]definitions.NotificationTemplate, 0, len(revision.Config.TemplateFiles)) - names := slices.Collect(maps.Keys(revision.Config.TemplateFiles)) - sort.Strings(names) - for _, name := range names { - content := revision.Config.TemplateFiles[name] - tmpl := definitions.NotificationTemplate{ - UID: legacy_storage.NameToUid(name), - Name: name, - Template: content, - ResourceVersion: calculateTemplateFingerprint(content), + if len(revision.Config.TemplateFiles) > 0 { + provenances, err := t.provenanceStore.GetProvenances(ctx, orgID, (&definitions.NotificationTemplate{}).ResourceType()) + if err != nil { + return nil, err } - provenance, ok := provenances[tmpl.ResourceID()] - if !ok { - provenance = models.ProvenanceNone + templates = make([]definitions.NotificationTemplate, 0, len(revision.Config.TemplateFiles)) + names := slices.Collect(maps.Keys(revision.Config.TemplateFiles)) + sort.Strings(names) + for _, name := range names { + content := revision.Config.TemplateFiles[name] + provenance, ok := provenances[(&definitions.NotificationTemplate{Name: name}).ResourceID()] + if !ok { + provenance = models.ProvenanceNone + } + templates = append(templates, newNotificationTemplate(name, content, provenance, definition.GrafanaTemplateKind)) } - tmpl.Provenance = definitions.Provenance(provenance) - templates = append(templates, tmpl) } - return templates, nil + var importedTemplates []definitions.NotificationTemplate + if t.includeImported && len(revision.Config.ExtraConfigs) > 0 && len(revision.Config.ExtraConfigs[0].TemplateFiles) > 0 { + imported := revision.Config.ExtraConfigs[0].TemplateFiles + importedTemplates = make([]definitions.NotificationTemplate, 0, len(imported)) + names := slices.Collect(maps.Keys(imported)) + sort.Strings(names) + for _, name := range names { + content := imported[name] + templates = append(templates, newNotificationTemplate(name, content, models.ProvenanceConvertedPrometheus, definition.MimirTemplateKind)) + } + } + return append(templates, importedTemplates...), nil } func (t *TemplateService) GetTemplate(ctx context.Context, orgID int64, nameOrUid string) (definitions.NotificationTemplate, error) { @@ -77,29 +95,21 @@ func (t *TemplateService) GetTemplate(ctx context.Context, orgID int64, nameOrUi if err != nil { return definitions.NotificationTemplate{}, err } - - existingName := nameOrUid - existingContent, ok := revision.Config.TemplateFiles[nameOrUid] - if !ok { - existingName, existingContent, ok = getTemplateByUid(revision.Config.TemplateFiles, nameOrUid) - } - if !ok { - return definitions.NotificationTemplate{}, ErrTemplateNotFound.Errorf("") - } - - tmpl := definitions.NotificationTemplate{ - UID: legacy_storage.NameToUid(existingName), - Name: existingName, - Template: existingContent, - ResourceVersion: calculateTemplateFingerprint(existingContent), - } - - provenance, err := t.provenanceStore.GetProvenance(ctx, &tmpl, orgID) + result, found, err := t.getTemplateByName(ctx, revision, orgID, nameOrUid) if err != nil { return definitions.NotificationTemplate{}, err } - tmpl.Provenance = definitions.Provenance(provenance) - return tmpl, nil + if found { + return result, nil + } + result, found, err = t.getTemplateByUID(ctx, revision, orgID, nameOrUid) + if err != nil { + return definitions.NotificationTemplate{}, err + } + if found { + return result, nil + } + return definitions.NotificationTemplate{}, ErrTemplateNotFound.Errorf("") } func (t *TemplateService) UpsertTemplate(ctx context.Context, orgID int64, tmpl definitions.NotificationTemplate) (definitions.NotificationTemplate, error) { @@ -135,6 +145,10 @@ func (t *TemplateService) CreateTemplate(ctx context.Context, orgID int64, tmpl if err != nil { return definitions.NotificationTemplate{}, MakeErrTemplateInvalid(err) } + if tmpl.Kind == definition.MimirTemplateKind { + return definitions.NotificationTemplate{}, MakeErrTemplateInvalid(errors.New("templates of kind 'Mimir' cannot be created")) + } + revision, err := t.configStore.Get(ctx, orgID) if err != nil { return definitions.NotificationTemplate{}, err @@ -143,6 +157,10 @@ func (t *TemplateService) CreateTemplate(ctx context.Context, orgID int64, tmpl } func (t *TemplateService) createTemplate(ctx context.Context, revision *legacy_storage.ConfigRevision, orgID int64, tmpl definitions.NotificationTemplate) (definitions.NotificationTemplate, error) { + if tmpl.Kind == definition.MimirTemplateKind { + return definitions.NotificationTemplate{}, MakeErrTemplateInvalid(errors.New("templates of kind 'Mimir' cannot be created")) + } + if revision.Config.TemplateFiles == nil { revision.Config.TemplateFiles = map[string]string{} } @@ -164,13 +182,7 @@ func (t *TemplateService) createTemplate(ctx context.Context, revision *legacy_s return definitions.NotificationTemplate{}, err } - return definitions.NotificationTemplate{ - UID: legacy_storage.NameToUid(tmpl.Name), - Name: tmpl.Name, - Template: tmpl.Template, - Provenance: tmpl.Provenance, - ResourceVersion: calculateTemplateFingerprint(tmpl.Template), - }, nil + return newNotificationTemplate(tmpl.Name, tmpl.Template, models.Provenance(tmpl.Provenance), tmpl.Kind), nil } func (t *TemplateService) UpdateTemplate(ctx context.Context, orgID int64, tmpl definitions.NotificationTemplate) (definitions.NotificationTemplate, error) { @@ -192,37 +204,39 @@ func (t *TemplateService) updateTemplate(ctx context.Context, revision *legacy_s } var found bool - var existingName, existingContent string + var err error + var existing definitions.NotificationTemplate // if UID is specified, look by UID. if tmpl.UID != "" { - existingName, existingContent, found = getTemplateByUid(revision.Config.TemplateFiles, tmpl.UID) - // do not fall back to name because we address by UID, and resource can be deleted\renamed + existing, found, err = t.getTemplateByUID(ctx, revision, orgID, tmpl.UID) } else { - existingName = tmpl.Name - existingContent, found = revision.Config.TemplateFiles[existingName] + existing, found, err = t.getTemplateByName(ctx, revision, orgID, tmpl.Name) + } + if err != nil { + return definitions.NotificationTemplate{}, err } if !found { return definitions.NotificationTemplate{}, ErrTemplateNotFound.Errorf("") } - if existingName != tmpl.Name { // if template is renamed, check if this name is already taken + if existing.Name != tmpl.Name { // if template is renamed, check if this name is already taken _, ok := revision.Config.TemplateFiles[tmpl.Name] if ok { // return error if template is being renamed to one that already exists return definitions.NotificationTemplate{}, ErrTemplateExists.Errorf("") } } - - // check that provenance is not changed in an invalid way - storedProvenance, err := t.provenanceStore.GetProvenance(ctx, &tmpl, orgID) - if err != nil { - return definitions.NotificationTemplate{}, err + if existing.Kind != tmpl.Kind { + return definitions.NotificationTemplate{}, MakeErrTemplateInvalid(errors.New("cannot change template kind")) } - if err := t.validator(storedProvenance, models.Provenance(tmpl.Provenance)); err != nil { + if existing.Provenance == definitions.Provenance(models.ProvenanceConvertedPrometheus) { + return definitions.NotificationTemplate{}, makeErrTemplateOrigin(existing, "update") + } + if err := t.validator(models.Provenance(existing.Provenance), models.Provenance(tmpl.Provenance)); err != nil { return definitions.NotificationTemplate{}, err } - err = t.checkOptimisticConcurrency(tmpl.Name, existingContent, models.Provenance(tmpl.Provenance), tmpl.ResourceVersion, "update") + err = t.checkOptimisticConcurrency(existing.Name, existing.Template, models.Provenance(tmpl.Provenance), tmpl.ResourceVersion, "update") if err != nil { return definitions.NotificationTemplate{}, err } @@ -230,9 +244,9 @@ func (t *TemplateService) updateTemplate(ctx context.Context, revision *legacy_s revision.Config.TemplateFiles[tmpl.Name] = tmpl.Template err = t.xact.InTransaction(ctx, func(ctx context.Context) error { - if existingName != tmpl.Name { // if template by was found by UID and it's name is different, then this is the rename operation. Delete old resources. - delete(revision.Config.TemplateFiles, existingName) - err := t.provenanceStore.DeleteProvenance(ctx, &definitions.NotificationTemplate{Name: existingName}, orgID) + if existing.Name != tmpl.Name { // if template by was found by UID and it's name is different, then this is the rename operation. Delete old resources. + delete(revision.Config.TemplateFiles, existing.Name) + err := t.provenanceStore.DeleteProvenance(ctx, &existing, orgID) if err != nil { return err } @@ -247,13 +261,8 @@ func (t *TemplateService) updateTemplate(ctx context.Context, revision *legacy_s return definitions.NotificationTemplate{}, err } - return definitions.NotificationTemplate{ - UID: legacy_storage.NameToUid(tmpl.Name), // if name was changed, this UID will not match the incoming one - Name: tmpl.Name, - Template: tmpl.Template, - Provenance: tmpl.Provenance, - ResourceVersion: calculateTemplateFingerprint(tmpl.Template), - }, nil + // if name was changed, this UID needs to be recalculated + return newNotificationTemplate(tmpl.Name, tmpl.Template, models.Provenance(tmpl.Provenance), tmpl.Kind), nil } func (t *TemplateService) DeleteTemplate(ctx context.Context, orgID int64, nameOrUid string, provenance definitions.Provenance, version string) error { @@ -261,44 +270,39 @@ func (t *TemplateService) DeleteTemplate(ctx context.Context, orgID int64, nameO if err != nil { return err } - - if revision.Config.TemplateFiles == nil { + existing, found, err := t.getTemplateByName(ctx, revision, orgID, nameOrUid) + if err != nil { + return err + } + if !found { + existing, found, err = t.getTemplateByUID(ctx, revision, orgID, nameOrUid) + } + if err != nil { + return err + } + if !found { return nil } - - existingName := nameOrUid - existing, ok := revision.Config.TemplateFiles[nameOrUid] - if !ok { - existingName, existing, ok = getTemplateByUid(revision.Config.TemplateFiles, nameOrUid) - } - if !ok { - return nil + if existing.Provenance == definitions.Provenance(models.ProvenanceConvertedPrometheus) { + return makeErrTemplateOrigin(existing, "delete") } - err = t.checkOptimisticConcurrency(existingName, existing, models.Provenance(provenance), version, "delete") + err = t.checkOptimisticConcurrency(existing.Name, existing.Template, models.Provenance(provenance), version, "delete") if err != nil { return err } - // check that provenance is not changed in an invalid way - storedProvenance, err := t.provenanceStore.GetProvenance(ctx, &definitions.NotificationTemplate{Name: existingName}, orgID) - if err != nil { - return err - } - if err = t.validator(storedProvenance, models.Provenance(provenance)); err != nil { + if err = t.validator(models.Provenance(existing.Provenance), models.Provenance(provenance)); err != nil { return err } - delete(revision.Config.TemplateFiles, existingName) + delete(revision.Config.TemplateFiles, existing.Name) return t.xact.InTransaction(ctx, func(ctx context.Context) error { if err := t.configStore.Save(ctx, revision, orgID); err != nil { return err } - tgt := definitions.NotificationTemplate{ - Name: existingName, - } - return t.provenanceStore.DeleteProvenance(ctx, &tgt, orgID) + return t.provenanceStore.DeleteProvenance(ctx, &existing, orgID) }) } @@ -323,11 +327,58 @@ func calculateTemplateFingerprint(t string) string { return fmt.Sprintf("%016x", sum.Sum64()) } -func getTemplateByUid(templates map[string]string, uid string) (string, string, bool) { - for n, tmpl := range templates { - if legacy_storage.NameToUid(n) == uid { - return n, tmpl, true - } +func newNotificationTemplate(name, content string, provenance models.Provenance, kind definition.TemplateKind) definitions.NotificationTemplate { + tmpl := definitions.NotificationTemplate{ + UID: templateUID(kind, name), + Name: name, + Template: content, + Provenance: definitions.Provenance(provenance), + Kind: kind, } - return "", "", false + tmpl.ResourceVersion = calculateTemplateFingerprint(content) + return tmpl +} + +func (t *TemplateService) getTemplateByName(ctx context.Context, revision *legacy_storage.ConfigRevision, orgID int64, name string) (definitions.NotificationTemplate, bool, error) { + existingContent, ok := revision.Config.TemplateFiles[name] + if !ok { + return definitions.NotificationTemplate{}, false, nil + } + provenance, err := t.provenanceStore.GetProvenance(ctx, &definitions.NotificationTemplate{Name: name}, orgID) + if err != nil { + return definitions.NotificationTemplate{}, false, err + } + return newNotificationTemplate(name, existingContent, provenance, definition.GrafanaTemplateKind), true, nil +} + +func (t *TemplateService) getTemplateByUID(ctx context.Context, revision *legacy_storage.ConfigRevision, orgID int64, uid string) (definitions.NotificationTemplate, bool, error) { + find := func(templates map[string]string, uid string, kind definition.TemplateKind) (string, string, bool) { + for n, tmpl := range templates { + if templateUID(kind, n) == uid { + return n, tmpl, true + } + } + return "", "", false + } + var provenance models.Provenance + name, content, ok := find(revision.Config.TemplateFiles, uid, definition.GrafanaTemplateKind) + if !ok { + if t.includeImported && len(revision.Config.ExtraConfigs) > 0 { + name, content, ok = find(revision.Config.ExtraConfigs[0].TemplateFiles, uid, definition.MimirTemplateKind) + if ok { + return newNotificationTemplate(name, content, models.ProvenanceConvertedPrometheus, definition.MimirTemplateKind), true, nil + } + } + return definitions.NotificationTemplate{}, false, nil + } + var err error + provenance, err = t.provenanceStore.GetProvenance(ctx, &definitions.NotificationTemplate{Name: name}, orgID) + if err != nil { + return definitions.NotificationTemplate{}, false, err + } + return newNotificationTemplate(name, content, provenance, definition.GrafanaTemplateKind), true, nil +} + +func templateUID(kind definition.TemplateKind, name string) string { + return legacy_storage.NameToUid(fmt.Sprintf("%s|%s", string(kind), name)) } diff --git a/pkg/services/ngalert/provisioning/templates_test.go b/pkg/services/ngalert/provisioning/templates_test.go index 5b989dd678d..44ced3ba7f9 100644 --- a/pkg/services/ngalert/provisioning/templates_test.go +++ b/pkg/services/ngalert/provisioning/templates_test.go @@ -6,6 +6,7 @@ import ( "fmt" "testing" + "github.com/grafana/alerting/definition" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" @@ -27,6 +28,15 @@ func TestGetTemplates(t *testing.T) { "template2": "test2", "template3": "test3", }, + ExtraConfigs: []definitions.ExtraConfiguration{ + { + Identifier: "1234", + TemplateFiles: map[string]string{ + "template1": "imported-test1", + "template4": "imported-test4", + }, + }, + }, }, } @@ -45,27 +55,24 @@ func TestGetTemplates(t *testing.T) { require.NoError(t, err) expected := []definitions.NotificationTemplate{ - { - UID: legacy_storage.NameToUid("template1"), - Name: "template1", - Template: "test1", - Provenance: definitions.Provenance(models.ProvenanceAPI), - ResourceVersion: calculateTemplateFingerprint("test1"), - }, - { - UID: legacy_storage.NameToUid("template2"), - Name: "template2", - Template: "test2", - Provenance: definitions.Provenance(models.ProvenanceFile), - ResourceVersion: calculateTemplateFingerprint("test2"), - }, - { - UID: legacy_storage.NameToUid("template3"), - Name: "template3", - Template: "test3", - Provenance: definitions.Provenance(models.ProvenanceNone), - ResourceVersion: calculateTemplateFingerprint("test3"), - }, + newNotificationTemplate( + "template1", + "test1", + models.ProvenanceAPI, + definition.GrafanaTemplateKind, + ), + newNotificationTemplate( + "template2", + "test2", + models.ProvenanceFile, + definition.GrafanaTemplateKind, + ), + newNotificationTemplate( + "template3", + "test3", + models.ProvenanceNone, + definition.GrafanaTemplateKind, + ), } require.EqualValues(t, expected, result) @@ -89,6 +96,60 @@ func TestGetTemplates(t *testing.T) { prov.AssertExpectations(t) }) + t.Run("returns imported templates if enabled", func(t *testing.T) { + sut, store, prov := createTemplateServiceSut() + sut = sut.WithIncludeImported() + store.GetFn = func(ctx context.Context, org int64) (*legacy_storage.ConfigRevision, error) { + assert.Equal(t, orgID, org) + return revision, nil + } + prov.EXPECT().GetProvenances(mock.Anything, mock.Anything, mock.Anything).Return(map[string]models.Provenance{ + "template1": models.ProvenanceAPI, + "template2": models.ProvenanceFile, + }, nil) + + result, err := sut.GetTemplates(context.Background(), orgID) + require.NoError(t, err) + + expected := []definitions.NotificationTemplate{ + newNotificationTemplate( + "template1", + "test1", + models.ProvenanceAPI, + definition.GrafanaTemplateKind, + ), + newNotificationTemplate( + "template2", + "test2", + models.ProvenanceFile, + definition.GrafanaTemplateKind, + ), + newNotificationTemplate( + "template3", + "test3", + models.ProvenanceNone, + definition.GrafanaTemplateKind, + ), + newNotificationTemplate( + "template1", + "imported-test1", + models.ProvenanceConvertedPrometheus, + definition.MimirTemplateKind, + ), + newNotificationTemplate( + "template4", + "imported-test4", + models.ProvenanceConvertedPrometheus, + definition.MimirTemplateKind, + ), + } + + require.EqualValues(t, expected, result) + + prov.AssertCalled(t, "GetProvenances", mock.Anything, orgID, (&definitions.NotificationTemplate{}).ResourceType()) + prov.AssertExpectations(t) + }) + t.Run("propagates errors", func(t *testing.T) { t.Run("when unable to read config", func(t *testing.T) { sut, store, prov := createTemplateServiceSut() @@ -127,15 +188,25 @@ func TestGetTemplate(t *testing.T) { orgID := int64(1) templateName := "template1" templateContent := "test1" + importedTemplateName := "template2" + importedTemplateContent := "imported" revision := &legacy_storage.ConfigRevision{ Config: &definitions.PostableUserConfig{ TemplateFiles: map[string]string{ templateName: templateContent, }, + ExtraConfigs: []definitions.ExtraConfiguration{ + { + Identifier: "1234", + TemplateFiles: map[string]string{ + importedTemplateName: importedTemplateContent, + }, + }, + }, }, } - t.Run("return a template from config file by name", func(t *testing.T) { + t.Run("return a template from config by name", func(t *testing.T) { sut, store, prov := createTemplateServiceSut() store.GetFn = func(ctx context.Context, org int64) (*legacy_storage.ConfigRevision, error) { assert.Equal(t, orgID, org) @@ -146,13 +217,12 @@ func TestGetTemplate(t *testing.T) { result, err := sut.GetTemplate(context.Background(), orgID, templateName) require.NoError(t, err) - expected := definitions.NotificationTemplate{ - UID: legacy_storage.NameToUid(templateName), - Name: templateName, - Template: templateContent, - Provenance: definitions.Provenance(models.ProvenanceAPI), - ResourceVersion: calculateTemplateFingerprint(templateContent), - } + expected := newNotificationTemplate( + templateName, + templateContent, + models.ProvenanceAPI, + definition.GrafanaTemplateKind, + ) require.Equal(t, expected, result) @@ -162,6 +232,62 @@ func TestGetTemplate(t *testing.T) { prov.AssertExpectations(t) }) + t.Run("imported templates cannot be retrieved by name", func(t *testing.T) { + sut, store, _ := createTemplateServiceSut() + store.GetFn = func(ctx context.Context, org int64) (*legacy_storage.ConfigRevision, error) { + assert.Equal(t, orgID, org) + return revision, nil + } + _, err := sut.GetTemplate(context.Background(), orgID, importedTemplateName) + require.ErrorIs(t, err, ErrTemplateNotFound) + }) + + t.Run("return a template from config by UID", func(t *testing.T) { + sut, store, prov := createTemplateServiceSut() + store.GetFn = func(ctx context.Context, org int64) (*legacy_storage.ConfigRevision, error) { + assert.Equal(t, orgID, org) + return revision, nil + } + prov.EXPECT().GetProvenance(mock.Anything, mock.Anything, mock.Anything).Return(models.ProvenanceNone, nil) + + result, err := sut.GetTemplate(context.Background(), orgID, templateUID(definition.GrafanaTemplateKind, templateName)) + require.NoError(t, err) + + expected := newNotificationTemplate( + templateName, + templateContent, + models.ProvenanceNone, + definition.GrafanaTemplateKind, + ) + require.Equal(t, expected, result) + }) + + t.Run("return an imported template from config by UID", func(t *testing.T) { + sut, store, prov := createTemplateServiceSut() + store.GetFn = func(ctx context.Context, org int64) (*legacy_storage.ConfigRevision, error) { + assert.Equal(t, orgID, org) + return revision, nil + } + + uid := templateUID(definition.MimirTemplateKind, importedTemplateName) + t.Run("should be not found without flag enabled", func(t *testing.T) { + _, err := sut.GetTemplate(context.Background(), orgID, uid) + require.ErrorIs(t, err, ErrTemplateNotFound) + }) + + result, err := sut.WithIncludeImported().GetTemplate(context.Background(), orgID, uid) + require.NoError(t, err) + + expected := newNotificationTemplate( + importedTemplateName, + importedTemplateContent, + models.ProvenanceConvertedPrometheus, + definition.MimirTemplateKind, + ) + require.Equal(t, expected, result) + prov.AssertExpectations(t) + }) + t.Run("returns ErrTemplateNotFound when template does not exist", func(t *testing.T) { sut, store, prov := createTemplateServiceSut() store.GetFn = func(ctx context.Context, org int64) (*legacy_storage.ConfigRevision, error) { @@ -242,18 +368,18 @@ func TestUpsertTemplate(t *testing.T) { Template: "{{ define \"test\"}} test {{ end }}", Provenance: definitions.Provenance(models.ProvenanceAPI), ResourceVersion: "", + Kind: definition.GrafanaTemplateKind, } result, err := sut.UpsertTemplate(context.Background(), orgID, tmpl) require.NoError(t, err) - require.Equal(t, definitions.NotificationTemplate{ - UID: legacy_storage.NameToUid(tmpl.Name), - Name: tmpl.Name, - Template: tmpl.Template, - Provenance: tmpl.Provenance, - ResourceVersion: calculateTemplateFingerprint(tmpl.Template), - }, result) + require.Equal(t, newNotificationTemplate( + tmpl.Name, + tmpl.Template, + models.Provenance(tmpl.Provenance), + tmpl.Kind, + ), result) require.Len(t, store.Calls, 2) @@ -284,18 +410,18 @@ func TestUpsertTemplate(t *testing.T) { Template: "{{ define \"test\"}} test {{ end }}", Provenance: definitions.Provenance(models.ProvenanceAPI), ResourceVersion: calculateTemplateFingerprint("test1"), + Kind: definition.GrafanaTemplateKind, } result, err := sut.UpsertTemplate(context.Background(), orgID, tmpl) require.NoError(t, err) - assert.Equal(t, definitions.NotificationTemplate{ - UID: legacy_storage.NameToUid(tmpl.Name), - Name: tmpl.Name, - Template: tmpl.Template, - Provenance: tmpl.Provenance, - ResourceVersion: calculateTemplateFingerprint(tmpl.Template), - }, result) + assert.Equal(t, newNotificationTemplate( + tmpl.Name, + tmpl.Template, + models.Provenance(tmpl.Provenance), + tmpl.Kind, + ), result) require.Len(t, store.Calls, 2) require.Equal(t, "Save", store.Calls[1].Method) @@ -326,13 +452,12 @@ func TestUpsertTemplate(t *testing.T) { result, err := sut.UpsertTemplate(context.Background(), orgID, tmpl) require.NoError(t, err) - assert.Equal(t, definitions.NotificationTemplate{ - UID: legacy_storage.NameToUid(tmpl.Name), - Name: tmpl.Name, - Template: tmpl.Template, - Provenance: tmpl.Provenance, - ResourceVersion: calculateTemplateFingerprint(tmpl.Template), - }, result) + assert.Equal(t, newNotificationTemplate( + tmpl.Name, + tmpl.Template, + models.Provenance(tmpl.Provenance), + definition.GrafanaTemplateKind, + ), result) require.Equal(t, "Save", store.Calls[1].Method) saved := store.Calls[1].Args[1].(*legacy_storage.ConfigRevision) @@ -356,18 +481,18 @@ func TestUpsertTemplate(t *testing.T) { Template: "content", Provenance: definitions.Provenance(models.ProvenanceNone), ResourceVersion: calculateTemplateFingerprint(currentTemplateContent), + Kind: definition.GrafanaTemplateKind, } result, _ := sut.UpsertTemplate(context.Background(), orgID, tmpl) expectedContent := fmt.Sprintf("{{ define \"%s\" }}\n content\n{{ end }}", templateName) - require.Equal(t, definitions.NotificationTemplate{ - UID: legacy_storage.NameToUid(tmpl.Name), - Name: tmpl.Name, - Template: expectedContent, - Provenance: tmpl.Provenance, - ResourceVersion: calculateTemplateFingerprint(expectedContent), - }, result) + require.Equal(t, newNotificationTemplate( + tmpl.Name, + expectedContent, + models.Provenance(tmpl.Provenance), + tmpl.Kind, + ), result) }) t.Run("does not reject template with unknown field", func(t *testing.T) { @@ -489,6 +614,21 @@ func TestUpsertTemplate(t *testing.T) { require.ErrorIs(t, err, ErrTemplateNotFound) }) + t.Run("rejects new templates of mimir kind", func(t *testing.T) { + sut, store, _ := createTemplateServiceSut() + store.GetFn = func(ctx context.Context, org int64) (*legacy_storage.ConfigRevision, error) { + return revision(), nil + } + template := definitions.NotificationTemplate{ + Name: "template2", + Template: "asdf-new", + Provenance: definitions.Provenance(models.ProvenanceNone), + Kind: definition.MimirTemplateKind, + } + _, err := sut.UpsertTemplate(context.Background(), orgID, template) + require.ErrorIs(t, err, ErrTemplateInvalid) + }) + t.Run("propagates errors", func(t *testing.T) { tmpl := definitions.NotificationTemplate{ Name: templateName, @@ -562,6 +702,7 @@ func TestCreateTemplate(t *testing.T) { Name: "new-template", Template: "{{ define \"test\"}} test {{ end }}", Provenance: definitions.Provenance(models.ProvenanceAPI), + Kind: definition.GrafanaTemplateKind, } revision := func() *legacy_storage.ConfigRevision { @@ -588,13 +729,12 @@ func TestCreateTemplate(t *testing.T) { result, err := sut.CreateTemplate(context.Background(), orgID, tmpl) require.NoError(t, err) - require.Equal(t, definitions.NotificationTemplate{ - UID: legacy_storage.NameToUid(tmpl.Name), - Name: tmpl.Name, - Template: tmpl.Template, - Provenance: tmpl.Provenance, - ResourceVersion: calculateTemplateFingerprint(tmpl.Template), - }, result) + require.Equal(t, newNotificationTemplate( + tmpl.Name, + tmpl.Template, + models.Provenance(tmpl.Provenance), + tmpl.Kind, + ), result) require.Len(t, store.Calls, 2) @@ -649,10 +789,33 @@ func TestCreateTemplate(t *testing.T) { require.ErrorIs(t, err, ErrTemplateInvalid) }) + t.Run("invalid kind", func(t *testing.T) { + tmpl := definitions.NotificationTemplate{ + Name: "new-template", + Template: "{{ define \"test\"}} test {{ end }}", + Kind: "unknown", + } + _, err := sut.CreateTemplate(context.Background(), orgID, tmpl) + require.ErrorIs(t, err, ErrTemplateInvalid) + }) + require.Empty(t, store.Calls) prov.AssertExpectations(t) }) + t.Run("rejects templates with mimir kind", func(t *testing.T) { + sut, _, _ := createTemplateServiceSut() + + tmpl := definitions.NotificationTemplate{ + Name: "new-template", + Template: "{{ define \"test\"}} test {{ end }}", + Kind: definition.MimirTemplateKind, + } + + _, err := sut.CreateTemplate(context.Background(), orgID, tmpl) + require.ErrorIs(t, err, ErrTemplateInvalid) + }) + t.Run("propagates errors", func(t *testing.T) { t.Run("when unable to read config", func(t *testing.T) { sut, store, _ := createTemplateServiceSut() @@ -706,6 +869,7 @@ func TestUpdateTemplate(t *testing.T) { Template: "{{ define \"test\"}} test {{ end }}", Provenance: definitions.Provenance(models.ProvenanceAPI), ResourceVersion: "", + Kind: definition.GrafanaTemplateKind, } amConfigToken := util.GenerateShortUID() @@ -771,7 +935,7 @@ func TestUpdateTemplate(t *testing.T) { }, { name: "by uid", - templateUid: legacy_storage.NameToUid(tmpl.UID), + templateUid: templateUID(tmpl.Kind, tmpl.Name), }, } @@ -791,13 +955,12 @@ func TestUpdateTemplate(t *testing.T) { result, err := sut.UpdateTemplate(context.Background(), orgID, tmpl) require.NoError(t, err) - assert.Equal(t, definitions.NotificationTemplate{ - UID: legacy_storage.NameToUid(tmpl.Name), - Name: tmpl.Name, - Template: tmpl.Template, - Provenance: tmpl.Provenance, - ResourceVersion: calculateTemplateFingerprint(tmpl.Template), - }, result) + assert.Equal(t, newNotificationTemplate( + tmpl.Name, + tmpl.Template, + models.Provenance(tmpl.Provenance), + tmpl.Kind, + ), result) require.Len(t, store.Calls, 2) require.Equal(t, "Save", store.Calls[1].Method) @@ -821,13 +984,12 @@ func TestUpdateTemplate(t *testing.T) { result, err := sut.UpdateTemplate(context.Background(), orgID, tmpl) require.NoError(t, err) - assert.Equal(t, definitions.NotificationTemplate{ - UID: legacy_storage.NameToUid(tmpl.Name), - Name: tmpl.Name, - Template: tmpl.Template, - Provenance: tmpl.Provenance, - ResourceVersion: calculateTemplateFingerprint(tmpl.Template), - }, result) + assert.Equal(t, newNotificationTemplate( + tmpl.Name, + tmpl.Template, + models.Provenance(tmpl.Provenance), + tmpl.Kind, + ), result) require.Equal(t, "Save", store.Calls[1].Method) saved := store.Calls[1].Args[1].(*legacy_storage.ConfigRevision) @@ -853,18 +1015,17 @@ func TestUpdateTemplate(t *testing.T) { oldName := tmpl.Name tmpl := tmpl - tmpl.UID = legacy_storage.NameToUid(tmpl.Name) // UID matches the current template - tmpl.Name = "new-template-name" // but name is different + tmpl.UID = templateUID(tmpl.Kind, tmpl.Name) // UID matches the current template + tmpl.Name = "new-template-name" // but name is different result, err := sut.UpdateTemplate(context.Background(), orgID, tmpl) require.NoError(t, err) - assert.Equal(t, definitions.NotificationTemplate{ - UID: legacy_storage.NameToUid(tmpl.Name), - Name: tmpl.Name, - Template: tmpl.Template, - Provenance: tmpl.Provenance, - ResourceVersion: calculateTemplateFingerprint(tmpl.Template), - }, result) + assert.Equal(t, newNotificationTemplate( + tmpl.Name, + tmpl.Template, + models.Provenance(tmpl.Provenance), + tmpl.Kind, + ), result) require.Len(t, store.Calls, 2) require.Equal(t, "Save", store.Calls[1].Method) @@ -882,6 +1043,7 @@ func TestUpdateTemplate(t *testing.T) { t.Run("rejects rename operation if template with the new name exists", func(t *testing.T) { sut, store, prov := createTemplateServiceSut() + prov.EXPECT().GetProvenance(mock.Anything, mock.Anything, mock.Anything).Return(models.ProvenanceNone, nil) store.GetFn = func(ctx context.Context, org int64) (*legacy_storage.ConfigRevision, error) { return &legacy_storage.ConfigRevision{ Config: &definitions.PostableUserConfig{ @@ -895,8 +1057,8 @@ func TestUpdateTemplate(t *testing.T) { } tmpl := tmpl - tmpl.UID = legacy_storage.NameToUid(tmpl.Name) // UID matches the current template - tmpl.Name = "new-template-name" // but name matches another existing template + tmpl.UID = templateUID(tmpl.Kind, tmpl.Name) // UID matches the current template + tmpl.Name = "new-template-name" // but name matches another existing template _, err := sut.UpdateTemplate(context.Background(), orgID, tmpl) require.ErrorIs(t, err, ErrTemplateExists) @@ -925,6 +1087,16 @@ func TestUpdateTemplate(t *testing.T) { require.ErrorIs(t, err, ErrTemplateInvalid) }) + t.Run("invalid kind", func(t *testing.T) { + tmpl := definitions.NotificationTemplate{ + Name: "", + Template: "", + Kind: "unknown", + } + _, err := sut.UpdateTemplate(context.Background(), orgID, tmpl) + require.ErrorIs(t, err, ErrTemplateInvalid) + }) + require.Empty(t, store.Calls) prov.AssertExpectations(t) }) @@ -975,6 +1147,27 @@ func TestUpdateTemplate(t *testing.T) { prov.AssertExpectations(t) }) + t.Run("rejects existing templates if kind changes", func(t *testing.T) { + sut, store, prov := createTemplateServiceSut() + store.GetFn = func(ctx context.Context, org int64) (*legacy_storage.ConfigRevision, error) { + return revision(), nil + } + prov.EXPECT().GetProvenance(mock.Anything, mock.Anything, mock.Anything).Return(models.ProvenanceNone, nil) + + template := definitions.NotificationTemplate{ + Name: "template1", + Template: "asdf-new", + ResourceVersion: "bad-version", + Provenance: definitions.Provenance(models.ProvenanceNone), + Kind: definition.MimirTemplateKind, + } + + _, err := sut.UpdateTemplate(context.Background(), orgID, template) + + require.ErrorIs(t, err, ErrTemplateInvalid) + prov.AssertExpectations(t) + }) + t.Run("propagates errors", func(t *testing.T) { t.Run("when unable to read config", func(t *testing.T) { sut, store, _ := createTemplateServiceSut() @@ -1062,7 +1255,7 @@ func TestDeleteTemplate(t *testing.T) { }, { name: "by uid", - templateNameOrUid: legacy_storage.NameToUid(templateName), + templateNameOrUid: templateUID(definition.GrafanaTemplateKind, templateName), }, } for _, tt := range testCase { @@ -1125,7 +1318,7 @@ func TestDeleteTemplate(t *testing.T) { } t.Run("should look by name before uid", func(t *testing.T) { - expectedToDelete := legacy_storage.NameToUid(templateName) + expectedToDelete := templateUID(definition.GrafanaTemplateKind, templateName) sut, store, prov := createTemplateServiceSut() store.GetFn = func(ctx context.Context, orgID int64) (*legacy_storage.ConfigRevision, error) { return &legacy_storage.ConfigRevision{ diff --git a/pkg/services/ngalert/state/historian/annotation.go b/pkg/services/ngalert/state/historian/annotation.go index d2353ec42d8..d9cdfaa9d2b 100644 --- a/pkg/services/ngalert/state/historian/annotation.go +++ b/pkg/services/ngalert/state/historian/annotation.go @@ -44,6 +44,7 @@ type AnnotationBackend struct { type RuleStore interface { GetAlertRuleByUID(ctx context.Context, query *ngmodels.GetAlertRuleByUIDQuery) (*ngmodels.AlertRule, error) GetUserVisibleNamespaces(ctx context.Context, orgID int64, user identity.Requester) (map[string]*folder.Folder, error) + GetAlertRuleVersionFolders(ctx context.Context, orgID int64, guid string) ([]string, error) } type AnnotationStore interface { diff --git a/pkg/services/ngalert/state/historian/loki.go b/pkg/services/ngalert/state/historian/loki.go index e07461f27bf..76e3e9025bd 100644 --- a/pkg/services/ngalert/state/historian/loki.go +++ b/pkg/services/ngalert/state/historian/loki.go @@ -505,30 +505,25 @@ func (h *RemoteLokiBackend) getFolderUIDsForFilter(ctx context.Context, query mo if err != nil { return nil, err } - if bypass { // if user has access to all rules and folder, remove filter + + if query.RuleUID != "" { + return h.getFolderUIDsForRuleFilter(ctx, query, bypass) + } + + // If the query has no rule filter, we need to return all folder UIDs the user has access to. + // For a user with access to all rules and folders, the full list of folders will likely be too large to be an + // effective optimization in Loki, so we skip folderUID filtering entirely in that case. + if bypass { return nil, nil } - // if there is a filter by rule UID, find that rule UID and make sure that user has access to it. - if query.RuleUID != "" { - rule, err := h.ruleStore.GetAlertRuleByUID(ctx, &models.GetAlertRuleByUIDQuery{ - UID: query.RuleUID, - OrgID: query.OrgID, - }) - if err != nil { - return nil, fmt.Errorf("failed to fetch alert rule by UID: %w", err) - } - if rule == nil { - return nil, models.ErrAlertRuleNotFound - } - return nil, h.ac.AuthorizeAccessInFolder(ctx, query.SignedInUser, rule) - } - // if no filter, then we need to get all namespaces user has access to + + // All folders the user has access to. folders, err := h.ruleStore.GetUserVisibleNamespaces(ctx, query.OrgID, query.SignedInUser) if err != nil { return nil, fmt.Errorf("failed to fetch folders that user can access: %w", err) } uids := make([]string, 0, len(folders)) - // now keep only UIDs of folder in which user can read rules. + // Keep only UIDs of folder in which user can read rules. for _, f := range folders { hasAccess, err := h.ac.HasAccessInFolder(ctx, query.SignedInUser, models.NewNamespace(f)) if err != nil { @@ -545,3 +540,71 @@ func (h *RemoteLokiBackend) getFolderUIDsForFilter(ctx context.Context, query mo sort.Strings(uids) return uids, nil } + +func (h *RemoteLokiBackend) getFolderUIDsForRuleFilter(ctx context.Context, query models.HistoryQuery, canReadAll bool) ([]string, error) { + rule, err := h.ruleStore.GetAlertRuleByUID(ctx, &models.GetAlertRuleByUIDQuery{ + UID: query.RuleUID, + OrgID: query.OrgID, + }) + if err != nil { + if canReadAll { + // When the user can read all rules, filtering by folder UID is purely an optimization, so we can ignore errors here. + h.log.FromContext(ctx).Debug("failed to fetch alert rule by UID", "err", err) + return nil, nil + } + return nil, fmt.Errorf("failed to fetch alert rule by UID: %w", err) + } + + // First, we check if the user has access to the current version of the rule. If not, we can return early. + // Whether we should check historical folders they might still have access to is not 100% clear, but it seems more + // intuitive to deny access in this case. + if !canReadAll { + if err := h.ac.AuthorizeAccessInFolder(ctx, query.SignedInUser, rule); err != nil { + return nil, err + } + } + + // We want to return folder UIDs when possible, as it's indexed in Loki and will help with query performance. + // However, by just returning the current folder UID the user can lose history when a rule is moved between folders. + // So, we attempt to get historical folder UIDs from the rule's history. + historicalFolders, err := h.ruleStore.GetAlertRuleVersionFolders(ctx, rule.OrgID, rule.GUID) + if err != nil { + // Including historical folders is an edge case enhancement, better to just log the error and continue + // with the current folder UID. + h.log.FromContext(ctx).Debug("failed to include historical folder UIDs for rule", "err", err) + } + + accessibleFolders := make([]string, 0, len(historicalFolders)+1) + dedup := make(map[string]struct{}) + + accessibleFolders = append(accessibleFolders, rule.GetNamespaceUID()) + dedup[rule.GetNamespaceUID()] = struct{}{} + + for _, folderUID := range historicalFolders { + if _, exists := dedup[folderUID]; exists { + continue + } + + if canReadAll { + // If the user can read all rules, no need to check access to each folder. + accessibleFolders = append(accessibleFolders, folderUID) + continue + } + + hasAccess, err := h.ac.HasAccessInFolder(ctx, query.SignedInUser, models.Namespace{ + UID: folderUID, + }) + if err != nil { + // Including historical folders is an edge case enhancement, better to just log the error and continue + // with the current folder UID. + h.log.FromContext(ctx).Debug("failed to check access to folder", "err", err, "folderUID", folderUID) + continue + } + if !hasAccess { + continue + } + accessibleFolders = append(accessibleFolders, folderUID) + } + + return accessibleFolders, nil +} diff --git a/pkg/services/ngalert/state/historian/loki_test.go b/pkg/services/ngalert/state/historian/loki_test.go index a01efe9563b..d5cd482d177 100644 --- a/pkg/services/ngalert/state/historian/loki_test.go +++ b/pkg/services/ngalert/state/historian/loki_test.go @@ -22,6 +22,7 @@ import ( alertingInstrument "github.com/grafana/alerting/http/instrument" "github.com/grafana/alerting/http/instrument/instrumenttest" + "github.com/grafana/grafana/pkg/apimachinery/identity" "github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/infra/tracing" @@ -868,7 +869,8 @@ func TestGetFolderUIDsForFilter(t *testing.T) { } result, err := createLoki(ac).getFolderUIDsForFilter(context.Background(), models.HistoryQuery{OrgID: orgID, RuleUID: rule.UID, SignedInUser: usr}) assert.NoError(t, err) - assert.Empty(t, result) + assert.Len(t, result, 1) + assert.Contains(t, result, rule.GetNamespaceUID()) assert.Len(t, ac.Calls, 1) assert.Equal(t, "CanReadAllRules", ac.Calls[0].MethodName) @@ -893,7 +895,8 @@ func TestGetFolderUIDsForFilter(t *testing.T) { result, err := loki.getFolderUIDsForFilter(context.Background(), models.HistoryQuery{OrgID: orgID, RuleUID: rule.UID, SignedInUser: usr}) assert.NoError(t, err) - assert.Empty(t, result) + assert.Len(t, result, 1) + assert.Contains(t, result, rule.GetNamespaceUID()) assert.Len(t, ac.Calls, 2) assert.Equal(t, "CanReadAllRules", ac.Calls[0].MethodName) @@ -916,6 +919,21 @@ func TestGetFolderUIDsForFilter(t *testing.T) { require.ErrorIs(t, err, models.ErrAlertRuleNotFound) }) }) + + t.Run("should return folderUID", func(t *testing.T) { + for _, authBypass := range []bool{true, false} { + t.Run(fmt.Sprintf("authBypass=%v", authBypass), func(t *testing.T) { + ac := &acfakes.FakeRuleService{} + ac.CanReadAllRulesFunc = func(ctx context.Context, requester identity.Requester) (bool, error) { + return authBypass, nil + } + result, err := createLoki(ac).getFolderUIDsForFilter(context.Background(), models.HistoryQuery{OrgID: orgID, RuleUID: rule.UID, SignedInUser: usr}) + assert.NoError(t, err) + assert.Len(t, result, 1) + assert.Contains(t, result, rule.GetNamespaceUID()) + }) + } + }) }) t.Run("when rule UID is empty", func(t *testing.T) { @@ -982,6 +1000,161 @@ func TestGetFolderUIDsForFilter(t *testing.T) { }) } +func TestGetFolderUIDsForFilterWithHistoricalFolders(t *testing.T) { + // Simple history generator to avoid repetitive code in test cases. + simpleHistory := func(guid string) map[string][]*models.AlertRuleVersion { + return map[string][]*models.AlertRuleVersion{ + guid: { + &models.AlertRuleVersion{AlertRule: models.RuleGen.With(models.RuleMuts.WithGUID(guid), models.RuleMuts.WithNamespaceUID("folder-current")).Generate()}, + &models.AlertRuleVersion{AlertRule: models.RuleGen.With(models.RuleMuts.WithGUID(guid), models.RuleMuts.WithNamespaceUID("folder-historical-1")).Generate()}, + &models.AlertRuleVersion{AlertRule: models.RuleGen.With(models.RuleMuts.WithGUID(guid), models.RuleMuts.WithNamespaceUID("folder-historical-2")).Generate()}, + &models.AlertRuleVersion{AlertRule: models.RuleGen.With(models.RuleMuts.WithGUID(guid), models.RuleMuts.WithNamespaceUID("folder-historical-3")).Generate()}, + }, + } + } + + // Helper to create simple folder access override functions. + canReadRulesInFolders := func(folderUids ...string) func(folderUID string) (bool, error) { + return func(folderUID string) (bool, error) { + for _, f := range folderUids { + if folderUID == f { + return true, nil + } + } + return false, nil + } + } + + // Helper to fail historical folders query. + failHistoryQueryHook := func(cmd any) error { + q, ok := cmd.(fakes.GenericRecordedQuery) + if !ok { + return nil + } + if q.Name == "GetAlertRuleVersionFolders" { + return errors.New("generic error") + } + return nil + } + + cases := []struct { + name string + // Setup. + existingHistory map[string][]*models.AlertRuleVersion + canReadAllRules bool + rule *models.AlertRule + + // Error overrides. + ruleStoreHook func(cmd any) error + folderAccessOverride func(folderUID string) (bool, error) + + // Expected. + expectedFolders []string + }{ + { + name: "should include historical folders when user can read all rules", + existingHistory: simpleHistory("guid-1"), + canReadAllRules: true, + rule: models.RuleGen.With(models.RuleMuts.WithGUID("guid-1"), models.RuleMuts.WithNamespaceUID("folder-current")).GenerateRef(), + expectedFolders: []string{"folder-current", "folder-historical-1", "folder-historical-2", "folder-historical-3"}, + }, + { + name: "should include only authorized historical folders", + existingHistory: simpleHistory("guid-1"), + folderAccessOverride: canReadRulesInFolders("folder-current", "folder-historical-2"), + rule: models.RuleGen.With(models.RuleMuts.WithGUID("guid-1"), models.RuleMuts.WithNamespaceUID("folder-current")).GenerateRef(), + expectedFolders: []string{"folder-current", "folder-historical-2"}, + }, + { + name: "if historical folders query fails, should return current folder", + existingHistory: simpleHistory("guid-1"), + canReadAllRules: true, + rule: models.RuleGen.With(models.RuleMuts.WithGUID("guid-1"), models.RuleMuts.WithNamespaceUID("folder-current")).GenerateRef(), + ruleStoreHook: failHistoryQueryHook, + expectedFolders: []string{"folder-current"}, + }, + { + name: "if historical folders query fails, should return current folder", + existingHistory: simpleHistory("guid-1"), + folderAccessOverride: canReadRulesInFolders("folder-current", "folder-historical-2"), + rule: models.RuleGen.With(models.RuleMuts.WithGUID("guid-1"), models.RuleMuts.WithNamespaceUID("folder-current")).GenerateRef(), + ruleStoreHook: failHistoryQueryHook, + expectedFolders: []string{"folder-current"}, + }, + { + name: "if access check for historical folders fails, should ignore", + existingHistory: simpleHistory("guid-1"), + rule: models.RuleGen.With(models.RuleMuts.WithGUID("guid-1"), models.RuleMuts.WithNamespaceUID("folder-current")).GenerateRef(), + folderAccessOverride: func(folderUID string) (bool, error) { + switch folderUID { + case "folder-current", "folder-historical-3": + return true, nil + case "folder-historical-2": + return false, nil + case "folder-historical-1": + return false, errors.New("generic error") + } + return false, nil + }, + expectedFolders: []string{"folder-current", "folder-historical-3"}, + }, + } + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + // Setup. + orgID := int64(1) + usr := accesscontrol.BackgroundUser("test", 1, org.RoleNone, nil) + + ac := &acfakes.FakeRuleService{} + ac.CanReadAllRulesFunc = func(ctx context.Context, requester identity.Requester) (bool, error) { + return tc.canReadAllRules, nil + } + ac.AuthorizeAccessInFolderFunc = func(ctx context.Context, requester identity.Requester, namespaced models.Namespaced) error { + if tc.canReadAllRules { + return nil + } + hasAccess, err := tc.folderAccessOverride(namespaced.GetNamespaceUID()) + if err != nil { + return err + } + if !hasAccess { + return rulesAuthz.ErrAuthorizationBase.Errorf("%w", err) + } + return nil + } + ac.HasAccessInFolderFunc = func(ctx context.Context, requester identity.Requester, namespaced models.Namespaced) (bool, error) { + if tc.canReadAllRules { + return true, nil + } + return tc.folderAccessOverride(namespaced.GetNamespaceUID()) + } + + rulesStore := fakes.NewRuleStore(t) + rulesStore.Rules = map[int64][]*models.AlertRule{ + orgID: { + tc.rule, + // Add some irrelevant rules to ensure they are ignored. + models.RuleGen.With(models.RuleMuts.WithNamespaceUID(tc.rule.GetNamespaceUID())).GenerateRef(), + models.RuleGen.With(models.RuleMuts.WithNamespaceUID("irrelevant-folder")).GenerateRef(), + }, + } + rulesStore.History = tc.existingHistory + if tc.ruleStoreHook != nil { + rulesStore.Hook = tc.ruleStoreHook + } + + loki := createTestLokiBackend(t, instrumenttest.NewFakeRequester(), metrics.NewHistorianMetrics(prometheus.NewRegistry(), metrics.Subsystem)) + loki.ruleStore = rulesStore + loki.ac = ac + + // Test conditions. + result, err := loki.getFolderUIDsForFilter(context.Background(), models.HistoryQuery{OrgID: orgID, RuleUID: tc.rule.UID, SignedInUser: usr}) + assert.NoError(t, err) + assert.ElementsMatch(t, tc.expectedFolders, result) + }) + } +} + func createTestLokiBackend(t *testing.T, req alertingInstrument.Requester, met *metrics.Historian) *RemoteLokiBackend { url, _ := url.Parse("http://some.url") cfg := lokiclient.LokiConfig{ diff --git a/pkg/services/ngalert/store/alert_rule.go b/pkg/services/ngalert/store/alert_rule.go index 4307778f9c6..30856587794 100644 --- a/pkg/services/ngalert/store/alert_rule.go +++ b/pkg/services/ngalert/store/alert_rule.go @@ -239,6 +239,27 @@ func (st DBstore) GetAlertRuleVersions(ctx context.Context, orgID int64, guid st return alertRules, nil } +// GetAlertRuleVersionFolders retrieves a list of unique folder UIDs that the given rule guid has belonged to. +// Returned slice is ordered with more recent folders first. +func (st DBstore) GetAlertRuleVersionFolders(ctx context.Context, orgID int64, guid string) ([]string, error) { + folders := make([]string, 0) + err := st.SQLStore.WithDbSession(ctx, func(sess *db.Session) error { + if err := sess.Table(new(alertRuleVersion)). + Select("rule_namespace_uid"). + Where("rule_org_id = ? AND rule_guid = ?", orgID, guid). + GroupBy("rule_namespace_uid"). + OrderBy("MAX(version) DESC"). + Find(&folders); err != nil { + return err + } + return nil + }) + if err != nil { + return nil, err + } + return folders, nil +} + // ListDeletedRules retrieves a list of deleted alert rules for the specified organization ID from the database. // It ensures that only the latest version of each rule is included and filters out invalid or duplicated versions. // Returns a slice of *models.AlertRule or an error if the operation fails. @@ -621,6 +642,23 @@ func (st DBstore) ListAlertRulesByGroup(ctx context.Context, query *ngmodels.Lis _ = rows.Close() }() + opts := AlertRuleConvertOptions{} + if query.Compact { + opts.ExcludeAlertQueries = true + opts.ExcludeNotificationSettings = true + opts.ExcludeMetadata = true + + if query.ReceiverName != "" || query.TimeIntervalName != "" { + // Need NotificationSettings for these filters + opts.ExcludeNotificationSettings = false + } + + if query.HasPrometheusRuleDefinition != nil { + // Need Metadata for this filter + opts.ExcludeMetadata = false + } + } + // Process rules and implement per-group pagination var groupsFetched int64 var rulesFetched int64 @@ -632,12 +670,7 @@ func (st DBstore) ListAlertRulesByGroup(ctx context.Context, query *ngmodels.Lis continue } - var converted ngmodels.AlertRule - if query.Compact { - converted, err = alertRuleToModelsAlertRuleCompact(*rule, st.Logger) - } else { - converted, err = alertRuleToModelsAlertRule(*rule, st.Logger) - } + converted, err := convertAlertRuleToModel(*rule, st.Logger, opts) if err != nil { st.Logger.Error("Invalid rule found in DB store, cannot convert, ignoring it", "func", "ListAlertRulesByGroup", "error", err) diff --git a/pkg/services/ngalert/store/alert_rule_test.go b/pkg/services/ngalert/store/alert_rule_test.go index 91db9edc32a..29b82f943ba 100644 --- a/pkg/services/ngalert/store/alert_rule_test.go +++ b/pkg/services/ngalert/store/alert_rule_test.go @@ -1727,6 +1727,55 @@ func TestIntegrationGetRuleVersions(t *testing.T) { }) } +func TestIntegrationGetAlertRuleVersionFolders(t *testing.T) { + tutil.SkipIntegrationTestInShortMode(t) + + // Setup. + cfg := setting.NewCfg() + cfg.UnifiedAlerting = setting.UnifiedAlertingSettings{BaseInterval: time.Duration(rand.Int64N(100)+1) * time.Second} + sqlStore := db.InitTestDB(t) + folderService := setupFolderService(t, sqlStore, cfg, featuremgmt.WithFeatures()) + b := &fakeBus{} + store := createTestStore(sqlStore, folderService, &logtest.Fake{}, cfg.UnifiedAlerting, b) + orgID := int64(1) + gen := models.RuleGen + gen = gen.With(gen.WithIntervalMatching(store.Cfg.BaseInterval), gen.WithOrgID(orgID), gen.WithVersion(1)) + + inserted, err := store.InsertAlertRules(context.Background(), &models.AlertingUserUID, []models.InsertRule{{AlertRule: gen.Generate()}}) + require.NoError(t, err) + ruleV1, err := store.GetAlertRuleByUID(context.Background(), &models.GetAlertRuleByUIDQuery{UID: inserted[0].UID}) + require.NoError(t, err) + + oldRule := ruleV1 + updatedRule := ruleV1 + updateRule := func(title string, folderUID string) { + oldRule = updatedRule + updatedRule = models.CopyRule(oldRule, gen.WithTitle(title), gen.WithNamespaceUID(folderUID)) + require.NoError(t, store.UpdateAlertRules(context.Background(), &models.AlertingUserUID, []models.UpdateRule{{Existing: oldRule, New: *updatedRule}})) + updatedRule.Version++ // Simulate version increment after update to avoid conflict errors. + } + + // Update rule a couple of times to create versions. + originalFolder := oldRule.NamespaceUID + updateRule(util.GenerateShortUID(), originalFolder) + updateRule(util.GenerateShortUID(), "newfolder-1") + updateRule(util.GenerateShortUID(), "newfolder-2") + updateRule(util.GenerateShortUID(), "newfolder-2") + updateRule(util.GenerateShortUID(), originalFolder) + updateRule(util.GenerateShortUID(), "current-folder") + + t.Run("should return rule versions folders sorted in decreasing order", func(t *testing.T) { + historicalFolders, err := store.GetAlertRuleVersionFolders(context.Background(), updatedRule.OrgID, updatedRule.GUID) + require.NoError(t, err) + assert.Equal(t, []string{ // Return folders with more recent first. + "current-folder", + originalFolder, + "newfolder-2", + "newfolder-1", + }, historicalFolders) + }) +} + // createAlertRule creates an alert rule in the database and returns it. // If a generator is not specified, uniqueness of primary key is not guaranteed. func createRule(tb testing.TB, store *DBstore, generator *models.AlertRuleGenerator) *models.AlertRule { diff --git a/pkg/services/ngalert/store/compat.go b/pkg/services/ngalert/store/compat.go index fbb69addc72..57dcf411853 100644 --- a/pkg/services/ngalert/store/compat.go +++ b/pkg/services/ngalert/store/compat.go @@ -15,22 +15,23 @@ type compactQuery struct { DatasourceUID string `json:"datasourceUid"` } -func alertRuleToModelsAlertRule(ar alertRule, l log.Logger) (models.AlertRule, error) { - return convertAlertRuleToModel(ar, l, false) +// AlertRuleConvertOptions controls which fields to parse during conversion from alertRule to models.AlertRule. +// By default all fields are included. Set Exclude* to true to skip parsing expensive fields. +type AlertRuleConvertOptions struct { + ExcludeAlertQueries bool // Only parse datasource UIDs from queries + ExcludeNotificationSettings bool + ExcludeMetadata bool } -// alertRuleToModelsAlertRuleCompact transforms an alertRule to a models.AlertRule -// ignoring alert queries (except for data source UIDs), notification settings, and metadata. -func alertRuleToModelsAlertRuleCompact(ar alertRule, l log.Logger) (models.AlertRule, error) { - return convertAlertRuleToModel(ar, l, true) +func alertRuleToModelsAlertRule(ar alertRule, l log.Logger) (models.AlertRule, error) { + return convertAlertRuleToModel(ar, l, AlertRuleConvertOptions{}) } // convertAlertRuleToModel creates a models.AlertRule from an alertRule. -// When 'compact' is set to 'true', it skips parsing the alert queries (except for the data source UID), notification -// settings, and metadata, thus reducing the number of JSON serializations needed. -func convertAlertRuleToModel(ar alertRule, l log.Logger, compact bool) (models.AlertRule, error) { +// opts.Exclude* fields control which expensive fields to skip parsing, reducing JSON serializations. +func convertAlertRuleToModel(ar alertRule, l log.Logger, opts AlertRuleConvertOptions) (models.AlertRule, error) { var data []models.AlertQuery - if compact { + if opts.ExcludeAlertQueries { var cqs []compactQuery if err := json.Unmarshal([]byte(ar.Data), &cqs); err != nil { return models.AlertRule{}, fmt.Errorf("failed to parse data: %w", err) @@ -118,7 +119,7 @@ func convertAlertRuleToModel(ar alertRule, l log.Logger, compact bool) (models.A } } - if !compact && ar.NotificationSettings != "" { + if !opts.ExcludeNotificationSettings && ar.NotificationSettings != "" { ns, err := parseNotificationSettings(ar.NotificationSettings) if err != nil { return models.AlertRule{}, fmt.Errorf("failed to parse notification settings: %w", err) @@ -126,7 +127,7 @@ func convertAlertRuleToModel(ar alertRule, l log.Logger, compact bool) (models.A result.NotificationSettings = ns } - if !compact && ar.Metadata != "" { + if !opts.ExcludeMetadata && ar.Metadata != "" { err = json.Unmarshal([]byte(ar.Metadata), &result.Metadata) if err != nil { return models.AlertRule{}, fmt.Errorf("failed to metadata: %w", err) diff --git a/pkg/services/ngalert/store/compat_test.go b/pkg/services/ngalert/store/compat_test.go index ef80f51d668..d4aab40931f 100644 --- a/pkg/services/ngalert/store/compat_test.go +++ b/pkg/services/ngalert/store/compat_test.go @@ -84,7 +84,11 @@ func TestAlertRuleToModelsAlertRuleCompact(t *testing.T) { Metadata: `{"editor_settings":{"simplified_query_and_expressions_section":true}}`, } - compactResult, err := alertRuleToModelsAlertRuleCompact(rule, &logtest.Fake{}) + compactResult, err := convertAlertRuleToModel(rule, &logtest.Fake{}, AlertRuleConvertOptions{ + ExcludeAlertQueries: true, + ExcludeNotificationSettings: true, + ExcludeMetadata: true, + }) require.NoError(t, err) // Should have datasource UIDs. @@ -142,6 +146,82 @@ func TestAlertRuleToModelsAlertRuleCompact(t *testing.T) { // Should have metadata (metadata is parsed from JSON to struct). require.NotEqual(t, ngmodels.AlertRuleMetadata{}, fullResult.Metadata) }) + + t.Run("compact mode with notification settings included for filtering", func(t *testing.T) { + rule := alertRule{ + ID: 1, + OrgID: 1, + UID: "test-uid", + Title: "Test Rule", + Condition: "A", + Data: `[{"datasourceUid":"ds1","refId":"A","queryType":"test","model":{"expr":"up"}}]`, + IntervalSeconds: 60, + Version: 1, + NamespaceUID: "ns-uid", + RuleGroup: "test-group", + NoDataState: "NoData", + ExecErrState: "Error", + NotificationSettings: `[{"receiver":"test-receiver"}]`, + Metadata: `{"editor_settings":{"simplified_query_and_expressions_section":true}}`, + } + + result, err := convertAlertRuleToModel(rule, &logtest.Fake{}, AlertRuleConvertOptions{ + ExcludeAlertQueries: true, + ExcludeNotificationSettings: false, + ExcludeMetadata: true, + }) + require.NoError(t, err) + + // Should have compact query data (only datasource UIDs). + require.Len(t, result.Data, 1) + require.Equal(t, "ds1", result.Data[0].DatasourceUID) + require.Empty(t, result.Data[0].RefID) + + // Should have notification settings for filtering. + require.Len(t, result.NotificationSettings, 1) + require.Equal(t, "test-receiver", result.NotificationSettings[0].Receiver) + + // Should not have metadata. + require.Equal(t, ngmodels.AlertRuleMetadata{}, result.Metadata) + }) + + t.Run("compact mode with metadata included for filtering", func(t *testing.T) { + rule := alertRule{ + ID: 1, + OrgID: 1, + UID: "test-uid", + Title: "Test Rule", + Condition: "A", + Data: `[{"datasourceUid":"ds1","refId":"A","queryType":"test","model":{"expr":"up"}}]`, + IntervalSeconds: 60, + Version: 1, + NamespaceUID: "ns-uid", + RuleGroup: "test-group", + NoDataState: "NoData", + ExecErrState: "Error", + NotificationSettings: `[{"receiver":"test-receiver"}]`, + Metadata: `{"prometheus_style_rule":{"original_rule_definition":"alert: TestAlert\n expr: rate(metric[5m]) > 1"}}`, + } + + result, err := convertAlertRuleToModel(rule, &logtest.Fake{}, AlertRuleConvertOptions{ + ExcludeAlertQueries: true, + ExcludeNotificationSettings: true, + ExcludeMetadata: false, + }) + require.NoError(t, err) + + // Should have compact query data (only datasource UIDs). + require.Len(t, result.Data, 1) + require.Equal(t, "ds1", result.Data[0].DatasourceUID) + require.Empty(t, result.Data[0].RefID) + + // Should not have notification settings. + require.Empty(t, result.NotificationSettings) + + // Should have metadata for filtering. + require.NotEqual(t, ngmodels.AlertRuleMetadata{}, result.Metadata) + require.True(t, result.HasPrometheusRuleDefinition()) + }) } func TestAlertRuleVersionToAlertRule(t *testing.T) { diff --git a/pkg/services/ngalert/store/instance_database.go b/pkg/services/ngalert/store/instance_database.go index a9d57d1ab8f..cc385ef4c63 100644 --- a/pkg/services/ngalert/store/instance_database.go +++ b/pkg/services/ngalert/store/instance_database.go @@ -364,10 +364,10 @@ func (st InstanceDBStore) insertInstancesBatch(sess *sqlstore.DBSession, batch [ query := strings.Builder{} placeholders := make([]string, 0, len(batch)) - args := make([]any, 0, len(batch)*13) + args := make([]any, 0, len(batch)*14) query.WriteString("INSERT INTO alert_instance ") - query.WriteString("(rule_org_id, rule_uid, labels, labels_hash, current_state, current_reason, current_state_since, current_state_end, last_eval_time, fired_at, resolved_at, last_sent_at, annotations) VALUES ") + query.WriteString("(rule_org_id, rule_uid, labels, labels_hash, current_state, current_reason, current_state_since, current_state_end, last_eval_time, fired_at, resolved_at, last_sent_at, result_fingerprint, annotations) VALUES ") for _, instance := range batch { if err := models.ValidateAlertInstance(instance); err != nil { @@ -387,7 +387,7 @@ func (st InstanceDBStore) insertInstancesBatch(sess *sqlstore.DBSession, batch [ continue } - placeholders = append(placeholders, "(?,?,?,?,?,?,?,?,?,?,?,?,?)") + placeholders = append(placeholders, "(?,?,?,?,?,?,?,?,?,?,?,?,?,?)") args = append(args, instance.RuleOrgID, instance.RuleUID, @@ -401,6 +401,7 @@ func (st InstanceDBStore) insertInstancesBatch(sess *sqlstore.DBSession, batch [ nullableTimeToUnix(instance.FiredAt), nullableTimeToUnix(instance.ResolvedAt), nullableTimeToUnix(instance.LastSentAt), + instance.ResultFingerprint, annotationsJSON, ) } diff --git a/pkg/services/ngalert/store/instance_database_test.go b/pkg/services/ngalert/store/instance_database_test.go index 3cf264d4a36..4f833d0fd17 100644 --- a/pkg/services/ngalert/store/instance_database_test.go +++ b/pkg/services/ngalert/store/instance_database_test.go @@ -8,6 +8,8 @@ import ( "time" "github.com/golang/snappy" + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" "github.com/grafana/grafana/pkg/util/testutil" "github.com/stretchr/testify/require" "google.golang.org/protobuf/proto" @@ -391,27 +393,33 @@ func TestIntegrationFullSync(t *testing.T) { t.Run("Should save all instances when batch size is bigger than 1", func(t *testing.T) { batchSize = 2 - newRuleUID := "y" - err := ng.InstanceStore.FullSync(ctx, append(instances, *models.AlertInstanceGen(models.InstanceMuts.WithOrgID(orgID), models.InstanceMuts.WithRuleUID(newRuleUID))), batchSize, nil) + testInstances := []models.AlertInstance{ + *models.AlertInstanceGen(models.InstanceMuts.WithOrgID(orgID), models.InstanceMuts.WithRuleUID("batch1"), models.InstanceMuts.WithResultFingerprint("fp0")), + *models.AlertInstanceGen(models.InstanceMuts.WithOrgID(orgID), models.InstanceMuts.WithRuleUID("batch2"), models.InstanceMuts.WithResultFingerprint("fp1")), + *models.AlertInstanceGen(models.InstanceMuts.WithOrgID(orgID), models.InstanceMuts.WithRuleUID("batch3"), models.InstanceMuts.WithResultFingerprint("fp2")), + } + + err := ng.InstanceStore.FullSync(ctx, testInstances, batchSize, nil) require.NoError(t, err) res, err := ng.InstanceStore.ListAlertInstances(ctx, &models.ListAlertInstancesQuery{ RuleOrgID: orgID, }) require.NoError(t, err) - require.Len(t, res, len(instances)+1) - for _, ruleUID := range append(ruleUIDs, newRuleUID) { - found := false - for _, instance := range res { - if instance.RuleUID == ruleUID { - found = true - continue - } - } - if !found { - t.Errorf("Instance with RuleUID '%s' not found", ruleUID) - } + + savedInstances := make([]models.AlertInstance, len(res)) + for i, r := range res { + savedInstances[i] = *r } + + opts := []cmp.Option{ + cmpopts.EquateApproxTime(time.Second), // we don't get the same precision back from the DB + cmpopts.EquateEmpty(), + cmpopts.SortSlices(func(a, b models.AlertInstance) bool { + return a.RuleUID < b.RuleUID + }), + } + require.Empty(t, cmp.Diff(testInstances, savedInstances, opts...)) }) t.Run("Should not fail when the instances are empty", func(t *testing.T) { diff --git a/pkg/services/ngalert/tests/fakes/rules.go b/pkg/services/ngalert/tests/fakes/rules.go index 42e30ddb052..f4b5afb282d 100644 --- a/pkg/services/ngalert/tests/fakes/rules.go +++ b/pkg/services/ngalert/tests/fakes/rules.go @@ -2,6 +2,7 @@ package fakes import ( "context" + "maps" "math/rand" "slices" "strings" @@ -612,6 +613,30 @@ func (f *RuleStore) GetAlertRuleVersions(_ context.Context, orgID int64, guid st return f.History[guid], nil } +func (f *RuleStore) GetAlertRuleVersionFolders(_ context.Context, orgID int64, guid string) ([]string, error) { + f.mtx.Lock() + defer f.mtx.Unlock() + + q := GenericRecordedQuery{ + Name: "GetAlertRuleVersionFolders", + Params: []any{orgID, guid}, + } + defer func() { + f.RecordedOps = append(f.RecordedOps, q) + }() + + if err := f.Hook(q); err != nil { + return nil, err + } + + folderSet := make(map[string]struct{}) + for _, rule := range f.History[guid] { + folderSet[rule.NamespaceUID] = struct{}{} + } + + return slices.Collect(maps.Keys(folderSet)), nil +} + func (f *RuleStore) ListDeletedRules(_ context.Context, orgID int64) ([]*models.AlertRule, error) { f.mtx.Lock() defer f.mtx.Unlock() diff --git a/pkg/services/pluginsintegration/installsync/syncer.go b/pkg/services/pluginsintegration/installsync/syncer.go index 6352f7900fa..7c483d21d01 100644 --- a/pkg/services/pluginsintegration/installsync/syncer.go +++ b/pkg/services/pluginsintegration/installsync/syncer.go @@ -217,7 +217,6 @@ func (s *syncer) syncNamespace(ctx context.Context, namespace string, source ins err := s.installRegistrar.Register(ctx, namespace, &install.PluginInstall{ ID: p.ID, Version: p.Info.Version, - Class: install.Class(p.Class), Source: source, }) if err != nil { diff --git a/pkg/services/pluginsintegration/pluginstore/plugins.go b/pkg/services/pluginsintegration/pluginstore/plugins.go index 8dccc2c3522..f4504d254c5 100644 --- a/pkg/services/pluginsintegration/pluginstore/plugins.go +++ b/pkg/services/pluginsintegration/pluginstore/plugins.go @@ -17,6 +17,7 @@ type Plugin struct { // App fields Parent *ParentPlugin + Children []string IncludedInAppID string DefaultNavURL string Pinned bool @@ -85,6 +86,18 @@ func ToGrafanaDTO(p *plugins.Plugin) Plugin { dto.Parent = &ParentPlugin{ID: p.Parent.ID} } + if len(p.Children) > 0 { + children := make([]string, 0, len(p.Children)) + for _, child := range p.Children { + if child != nil { + children = append(children, child.ID) + } + } + if len(children) > 0 { + dto.Children = children + } + } + return dto } diff --git a/pkg/services/sqlstore/migrations/accesscontrol/alerting.go b/pkg/services/sqlstore/migrations/accesscontrol/alerting.go index f9942fac80e..deddf59eb12 100644 --- a/pkg/services/sqlstore/migrations/accesscontrol/alerting.go +++ b/pkg/services/sqlstore/migrations/accesscontrol/alerting.go @@ -116,3 +116,49 @@ func (m *receiverCreateScopeMigration) Exec(sess *xorm.Session, mg *migrator.Mig func AddReceiverCreateScopeMigration(mg *migrator.Migrator) { mg.AddMigration("remove scope from alert.notifications.receivers:create", &receiverCreateScopeMigration{}) } + +type receiverProtectedFieldsEditor struct { + migrator.MigrationBase +} + +var _ migrator.CodeMigration = new(alertingMigrator) + +func (m *receiverProtectedFieldsEditor) SQL(migrator.Dialect) string { + return "code migration" +} + +func (m *receiverProtectedFieldsEditor) Exec(sess *xorm.Session, mg *migrator.Migrator) error { + sql := `SELECT * + FROM permission AS P + WHERE action = 'alert.notifications.receivers.secrets:read' + AND EXISTS(SELECT 1 FROM role AS R WHERE R.id = P.role_id AND R.name LIKE 'managed:%') + AND NOT EXISTS(SELECT 1 + FROM permission AS P2 + WHERE P2.role_id = P.role_id + AND P2.action = 'alert.notifications.receivers.protected:write' AND P2.scope = P.scope + )` + var results []accesscontrol.Permission + if err := sess.SQL(sql).Find(&results); err != nil { + return fmt.Errorf("failed to query permissions: %w", err) + } + + permissionsToCreate := make([]accesscontrol.Permission, 0, len(results)) + rolesAffected := make(map[int64][]string, 0) + for _, result := range results { + result.ID = 0 + result.Action = "alert.notifications.receivers.protected:write" + result.Created = time.Now() + result.Updated = time.Now() + permissionsToCreate = append(permissionsToCreate, result) + rolesAffected[result.RoleID] = append(rolesAffected[result.RoleID], result.Identifier) + } + _, err := sess.InsertMulti(&permissionsToCreate) + for id, ids := range rolesAffected { + mg.Logger.Debug("Added permission 'alert.notifications.receivers.protected:write' to managed role", "roleID", id, "identifiers", ids) + } + return err +} + +func AddReceiverProtectedFieldsEditor(mg *migrator.Migrator) { + mg.AddMigration("add 'alert.notifications.receivers.protected:write' to receiver admins", &receiverProtectedFieldsEditor{}) +} diff --git a/pkg/services/sqlstore/migrations/cloud_migrations.go b/pkg/services/sqlstore/migrations/cloud_migrations.go index 7a602bf7d42..c6240037d04 100644 --- a/pkg/services/sqlstore/migrations/cloud_migrations.go +++ b/pkg/services/sqlstore/migrations/cloud_migrations.go @@ -198,10 +198,11 @@ func addCloudMigrationsMigrations(mg *Migrator) { Postgres("ALTER TABLE cloud_migration_resource ALTER COLUMN resource_uid TYPE VARCHAR(255);")) mg.AddMigration("create cloud_migration_snapshot_partition table v1", NewAddTableMigration(migrationSnapshotPartitionTable)) - mg.AddMigration("add cloud_migration_snapshot_partition srp_unique index", NewAddIndexMigration(migrationSnapshotPartitionTable, &Index{ + srpUniqueIndex := Index{ Name: "srp_unique", Cols: []string{"snapshot_uid", "resource_type", "partition_number"}, Type: UniqueIndex, - })) + } + mg.AddMigration("add cloud_migration_snapshot_partition srp_unique index", NewAddIndexMigration(migrationSnapshotPartitionTable, &srpUniqueIndex)) mg.AddMigration("add resource_storage_type column to cloud_migration_snapshot table", NewAddColumnMigration(migrationSnapshotTable, &Column{ Name: "resource_storage_type", Type: DB_Varchar, @@ -224,4 +225,16 @@ func addCloudMigrationsMigrations(mg *Migrator) { Type: DB_Blob, Nullable: true, })) + + updatedCloudMigrationSnapshotPartitionTable := Table{ + Name: "cloud_migration_snapshot_partition", + Columns: []*Column{ + {Name: "snapshot_uid", Type: DB_NVarchar, Length: 40, Nullable: false, IsPrimaryKey: true}, + {Name: "partition_number", Type: DB_Int, Nullable: false, IsPrimaryKey: true}, + {Name: "resource_type", Type: DB_Varchar, Length: 255, Nullable: false, IsPrimaryKey: true}, + {Name: "data", Type: DB_LongBlob, Nullable: false}, + }, + PrimaryKeys: []string{"snapshot_uid", "resource_type", "partition_number"}, + } + ConvertUniqueKeyToPrimaryKey(mg, srpUniqueIndex, updatedCloudMigrationSnapshotPartitionTable) } diff --git a/pkg/services/sqlstore/migrations/db_file_storage.go b/pkg/services/sqlstore/migrations/db_file_storage.go index e8ca9348455..c44344307ac 100644 --- a/pkg/services/sqlstore/migrations/db_file_storage.go +++ b/pkg/services/sqlstore/migrations/db_file_storage.go @@ -91,7 +91,7 @@ func convertFilePathHashIndexToPrimaryKey(mg *migrator.Migrator) { mg.AddMigration("drop file_path unique index from file table if it exists (mysql)", mysqlMigration2) mysqlMigration3 := migrator.NewRawSQLMigration("").Mysql(`ALTER TABLE file ADD PRIMARY KEY (path_hash);`) - mysqlMigration3.Condition = &migrator.IfPrimaryKeyNotExistsCondition{TableName: "file", ColumnName: "path_hash"} + mysqlMigration3.Condition = &migrator.IfPrimaryKeyNotExistsCondition{TableName: "file"} mg.AddMigration("add primary key to file table if it doesn't exist (mysql)", mysqlMigration3) postgres := ` @@ -162,7 +162,7 @@ func convertFileMetaPathHashKeyIndexToPrimaryKey(mg *migrator.Migrator) { mg.AddMigration("drop file_path unique index from file_meta table if it exists (mysql)", mysqlMigration2) mysqlMigration3 := migrator.NewRawSQLMigration("").Mysql(`ALTER TABLE file_meta ADD PRIMARY KEY (path_hash, ` + "`key`" + `);`) - mysqlMigration3.Condition = &migrator.IfPrimaryKeyNotExistsCondition{TableName: "file_meta", ColumnName: "path_hash"} + mysqlMigration3.Condition = &migrator.IfPrimaryKeyNotExistsCondition{TableName: "file_meta"} mg.AddMigration("add primary key to file_meta table if it doesn't exist (mysql)", mysqlMigration3) postgres := ` diff --git a/pkg/services/sqlstore/migrations/migrations.go b/pkg/services/sqlstore/migrations/migrations.go index 9f0191dc9ff..17dd7b9c068 100644 --- a/pkg/services/sqlstore/migrations/migrations.go +++ b/pkg/services/sqlstore/migrations/migrations.go @@ -168,4 +168,6 @@ func (oss *OSSMigrations) AddMigration(mg *Migrator) { ualert.CollateBinAlertRuleNamespace(mg) ualert.CollateBinAlertRuleGroup(mg) + + accesscontrol.AddReceiverProtectedFieldsEditor(mg) } diff --git a/pkg/services/sqlstore/migrator/dialect.go b/pkg/services/sqlstore/migrator/dialect.go index bec421e36e2..d75f87989f7 100644 --- a/pkg/services/sqlstore/migrator/dialect.go +++ b/pkg/services/sqlstore/migrator/dialect.go @@ -7,6 +7,7 @@ import ( "strconv" "strings" + "github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/services/sqlstore/session" "github.com/grafana/grafana/pkg/util/xorm" ) @@ -77,7 +78,7 @@ type Dialect interface { // CreateDatabaseFromSnapshot is called when migration log table is not found. // Dialect can recreate all tables from existing snapshot. After successful (nil error) return, // migrator will list migrations from the log, and apply all missing migrations. - CreateDatabaseFromSnapshot(ctx context.Context, engine *xorm.Engine, migrationLogTableName string) error + CreateDatabaseFromSnapshot(ctx context.Context, engine *xorm.Engine, migrationLogTableName string, logger log.Logger) error IsUniqueConstraintViolation(err error) bool ErrorMessage(err error) string @@ -253,7 +254,7 @@ func (b *BaseDialect) CopyTableData(sourceTable string, targetTable string, sour targetColsSQL := b.QuoteColList(targetCols) quote := b.dialect.Quote - return fmt.Sprintf("INSERT INTO %s (%s) SELECT %s FROM %s", quote(targetTable), targetColsSQL, sourceColsSQL, quote(sourceTable)) + return fmt.Sprintf("INSERT INTO %s (%s)\nSELECT %s\nFROM %s", quote(targetTable), targetColsSQL, sourceColsSQL, quote(sourceTable)) } func (b *BaseDialect) DropTable(tableName string) string { @@ -355,7 +356,7 @@ func (b *BaseDialect) CleanDB(engine *xorm.Engine) error { return nil } -func (b *BaseDialect) CreateDatabaseFromSnapshot(ctx context.Context, engine *xorm.Engine, tableName string) error { +func (b *BaseDialect) CreateDatabaseFromSnapshot(ctx context.Context, engine *xorm.Engine, migrationLogTableName string, logger log.Logger) error { return nil } diff --git a/pkg/services/sqlstore/migrator/migrations.go b/pkg/services/sqlstore/migrator/migrations.go index b785fd867d5..ebc9573d111 100644 --- a/pkg/services/sqlstore/migrator/migrations.go +++ b/pkg/services/sqlstore/migrator/migrations.go @@ -1,6 +1,8 @@ package migrator import ( + "fmt" + "slices" "strings" ) @@ -271,3 +273,155 @@ func NewTableCharsetMigration(tableName string, columns []*Column) *TableCharset func (m *TableCharsetMigration) SQL(d Dialect) string { return d.UpdateTableSQL(m.tableName, m.columns) } + +type addPrimaryKeyMigration struct { + MigrationBase + tableName string + uniqueKey Index + + // Used for Sqlite recreation of the table. Temporary table will have tableName + "_new" suffix. + table Table +} + +func (m *addPrimaryKeyMigration) SQL(d Dialect) string { + if d.DriverName() == SQLite { + // Final SQL will do following in the individual statements: + // 1. Create new temporary table + // 2. Copy data from old table to temporary table + // 3. Drop old table, rename temporary table to original name + // 4. Recreate indexes for table. + // + // For example: + // + // CREATE TABLE file_new + // ( + // path TEXT NOT NULL, + // path_hash TEXT NOT NULL, + // parent_folder_path_hash TEXT NOT NULL, + // contents BLOB NOT NULL, + // etag TEXT NOT NULL, + // cache_control TEXT NOT NULL, + // content_disposition TEXT NOT NULL, + // updated DATETIME NOT NULL, + // created DATETIME NOT NULL, + // size INTEGER NOT NULL, + // mime_type TEXT NOT NULL, + // + // PRIMARY KEY (path_hash) + // ); + // + // INSERT INTO file_new (path, path_hash, parent_folder_path_hash, contents, etag, cache_control, content_disposition, updated, created, size, mime_type) + // SELECT path, path_hash, parent_folder_path_hash, contents, etag, cache_control, content_disposition, updated, created, size, mime_type FROM file; + // + // DROP TABLE file; + // ALTER TABLE file_new RENAME TO file; + // + // CREATE INDEX IDX_file_parent_folder_path_hash ON file (parent_folder_path_hash); + + tempTable := m.table + tempTable.Name = m.tableName + "_new" + + statements := strings.Builder{} + + statements.WriteString(d.CreateTableSQL(&tempTable)) + statements.WriteString("\n") // CreateTableSQL adds semicolon + + cols := make([]string, 0, len(tempTable.Columns)) + for _, col := range tempTable.Columns { + cols = append(cols, col.Name) + } + statements.WriteString(d.CopyTableData(m.tableName, tempTable.Name, cols, cols)) + statements.WriteString(";\n") + + statements.WriteString(d.DropTable(m.tableName)) + statements.WriteString(";\n") + + statements.WriteString(d.RenameTable(tempTable.Name, m.tableName)) + statements.WriteString(";\n") + + for _, idx := range tempTable.Indices { + // Use real table name, not temporary one now + statements.WriteString(d.CreateIndexSQL(m.tableName, idx)) + statements.WriteString("\n") // CreateIndexSQL adds semicolon + } + + return statements.String() + } else if d.DriverName() == Postgres { + quotesCols := make([]string, 0, len(m.uniqueKey.Cols)) + for _, c := range m.uniqueKey.Cols { + quotesCols = append(quotesCols, d.Quote(c)) + } + + return fmt.Sprintf(` + DO $$ + BEGIN + -- Drop the unique constraint if it exists + DROP INDEX IF EXISTS %s; + + -- Add primary key if it doesn't already exist + IF NOT EXISTS (SELECT 1 FROM pg_index i WHERE indrelid = '%s'::regclass AND indisprimary) THEN + ALTER TABLE %s ADD PRIMARY KEY (%s); + END IF; + END $$;`, d.Quote(m.uniqueKey.XName(m.tableName)), m.tableName, d.Quote(m.tableName), strings.Join(quotesCols, ",")) + } else { + return "" + } +} + +// ConvertUniqueKeyToPrimaryKey adds series of migrations to convert existing unique key to PRIMARY KEY. +// For Sqlite this means recreating the table, which only works if there are no foreign keys referencing the table. +func ConvertUniqueKeyToPrimaryKey(mg *Migrator, uniqueKey Index, finalTable Table) { + tableName := finalTable.Name + if tableName == "" { + panic("invalid table name") + } + if len(uniqueKey.Cols) == 0 || uniqueKey.Type != UniqueIndex { + panic("invalid unique type") + } + if !slices.Equal(uniqueKey.Cols, finalTable.PrimaryKeys) { + panic("invalid primary key in the final table") + } + + colPks := map[string]bool{} + for _, col := range finalTable.Columns { + if col.IsPrimaryKey { + colPks[col.Name] = true + } + } + for _, c := range uniqueKey.Cols { + if !colPks[c] { + panic(fmt.Sprintf("column %s is not part of primary key in the table definition", c)) + } + } + + columnsList := strings.Join(uniqueKey.Cols, ",") + + mysqlQuote := NewDialect(MySQL).Quote + mysqlQuotedColumns := make([]string, 0, len(uniqueKey.Cols)) + for _, col := range uniqueKey.Cols { + mysqlQuotedColumns = append(mysqlQuotedColumns, mysqlQuote(col)) + } + + // migration 1 is to handle cases where the table was created with sql_generate_invisible_primary_key = ON + // in this case we need to do the conversion in one sql statement + mysqlMigration1 := NewRawSQLMigration("").Mysql(fmt.Sprintf(` + ALTER TABLE %s + DROP PRIMARY KEY, + DROP COLUMN my_row_id, + DROP INDEX %s, + ADD PRIMARY KEY (%s); + `, tableName, uniqueKey.XName(tableName), strings.Join(mysqlQuotedColumns, ","))) + mysqlMigration1.Condition = &IfColumnExistsCondition{TableName: tableName, ColumnName: "my_row_id"} + mg.AddMigration(fmt.Sprintf("drop my_row_id and add primary key with columns %s to table %s if my_row_id exists (auto-generated mysql column)", columnsList, tableName), mysqlMigration1) + + mysqlMigration2 := NewRawSQLMigration("").Mysql(fmt.Sprintf(`ALTER TABLE %s DROP INDEX %s`, tableName, uniqueKey.XName(tableName))) + mysqlMigration2.Condition = &IfIndexExistsCondition{TableName: tableName, IndexName: uniqueKey.XName(tableName)} + mg.AddMigration(fmt.Sprintf("drop unique index %s from %s table if it exists (mysql)", uniqueKey.XName(tableName), tableName), mysqlMigration2) + + mysqlMigration3 := NewRawSQLMigration("").Mysql(fmt.Sprintf(`ALTER TABLE %s ADD PRIMARY KEY (%s)`, tableName, strings.Join(mysqlQuotedColumns, ","))) + mysqlMigration3.Condition = &IfPrimaryKeyNotExistsCondition{TableName: tableName} + mg.AddMigration(fmt.Sprintf("add primary key with columns %s to table %s if it doesn't exist (mysql)", columnsList, tableName), mysqlMigration3) + + // postgres and sqlite statements are idempotent so we can have only one condition-less migration + mg.AddMigration(fmt.Sprintf("add primary key with columns %s to table %s (postgres and sqlite)", columnsList, tableName), &addPrimaryKeyMigration{tableName: tableName, uniqueKey: uniqueKey, table: finalTable}) +} diff --git a/pkg/services/sqlstore/migrator/migrations_test.go b/pkg/services/sqlstore/migrator/migrations_test.go new file mode 100644 index 00000000000..ebf7c4f48f6 --- /dev/null +++ b/pkg/services/sqlstore/migrator/migrations_test.go @@ -0,0 +1,79 @@ +package migrator + +import ( + _ "embed" + "testing" + + "github.com/stretchr/testify/require" +) + +//go:embed testdata/sqlite_file_migration_statement.sql +var sqliteMigrationStatement string + +func TestConvertUniqueKeyToPrimaryKey(t *testing.T) { + names := []string{ + "drop my_row_id and add primary key with columns path_hash,etag to table file if my_row_id exists (auto-generated mysql column)", + "drop unique index UQE_file_path_hash_etag from file table if it exists (mysql)", + "add primary key with columns path_hash,etag to table file if it doesn't exist (mysql)", + "add primary key with columns path_hash,etag to table file (postgres and sqlite)", + } + expectedMigrations := map[string][]ExpectedMigration{ + MySQL: { + {Id: names[0], SQL: ` + ALTER TABLE file + DROP PRIMARY KEY, + DROP COLUMN my_row_id, + DROP INDEX UQE_file_path_hash_etag, + ADD PRIMARY KEY (` + "`path_hash`" + `,` + "`etag`" + `);`}, + {Id: names[1], SQL: "ALTER TABLE file DROP INDEX UQE_file_path_hash_etag"}, + {Id: names[2], SQL: "ALTER TABLE file ADD PRIMARY KEY (`path_hash`,`etag`)"}, + {Id: names[3], SQL: ""}, + }, + Postgres: { + {Id: names[0], SQL: ""}, + {Id: names[1], SQL: ""}, + {Id: names[2], SQL: ""}, + {Id: names[3], SQL: ` + DO $$ + BEGIN + -- Drop the unique constraint if it exists + DROP INDEX IF EXISTS "UQE_file_path_hash_etag"; + + -- Add primary key if it doesn't already exist + IF NOT EXISTS (SELECT 1 FROM pg_index i WHERE indrelid = 'file'::regclass AND indisprimary) THEN + ALTER TABLE "file" ADD PRIMARY KEY ("path_hash","etag"); + END IF; + END $$;`}, + }, + SQLite: { + {Id: names[0], SQL: ""}, + {Id: names[1], SQL: ""}, + {Id: names[2], SQL: ""}, + {Id: names[3], SQL: sqliteMigrationStatement}, // Embed used here because sqlite statement is full of backquotes. + }, + } + + for dialectName, migrations := range expectedMigrations { + t.Run(dialectName, func(t *testing.T) { + err := CheckExpectedMigrations(dialectName, migrations, func(migrator *Migrator) { + ConvertUniqueKeyToPrimaryKey(migrator, + Index{Cols: []string{"path_hash", "etag"}, Type: UniqueIndex}, // Convert this unique key to primary key + Table{ + Name: "file", + Columns: []*Column{ + {Name: "path", Type: DB_NVarchar, Length: 1024, Nullable: false}, + {Name: "path_hash", Type: DB_NVarchar, Length: 64, Nullable: false, IsPrimaryKey: true}, + {Name: "parent_folder_path_hash", Type: DB_NVarchar, Length: 64, Nullable: false}, + {Name: "contents", Type: DB_Blob, Nullable: false}, + {Name: "etag", Type: DB_NVarchar, Length: 32, Nullable: false, IsPrimaryKey: true}, + }, + PrimaryKeys: []string{"path_hash", "etag"}, + Indices: []*Index{ + {Cols: []string{"parent_folder_path_hash"}}, + }, + }) + }) + require.NoError(t, err) + }) + } +} diff --git a/pkg/services/sqlstore/migrator/migrator.go b/pkg/services/sqlstore/migrator/migrator.go index 75ebf8e540b..ca921affdac 100644 --- a/pkg/services/sqlstore/migrator/migrator.go +++ b/pkg/services/sqlstore/migrator/migrator.go @@ -8,7 +8,6 @@ import ( _ "github.com/go-sql-driver/mysql" "github.com/golang-migrate/migrate/v4/database" - "github.com/grafana/grafana/pkg/util/sqlite" _ "github.com/lib/pq" "github.com/prometheus/client_golang/prometheus" "go.opentelemetry.io/otel" @@ -17,6 +16,8 @@ import ( "go.opentelemetry.io/otel/trace" "go.uber.org/atomic" + "github.com/grafana/grafana/pkg/util/sqlite" + "github.com/grafana/grafana/pkg/util/xorm" "github.com/grafana/grafana/pkg/infra/log" @@ -67,12 +68,16 @@ func NewMigrator(engine *xorm.Engine, cfg *setting.Cfg) *Migrator { // NewScopedMigrator should only be used for the transition to a new storage engine func NewScopedMigrator(engine *xorm.Engine, cfg *setting.Cfg, scope string) *Migrator { + return newMigrator(engine, cfg, scope, NewDialect(engine.DriverName())) +} + +func newMigrator(engine *xorm.Engine, cfg *setting.Cfg, scope string, dialect Dialect) *Migrator { mg := &Migrator{ Cfg: cfg, DBEngine: engine, migrations: make([]Migration, 0), migrationIds: make(map[string]struct{}), - Dialect: NewDialect(engine.DriverName()), + Dialect: dialect, metrics: migratorMetrics{ migCount: prometheus.NewCounterVec(prometheus.CounterOpts{ Namespace: "grafana_database", @@ -245,7 +250,7 @@ func (mg *Migrator) run(ctx context.Context) (err error) { if !migrationLogExists { // Check if dialect can initialize database from a snapshot. - err := mg.Dialect.CreateDatabaseFromSnapshot(ctx, mg.DBEngine, mg.tableName) + err := mg.Dialect.CreateDatabaseFromSnapshot(ctx, mg.DBEngine, mg.tableName, logger) if err != nil { return fmt.Errorf("failed to create database from snapshot: %w", err) } diff --git a/pkg/services/sqlstore/migrator/mysql_dialect.go b/pkg/services/sqlstore/migrator/mysql_dialect.go index 5a76b4555ca..c356caa8f1c 100644 --- a/pkg/services/sqlstore/migrator/mysql_dialect.go +++ b/pkg/services/sqlstore/migrator/mysql_dialect.go @@ -1,15 +1,19 @@ package migrator import ( + "context" "database/sql" + "embed" "errors" "fmt" + "path" "strconv" "strings" "github.com/VividCortex/mysqlerr" "github.com/go-sql-driver/mysql" + "github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/util/xorm" ) @@ -317,3 +321,87 @@ func (db *MySQLDialect) GetDBName(dsn string) (string, error) { return cfg.DBName, nil } + +//go:embed snapshot/*.sql +var sqlFiles embed.FS + +func (db *MySQLDialect) CreateDatabaseFromSnapshot(ctx context.Context, engine *xorm.Engine, migrationLogTableName string, logger log.Logger) error { + // Entire schema is generated only when called with "migration_log" table. + // Normally if schema creates other "*_migration_log" tables, we don't get here. However if new migration table is introduced by later migration, + // CreateDatabaseFromSnapshot may be called for given table, but if it wasn't part of original schema, we can't do anything here. + if migrationLogTableName != "migration_log" { + return nil + } + + entries, err := sqlFiles.ReadDir("snapshot") + if err != nil { + return err + } + + logger.Info("creating database schema from snapshot") + + for _, entry := range entries { + logger.Debug("using snapshot file", "file", entry.Name()) + data, err := sqlFiles.ReadFile(path.Join("snapshot", entry.Name())) + if err != nil { + return err + } + + statements := extractStatements(string(data)) + if err := db.executeStatements(engine, statements); err != nil { + return err + } + } + + logger.Info("successfully created database schema from snapshot") + return nil +} + +func extractStatements(schema string) []string { + lines := strings.Split(schema, "\n") + + statements := make([]string, 0, len(lines)) + + sb := strings.Builder{} + for _, line := range lines { + line = strings.TrimSpace(line) + if strings.HasPrefix(line, "--") { + continue + } + + if line == "" { + continue + } + + endOfStatement := false + if strings.HasSuffix(line, ";") { + endOfStatement = true + line = strings.TrimSuffix(line, ";") + } + + if sb.Len() > 0 { + sb.WriteRune('\n') + } + sb.WriteString(line) + if endOfStatement && sb.Len() > 0 { + statements = append(statements, sb.String()) + sb.Reset() + } + } + + if sb.Len() > 0 { + statements = append(statements, sb.String()) + } + return statements +} + +func (s *MySQLDialect) executeStatements(engine *xorm.Engine, statements []string) error { + sess := engine.NewSession() + for _, s := range statements { + _, err := sess.Exec(s) + if err != nil { + return fmt.Errorf("statement %s failed with error: %v", s, err) + } + } + return nil +} diff --git a/pkg/services/sqlstore/migrator/snapshot/00-schema.sql b/pkg/services/sqlstore/migrator/snapshot/00-schema.sql new file mode 100644 index 00000000000..9907f7083cf --- /dev/null +++ b/pkg/services/sqlstore/migrator/snapshot/00-schema.sql @@ -0,0 +1,2325 @@ +-- MySQL dump 10.13 Distrib 8.4.5, for Linux (x86_64) +-- +-- Host: localhost Database: hg_dump +-- ------------------------------------------------------ +-- Server version 8.4.5 + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!50503 SET NAMES utf8mb4 */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; + +-- +-- Table structure for table `alert` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `alert` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `version` bigint NOT NULL, + `dashboard_id` bigint NOT NULL, + `panel_id` bigint NOT NULL, + `org_id` bigint NOT NULL, + `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `message` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `state` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `settings` mediumtext COLLATE utf8mb4_unicode_ci, + `frequency` bigint NOT NULL, + `handler` bigint NOT NULL, + `severity` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `silenced` tinyint(1) NOT NULL, + `execution_error` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `eval_data` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `eval_date` datetime DEFAULT NULL, + `new_state_date` datetime NOT NULL, + `state_changes` int NOT NULL, + `created` datetime NOT NULL, + `updated` datetime NOT NULL, + `for` bigint DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `IDX_alert_org_id_id` (`org_id`,`id`), + KEY `IDX_alert_state` (`state`), + KEY `IDX_alert_dashboard_id` (`dashboard_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `alert_configuration` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `alert_configuration` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `alertmanager_configuration` mediumtext COLLATE utf8mb4_unicode_ci, + `configuration_version` varchar(3) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `created_at` int NOT NULL, + `default` tinyint(1) NOT NULL DEFAULT '0', + `org_id` bigint NOT NULL DEFAULT '0', + `configuration_hash` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'not-yet-calculated', + PRIMARY KEY (`id`), + UNIQUE KEY `UQE_alert_configuration_org_id` (`org_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `alert_configuration_history` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `alert_configuration_history` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `org_id` bigint NOT NULL DEFAULT '0', + `alertmanager_configuration` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `configuration_hash` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'not-yet-calculated', + `configuration_version` varchar(3) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `created_at` int NOT NULL, + `default` tinyint(1) NOT NULL DEFAULT '0', + `last_applied` int NOT NULL DEFAULT '0', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `alert_image` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `alert_image` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `token` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `path` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `url` varchar(2048) COLLATE utf8mb4_unicode_ci NOT NULL, + `created_at` datetime NOT NULL, + `expires_at` datetime NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `UQE_alert_image_token` (`token`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `alert_instance` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `alert_instance` ( + `rule_org_id` bigint NOT NULL, + `rule_uid` varchar(40) COLLATE utf8mb4_unicode_ci NOT NULL, + `labels` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `labels_hash` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `current_state` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `current_state_since` bigint NOT NULL, + `last_eval_time` bigint NOT NULL, + `current_state_end` bigint NOT NULL DEFAULT '0', + `current_reason` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `result_fingerprint` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `resolved_at` bigint DEFAULT NULL, + `last_sent_at` bigint DEFAULT NULL, + `fired_at` bigint DEFAULT NULL, + `annotations` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + PRIMARY KEY (`rule_org_id`,`rule_uid`,`labels_hash`), + KEY `IDX_alert_instance_rule_org_id_rule_uid_current_state` (`rule_org_id`,`rule_uid`,`current_state`), + KEY `IDX_alert_instance_rule_org_id_current_state` (`rule_org_id`,`current_state`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `alert_notification` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `alert_notification` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `org_id` bigint NOT NULL, + `name` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `settings` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `created` datetime NOT NULL, + `updated` datetime NOT NULL, + `is_default` tinyint(1) NOT NULL DEFAULT '0', + `frequency` bigint DEFAULT NULL, + `send_reminder` tinyint(1) DEFAULT '0', + `disable_resolve_message` tinyint(1) NOT NULL DEFAULT '0', + `uid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `secure_settings` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + PRIMARY KEY (`id`), + UNIQUE KEY `UQE_alert_notification_org_id_uid` (`org_id`,`uid`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `alert_notification_state` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `alert_notification_state` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `org_id` bigint NOT NULL, + `alert_id` bigint NOT NULL, + `notifier_id` bigint NOT NULL, + `state` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `version` bigint NOT NULL, + `updated_at` bigint NOT NULL, + `alert_rule_state_updated_version` bigint NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `UQE_alert_notification_state_org_id_alert_id_notifier_id` (`org_id`,`alert_id`,`notifier_id`), + KEY `IDX_alert_notification_state_alert_id` (`alert_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `alert_rule` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `alert_rule` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `org_id` bigint NOT NULL, + `title` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `condition` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `data` mediumtext COLLATE utf8mb4_unicode_ci, + `updated` datetime NOT NULL, + `interval_seconds` bigint NOT NULL DEFAULT '60', + `version` int NOT NULL DEFAULT '0', + `uid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '0', + `namespace_uid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, + `rule_group` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL, + `no_data_state` varchar(15) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'NoData', + `exec_err_state` varchar(15) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'Alerting', + `for` bigint NOT NULL DEFAULT '0', + `annotations` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `labels` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `dashboard_uid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `panel_id` bigint DEFAULT NULL, + `rule_group_idx` bigint DEFAULT NULL, + `is_paused` tinyint(1) NOT NULL DEFAULT '0', + `notification_settings` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `record` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `metadata` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `updated_by` varchar(190) COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `guid` varchar(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '', + `keep_firing_for` bigint NOT NULL DEFAULT '0', + `missing_series_evals_to_resolve` smallint DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `UQE_alert_rule_org_id_uid` (`org_id`,`uid`), + UNIQUE KEY `UQE_alert_rule_guid` (`guid`), + KEY `IDX_alert_rule_org_id_namespace_uid_rule_group` (`org_id`,`namespace_uid`,`rule_group`), + KEY `IDX_alert_rule_org_id_dashboard_uid_panel_id` (`org_id`,`dashboard_uid`,`panel_id`), + KEY `IDX_alert_rule_org_id_namespace_uid_rule_group_rule_group_idx` (`org_id`,`namespace_uid`,`rule_group`,`rule_group_idx`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `alert_rule_state` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `alert_rule_state` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `org_id` bigint NOT NULL, + `rule_uid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `data` longblob NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `UQE_alert_rule_state_org_id_rule_uid` (`org_id`,`rule_uid`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `alert_rule_tag` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `alert_rule_tag` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `alert_id` bigint NOT NULL, + `tag_id` bigint NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `UQE_alert_rule_tag_alert_id_tag_id` (`alert_id`,`tag_id`), + KEY `IDX_alert_rule_tag_alert_id` (`alert_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `alert_rule_version` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `alert_rule_version` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `rule_org_id` bigint NOT NULL, + `rule_uid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '0', + `rule_namespace_uid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `rule_group` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `parent_version` int NOT NULL, + `restored_from` int NOT NULL, + `version` int NOT NULL, + `created` datetime NOT NULL, + `title` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `condition` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `data` mediumtext COLLATE utf8mb4_unicode_ci, + `interval_seconds` bigint NOT NULL, + `no_data_state` varchar(15) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'NoData', + `exec_err_state` varchar(15) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'Alerting', + `for` bigint NOT NULL DEFAULT '0', + `annotations` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `labels` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `rule_group_idx` bigint DEFAULT NULL, + `is_paused` tinyint(1) NOT NULL DEFAULT '0', + `message` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `notification_settings` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `record` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `metadata` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `created_by` varchar(190) COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `rule_guid` varchar(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '', + `keep_firing_for` bigint NOT NULL DEFAULT '0', + `missing_series_evals_to_resolve` smallint DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `UQE_alert_rule_version_rule_org_id_rule_uid_rule_guid_version` (`rule_org_id`,`rule_uid`,`rule_guid`,`version`), + UNIQUE KEY `UQE_alert_rule_version_rule_guid_version` (`rule_guid`,`version`), + KEY `IDX_alert_rule_version_rule_org_id_rule_namespace_uid_rule_group` (`rule_org_id`,`rule_namespace_uid`,`rule_group`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `annotation` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `annotation` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `org_id` bigint NOT NULL, + `alert_id` bigint DEFAULT NULL, + `user_id` bigint DEFAULT NULL, + `dashboard_id` bigint DEFAULT NULL, + `panel_id` bigint DEFAULT NULL, + `category_id` bigint DEFAULT NULL, + `type` varchar(25) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `title` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `text` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `metric` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `prev_state` varchar(40) COLLATE utf8mb4_unicode_ci NOT NULL, + `new_state` varchar(40) COLLATE utf8mb4_unicode_ci NOT NULL, + `data` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `epoch` bigint NOT NULL, + `region_id` bigint DEFAULT '0', + `tags` varchar(4096) COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `created` bigint DEFAULT '0', + `updated` bigint DEFAULT '0', + `epoch_end` bigint NOT NULL DEFAULT '0', + `dashboard_uid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `IDX_annotation_org_id_alert_id` (`org_id`,`alert_id`), + KEY `IDX_annotation_org_id_type` (`org_id`,`type`), + KEY `IDX_annotation_org_id_created` (`org_id`,`created`), + KEY `IDX_annotation_org_id_updated` (`org_id`,`updated`), + KEY `IDX_annotation_org_id_dashboard_id_epoch_end_epoch` (`org_id`,`dashboard_id`,`epoch_end`,`epoch`), + KEY `IDX_annotation_org_id_epoch_end_epoch` (`org_id`,`epoch_end`,`epoch`), + KEY `IDX_annotation_alert_id` (`alert_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `annotation_tag` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `annotation_tag` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `annotation_id` bigint NOT NULL, + `tag_id` bigint NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `UQE_annotation_tag_annotation_id_tag_id` (`annotation_id`,`tag_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `anon_device` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `anon_device` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `client_ip` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `created_at` datetime NOT NULL, + `device_id` varchar(127) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `updated_at` datetime NOT NULL, + `user_agent` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `UQE_anon_device_device_id` (`device_id`), + KEY `IDX_anon_device_updated_at` (`updated_at`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `api_key` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `api_key` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `org_id` bigint NOT NULL, + `name` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `key` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `role` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `created` datetime NOT NULL, + `updated` datetime NOT NULL, + `expires` bigint DEFAULT NULL, + `service_account_id` bigint DEFAULT NULL, + `last_used_at` datetime DEFAULT NULL, + `is_revoked` tinyint(1) DEFAULT '0', + PRIMARY KEY (`id`), + UNIQUE KEY `UQE_api_key_key` (`key`), + UNIQUE KEY `UQE_api_key_org_id_name` (`org_id`,`name`), + KEY `IDX_api_key_org_id` (`org_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `builtin_role` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `builtin_role` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `role` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `role_id` bigint NOT NULL, + `created` datetime NOT NULL, + `updated` datetime NOT NULL, + `org_id` bigint NOT NULL DEFAULT '0', + PRIMARY KEY (`id`), + UNIQUE KEY `UQE_builtin_role_org_id_role_id_role` (`org_id`,`role_id`,`role`), + KEY `IDX_builtin_role_role_id` (`role_id`), + KEY `IDX_builtin_role_role` (`role`), + KEY `IDX_builtin_role_org_id` (`org_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `cache_data` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `cache_data` ( + `cache_key` varchar(168) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `data` blob NOT NULL, + `expires` int NOT NULL, + `created_at` int NOT NULL, + PRIMARY KEY (`cache_key`), + UNIQUE KEY `UQE_cache_data_cache_key` (`cache_key`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `cloud_migration_resource` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `cloud_migration_resource` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `uid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `resource_type` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `resource_uid` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL, + `status` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `error_string` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `snapshot_uid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `name` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `parent_name` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `error_code` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `cloud_migration_session` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `cloud_migration_session` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `uid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `auth_token` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `slug` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `stack_id` bigint NOT NULL, + `region_slug` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `cluster_slug` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `created` datetime NOT NULL, + `updated` datetime NOT NULL, + `org_id` bigint NOT NULL DEFAULT '1', + PRIMARY KEY (`id`), + UNIQUE KEY `UQE_cloud_migration_session_uid` (`uid`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `cloud_migration_snapshot` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `cloud_migration_snapshot` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `uid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `session_uid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `created` datetime NOT NULL, + `updated` datetime NOT NULL, + `finished` datetime DEFAULT NULL, + `upload_url` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `status` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `local_directory` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `gms_snapshot_uid` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `encryption_key` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `error_string` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `resource_storage_type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `encryption_algo` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `metadata` blob, + `public_key` blob, + PRIMARY KEY (`id`), + UNIQUE KEY `UQE_cloud_migration_snapshot_uid` (`uid`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `cloud_migration_snapshot_partition` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `cloud_migration_snapshot_partition` ( + `snapshot_uid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `partition_number` int NOT NULL, + `resource_type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `data` longblob NOT NULL, + PRIMARY KEY (`snapshot_uid`,`resource_type`,`partition_number`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `correlation` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `correlation` ( + `uid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `org_id` bigint NOT NULL DEFAULT '0', + `source_uid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `target_uid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `label` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `description` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `config` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `provisioned` tinyint(1) NOT NULL DEFAULT '0', + `type` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'query', + PRIMARY KEY (`uid`,`org_id`,`source_uid`), + KEY `IDX_correlation_uid` (`uid`), + KEY `IDX_correlation_source_uid` (`source_uid`), + KEY `IDX_correlation_org_id` (`org_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `dashboard` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `dashboard` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `version` int NOT NULL, + `slug` varchar(189) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `title` varchar(189) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `data` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `org_id` bigint NOT NULL, + `created` datetime NOT NULL, + `updated` datetime NOT NULL, + `updated_by` int DEFAULT NULL, + `created_by` int DEFAULT NULL, + `gnet_id` bigint DEFAULT NULL, + `plugin_id` varchar(189) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `folder_id` bigint NOT NULL DEFAULT '0', + `is_folder` tinyint(1) NOT NULL DEFAULT '0', + `has_acl` tinyint(1) NOT NULL DEFAULT '0', + `uid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `is_public` tinyint(1) NOT NULL DEFAULT '0', + `deleted` datetime DEFAULT NULL, + `api_version` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `folder_uid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `UQE_dashboard_org_id_uid` (`org_id`,`uid`), + KEY `IDX_dashboard_org_id` (`org_id`), + KEY `IDX_dashboard_gnet_id` (`gnet_id`), + KEY `IDX_dashboard_org_id_plugin_id` (`org_id`,`plugin_id`), + KEY `IDX_dashboard_title` (`title`), + KEY `IDX_dashboard_is_folder` (`is_folder`), + KEY `IDX_dashboard_deleted` (`deleted`), + KEY `IDX_dashboard_org_id_folder_id_title` (`org_id`,`folder_id`,`title`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `dashboard_acl` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `dashboard_acl` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `org_id` bigint NOT NULL, + `dashboard_id` bigint NOT NULL, + `user_id` bigint DEFAULT NULL, + `team_id` bigint DEFAULT NULL, + `permission` smallint NOT NULL DEFAULT '4', + `role` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `created` datetime NOT NULL, + `updated` datetime NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `UQE_dashboard_acl_dashboard_id_user_id` (`dashboard_id`,`user_id`), + UNIQUE KEY `UQE_dashboard_acl_dashboard_id_team_id` (`dashboard_id`,`team_id`), + KEY `IDX_dashboard_acl_dashboard_id` (`dashboard_id`), + KEY `IDX_dashboard_acl_user_id` (`user_id`), + KEY `IDX_dashboard_acl_team_id` (`team_id`), + KEY `IDX_dashboard_acl_org_id_role` (`org_id`,`role`), + KEY `IDX_dashboard_acl_permission` (`permission`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `dashboard_provisioning` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `dashboard_provisioning` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `dashboard_id` bigint DEFAULT NULL, + `name` varchar(150) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `external_id` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `updated` int NOT NULL DEFAULT '0', + `check_sum` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `IDX_dashboard_provisioning_dashboard_id` (`dashboard_id`), + KEY `IDX_dashboard_provisioning_dashboard_id_name` (`dashboard_id`,`name`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `dashboard_public` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `dashboard_public` ( + `uid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `dashboard_uid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `org_id` bigint NOT NULL, + `time_settings` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `template_variables` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `access_token` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `created_by` int NOT NULL, + `updated_by` int DEFAULT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime DEFAULT NULL, + `is_enabled` tinyint(1) NOT NULL DEFAULT '0', + `annotations_enabled` tinyint(1) NOT NULL DEFAULT '0', + `time_selection_enabled` tinyint(1) NOT NULL DEFAULT '0', + `share` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'public', + PRIMARY KEY (`uid`), + UNIQUE KEY `UQE_dashboard_public_config_uid` (`uid`), + UNIQUE KEY `UQE_dashboard_public_config_access_token` (`access_token`), + KEY `IDX_dashboard_public_config_org_id_dashboard_uid` (`org_id`,`dashboard_uid`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `dashboard_public_email_share` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `dashboard_public_email_share` ( + `uid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `public_dashboard_uid` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `recipient` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `type` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'email', + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`uid`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `dashboard_public_magic_link` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `dashboard_public_magic_link` ( + `uid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `token_uuid` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `public_dashboard_uid` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `email` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + PRIMARY KEY (`uid`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `dashboard_public_session` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `dashboard_public_session` ( + `uid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `cookie_uuid` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `public_dashboard_uid` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `email` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `created_at` datetime NOT NULL, + `updated_at` datetime NOT NULL, + `last_seen_at` datetime DEFAULT NULL, + PRIMARY KEY (`uid`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `dashboard_public_usage_by_day` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `dashboard_public_usage_by_day` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `public_dashboard_uid` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `day` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `views` bigint NOT NULL, + `queries` bigint NOT NULL, + `errors` bigint NOT NULL, + `load_duration` float NOT NULL, + `cached_queries` bigint NOT NULL DEFAULT '0', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `dashboard_snapshot` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `dashboard_snapshot` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `key` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `delete_key` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `org_id` bigint NOT NULL, + `user_id` bigint NOT NULL, + `external` tinyint(1) NOT NULL, + `external_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `dashboard` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `expires` datetime NOT NULL, + `created` datetime NOT NULL, + `updated` datetime NOT NULL, + `external_delete_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `dashboard_encrypted` mediumblob, + PRIMARY KEY (`id`), + UNIQUE KEY `UQE_dashboard_snapshot_key` (`key`), + UNIQUE KEY `UQE_dashboard_snapshot_delete_key` (`delete_key`), + KEY `IDX_dashboard_snapshot_user_id` (`user_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `dashboard_tag` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `dashboard_tag` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `dashboard_id` bigint NOT NULL, + `term` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `dashboard_uid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `org_id` bigint DEFAULT '1', + PRIMARY KEY (`id`), + KEY `IDX_dashboard_tag_dashboard_id` (`dashboard_id`), + KEY `IDX_dashboard_tag_dashboard_uid` (`dashboard_uid`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `dashboard_usage_by_day` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `dashboard_usage_by_day` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `dashboard_id` bigint NOT NULL, + `day` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `views` bigint NOT NULL, + `queries` bigint NOT NULL, + `errors` bigint NOT NULL, + `load_duration` float NOT NULL, + `cached_queries` bigint NOT NULL DEFAULT '0', + `dashboard_uid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `org_id` bigint DEFAULT '1', + PRIMARY KEY (`id`), + UNIQUE KEY `UQE_dashboard_usage_by_day_dashboard_id_day` (`dashboard_id`,`day`), + UNIQUE KEY `UQE_dashboard_usage_by_day_dashboard_uid_org_id_day` (`dashboard_uid`,`org_id`,`day`), + KEY `IDX_dashboard_usage_by_day_dashboard_id` (`dashboard_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `dashboard_usage_sums` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `dashboard_usage_sums` ( + `dashboard_id` bigint NOT NULL, + `updated` datetime NOT NULL, + `views_last_1_days` bigint NOT NULL, + `views_last_7_days` bigint NOT NULL, + `views_last_30_days` bigint NOT NULL, + `views_total` bigint NOT NULL, + `queries_last_1_days` bigint NOT NULL, + `queries_last_7_days` bigint NOT NULL, + `queries_last_30_days` bigint NOT NULL, + `queries_total` bigint NOT NULL, + `errors_last_1_days` bigint NOT NULL DEFAULT '0', + `errors_last_7_days` bigint NOT NULL DEFAULT '0', + `errors_last_30_days` bigint NOT NULL DEFAULT '0', + `errors_total` bigint NOT NULL DEFAULT '0', + `dashboard_uid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `org_id` bigint DEFAULT '1', + PRIMARY KEY (`dashboard_id`), + UNIQUE KEY `UQE_dashboard_usage_sums_org_id_dashboard_uid` (`org_id`,`dashboard_uid`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `dashboard_version` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `dashboard_version` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `dashboard_id` bigint NOT NULL, + `parent_version` int NOT NULL, + `restored_from` int NOT NULL, + `version` int NOT NULL, + `created` datetime NOT NULL, + `created_by` bigint NOT NULL, + `message` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `data` mediumtext COLLATE utf8mb4_unicode_ci, + `api_version` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `UQE_dashboard_version_dashboard_id_version` (`dashboard_id`,`version`), + KEY `IDX_dashboard_version_dashboard_id` (`dashboard_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `data_keys` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `data_keys` ( + `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `active` tinyint(1) NOT NULL, + `scope` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `provider` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `encrypted_data` blob NOT NULL, + `created` datetime NOT NULL, + `updated` datetime NOT NULL, + `label` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + PRIMARY KEY (`name`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `data_source` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `data_source` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `org_id` bigint NOT NULL, + `version` int NOT NULL, + `type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `name` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `access` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `user` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `database` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `basic_auth` tinyint(1) NOT NULL, + `basic_auth_user` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `basic_auth_password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `is_default` tinyint(1) NOT NULL, + `json_data` mediumtext COLLATE utf8mb4_unicode_ci, + `created` datetime NOT NULL, + `updated` datetime NOT NULL, + `with_credentials` tinyint(1) NOT NULL DEFAULT '0', + `secure_json_data` mediumtext COLLATE utf8mb4_unicode_ci, + `read_only` tinyint(1) DEFAULT NULL, + `uid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '0', + `is_prunable` tinyint(1) DEFAULT '0', + `api_version` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `UQE_data_source_org_id_name` (`org_id`,`name`), + UNIQUE KEY `UQE_data_source_org_id_uid` (`org_id`,`uid`), + KEY `IDX_data_source_org_id` (`org_id`), + KEY `IDX_data_source_org_id_is_default` (`org_id`,`is_default`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `data_source_acl` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `data_source_acl` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `org_id` bigint NOT NULL, + `data_source_id` bigint NOT NULL, + `team_id` bigint NOT NULL, + `user_id` bigint NOT NULL, + `permission` smallint NOT NULL, + `created` datetime NOT NULL, + `updated` datetime NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `UQE_data_source_acl_data_source_id_team_id_user_id` (`data_source_id`,`team_id`,`user_id`), + KEY `IDX_data_source_acl_data_source_id` (`data_source_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `data_source_cache` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `data_source_cache` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `data_source_id` bigint NOT NULL, + `enabled` tinyint(1) NOT NULL, + `ttl_ms` bigint NOT NULL, + `created` datetime NOT NULL, + `updated` datetime NOT NULL, + `use_default_ttl` tinyint(1) NOT NULL DEFAULT '1', + `data_source_uid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '0', + `ttl_resources_ms` bigint NOT NULL DEFAULT '300000', + PRIMARY KEY (`id`), + KEY `IDX_data_source_cache_data_source_id` (`data_source_id`), + KEY `IDX_data_source_cache_data_source_uid` (`data_source_uid`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `data_source_usage_by_day` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `data_source_usage_by_day` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `data_source_id` bigint NOT NULL, + `day` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `queries` bigint NOT NULL, + `errors` bigint NOT NULL, + `load_duration_ms` bigint NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `UQE_data_source_usage_by_day_data_source_id_day` (`data_source_id`,`day`), + KEY `IDX_data_source_usage_by_day_data_source_id` (`data_source_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `entity_event` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `entity_event` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `entity_id` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `event_type` varchar(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `created` bigint NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `file` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `file` ( + `path` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `path_hash` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `parent_folder_path_hash` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `contents` mediumblob, + `etag` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `cache_control` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `content_disposition` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `updated` datetime NOT NULL, + `created` datetime NOT NULL, + `size` bigint NOT NULL, + `mime_type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + PRIMARY KEY (`path_hash`), + KEY `IDX_file_parent_folder_path_hash` (`parent_folder_path_hash`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `file_meta` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `file_meta` ( + `path_hash` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `key` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `value` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + PRIMARY KEY (`path_hash`,`key`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `folder` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `folder` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `uid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `org_id` bigint NOT NULL, + `title` varchar(189) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `description` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `parent_uid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `created` datetime NOT NULL, + `updated` datetime NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `UQE_folder_org_id_uid` (`org_id`,`uid`), + KEY `IDX_folder_org_id_parent_uid` (`org_id`,`parent_uid`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `kv_store` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `kv_store` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `org_id` bigint NOT NULL, + `namespace` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `key` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `value` longtext COLLATE utf8mb4_unicode_ci NOT NULL, + `created` datetime NOT NULL, + `updated` datetime NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `UQE_kv_store_org_id_namespace_key` (`org_id`,`namespace`,`key`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `library_element` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `library_element` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `org_id` bigint NOT NULL, + `folder_id` bigint NOT NULL, + `uid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `name` varchar(150) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `kind` bigint NOT NULL, + `type` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `description` varchar(2048) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `model` mediumtext COLLATE utf8mb4_unicode_ci NOT NULL, + `created` datetime NOT NULL, + `created_by` bigint NOT NULL, + `updated` datetime NOT NULL, + `updated_by` bigint NOT NULL, + `version` bigint NOT NULL, + `folder_uid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `UQE_library_element_org_id_uid` (`org_id`,`uid`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `library_element_connection` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `library_element_connection` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `element_id` bigint NOT NULL, + `kind` bigint NOT NULL, + `connection_id` bigint NOT NULL, + `created` datetime NOT NULL, + `created_by` bigint NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `UQE_library_element_connection_element_id_kind_connection_id` (`element_id`,`kind`,`connection_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `license_token` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `license_token` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `token` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `created` datetime NOT NULL, + `updated` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `login_attempt` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `login_attempt` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `username` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `ip_address` varchar(50) COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `created` bigint DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `IDX_login_attempt_username` (`username`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `migration_log` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `migration_log` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `migration_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `sql` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `success` tinyint(1) NOT NULL, + `error` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `timestamp` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `ngalert_configuration` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `ngalert_configuration` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `org_id` bigint NOT NULL, + `alertmanagers` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `created_at` int NOT NULL, + `updated_at` int NOT NULL, + `send_alerts_to` smallint NOT NULL DEFAULT '0', + PRIMARY KEY (`id`), + UNIQUE KEY `UQE_ngalert_configuration_org_id` (`org_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `org` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `org` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `version` int NOT NULL, + `name` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `address1` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `address2` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `city` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `state` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `zip_code` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `country` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `billing_email` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `created` datetime NOT NULL, + `updated` datetime NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `UQE_org_name` (`name`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `org_user` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `org_user` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `org_id` bigint NOT NULL, + `user_id` bigint NOT NULL, + `role` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `created` datetime NOT NULL, + `updated` datetime NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `UQE_org_user_org_id_user_id` (`org_id`,`user_id`), + KEY `IDX_org_user_org_id` (`org_id`), + KEY `IDX_org_user_user_id` (`user_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `permission` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `permission` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `role_id` bigint NOT NULL, + `action` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `scope` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `created` datetime NOT NULL, + `updated` datetime NOT NULL, + `kind` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '', + `attribute` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '', + `identifier` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '', + PRIMARY KEY (`id`), + UNIQUE KEY `UQE_permission_action_scope_role_id` (`action`,`scope`,`role_id`), + KEY `IDX_permission_identifier` (`identifier`), + KEY `IDX_permission_role_id_action` (`role_id`,`action`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `playlist` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `playlist` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `interval` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `org_id` bigint NOT NULL, + `created_at` bigint NOT NULL DEFAULT '0', + `updated_at` bigint NOT NULL DEFAULT '0', + `uid` varchar(80) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '0', + PRIMARY KEY (`id`), + UNIQUE KEY `UQE_playlist_org_id_uid` (`org_id`,`uid`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `playlist_item` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `playlist_item` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `playlist_id` bigint NOT NULL, + `type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `value` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `title` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `order` int NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `plugin_setting` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `plugin_setting` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `org_id` bigint NOT NULL DEFAULT '1', + `plugin_id` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `enabled` tinyint(1) NOT NULL, + `pinned` tinyint(1) NOT NULL, + `json_data` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `secure_json_data` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `created` datetime NOT NULL, + `updated` datetime NOT NULL, + `plugin_version` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `UQE_plugin_setting_org_id_plugin_id` (`org_id`,`plugin_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `preferences` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `preferences` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `org_id` bigint NOT NULL, + `user_id` bigint NOT NULL, + `version` int NOT NULL, + `home_dashboard_id` bigint NOT NULL, + `timezone` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `theme` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `created` datetime NOT NULL, + `updated` datetime NOT NULL, + `team_id` bigint DEFAULT NULL, + `week_start` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `json_data` mediumtext COLLATE utf8mb4_unicode_ci, + `home_dashboard_uid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `IDX_preferences_org_id` (`org_id`), + KEY `IDX_preferences_user_id` (`user_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `provenance_type` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `provenance_type` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `org_id` bigint NOT NULL, + `record_key` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `record_type` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `provenance` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `UQE_provenance_type_record_type_record_key_org_id` (`record_type`,`record_key`,`org_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `query_history` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `query_history` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `uid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `org_id` bigint NOT NULL, + `datasource_uid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `created_by` bigint DEFAULT NULL, + `created_at` int NOT NULL, + `comment` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `queries` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + PRIMARY KEY (`id`), + KEY `IDX_query_history_org_id_created_by_datasource_uid` (`org_id`,`created_by`,`datasource_uid`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `query_history_details` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `query_history_details` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `query_history_item_uid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `datasource_uid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `query_history_star` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `query_history_star` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `query_uid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `user_id` bigint DEFAULT NULL, + `org_id` bigint NOT NULL DEFAULT '1', + PRIMARY KEY (`id`), + UNIQUE KEY `UQE_query_history_star_user_id_query_uid` (`user_id`,`query_uid`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `quota` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `quota` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `org_id` bigint DEFAULT NULL, + `user_id` bigint DEFAULT NULL, + `target` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `limit` bigint NOT NULL, + `created` datetime NOT NULL, + `updated` datetime NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `UQE_quota_org_id_user_id_target` (`org_id`,`user_id`,`target`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `recording_rules` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `recording_rules` ( + `id` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `target_ref_id` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `name` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `description` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `org_id` bigint NOT NULL, + `interval` bigint NOT NULL, + `range` bigint NOT NULL, + `active` tinyint(1) NOT NULL DEFAULT '0', + `count` tinyint(1) NOT NULL DEFAULT '0', + `queries` blob NOT NULL, + `created_at` datetime NOT NULL, + `prom_name` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + PRIMARY KEY (`id`,`target_ref_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `remote_write_targets` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `remote_write_targets` ( + `id` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `data_source_uid` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `write_path` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `org_id` int NOT NULL, + PRIMARY KEY (`id`,`data_source_uid`,`write_path`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `report` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `report` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `user_id` bigint NOT NULL, + `org_id` bigint NOT NULL, + `dashboard_id` bigint NOT NULL, + `name` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `recipients` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `reply_to` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `message` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `schedule_frequency` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `schedule_day` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `schedule_hour` bigint NOT NULL, + `schedule_minute` bigint NOT NULL, + `created` datetime NOT NULL, + `updated` datetime NOT NULL, + `schedule_timezone` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'Europe/Stockholm', + `time_from` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `time_to` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `pdf_landscape` tinyint(1) DEFAULT NULL, + `schedule_day_of_month` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `pdf_layout` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `pdf_orientation` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `dashboard_uid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `template_vars` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `enable_dashboard_url` tinyint(1) DEFAULT NULL, + `state` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `enable_csv` tinyint(1) DEFAULT NULL, + `schedule_start` int DEFAULT NULL, + `schedule_end` int DEFAULT NULL, + `schedule_interval_frequency` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `schedule_interval_amount` bigint DEFAULT NULL, + `schedule_workdays_only` tinyint(1) DEFAULT NULL, + `formats` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '["pdf"]', + `scale_factor` smallint NOT NULL DEFAULT '2', + `uid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `pdf_show_template_variables` tinyint(1) NOT NULL DEFAULT '0', + `pdf_combine_one_file` tinyint(1) NOT NULL DEFAULT '1', + `subject` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + PRIMARY KEY (`id`), + UNIQUE KEY `UQE_report_org_id_uid` (`org_id`,`uid`), + KEY `IDX_report_user_id` (`user_id`), + KEY `IDX_report_dashboard_id` (`dashboard_id`), + KEY `IDX_report_org_id` (`org_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `report_dashboards` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `report_dashboards` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `report_id` bigint NOT NULL, + `dashboard_uid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '', + `report_variables` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `time_to` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `time_from` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `created` datetime DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `IDX_report_dashboards_report_id` (`report_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `report_settings` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `report_settings` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `user_id` bigint NOT NULL, + `org_id` bigint NOT NULL, + `branding_report_logo_url` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `branding_email_logo_url` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `branding_email_footer_link` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `branding_email_footer_text` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `branding_email_footer_mode` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `pdf_theme` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'light', + `embedded_image_theme` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'dark', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `resource` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `resource` ( + `guid` varchar(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `resource_version` bigint DEFAULT NULL, + `group` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `resource` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `namespace` varchar(63) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `name` varchar(253) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `value` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `action` int NOT NULL, + `label_set` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `previous_resource_version` bigint DEFAULT NULL, + `folder` varchar(253) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '', + PRIMARY KEY (`guid`), + UNIQUE KEY `UQE_resource_namespace_group_resource_name` (`namespace`,`group`,`resource`,`name`), + KEY `IDX_resource_group_resource` (`group`,`resource`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `resource_blob` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `resource_blob` ( + `uuid` char(36) COLLATE utf8mb4_unicode_ci NOT NULL, + `created` datetime NOT NULL, + `group` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `resource` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `namespace` varchar(63) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `name` varchar(253) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `value` longblob NOT NULL, + `hash` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `content_type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + PRIMARY KEY (`uuid`), + KEY `IDX_resource_history_namespace_group_name` (`namespace`,`group`,`resource`,`name`), + KEY `IDX_resource_blob_created` (`created`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `resource_events` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `resource_events` ( + `key_path` varchar(2048) CHARACTER SET latin1 COLLATE latin1_bin NOT NULL, + `value` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + PRIMARY KEY (`key_path`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `resource_history` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `resource_history` ( + `guid` varchar(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `resource_version` bigint DEFAULT NULL, + `group` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `resource` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `namespace` varchar(63) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `name` varchar(253) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `value` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `action` int NOT NULL, + `label_set` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `previous_resource_version` bigint DEFAULT NULL, + `folder` varchar(253) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '', + `generation` bigint NOT NULL DEFAULT '0', + `key_path` varchar(2048) CHARACTER SET latin1 COLLATE latin1_bin NOT NULL DEFAULT '', + PRIMARY KEY (`guid`), + UNIQUE KEY `UQE_resource_history_namespace_group_name_version` (`namespace`,`group`,`resource`,`name`,`resource_version`), + KEY `IDX_resource_history_resource_version` (`resource_version`), + KEY `IDX_resource_history_group_resource_resource_version` (`group`,`resource`,`resource_version`), + KEY `IDX_resource_history_namespace_group_resource_action_version` (`namespace`,`group`,`resource`,`action`,`resource_version`), + KEY `IDX_resource_history_namespace_group_resource_name_generation` (`namespace`,`group`,`resource`,`name`,`generation`), + KEY `IDX_resource_history_key_path` (`key_path`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `resource_last_import_time` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `resource_last_import_time` ( + `group` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `resource` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `namespace` varchar(63) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `last_import_time` datetime NOT NULL, + PRIMARY KEY (`group`,`resource`,`namespace`), + KEY `UQE_resource_last_import_time_last_import_time` (`last_import_time`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `resource_migration_log` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `resource_migration_log` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `migration_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `sql` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `success` tinyint(1) NOT NULL, + `error` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `timestamp` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `resource_version` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `resource_version` ( + `group` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `resource` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `resource_version` bigint NOT NULL, + PRIMARY KEY (`group`,`resource`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `role` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `role` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `name` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `description` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `version` bigint NOT NULL, + `org_id` bigint NOT NULL, + `uid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `created` datetime NOT NULL, + `updated` datetime NOT NULL, + `display_name` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `group_name` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `hidden` tinyint(1) NOT NULL DEFAULT '0', + PRIMARY KEY (`id`), + UNIQUE KEY `UQE_role_org_id_name` (`org_id`,`name`), + UNIQUE KEY `UQE_role_uid` (`uid`), + KEY `IDX_role_org_id` (`org_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `secret_data_key` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `secret_data_key` ( + `uid` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `namespace` varchar(253) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `label` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `active` tinyint(1) NOT NULL, + `provider` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `encrypted_data` blob NOT NULL, + `created` datetime NOT NULL, + `updated` datetime NOT NULL, + PRIMARY KEY (`uid`), + KEY `IDX_secret_data_key_namespace_label_active` (`namespace`,`label`,`active`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `secret_encrypted_value` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `secret_encrypted_value` ( + `namespace` varchar(253) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `name` varchar(253) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `version` bigint NOT NULL, + `encrypted_data` blob NOT NULL, + `created` bigint NOT NULL, + `updated` bigint NOT NULL, + `data_key_id` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '', + PRIMARY KEY (`namespace`,`name`,`version`), + KEY `IDX_secret_encrypted_value_data_key_id` (`data_key_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `secret_keeper` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `secret_keeper` ( + `guid` varchar(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `name` varchar(253) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `namespace` varchar(253) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `annotations` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `labels` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `created` bigint NOT NULL, + `created_by` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `updated` bigint NOT NULL, + `updated_by` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `description` varchar(253) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `type` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `payload` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `active` tinyint(1) NOT NULL DEFAULT '0', + PRIMARY KEY (`guid`), + UNIQUE KEY `UQE_secret_keeper_namespace_name` (`namespace`,`name`), + KEY `IDX_secret_keeper_namespace_name_active` (`namespace`,`name`,`active`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `secret_migration_log` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `secret_migration_log` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `migration_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `sql` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `success` tinyint(1) NOT NULL, + `error` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `timestamp` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `secret_secure_value` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `secret_secure_value` ( + `guid` varchar(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `name` varchar(253) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `namespace` varchar(253) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `annotations` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `labels` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `created` bigint NOT NULL, + `created_by` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `updated` bigint NOT NULL, + `updated_by` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `external_id` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `active` tinyint(1) NOT NULL, + `version` bigint NOT NULL, + `description` varchar(253) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `keeper` varchar(253) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `decrypters` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `ref` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `owner_reference_api_group` varchar(253) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `owner_reference_api_version` varchar(253) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `owner_reference_kind` varchar(253) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `owner_reference_name` varchar(253) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `lease_token` varchar(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `lease_created` bigint NOT NULL DEFAULT '0', + PRIMARY KEY (`guid`), + UNIQUE KEY `UQE_secret_secure_value_namespace_name_version_active` (`namespace`,`name`,`version`,`active`), + UNIQUE KEY `UQE_secret_secure_value_namespace_name_version` (`namespace`,`name`,`version`), + KEY `IDX_secret_secure_value_namespace_active_updated` (`namespace`,`active`,`updated`), + KEY `IDX_secret_secure_value_lease_token` (`lease_token`), + KEY `IDX_secret_secure_value_lease_created` (`lease_created`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `secrets` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `secrets` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `org_id` bigint NOT NULL, + `namespace` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `value` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `created` datetime NOT NULL, + `updated` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `seed_assignment` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `seed_assignment` ( + `id` int NOT NULL AUTO_INCREMENT, + `builtin_role` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `role_name` varchar(190) COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `action` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `scope` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `origin` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `UQE_seed_assignment_builtin_role_role_name` (`builtin_role`,`role_name`), + UNIQUE KEY `UQE_seed_assignment_builtin_role_action_scope` (`builtin_role`,`action`,`scope`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `server_lock` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `server_lock` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `operation_uid` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `version` bigint NOT NULL, + `last_execution` bigint NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `UQE_server_lock_operation_uid` (`operation_uid`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `session` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `session` ( + `key` char(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `data` blob NOT NULL, + `expiry` int NOT NULL, + PRIMARY KEY (`key`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `setting` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `setting` ( + `section` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `key` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `value` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `encrypted_value` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + PRIMARY KEY (`section`,`key`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `short_url` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `short_url` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `org_id` bigint NOT NULL, + `uid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `path` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `created_by` bigint DEFAULT NULL, + `created_at` int NOT NULL, + `last_seen_at` int DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `UQE_short_url_org_id_uid` (`org_id`,`uid`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `signing_key` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `signing_key` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `key_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `private_key` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `added_at` datetime NOT NULL, + `expires_at` datetime DEFAULT NULL, + `alg` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `UQE_signing_key_key_id` (`key_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `sso_setting` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `sso_setting` ( + `id` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `provider` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `settings` mediumtext COLLATE utf8mb4_unicode_ci NOT NULL, + `created` datetime NOT NULL, + `updated` datetime NOT NULL, + `is_deleted` tinyint(1) NOT NULL DEFAULT '0', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `star` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `star` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `user_id` bigint NOT NULL, + `dashboard_id` bigint NOT NULL, + `dashboard_uid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `org_id` bigint DEFAULT '1', + `updated` datetime DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `UQE_star_user_id_dashboard_id` (`user_id`,`dashboard_id`), + UNIQUE KEY `UQE_star_user_id_dashboard_uid_org_id` (`user_id`,`dashboard_uid`,`org_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `tag` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `tag` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `key` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `value` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `UQE_tag_key_value` (`key`,`value`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `team` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `team` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `name` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `org_id` bigint NOT NULL, + `created` datetime NOT NULL, + `updated` datetime NOT NULL, + `uid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `external_uid` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `is_provisioned` tinyint(1) DEFAULT NULL, + `email` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `UQE_team_org_id_name` (`org_id`,`name`), + UNIQUE KEY `UQE_team_org_id_uid` (`org_id`,`uid`), + KEY `IDX_team_org_id` (`org_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `team_group` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `team_group` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `org_id` bigint NOT NULL, + `team_id` bigint NOT NULL, + `group_id` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `created` datetime NOT NULL, + `updated` datetime NOT NULL, + `uid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `UQE_team_group_org_id_team_id_group_id` (`org_id`,`team_id`,`group_id`), + UNIQUE KEY `UQE_team_group_uid` (`uid`), + KEY `IDX_team_group_org_id` (`org_id`), + KEY `IDX_team_group_group_id` (`group_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `team_member` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `team_member` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `org_id` bigint NOT NULL, + `team_id` bigint NOT NULL, + `user_id` bigint NOT NULL, + `created` datetime NOT NULL, + `updated` datetime NOT NULL, + `external` tinyint(1) DEFAULT NULL, + `permission` smallint DEFAULT NULL, + `uid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `UQE_team_member_org_id_team_id_user_id` (`org_id`,`team_id`,`user_id`), + UNIQUE KEY `UQE_team_member_uid` (`uid`), + KEY `IDX_team_member_org_id` (`org_id`), + KEY `IDX_team_member_team_id` (`team_id`), + KEY `IDX_team_member_user_id_org_id` (`user_id`,`org_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `team_role` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `team_role` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `org_id` bigint NOT NULL, + `team_id` bigint NOT NULL, + `role_id` bigint NOT NULL, + `created` datetime NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `UQE_team_role_org_id_team_id_role_id` (`org_id`,`team_id`,`role_id`), + KEY `IDX_team_role_org_id` (`org_id`), + KEY `IDX_team_role_team_id` (`team_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `temp_user` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `temp_user` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `org_id` bigint NOT NULL, + `version` int NOT NULL, + `email` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `role` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `code` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `status` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `invited_by_user_id` bigint DEFAULT NULL, + `email_sent` tinyint(1) NOT NULL, + `email_sent_on` datetime DEFAULT NULL, + `remote_addr` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `created` int NOT NULL DEFAULT '0', + `updated` int NOT NULL DEFAULT '0', + PRIMARY KEY (`id`), + KEY `IDX_temp_user_email` (`email`), + KEY `IDX_temp_user_org_id` (`org_id`), + KEY `IDX_temp_user_code` (`code`), + KEY `IDX_temp_user_status` (`status`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `test_data` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `test_data` ( + `id` int NOT NULL AUTO_INCREMENT, + `metric1` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `metric2` varchar(150) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `value_big_int` bigint DEFAULT NULL, + `value_double` double DEFAULT NULL, + `value_float` float DEFAULT NULL, + `value_int` int DEFAULT NULL, + `time_epoch` bigint NOT NULL, + `time_date_time` datetime NOT NULL, + `time_time_stamp` timestamp NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `unifiedstorage_migration_log` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `unifiedstorage_migration_log` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `migration_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `sql` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `success` tinyint(1) NOT NULL, + `error` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `timestamp` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `user` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `user` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `version` int NOT NULL, + `login` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `email` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `salt` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `rands` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `company` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `org_id` bigint NOT NULL, + `is_admin` tinyint(1) NOT NULL, + `email_verified` tinyint(1) DEFAULT NULL, + `theme` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `created` datetime NOT NULL, + `updated` datetime NOT NULL, + `help_flags1` bigint NOT NULL DEFAULT '0', + `last_seen_at` datetime DEFAULT NULL, + `is_disabled` tinyint(1) NOT NULL DEFAULT '0', + `is_service_account` tinyint(1) DEFAULT '0', + `uid` varchar(190) COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `is_provisioned` tinyint(1) NOT NULL DEFAULT '0', + PRIMARY KEY (`id`), + UNIQUE KEY `UQE_user_login` (`login`), + UNIQUE KEY `UQE_user_email` (`email`), + UNIQUE KEY `UQE_user_uid` (`uid`), + KEY `IDX_user_login_email` (`login`,`email`), + KEY `IDX_user_is_service_account_last_seen_at` (`is_service_account`,`last_seen_at`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `user_auth` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `user_auth` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `user_id` bigint NOT NULL, + `auth_module` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `auth_id` varchar(190) COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `created` datetime NOT NULL, + `o_auth_access_token` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `o_auth_refresh_token` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `o_auth_token_type` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `o_auth_expiry` datetime DEFAULT NULL, + `o_auth_id_token` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `external_uid` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + PRIMARY KEY (`id`), + KEY `IDX_user_auth_auth_module_auth_id` (`auth_module`,`auth_id`), + KEY `IDX_user_auth_user_id` (`user_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `user_auth_token` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `user_auth_token` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `user_id` bigint NOT NULL, + `auth_token` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `prev_auth_token` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `user_agent` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `client_ip` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `auth_token_seen` tinyint(1) NOT NULL, + `seen_at` int DEFAULT NULL, + `rotated_at` int NOT NULL, + `created_at` int NOT NULL, + `updated_at` int NOT NULL, + `revoked_at` int DEFAULT NULL, + `external_session_id` bigint DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `UQE_user_auth_token_auth_token` (`auth_token`), + UNIQUE KEY `UQE_user_auth_token_prev_auth_token` (`prev_auth_token`), + KEY `IDX_user_auth_token_user_id` (`user_id`), + KEY `IDX_user_auth_token_revoked_at` (`revoked_at`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `user_dashboard_views` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `user_dashboard_views` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `user_id` bigint NOT NULL, + `dashboard_id` bigint NOT NULL, + `viewed` datetime NOT NULL, + `org_id` bigint DEFAULT NULL, + `dashboard_uid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `UQE_user_dashboard_views_user_id_dashboard_id` (`user_id`,`dashboard_id`), + UNIQUE KEY `UQE_user_dashboard_views_user_id_org_id_dashboard_uid` (`user_id`,`org_id`,`dashboard_uid`), + KEY `IDX_user_dashboard_views_user_id` (`user_id`), + KEY `IDX_user_dashboard_views_dashboard_id` (`dashboard_id`), + KEY `IDX_user_dashboard_views_org_id_dashboard_uid` (`org_id`,`dashboard_uid`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `user_external_session` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `user_external_session` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `user_auth_id` bigint NOT NULL, + `user_id` bigint NOT NULL, + `auth_module` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `access_token` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `id_token` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `refresh_token` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, + `session_id` varchar(1024) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL, + `session_id_hash` char(44) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `name_id` varchar(1024) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci DEFAULT NULL, + `name_id_hash` char(44) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL, + `expires_at` datetime DEFAULT NULL, + `created_at` datetime NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `user_role` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `user_role` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `org_id` bigint NOT NULL, + `user_id` bigint NOT NULL, + `role_id` bigint NOT NULL, + `created` datetime NOT NULL, + `group_mapping_uid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '', + PRIMARY KEY (`id`), + UNIQUE KEY `UQE_user_role_org_id_user_id_role_id_group_mapping_uid` (`org_id`,`user_id`,`role_id`,`group_mapping_uid`), + KEY `IDX_user_role_org_id` (`org_id`), + KEY `IDX_user_role_user_id` (`user_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `user_stats` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `user_stats` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `user_id` bigint NOT NULL, + `billing_role` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `created` datetime NOT NULL, + `updated` datetime NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `UQE_user_stats_user_id` (`user_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; + diff --git a/pkg/services/sqlstore/migrator/snapshot/96-secret_migration_log.sql b/pkg/services/sqlstore/migrator/snapshot/96-secret_migration_log.sql new file mode 100644 index 00000000000..f5ae4ff6ab8 --- /dev/null +++ b/pkg/services/sqlstore/migrator/snapshot/96-secret_migration_log.sql @@ -0,0 +1,57 @@ +-- MySQL dump 10.13 Distrib 8.4.5, for Linux (x86_64) +-- +-- Host: localhost Database: hg_dump +-- ------------------------------------------------------ +-- Server version 8.4.5 +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; + +-- +-- Dumping data for table `secret_migration_log` +-- + +INSERT INTO `secret_migration_log` (`migration_id`, `sql`, `success`, `error`, `timestamp`) VALUES + ('create secret_migration_log table','CREATE TABLE IF NOT EXISTS `secret_migration_log` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `migration_id` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `sql` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `success` TINYINT(1) NOT NULL\n, `error` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `timestamp` DATETIME NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('Initialize secrets tables','',1,'','2022-01-01 00:00:00'), + ('drop table secret_secure_value','DROP TABLE IF EXISTS `secret_secure_value`',1,'','2022-01-01 00:00:00'), + ('create table secret_secure_value','CREATE TABLE IF NOT EXISTS `secret_secure_value` (\n`guid` VARCHAR(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci PRIMARY KEY NOT NULL\n, `name` VARCHAR(253) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `namespace` VARCHAR(253) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `annotations` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `labels` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `created` BIGINT(20) NOT NULL\n, `created_by` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `updated` BIGINT(20) NOT NULL\n, `updated_by` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `external_id` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `active` TINYINT(1) NOT NULL\n, `version` BIGINT(20) NOT NULL\n, `description` VARCHAR(253) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `keeper` VARCHAR(253) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `decrypters` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `ref` VARCHAR(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('create table secret_secure_value, index: 0','CREATE UNIQUE INDEX `UQE_secret_secure_value_namespace_name_version_active` ON `secret_secure_value` (`namespace`,`name`,`version`,`active`);',1,'','2022-01-01 00:00:00'), + ('create table secret_secure_value, index: 1','CREATE UNIQUE INDEX `UQE_secret_secure_value_namespace_name_version` ON `secret_secure_value` (`namespace`,`name`,`version`);',1,'','2022-01-01 00:00:00'), + ('drop table secret_keeper','DROP TABLE IF EXISTS `secret_keeper`',1,'','2022-01-01 00:00:00'), + ('create table secret_keeper','CREATE TABLE IF NOT EXISTS `secret_keeper` (\n`guid` VARCHAR(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci PRIMARY KEY NOT NULL\n, `name` VARCHAR(253) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `namespace` VARCHAR(253) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `annotations` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `labels` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `created` BIGINT(20) NOT NULL\n, `created_by` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `updated` BIGINT(20) NOT NULL\n, `updated_by` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `description` VARCHAR(253) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `type` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `payload` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('create table secret_keeper, index: 0','CREATE UNIQUE INDEX `UQE_secret_keeper_namespace_name` ON `secret_keeper` (`namespace`,`name`);',1,'','2022-01-01 00:00:00'), + ('drop table secret_data_key','DROP TABLE IF EXISTS `secret_data_key`',1,'','2022-01-01 00:00:00'), + ('create table secret_data_key','CREATE TABLE IF NOT EXISTS `secret_data_key` (\n`uid` VARCHAR(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci PRIMARY KEY NOT NULL\n, `namespace` VARCHAR(253) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `label` VARCHAR(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `active` TINYINT(1) NOT NULL\n, `provider` VARCHAR(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `encrypted_data` BLOB NOT NULL\n, `created` DATETIME NOT NULL\n, `updated` DATETIME NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('drop table secret_encrypted_value','DROP TABLE IF EXISTS `secret_encrypted_value`',1,'','2022-01-01 00:00:00'), + ('create table secret_encrypted_value','CREATE TABLE IF NOT EXISTS `secret_encrypted_value` (\n`namespace` VARCHAR(253) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `name` VARCHAR(253) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `version` BIGINT(20) NOT NULL\n, `encrypted_data` BLOB NOT NULL\n, `created` BIGINT(20) NOT NULL\n, `updated` BIGINT(20) NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('create table secret_encrypted_value, index: 0','CREATE UNIQUE INDEX `UQE_secret_encrypted_value_namespace_name_version` ON `secret_encrypted_value` (`namespace`,`name`,`version`);',1,'','2022-01-01 00:00:00'), + ('create index for list on secret_secure_value','CREATE INDEX `IDX_secret_secure_value_namespace_active_updated` ON `secret_secure_value` (`namespace`,`active`,`updated`);',1,'','2022-01-01 00:00:00'), + ('create index for list and read current on secret_data_key','CREATE INDEX `IDX_secret_data_key_namespace_label_active` ON `secret_data_key` (`namespace`,`label`,`active`);',1,'','2022-01-01 00:00:00'), + ('add owner_reference_api_group column to secret_secure_value','alter table `secret_secure_value` ADD COLUMN `owner_reference_api_group` VARCHAR(253) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('add owner_reference_api_version column to secret_secure_value','alter table `secret_secure_value` ADD COLUMN `owner_reference_api_version` VARCHAR(253) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('add owner_reference_kind column to secret_secure_value','alter table `secret_secure_value` ADD COLUMN `owner_reference_kind` VARCHAR(253) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('add owner_reference_name column to secret_secure_value','alter table `secret_secure_value` ADD COLUMN `owner_reference_name` VARCHAR(253) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('add lease_token column to secret_secure_value','alter table `secret_secure_value` ADD COLUMN `lease_token` VARCHAR(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('add lease_token index to secret_secure_value','CREATE INDEX `IDX_secret_secure_value_lease_token` ON `secret_secure_value` (`lease_token`);',1,'','2022-01-01 00:00:00'), + ('add lease_created column to secret_secure_value','alter table `secret_secure_value` ADD COLUMN `lease_created` BIGINT(20) NOT NULL DEFAULT 0 ',1,'','2022-01-01 00:00:00'), + ('add lease_created index to secret_secure_value','CREATE INDEX `IDX_secret_secure_value_lease_created` ON `secret_secure_value` (`lease_created`);',1,'','2022-01-01 00:00:00'), + ('add data_key_id column to secret_encrypted_value','alter table `secret_encrypted_value` ADD COLUMN `data_key_id` VARCHAR(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT \'\' ',1,'','2022-01-01 00:00:00'), + ('add data_key_id index to secret_encrypted_value','CREATE INDEX `IDX_secret_encrypted_value_data_key_id` ON `secret_encrypted_value` (`data_key_id`);',1,'','2022-01-01 00:00:00'), + ('add active column to secret_keeper','alter table `secret_keeper` ADD COLUMN `active` TINYINT(1) NOT NULL DEFAULT 0 ',1,'','2022-01-01 00:00:00'), + ('add active column index to secret_keeper','CREATE INDEX `IDX_secret_keeper_namespace_name_active` ON `secret_keeper` (`namespace`,`name`,`active`);',1,'','2022-01-01 00:00:00'), + ('set secret_secure_value.keeper to \'system\' where keeper is null in secret_secure_value','UPDATE secret_secure_value SET keeper = \'system\' WHERE keeper IS NULL',1,'','2022-01-01 00:00:00'), + ('drop my_row_id and add primary key with columns namespace,name,version to table secret_encrypted_value if my_row_id exists (auto-generated mysql column)','\n ALTER TABLE secret_encrypted_value\n DROP PRIMARY KEY,\n DROP COLUMN my_row_id,\n DROP INDEX UQE_secret_encrypted_value_namespace_name_version,\n ADD PRIMARY KEY (`namespace`,`name`,`version`);\n ',1,'','2022-01-01 00:00:00'), + ('drop unique index UQE_secret_encrypted_value_namespace_name_version from secret_encrypted_value table if it exists (mysql)','ALTER TABLE secret_encrypted_value DROP INDEX UQE_secret_encrypted_value_namespace_name_version',1,'','2022-01-01 00:00:00'), + ('add primary key with columns namespace,name,version to table secret_encrypted_value if it doesn\'t exist (mysql)','ALTER TABLE secret_encrypted_value ADD PRIMARY KEY (`namespace`,`name`,`version`)',1,'','2022-01-01 00:00:00'), + ('add primary key with columns namespace,name,version to table secret_encrypted_value (postgres and sqlite)','',1,'','2022-01-01 00:00:00'); +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; + diff --git a/pkg/services/sqlstore/migrator/snapshot/97-resource_migration_log.sql b/pkg/services/sqlstore/migrator/snapshot/97-resource_migration_log.sql new file mode 100644 index 00000000000..35327ae4531 --- /dev/null +++ b/pkg/services/sqlstore/migrator/snapshot/97-resource_migration_log.sql @@ -0,0 +1,60 @@ +-- MySQL dump 10.13 Distrib 8.4.5, for Linux (x86_64) +-- +-- Host: localhost Database: hg_dump +-- ------------------------------------------------------ +-- Server version 8.4.5 +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; + +-- +-- Dumping data for table `resource_migration_log` +-- + +INSERT INTO `resource_migration_log` (`migration_id`, `sql`, `success`, `error`, `timestamp`) VALUES + ('create resource_migration_log table','CREATE TABLE IF NOT EXISTS `resource_migration_log` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `migration_id` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `sql` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `success` TINYINT(1) NOT NULL\n, `error` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `timestamp` DATETIME NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('Initialize resource tables','',1,'','2022-01-01 00:00:00'), + ('drop table resource','DROP TABLE IF EXISTS `resource`',1,'','2022-01-01 00:00:00'), + ('create table resource','CREATE TABLE IF NOT EXISTS `resource` (\n`guid` VARCHAR(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci PRIMARY KEY NOT NULL\n, `resource_version` BIGINT(20) NULL\n, `group` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `resource` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `namespace` VARCHAR(63) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `name` VARCHAR(253) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `value` LONGTEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `action` INT NOT NULL\n, `label_set` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('create table resource, index: 0','CREATE UNIQUE INDEX `UQE_resource_namespace_group_resource_name` ON `resource` (`namespace`,`group`,`resource`,`name`);',1,'','2022-01-01 00:00:00'), + ('drop table resource_history','DROP TABLE IF EXISTS `resource_history`',1,'','2022-01-01 00:00:00'), + ('create table resource_history','CREATE TABLE IF NOT EXISTS `resource_history` (\n`guid` VARCHAR(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci PRIMARY KEY NOT NULL\n, `resource_version` BIGINT(20) NULL\n, `group` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `resource` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `namespace` VARCHAR(63) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `name` VARCHAR(253) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `value` LONGTEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `action` INT NOT NULL\n, `label_set` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('create table resource_history, index: 0','CREATE UNIQUE INDEX `UQE_resource_history_namespace_group_name_version` ON `resource_history` (`namespace`,`group`,`resource`,`name`,`resource_version`);',1,'','2022-01-01 00:00:00'), + ('create table resource_history, index: 1','CREATE INDEX `IDX_resource_history_resource_version` ON `resource_history` (`resource_version`);',1,'','2022-01-01 00:00:00'), + ('drop table resource_version','DROP TABLE IF EXISTS `resource_version`',1,'','2022-01-01 00:00:00'), + ('create table resource_version','CREATE TABLE IF NOT EXISTS `resource_version` (\n`group` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `resource` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `resource_version` BIGINT(20) NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('create table resource_version, index: 0','CREATE UNIQUE INDEX `UQE_resource_version_group_resource` ON `resource_version` (`group`,`resource`);',1,'','2022-01-01 00:00:00'), + ('drop table resource_blob','DROP TABLE IF EXISTS `resource_blob`',1,'','2022-01-01 00:00:00'), + ('create table resource_blob','CREATE TABLE IF NOT EXISTS `resource_blob` (\n`uuid` CHAR(36) PRIMARY KEY NOT NULL\n, `created` DATETIME NOT NULL\n, `group` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `resource` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `namespace` VARCHAR(63) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `name` VARCHAR(253) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `value` LONGBLOB NOT NULL\n, `hash` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `content_type` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('create table resource_blob, index: 0','CREATE INDEX `IDX_resource_history_namespace_group_name` ON `resource_blob` (`namespace`,`group`,`resource`,`name`);',1,'','2022-01-01 00:00:00'), + ('create table resource_blob, index: 1','CREATE INDEX `IDX_resource_blob_created` ON `resource_blob` (`created`);',1,'','2022-01-01 00:00:00'), + ('drop table resource_last_import_time','DROP TABLE IF EXISTS `resource_last_import_time`',1,'','2022-01-01 00:00:00'), + ('create table resource_last_import_time','CREATE TABLE IF NOT EXISTS `resource_last_import_time` (\n`group` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `resource` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `namespace` VARCHAR(63) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `last_import_time` DATETIME NOT NULL\n, PRIMARY KEY ( `group`,`resource`,`namespace` )) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('Add column previous_resource_version in resource_history','alter table `resource_history` ADD COLUMN `previous_resource_version` BIGINT(20) NULL ',1,'','2022-01-01 00:00:00'), + ('Add column previous_resource_version in resource','alter table `resource` ADD COLUMN `previous_resource_version` BIGINT(20) NULL ',1,'','2022-01-01 00:00:00'), + ('Add index to resource_history for polling','CREATE INDEX `IDX_resource_history_group_resource_resource_version` ON `resource_history` (`group`,`resource`,`resource_version`);',1,'','2022-01-01 00:00:00'), + ('Add index to resource for loading','CREATE INDEX `IDX_resource_group_resource` ON `resource` (`group`,`resource`);',1,'','2022-01-01 00:00:00'), + ('Add column folder in resource_history','alter table `resource_history` ADD COLUMN `folder` VARCHAR(253) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT \'\' ',1,'','2022-01-01 00:00:00'), + ('Add column folder in resource','alter table `resource` ADD COLUMN `folder` VARCHAR(253) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT \'\' ',1,'','2022-01-01 00:00:00'), + ('Migrate DeletionMarkers to real Resource objects','Find rows in resource_history with value LIKE {\"kind\":\"DeletedMarker\"%',1,'','2022-01-01 00:00:00'), + ('Add index to resource_history for get trash','CREATE INDEX `IDX_resource_history_namespace_group_resource_action_version` ON `resource_history` (`namespace`,`group`,`resource`,`action`,`resource_version`);',1,'','2022-01-01 00:00:00'), + ('Add generation to resource history','alter table `resource_history` ADD COLUMN `generation` BIGINT(20) NOT NULL DEFAULT 0 ',1,'','2022-01-01 00:00:00'), + ('Add generation index to resource history','CREATE INDEX `IDX_resource_history_namespace_group_resource_name_generation` ON `resource_history` (`namespace`,`group`,`resource`,`name`,`generation`);',1,'','2022-01-01 00:00:00'), + ('Add UQE_resource_last_import_time_last_import_time index','CREATE INDEX `UQE_resource_last_import_time_last_import_time` ON `resource_last_import_time` (`last_import_time`);',1,'','2022-01-01 00:00:00'), + ('Add key_path column to resource_history','alter table `resource_history` ADD COLUMN `key_path` VARCHAR(2048) CHARACTER SET latin1 COLLATE latin1_bin NOT NULL DEFAULT \'\' ',1,'','2022-01-01 00:00:00'), + ('create table resource_events','CREATE TABLE IF NOT EXISTS `resource_events` (\n`key_path` VARCHAR(2048) CHARACTER SET latin1 COLLATE latin1_bin PRIMARY KEY NOT NULL\n, `value` MEDIUMTEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('Add IDX_resource_history_key_path index','CREATE INDEX `IDX_resource_history_key_path` ON `resource_history` (`key_path`);',1,'','2022-01-01 00:00:00'), + ('drop my_row_id and add primary key with columns group,resource to table resource_version if my_row_id exists (auto-generated mysql column)','\n ALTER TABLE resource_version\n DROP PRIMARY KEY,\n DROP COLUMN my_row_id,\n DROP INDEX UQE_resource_version_group_resource,\n ADD PRIMARY KEY (`group`,`resource`);\n ',1,'','2022-01-01 00:00:00'), + ('drop unique index UQE_resource_version_group_resource from resource_version table if it exists (mysql)','ALTER TABLE resource_version DROP INDEX UQE_resource_version_group_resource',1,'','2022-01-01 00:00:00'), + ('add primary key with columns group,resource to table resource_version if it doesn\'t exist (mysql)','ALTER TABLE resource_version ADD PRIMARY KEY (`group`,`resource`)',1,'','2022-01-01 00:00:00'), + ('add primary key with columns group,resource to table resource_version (postgres and sqlite)','',1,'','2022-01-01 00:00:00'); +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; + diff --git a/pkg/services/sqlstore/migrator/snapshot/98-data.sql b/pkg/services/sqlstore/migrator/snapshot/98-data.sql new file mode 100644 index 00000000000..de4d2e04323 --- /dev/null +++ b/pkg/services/sqlstore/migrator/snapshot/98-data.sql @@ -0,0 +1,469 @@ +-- MySQL dump 10.13 Distrib 8.4.5, for Linux (x86_64) +-- +-- Host: localhost Database: hg_dump +-- ------------------------------------------------------ +-- Server version 8.4.5 +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; + +-- +-- Dumping data for table `alert` +-- + + +-- +-- Dumping data for table `alert_image` +-- + + +-- +-- Dumping data for table `alert_instance` +-- + + +-- +-- Dumping data for table `alert_notification` +-- + + +-- +-- Dumping data for table `alert_notification_state` +-- + + +-- +-- Dumping data for table `alert_rule` +-- + + +-- +-- Dumping data for table `alert_rule_state` +-- + + +-- +-- Dumping data for table `alert_rule_tag` +-- + + +-- +-- Dumping data for table `alert_rule_version` +-- + + +-- +-- Dumping data for table `annotation` +-- + + +-- +-- Dumping data for table `annotation_tag` +-- + + +-- +-- Dumping data for table `anon_device` +-- + + +-- +-- Dumping data for table `api_key` +-- + + +-- +-- Dumping data for table `cache_data` +-- + + +-- +-- Dumping data for table `cloud_migration_resource` +-- + + +-- +-- Dumping data for table `cloud_migration_session` +-- + + +-- +-- Dumping data for table `cloud_migration_snapshot` +-- + + +-- +-- Dumping data for table `cloud_migration_snapshot_partition` +-- + + +-- +-- Dumping data for table `correlation` +-- + + +-- +-- Dumping data for table `dashboard` +-- + + +-- +-- Dumping data for table `dashboard_acl` +-- + +INSERT INTO `dashboard_acl` (`id`, `org_id`, `dashboard_id`, `user_id`, `team_id`, `permission`, `role`, `created`, `updated`) VALUES + (1,-1,-1,NULL,NULL,1,'Viewer','2022-01-01 00:00:00','2022-01-01 00:00:00'), + (2,-1,-1,NULL,NULL,2,'Editor','2022-01-01 00:00:00','2022-01-01 00:00:00'); + +-- +-- Dumping data for table `dashboard_provisioning` +-- + + +-- +-- Dumping data for table `dashboard_public` +-- + + +-- +-- Dumping data for table `dashboard_public_email_share` +-- + + +-- +-- Dumping data for table `dashboard_public_magic_link` +-- + + +-- +-- Dumping data for table `dashboard_public_session` +-- + + +-- +-- Dumping data for table `dashboard_public_usage_by_day` +-- + + +-- +-- Dumping data for table `dashboard_snapshot` +-- + + +-- +-- Dumping data for table `dashboard_tag` +-- + + +-- +-- Dumping data for table `dashboard_usage_by_day` +-- + + +-- +-- Dumping data for table `dashboard_usage_sums` +-- + + +-- +-- Dumping data for table `dashboard_version` +-- + + +-- +-- Dumping data for table `data_keys` +-- + + +-- +-- Dumping data for table `data_source` +-- + + +-- +-- Dumping data for table `data_source_acl` +-- + + +-- +-- Dumping data for table `data_source_cache` +-- + + +-- +-- Dumping data for table `data_source_usage_by_day` +-- + + +-- +-- Dumping data for table `entity_event` +-- + + +-- +-- Dumping data for table `file` +-- + + +-- +-- Dumping data for table `file_meta` +-- + + +-- +-- Dumping data for table `folder` +-- + + +-- +-- Dumping data for table `library_element` +-- + + +-- +-- Dumping data for table `library_element_connection` +-- + + +-- +-- Dumping data for table `license_token` +-- + + +-- +-- Dumping data for table `login_attempt` +-- + + +-- +-- Dumping data for table `ngalert_configuration` +-- + + +-- +-- Dumping data for table `playlist` +-- + + +-- +-- Dumping data for table `playlist_item` +-- + + +-- +-- Dumping data for table `plugin_setting` +-- + + +-- +-- Dumping data for table `preferences` +-- + + +-- +-- Dumping data for table `provenance_type` +-- + + +-- +-- Dumping data for table `query_history` +-- + + +-- +-- Dumping data for table `query_history_details` +-- + + +-- +-- Dumping data for table `query_history_star` +-- + + +-- +-- Dumping data for table `quota` +-- + + +-- +-- Dumping data for table `recording_rules` +-- + + +-- +-- Dumping data for table `remote_write_targets` +-- + + +-- +-- Dumping data for table `report` +-- + + +-- +-- Dumping data for table `report_dashboards` +-- + + +-- +-- Dumping data for table `report_settings` +-- + + +-- +-- Dumping data for table `resource` +-- + + +-- +-- Dumping data for table `resource_blob` +-- + + +-- +-- Dumping data for table `resource_events` +-- + + +-- +-- Dumping data for table `resource_history` +-- + + +-- +-- Dumping data for table `secret_data_key` +-- + + +-- +-- Dumping data for table `secret_encrypted_value` +-- + + +-- +-- Dumping data for table `secret_keeper` +-- + + +-- +-- Dumping data for table `secret_secure_value` +-- + + +-- +-- Dumping data for table `secrets` +-- + + +-- +-- Dumping data for table `session` +-- + + +-- +-- Dumping data for table `setting` +-- + + +-- +-- Dumping data for table `short_url` +-- + + +-- +-- Dumping data for table `signing_key` +-- + + +-- +-- Dumping data for table `sso_setting` +-- + + +-- +-- Dumping data for table `star` +-- + + +-- +-- Dumping data for table `tag` +-- + + +-- +-- Dumping data for table `team` +-- + + +-- +-- Dumping data for table `team_group` +-- + + +-- +-- Dumping data for table `team_member` +-- + + +-- +-- Dumping data for table `team_role` +-- + + +-- +-- Dumping data for table `temp_user` +-- + + +-- +-- Dumping data for table `test_data` +-- + + +-- +-- Dumping data for table `unifiedstorage_migration_log` +-- + +INSERT INTO `unifiedstorage_migration_log` (`id`, `migration_id`, `sql`, `success`, `error`, `timestamp`) VALUES + (1,'create unifiedstorage_migration_log table','CREATE TABLE IF NOT EXISTS `unifiedstorage_migration_log` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `migration_id` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `sql` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `success` TINYINT(1) NOT NULL\n, `error` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `timestamp` DATETIME NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + (2,'playlists migration','unified storage data migration: playlists',1,'','2022-01-01 00:00:00'); + +-- +-- Dumping data for table `user_auth` +-- + + +-- +-- Dumping data for table `user_auth_token` +-- + + +-- +-- Dumping data for table `user_dashboard_views` +-- + + +-- +-- Dumping data for table `user_external_session` +-- + + +-- +-- Dumping data for table `user_role` +-- + + +-- +-- Dumping data for table `user_stats` +-- + +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; + diff --git a/pkg/services/sqlstore/migrator/snapshot/99-migration_log.sql b/pkg/services/sqlstore/migrator/snapshot/99-migration_log.sql new file mode 100644 index 00000000000..b4900f95f13 --- /dev/null +++ b/pkg/services/sqlstore/migrator/snapshot/99-migration_log.sql @@ -0,0 +1,850 @@ +-- MySQL dump 10.13 Distrib 8.4.5, for Linux (x86_64) +-- +-- Host: localhost Database: hg_dump +-- ------------------------------------------------------ +-- Server version 8.4.5 +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; + +-- +-- Dumping data for table `migration_log` +-- + +INSERT INTO `migration_log` (`migration_id`, `sql`, `success`, `error`, `timestamp`) VALUES + ('create migration_log table','CREATE TABLE IF NOT EXISTS `migration_log` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `migration_id` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `sql` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `success` TINYINT(1) NOT NULL\n, `error` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `timestamp` DATETIME NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('create user table','CREATE TABLE IF NOT EXISTS `user` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `version` INT NOT NULL\n, `login` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `email` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `name` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `password` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `salt` VARCHAR(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `rands` VARCHAR(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `company` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `account_id` BIGINT(20) NOT NULL\n, `is_admin` TINYINT(1) NOT NULL\n, `created` DATETIME NOT NULL\n, `updated` DATETIME NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('add unique index user.login','CREATE UNIQUE INDEX `UQE_user_login` ON `user` (`login`);',1,'','2022-01-01 00:00:00'), + ('add unique index user.email','CREATE UNIQUE INDEX `UQE_user_email` ON `user` (`email`);',1,'','2022-01-01 00:00:00'), + ('drop index UQE_user_login - v1','DROP INDEX `UQE_user_login` ON `user`',1,'','2022-01-01 00:00:00'), + ('drop index UQE_user_email - v1','DROP INDEX `UQE_user_email` ON `user`',1,'','2022-01-01 00:00:00'), + ('Rename table user to user_v1 - v1','ALTER TABLE `user` RENAME TO `user_v1`',1,'','2022-01-01 00:00:00'), + ('create user table v2','CREATE TABLE IF NOT EXISTS `user` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `version` INT NOT NULL\n, `login` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `email` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `name` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `password` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `salt` VARCHAR(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `rands` VARCHAR(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `company` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `org_id` BIGINT(20) NOT NULL\n, `is_admin` TINYINT(1) NOT NULL\n, `email_verified` TINYINT(1) NULL\n, `theme` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `created` DATETIME NOT NULL\n, `updated` DATETIME NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('create index UQE_user_login - v2','CREATE UNIQUE INDEX `UQE_user_login` ON `user` (`login`);',1,'','2022-01-01 00:00:00'), + ('create index UQE_user_email - v2','CREATE UNIQUE INDEX `UQE_user_email` ON `user` (`email`);',1,'','2022-01-01 00:00:00'), + ('copy data_source v1 to v2','INSERT INTO `user` (`version`\n, `email`\n, `name`\n, `password`\n, `is_admin`\n, `id`\n, `login`\n, `salt`\n, `rands`\n, `company`\n, `org_id`\n, `created`\n, `updated`)\nSELECT `version`\n, `email`\n, `name`\n, `password`\n, `is_admin`\n, `id`\n, `login`\n, `salt`\n, `rands`\n, `company`\n, `account_id`\n, `created`\n, `updated`\nFROM `user_v1`',1,'','2022-01-01 00:00:00'), + ('Drop old table user_v1','DROP TABLE IF EXISTS `user_v1`',1,'','2022-01-01 00:00:00'), + ('Add column help_flags1 to user table','alter table `user` ADD COLUMN `help_flags1` BIGINT(20) NOT NULL DEFAULT 0 ',1,'','2022-01-01 00:00:00'), + ('Update user table charset','ALTER TABLE `user` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, MODIFY `login` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL , MODIFY `email` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL , MODIFY `name` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL , MODIFY `password` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL , MODIFY `salt` VARCHAR(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL , MODIFY `rands` VARCHAR(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL , MODIFY `company` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL , MODIFY `theme` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ;',1,'','2022-01-01 00:00:00'), + ('Add last_seen_at column to user','alter table `user` ADD COLUMN `last_seen_at` DATETIME NULL ',1,'','2022-01-01 00:00:00'), + ('Add missing user data','code migration',1,'','2022-01-01 00:00:00'), + ('Add is_disabled column to user','alter table `user` ADD COLUMN `is_disabled` TINYINT(1) NOT NULL DEFAULT 0 ',1,'','2022-01-01 00:00:00'), + ('Add index user.login/user.email','CREATE INDEX `IDX_user_login_email` ON `user` (`login`,`email`);',1,'','2022-01-01 00:00:00'), + ('Add is_service_account column to user','alter table `user` ADD COLUMN `is_service_account` TINYINT(1) NOT NULL DEFAULT 0 ',1,'','2022-01-01 00:00:00'), + ('Update is_service_account column to nullable','ALTER TABLE user MODIFY is_service_account BOOLEAN DEFAULT 0;',1,'','2022-01-01 00:00:00'), + ('Add uid column to user','alter table `user` ADD COLUMN `uid` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('Update uid column values for users','UPDATE user SET uid=concat(\'u\',lpad(id,9,\'0\')) WHERE uid IS NULL;',1,'','2022-01-01 00:00:00'), + ('Make sure users uid are set','UPDATE user SET uid=concat(\'u\',lpad(id,9,\'0\')) WHERE uid is NULL OR uid = \'\';',1,'','2022-01-01 00:00:00'), + ('Add unique index user_uid','CREATE UNIQUE INDEX `UQE_user_uid` ON `user` (`uid`);',1,'','2022-01-01 00:00:00'), + ('Add is_provisioned column to user','alter table `user` ADD COLUMN `is_provisioned` TINYINT(1) NOT NULL DEFAULT 0 ',1,'','2022-01-01 00:00:00'), + ('update login field with orgid to allow for multiple service accounts with same name across orgs','code migration',1,'','2022-01-01 00:00:00'), + ('update service accounts login field orgid to appear only once','code migration',1,'','2022-01-01 00:00:00'), + ('update login and email fields to lowercase','code migration',1,'','2022-01-01 00:00:00'), + ('update login and email fields to lowercase2','code migration',1,'','2022-01-01 00:00:00'), + ('Add index on user.is_service_account and user.last_seen_at','CREATE INDEX `IDX_user_is_service_account_last_seen_at` ON `user` (`is_service_account`,`last_seen_at`);',1,'','2022-01-01 00:00:00'), + ('Expand user.uid length to 190','ALTER TABLE user MODIFY uid VARCHAR(190);',1,'','2022-01-01 00:00:00'), + ('Prefix SCIM uid for provisioned users','UPDATE user SET uid = CONCAT(\'scim-\', uid) WHERE is_provisioned = 1 AND uid NOT LIKE \'scim-%\';',1,'','2022-01-01 00:00:00'), + ('create temp user table v1-7','CREATE TABLE IF NOT EXISTS `temp_user` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `org_id` BIGINT(20) NOT NULL\n, `version` INT NOT NULL\n, `email` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `name` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `role` VARCHAR(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `code` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `status` VARCHAR(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `invited_by_user_id` BIGINT(20) NULL\n, `email_sent` TINYINT(1) NOT NULL\n, `email_sent_on` DATETIME NULL\n, `remote_addr` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `created` DATETIME NOT NULL\n, `updated` DATETIME NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('create index IDX_temp_user_email - v1-7','CREATE INDEX `IDX_temp_user_email` ON `temp_user` (`email`);',1,'','2022-01-01 00:00:00'), + ('create index IDX_temp_user_org_id - v1-7','CREATE INDEX `IDX_temp_user_org_id` ON `temp_user` (`org_id`);',1,'','2022-01-01 00:00:00'), + ('create index IDX_temp_user_code - v1-7','CREATE INDEX `IDX_temp_user_code` ON `temp_user` (`code`);',1,'','2022-01-01 00:00:00'), + ('create index IDX_temp_user_status - v1-7','CREATE INDEX `IDX_temp_user_status` ON `temp_user` (`status`);',1,'','2022-01-01 00:00:00'), + ('Update temp_user table charset','ALTER TABLE `temp_user` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, MODIFY `email` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL , MODIFY `name` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL , MODIFY `role` VARCHAR(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL , MODIFY `code` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL , MODIFY `status` VARCHAR(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL , MODIFY `remote_addr` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ;',1,'','2022-01-01 00:00:00'), + ('drop index IDX_temp_user_email - v1','DROP INDEX `IDX_temp_user_email` ON `temp_user`',1,'','2022-01-01 00:00:00'), + ('drop index IDX_temp_user_org_id - v1','DROP INDEX `IDX_temp_user_org_id` ON `temp_user`',1,'','2022-01-01 00:00:00'), + ('drop index IDX_temp_user_code - v1','DROP INDEX `IDX_temp_user_code` ON `temp_user`',1,'','2022-01-01 00:00:00'), + ('drop index IDX_temp_user_status - v1','DROP INDEX `IDX_temp_user_status` ON `temp_user`',1,'','2022-01-01 00:00:00'), + ('Rename table temp_user to temp_user_tmp_qwerty - v1','ALTER TABLE `temp_user` RENAME TO `temp_user_tmp_qwerty`',1,'','2022-01-01 00:00:00'), + ('create temp_user v2','CREATE TABLE IF NOT EXISTS `temp_user` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `org_id` BIGINT(20) NOT NULL\n, `version` INT NOT NULL\n, `email` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `name` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `role` VARCHAR(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `code` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `status` VARCHAR(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `invited_by_user_id` BIGINT(20) NULL\n, `email_sent` TINYINT(1) NOT NULL\n, `email_sent_on` DATETIME NULL\n, `remote_addr` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `created` INT NOT NULL DEFAULT 0\n, `updated` INT NOT NULL DEFAULT 0\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('create index IDX_temp_user_email - v2','CREATE INDEX `IDX_temp_user_email` ON `temp_user` (`email`);',1,'','2022-01-01 00:00:00'), + ('create index IDX_temp_user_org_id - v2','CREATE INDEX `IDX_temp_user_org_id` ON `temp_user` (`org_id`);',1,'','2022-01-01 00:00:00'), + ('create index IDX_temp_user_code - v2','CREATE INDEX `IDX_temp_user_code` ON `temp_user` (`code`);',1,'','2022-01-01 00:00:00'), + ('create index IDX_temp_user_status - v2','CREATE INDEX `IDX_temp_user_status` ON `temp_user` (`status`);',1,'','2022-01-01 00:00:00'), + ('copy temp_user v1 to v2','INSERT INTO `temp_user` (`invited_by_user_id`\n, `email_sent`\n, `email_sent_on`\n, `org_id`\n, `version`\n, `email`\n, `name`\n, `code`\n, `status`\n, `remote_addr`\n, `id`\n, `role`)\nSELECT `invited_by_user_id`\n, `email_sent`\n, `email_sent_on`\n, `org_id`\n, `version`\n, `email`\n, `name`\n, `code`\n, `status`\n, `remote_addr`\n, `id`\n, `role`\nFROM `temp_user_tmp_qwerty`',1,'','2022-01-01 00:00:00'), + ('drop temp_user_tmp_qwerty','DROP TABLE IF EXISTS `temp_user_tmp_qwerty`',1,'','2022-01-01 00:00:00'), + ('Set created for temp users that will otherwise prematurely expire','code migration',1,'','2022-01-01 00:00:00'), + ('create star table','CREATE TABLE IF NOT EXISTS `star` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `user_id` BIGINT(20) NOT NULL\n, `dashboard_id` BIGINT(20) NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('add unique index star.user_id_dashboard_id','CREATE UNIQUE INDEX `UQE_star_user_id_dashboard_id` ON `star` (`user_id`,`dashboard_id`);',1,'','2022-01-01 00:00:00'), + ('Add column dashboard_uid in star','alter table `star` ADD COLUMN `dashboard_uid` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('Add column org_id in star','alter table `star` ADD COLUMN `org_id` BIGINT(20) NULL DEFAULT 1 ',1,'','2022-01-01 00:00:00'), + ('Add column updated in star','alter table `star` ADD COLUMN `updated` DATETIME NULL ',1,'','2022-01-01 00:00:00'), + ('add index in star table on dashboard_uid, org_id and user_id columns','CREATE UNIQUE INDEX `UQE_star_user_id_dashboard_uid_org_id` ON `star` (`user_id`,`dashboard_uid`,`org_id`);',1,'','2022-01-01 00:00:00'), + ('create org table v1','CREATE TABLE IF NOT EXISTS `org` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `version` INT NOT NULL\n, `name` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `address1` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `address2` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `city` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `state` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `zip_code` VARCHAR(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `country` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `billing_email` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `created` DATETIME NOT NULL\n, `updated` DATETIME NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('create index UQE_org_name - v1','CREATE UNIQUE INDEX `UQE_org_name` ON `org` (`name`);',1,'','2022-01-01 00:00:00'), + ('create org_user table v1','CREATE TABLE IF NOT EXISTS `org_user` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `org_id` BIGINT(20) NOT NULL\n, `user_id` BIGINT(20) NOT NULL\n, `role` VARCHAR(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `created` DATETIME NOT NULL\n, `updated` DATETIME NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('create index IDX_org_user_org_id - v1','CREATE INDEX `IDX_org_user_org_id` ON `org_user` (`org_id`);',1,'','2022-01-01 00:00:00'), + ('create index UQE_org_user_org_id_user_id - v1','CREATE UNIQUE INDEX `UQE_org_user_org_id_user_id` ON `org_user` (`org_id`,`user_id`);',1,'','2022-01-01 00:00:00'), + ('create index IDX_org_user_user_id - v1','CREATE INDEX `IDX_org_user_user_id` ON `org_user` (`user_id`);',1,'','2022-01-01 00:00:00'), + ('Update org table charset','ALTER TABLE `org` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, MODIFY `name` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL , MODIFY `address1` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL , MODIFY `address2` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL , MODIFY `city` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL , MODIFY `state` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL , MODIFY `zip_code` VARCHAR(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL , MODIFY `country` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL , MODIFY `billing_email` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ;',1,'','2022-01-01 00:00:00'), + ('Update org_user table charset','ALTER TABLE `org_user` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, MODIFY `role` VARCHAR(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL ;',1,'','2022-01-01 00:00:00'), + ('Migrate all Read Only Viewers to Viewers','UPDATE org_user SET role = \'Viewer\' WHERE role = \'Read Only Editor\'',1,'','2022-01-01 00:00:00'), + ('create dashboard table','CREATE TABLE IF NOT EXISTS `dashboard` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `version` INT NOT NULL\n, `slug` VARCHAR(189) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `title` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `data` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `account_id` BIGINT(20) NOT NULL\n, `created` DATETIME NOT NULL\n, `updated` DATETIME NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('add index dashboard.account_id','CREATE INDEX `IDX_dashboard_account_id` ON `dashboard` (`account_id`);',1,'','2022-01-01 00:00:00'), + ('add unique index dashboard_account_id_slug','CREATE UNIQUE INDEX `UQE_dashboard_account_id_slug` ON `dashboard` (`account_id`,`slug`);',1,'','2022-01-01 00:00:00'), + ('create dashboard_tag table','CREATE TABLE IF NOT EXISTS `dashboard_tag` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `dashboard_id` BIGINT(20) NOT NULL\n, `term` VARCHAR(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('add unique index dashboard_tag.dasboard_id_term','CREATE UNIQUE INDEX `UQE_dashboard_tag_dashboard_id_term` ON `dashboard_tag` (`dashboard_id`,`term`);',1,'','2022-01-01 00:00:00'), + ('drop index UQE_dashboard_tag_dashboard_id_term - v1','DROP INDEX `UQE_dashboard_tag_dashboard_id_term` ON `dashboard_tag`',1,'','2022-01-01 00:00:00'), + ('Rename table dashboard to dashboard_v1 - v1','ALTER TABLE `dashboard` RENAME TO `dashboard_v1`',1,'','2022-01-01 00:00:00'), + ('create dashboard v2','CREATE TABLE IF NOT EXISTS `dashboard` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `version` INT NOT NULL\n, `slug` VARCHAR(189) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `title` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `data` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `org_id` BIGINT(20) NOT NULL\n, `created` DATETIME NOT NULL\n, `updated` DATETIME NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('create index IDX_dashboard_org_id - v2','CREATE INDEX `IDX_dashboard_org_id` ON `dashboard` (`org_id`);',1,'','2022-01-01 00:00:00'), + ('create index UQE_dashboard_org_id_slug - v2','CREATE UNIQUE INDEX `UQE_dashboard_org_id_slug` ON `dashboard` (`org_id`,`slug`);',1,'','2022-01-01 00:00:00'), + ('copy dashboard v1 to v2','INSERT INTO `dashboard` (`id`\n, `version`\n, `slug`\n, `title`\n, `data`\n, `org_id`\n, `created`\n, `updated`)\nSELECT `id`\n, `version`\n, `slug`\n, `title`\n, `data`\n, `account_id`\n, `created`\n, `updated`\nFROM `dashboard_v1`',1,'','2022-01-01 00:00:00'), + ('drop table dashboard_v1','DROP TABLE IF EXISTS `dashboard_v1`',1,'','2022-01-01 00:00:00'), + ('alter dashboard.data to mediumtext v1','ALTER TABLE dashboard MODIFY data MEDIUMTEXT;',1,'','2022-01-01 00:00:00'), + ('Add column updated_by in dashboard - v2','alter table `dashboard` ADD COLUMN `updated_by` INT NULL ',1,'','2022-01-01 00:00:00'), + ('Add column created_by in dashboard - v2','alter table `dashboard` ADD COLUMN `created_by` INT NULL ',1,'','2022-01-01 00:00:00'), + ('Add column gnetId in dashboard','alter table `dashboard` ADD COLUMN `gnet_id` BIGINT(20) NULL ',1,'','2022-01-01 00:00:00'), + ('Add index for gnetId in dashboard','CREATE INDEX `IDX_dashboard_gnet_id` ON `dashboard` (`gnet_id`);',1,'','2022-01-01 00:00:00'), + ('Add column plugin_id in dashboard','alter table `dashboard` ADD COLUMN `plugin_id` VARCHAR(189) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('Add index for plugin_id in dashboard','CREATE INDEX `IDX_dashboard_org_id_plugin_id` ON `dashboard` (`org_id`,`plugin_id`);',1,'','2022-01-01 00:00:00'), + ('Add index for dashboard_id in dashboard_tag','CREATE INDEX `IDX_dashboard_tag_dashboard_id` ON `dashboard_tag` (`dashboard_id`);',1,'','2022-01-01 00:00:00'), + ('Update dashboard table charset','ALTER TABLE `dashboard` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, MODIFY `slug` VARCHAR(189) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL , MODIFY `title` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL , MODIFY `plugin_id` VARCHAR(189) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL , MODIFY `data` MEDIUMTEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL ;',1,'','2022-01-01 00:00:00'), + ('Update dashboard_tag table charset','ALTER TABLE `dashboard_tag` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, MODIFY `term` VARCHAR(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL ;',1,'','2022-01-01 00:00:00'), + ('Add column folder_id in dashboard','alter table `dashboard` ADD COLUMN `folder_id` BIGINT(20) NOT NULL DEFAULT 0 ',1,'','2022-01-01 00:00:00'), + ('Add column isFolder in dashboard','alter table `dashboard` ADD COLUMN `is_folder` TINYINT(1) NOT NULL DEFAULT 0 ',1,'','2022-01-01 00:00:00'), + ('Add column has_acl in dashboard','alter table `dashboard` ADD COLUMN `has_acl` TINYINT(1) NOT NULL DEFAULT 0 ',1,'','2022-01-01 00:00:00'), + ('Add column uid in dashboard','alter table `dashboard` ADD COLUMN `uid` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('Update uid column values in dashboard','UPDATE dashboard SET uid=lpad(id,9,\'0\') WHERE uid IS NULL;',1,'','2022-01-01 00:00:00'), + ('Add unique index dashboard_org_id_uid','CREATE UNIQUE INDEX `UQE_dashboard_org_id_uid` ON `dashboard` (`org_id`,`uid`);',1,'','2022-01-01 00:00:00'), + ('Remove unique index org_id_slug','DROP INDEX `UQE_dashboard_org_id_slug` ON `dashboard`',1,'','2022-01-01 00:00:00'), + ('Update dashboard title length','ALTER TABLE `dashboard` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, MODIFY `title` VARCHAR(189) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL ;',1,'','2022-01-01 00:00:00'), + ('Add unique index for dashboard_org_id_title_folder_id','CREATE UNIQUE INDEX `UQE_dashboard_org_id_folder_id_title` ON `dashboard` (`org_id`,`folder_id`,`title`);',1,'','2022-01-01 00:00:00'), + ('create dashboard_provisioning','CREATE TABLE IF NOT EXISTS `dashboard_provisioning` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `dashboard_id` BIGINT(20) NULL\n, `name` VARCHAR(150) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `external_id` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `updated` DATETIME NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('Rename table dashboard_provisioning to dashboard_provisioning_tmp_qwerty - v1','ALTER TABLE `dashboard_provisioning` RENAME TO `dashboard_provisioning_tmp_qwerty`',1,'','2022-01-01 00:00:00'), + ('create dashboard_provisioning v2','CREATE TABLE IF NOT EXISTS `dashboard_provisioning` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `dashboard_id` BIGINT(20) NULL\n, `name` VARCHAR(150) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `external_id` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `updated` INT NOT NULL DEFAULT 0\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('create index IDX_dashboard_provisioning_dashboard_id - v2','CREATE INDEX `IDX_dashboard_provisioning_dashboard_id` ON `dashboard_provisioning` (`dashboard_id`);',1,'','2022-01-01 00:00:00'), + ('create index IDX_dashboard_provisioning_dashboard_id_name - v2','CREATE INDEX `IDX_dashboard_provisioning_dashboard_id_name` ON `dashboard_provisioning` (`dashboard_id`,`name`);',1,'','2022-01-01 00:00:00'), + ('copy dashboard_provisioning v1 to v2','INSERT INTO `dashboard_provisioning` (`name`\n, `external_id`\n, `id`\n, `dashboard_id`)\nSELECT `name`\n, `external_id`\n, `id`\n, `dashboard_id`\nFROM `dashboard_provisioning_tmp_qwerty`',1,'','2022-01-01 00:00:00'), + ('drop dashboard_provisioning_tmp_qwerty','DROP TABLE IF EXISTS `dashboard_provisioning_tmp_qwerty`',1,'','2022-01-01 00:00:00'), + ('Add check_sum column','alter table `dashboard_provisioning` ADD COLUMN `check_sum` VARCHAR(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('Add index for dashboard_title','CREATE INDEX `IDX_dashboard_title` ON `dashboard` (`title`);',1,'','2022-01-01 00:00:00'), + ('delete tags for deleted dashboards','DELETE FROM dashboard_tag WHERE dashboard_id NOT IN (SELECT id FROM dashboard)',1,'','2022-01-01 00:00:00'), + ('delete stars for deleted dashboards','DELETE FROM star WHERE dashboard_id NOT IN (SELECT id FROM dashboard)',1,'','2022-01-01 00:00:00'), + ('Add index for dashboard_is_folder','CREATE INDEX `IDX_dashboard_is_folder` ON `dashboard` (`is_folder`);',1,'','2022-01-01 00:00:00'), + ('Add isPublic for dashboard','alter table `dashboard` ADD COLUMN `is_public` TINYINT(1) NOT NULL DEFAULT 0 ',1,'','2022-01-01 00:00:00'), + ('Add deleted for dashboard','alter table `dashboard` ADD COLUMN `deleted` DATETIME NULL ',1,'','2022-01-01 00:00:00'), + ('Add index for deleted','CREATE INDEX `IDX_dashboard_deleted` ON `dashboard` (`deleted`);',1,'','2022-01-01 00:00:00'), + ('Add column dashboard_uid in dashboard_tag','alter table `dashboard_tag` ADD COLUMN `dashboard_uid` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('Add column org_id in dashboard_tag','alter table `dashboard_tag` ADD COLUMN `org_id` BIGINT(20) NULL DEFAULT 1 ',1,'','2022-01-01 00:00:00'), + ('Add missing dashboard_uid and org_id to dashboard_tag','code migration',1,'','2022-01-01 00:00:00'), + ('Add apiVersion for dashboard','alter table `dashboard` ADD COLUMN `api_version` VARCHAR(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('Add index for dashboard_uid on dashboard_tag table','CREATE INDEX `IDX_dashboard_tag_dashboard_uid` ON `dashboard_tag` (`dashboard_uid`);',1,'','2022-01-01 00:00:00'), + ('Add missing dashboard_uid and org_id to star','code migration',1,'','2022-01-01 00:00:00'), + ('create data_source table','CREATE TABLE IF NOT EXISTS `data_source` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `account_id` BIGINT(20) NOT NULL\n, `version` INT NOT NULL\n, `type` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `name` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `access` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `url` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `password` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `user` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `database` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `basic_auth` TINYINT(1) NOT NULL\n, `basic_auth_user` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `basic_auth_password` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `is_default` TINYINT(1) NOT NULL\n, `created` DATETIME NOT NULL\n, `updated` DATETIME NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('add index data_source.account_id','CREATE INDEX `IDX_data_source_account_id` ON `data_source` (`account_id`);',1,'','2022-01-01 00:00:00'), + ('add unique index data_source.account_id_name','CREATE UNIQUE INDEX `UQE_data_source_account_id_name` ON `data_source` (`account_id`,`name`);',1,'','2022-01-01 00:00:00'), + ('drop index IDX_data_source_account_id - v1','DROP INDEX `IDX_data_source_account_id` ON `data_source`',1,'','2022-01-01 00:00:00'), + ('drop index UQE_data_source_account_id_name - v1','DROP INDEX `UQE_data_source_account_id_name` ON `data_source`',1,'','2022-01-01 00:00:00'), + ('Rename table data_source to data_source_v1 - v1','ALTER TABLE `data_source` RENAME TO `data_source_v1`',1,'','2022-01-01 00:00:00'), + ('create data_source table v2','CREATE TABLE IF NOT EXISTS `data_source` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `org_id` BIGINT(20) NOT NULL\n, `version` INT NOT NULL\n, `type` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `name` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `access` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `url` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `password` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `user` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `database` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `basic_auth` TINYINT(1) NOT NULL\n, `basic_auth_user` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `basic_auth_password` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `is_default` TINYINT(1) NOT NULL\n, `json_data` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `created` DATETIME NOT NULL\n, `updated` DATETIME NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('create index IDX_data_source_org_id - v2','CREATE INDEX `IDX_data_source_org_id` ON `data_source` (`org_id`);',1,'','2022-01-01 00:00:00'), + ('create index UQE_data_source_org_id_name - v2','CREATE UNIQUE INDEX `UQE_data_source_org_id_name` ON `data_source` (`org_id`,`name`);',1,'','2022-01-01 00:00:00'), + ('Drop old table data_source_v1 #2','DROP TABLE IF EXISTS `data_source_v1`',1,'','2022-01-01 00:00:00'), + ('Add column with_credentials','alter table `data_source` ADD COLUMN `with_credentials` TINYINT(1) NOT NULL DEFAULT 0 ',1,'','2022-01-01 00:00:00'), + ('Add secure json data column','alter table `data_source` ADD COLUMN `secure_json_data` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('Update data_source table charset','ALTER TABLE `data_source` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, MODIFY `type` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL , MODIFY `name` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL , MODIFY `access` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL , MODIFY `url` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL , MODIFY `password` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL , MODIFY `user` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL , MODIFY `database` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL , MODIFY `basic_auth_user` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL , MODIFY `basic_auth_password` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL , MODIFY `json_data` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL , MODIFY `secure_json_data` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ;',1,'','2022-01-01 00:00:00'), + ('Update initial version to 1','UPDATE data_source SET version = 1 WHERE version = 0',1,'','2022-01-01 00:00:00'), + ('Add read_only data column','alter table `data_source` ADD COLUMN `read_only` TINYINT(1) NULL ',1,'','2022-01-01 00:00:00'), + ('Migrate logging ds to loki ds','UPDATE data_source SET type = \'loki\' WHERE type = \'logging\'',1,'','2022-01-01 00:00:00'), + ('Update json_data with nulls','UPDATE data_source SET json_data = \'{}\' WHERE json_data is null',1,'','2022-01-01 00:00:00'), + ('Add uid column','alter table `data_source` ADD COLUMN `uid` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 0 ',1,'','2022-01-01 00:00:00'), + ('Update uid value','UPDATE data_source SET uid=lpad(id,9,\'0\');',1,'','2022-01-01 00:00:00'), + ('Add unique index datasource_org_id_uid','CREATE UNIQUE INDEX `UQE_data_source_org_id_uid` ON `data_source` (`org_id`,`uid`);',1,'','2022-01-01 00:00:00'), + ('add unique index datasource_org_id_is_default','CREATE INDEX `IDX_data_source_org_id_is_default` ON `data_source` (`org_id`,`is_default`);',1,'','2022-01-01 00:00:00'), + ('Add is_prunable column','alter table `data_source` ADD COLUMN `is_prunable` TINYINT(1) NULL DEFAULT 0 ',1,'','2022-01-01 00:00:00'), + ('Add api_version column','alter table `data_source` ADD COLUMN `api_version` VARCHAR(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('Update secure_json_data column to MediumText','ALTER TABLE data_source MODIFY COLUMN secure_json_data MEDIUMTEXT;',1,'','2022-01-01 00:00:00'), + ('Update json_data column to MediumText','ALTER TABLE data_source MODIFY COLUMN json_data MEDIUMTEXT;',1,'','2022-01-01 00:00:00'), + ('create api_key table','CREATE TABLE IF NOT EXISTS `api_key` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `account_id` BIGINT(20) NOT NULL\n, `name` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `key` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `role` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `created` DATETIME NOT NULL\n, `updated` DATETIME NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('add index api_key.account_id','CREATE INDEX `IDX_api_key_account_id` ON `api_key` (`account_id`);',1,'','2022-01-01 00:00:00'), + ('add index api_key.key','CREATE UNIQUE INDEX `UQE_api_key_key` ON `api_key` (`key`);',1,'','2022-01-01 00:00:00'), + ('add index api_key.account_id_name','CREATE UNIQUE INDEX `UQE_api_key_account_id_name` ON `api_key` (`account_id`,`name`);',1,'','2022-01-01 00:00:00'), + ('drop index IDX_api_key_account_id - v1','DROP INDEX `IDX_api_key_account_id` ON `api_key`',1,'','2022-01-01 00:00:00'), + ('drop index UQE_api_key_key - v1','DROP INDEX `UQE_api_key_key` ON `api_key`',1,'','2022-01-01 00:00:00'), + ('drop index UQE_api_key_account_id_name - v1','DROP INDEX `UQE_api_key_account_id_name` ON `api_key`',1,'','2022-01-01 00:00:00'), + ('Rename table api_key to api_key_v1 - v1','ALTER TABLE `api_key` RENAME TO `api_key_v1`',1,'','2022-01-01 00:00:00'), + ('create api_key table v2','CREATE TABLE IF NOT EXISTS `api_key` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `org_id` BIGINT(20) NOT NULL\n, `name` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `key` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `role` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `created` DATETIME NOT NULL\n, `updated` DATETIME NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('create index IDX_api_key_org_id - v2','CREATE INDEX `IDX_api_key_org_id` ON `api_key` (`org_id`);',1,'','2022-01-01 00:00:00'), + ('create index UQE_api_key_key - v2','CREATE UNIQUE INDEX `UQE_api_key_key` ON `api_key` (`key`);',1,'','2022-01-01 00:00:00'), + ('create index UQE_api_key_org_id_name - v2','CREATE UNIQUE INDEX `UQE_api_key_org_id_name` ON `api_key` (`org_id`,`name`);',1,'','2022-01-01 00:00:00'), + ('copy api_key v1 to v2','INSERT INTO `api_key` (`name`\n, `key`\n, `role`\n, `created`\n, `updated`\n, `id`\n, `org_id`)\nSELECT `name`\n, `key`\n, `role`\n, `created`\n, `updated`\n, `id`\n, `account_id`\nFROM `api_key_v1`',1,'','2022-01-01 00:00:00'), + ('Drop old table api_key_v1','DROP TABLE IF EXISTS `api_key_v1`',1,'','2022-01-01 00:00:00'), + ('Update api_key table charset','ALTER TABLE `api_key` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, MODIFY `name` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL , MODIFY `key` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL , MODIFY `role` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL ;',1,'','2022-01-01 00:00:00'), + ('Add expires to api_key table','alter table `api_key` ADD COLUMN `expires` BIGINT(20) NULL ',1,'','2022-01-01 00:00:00'), + ('Add service account foreign key','alter table `api_key` ADD COLUMN `service_account_id` BIGINT(20) NULL ',1,'','2022-01-01 00:00:00'), + ('set service account foreign key to nil if 0','UPDATE api_key SET service_account_id = NULL WHERE service_account_id = 0;',1,'','2022-01-01 00:00:00'), + ('Add last_used_at to api_key table','alter table `api_key` ADD COLUMN `last_used_at` DATETIME NULL ',1,'','2022-01-01 00:00:00'), + ('Add is_revoked column to api_key table','alter table `api_key` ADD COLUMN `is_revoked` TINYINT(1) NULL DEFAULT 0 ',1,'','2022-01-01 00:00:00'), + ('create dashboard_snapshot table v4','CREATE TABLE IF NOT EXISTS `dashboard_snapshot` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `name` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `key` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `dashboard` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `expires` DATETIME NOT NULL\n, `created` DATETIME NOT NULL\n, `updated` DATETIME NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('drop table dashboard_snapshot_v4 #1','DROP TABLE IF EXISTS `dashboard_snapshot`',1,'','2022-01-01 00:00:00'), + ('create dashboard_snapshot table v5 #2','CREATE TABLE IF NOT EXISTS `dashboard_snapshot` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `name` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `key` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `delete_key` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `org_id` BIGINT(20) NOT NULL\n, `user_id` BIGINT(20) NOT NULL\n, `external` TINYINT(1) NOT NULL\n, `external_url` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `dashboard` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `expires` DATETIME NOT NULL\n, `created` DATETIME NOT NULL\n, `updated` DATETIME NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('create index UQE_dashboard_snapshot_key - v5','CREATE UNIQUE INDEX `UQE_dashboard_snapshot_key` ON `dashboard_snapshot` (`key`);',1,'','2022-01-01 00:00:00'), + ('create index UQE_dashboard_snapshot_delete_key - v5','CREATE UNIQUE INDEX `UQE_dashboard_snapshot_delete_key` ON `dashboard_snapshot` (`delete_key`);',1,'','2022-01-01 00:00:00'), + ('create index IDX_dashboard_snapshot_user_id - v5','CREATE INDEX `IDX_dashboard_snapshot_user_id` ON `dashboard_snapshot` (`user_id`);',1,'','2022-01-01 00:00:00'), + ('alter dashboard_snapshot to mediumtext v2','ALTER TABLE dashboard_snapshot MODIFY dashboard MEDIUMTEXT;',1,'','2022-01-01 00:00:00'), + ('Update dashboard_snapshot table charset','ALTER TABLE `dashboard_snapshot` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, MODIFY `name` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL , MODIFY `key` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL , MODIFY `delete_key` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL , MODIFY `external_url` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL , MODIFY `dashboard` MEDIUMTEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL ;',1,'','2022-01-01 00:00:00'), + ('Add column external_delete_url to dashboard_snapshots table','alter table `dashboard_snapshot` ADD COLUMN `external_delete_url` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('Add encrypted dashboard json column','alter table `dashboard_snapshot` ADD COLUMN `dashboard_encrypted` BLOB NULL ',1,'','2022-01-01 00:00:00'), + ('Change dashboard_encrypted column to MEDIUMBLOB','ALTER TABLE dashboard_snapshot MODIFY dashboard_encrypted MEDIUMBLOB;',1,'','2022-01-01 00:00:00'), + ('create quota table v1','CREATE TABLE IF NOT EXISTS `quota` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `org_id` BIGINT(20) NULL\n, `user_id` BIGINT(20) NULL\n, `target` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `limit` BIGINT(20) NOT NULL\n, `created` DATETIME NOT NULL\n, `updated` DATETIME NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('create index UQE_quota_org_id_user_id_target - v1','CREATE UNIQUE INDEX `UQE_quota_org_id_user_id_target` ON `quota` (`org_id`,`user_id`,`target`);',1,'','2022-01-01 00:00:00'), + ('Update quota table charset','ALTER TABLE `quota` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, MODIFY `target` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL ;',1,'','2022-01-01 00:00:00'), + ('create plugin_setting table','CREATE TABLE IF NOT EXISTS `plugin_setting` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `org_id` BIGINT(20) NULL\n, `plugin_id` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `enabled` TINYINT(1) NOT NULL\n, `pinned` TINYINT(1) NOT NULL\n, `json_data` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `secure_json_data` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `created` DATETIME NOT NULL\n, `updated` DATETIME NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('create index UQE_plugin_setting_org_id_plugin_id - v1','CREATE UNIQUE INDEX `UQE_plugin_setting_org_id_plugin_id` ON `plugin_setting` (`org_id`,`plugin_id`);',1,'','2022-01-01 00:00:00'), + ('Add column plugin_version to plugin_settings','alter table `plugin_setting` ADD COLUMN `plugin_version` VARCHAR(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('Update plugin_setting table charset','ALTER TABLE `plugin_setting` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, MODIFY `plugin_id` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL , MODIFY `json_data` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL , MODIFY `secure_json_data` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL , MODIFY `plugin_version` VARCHAR(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ;',1,'','2022-01-01 00:00:00'), + ('update NULL org_id to 1','UPDATE plugin_setting SET org_id=1 where org_id IS NULL;',1,'','2022-01-01 00:00:00'), + ('make org_id NOT NULL and DEFAULT VALUE 1','ALTER TABLE plugin_setting MODIFY COLUMN org_id BIGINT NOT NULL DEFAULT 1;',1,'','2022-01-01 00:00:00'), + ('create session table','CREATE TABLE IF NOT EXISTS `session` (\n`key` CHAR(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci PRIMARY KEY NOT NULL\n, `data` BLOB NOT NULL\n, `expiry` INTEGER(255) NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('Drop old table playlist table','DROP TABLE IF EXISTS `playlist`',1,'','2022-01-01 00:00:00'), + ('Drop old table playlist_item table','DROP TABLE IF EXISTS `playlist_item`',1,'','2022-01-01 00:00:00'), + ('create playlist table v2','CREATE TABLE IF NOT EXISTS `playlist` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `name` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `interval` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `org_id` BIGINT(20) NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('create playlist item table v2','CREATE TABLE IF NOT EXISTS `playlist_item` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `playlist_id` BIGINT(20) NOT NULL\n, `type` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `value` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `title` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `order` INT NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('Update playlist table charset','ALTER TABLE `playlist` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, MODIFY `name` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL , MODIFY `interval` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL ;',1,'','2022-01-01 00:00:00'), + ('Update playlist_item table charset','ALTER TABLE `playlist_item` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, MODIFY `type` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL , MODIFY `value` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL , MODIFY `title` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL ;',1,'','2022-01-01 00:00:00'), + ('Add playlist column created_at','alter table `playlist` ADD COLUMN `created_at` BIGINT(20) NOT NULL DEFAULT 0 ',1,'','2022-01-01 00:00:00'), + ('Add playlist column updated_at','alter table `playlist` ADD COLUMN `updated_at` BIGINT(20) NOT NULL DEFAULT 0 ',1,'','2022-01-01 00:00:00'), + ('drop preferences table v2','DROP TABLE IF EXISTS `preferences`',1,'','2022-01-01 00:00:00'), + ('drop preferences table v3','DROP TABLE IF EXISTS `preferences`',1,'','2022-01-01 00:00:00'), + ('create preferences table v3','CREATE TABLE IF NOT EXISTS `preferences` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `org_id` BIGINT(20) NOT NULL\n, `user_id` BIGINT(20) NOT NULL\n, `version` INT NOT NULL\n, `home_dashboard_id` BIGINT(20) NOT NULL\n, `timezone` VARCHAR(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `theme` VARCHAR(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `created` DATETIME NOT NULL\n, `updated` DATETIME NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('Update preferences table charset','ALTER TABLE `preferences` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, MODIFY `timezone` VARCHAR(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL , MODIFY `theme` VARCHAR(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL ;',1,'','2022-01-01 00:00:00'), + ('Add column team_id in preferences','alter table `preferences` ADD COLUMN `team_id` BIGINT(20) NULL ',1,'','2022-01-01 00:00:00'), + ('Update team_id column values in preferences','UPDATE preferences SET team_id=0 WHERE team_id IS NULL;',1,'','2022-01-01 00:00:00'), + ('Add column week_start in preferences','alter table `preferences` ADD COLUMN `week_start` VARCHAR(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('Add column preferences.json_data','alter table `preferences` ADD COLUMN `json_data` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('alter preferences.json_data to mediumtext v1','ALTER TABLE preferences MODIFY json_data MEDIUMTEXT;',1,'','2022-01-01 00:00:00'), + ('Add preferences index org_id','CREATE INDEX `IDX_preferences_org_id` ON `preferences` (`org_id`);',1,'','2022-01-01 00:00:00'), + ('Add preferences index user_id','CREATE INDEX `IDX_preferences_user_id` ON `preferences` (`user_id`);',1,'','2022-01-01 00:00:00'), + ('Add home_dashboard_uid column to preferences table','alter table `preferences` ADD COLUMN `home_dashboard_uid` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('Add missing dashboard_uid to preferences table','code migration',1,'','2022-01-01 00:00:00'), + ('create alert table v1','CREATE TABLE IF NOT EXISTS `alert` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `version` BIGINT(20) NOT NULL\n, `dashboard_id` BIGINT(20) NOT NULL\n, `panel_id` BIGINT(20) NOT NULL\n, `org_id` BIGINT(20) NOT NULL\n, `name` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `message` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `state` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `settings` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `frequency` BIGINT(20) NOT NULL\n, `handler` BIGINT(20) NOT NULL\n, `severity` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `silenced` TINYINT(1) NOT NULL\n, `execution_error` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `eval_data` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `eval_date` DATETIME NULL\n, `new_state_date` DATETIME NOT NULL\n, `state_changes` INT NOT NULL\n, `created` DATETIME NOT NULL\n, `updated` DATETIME NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('add index alert org_id & id ','CREATE INDEX `IDX_alert_org_id_id` ON `alert` (`org_id`,`id`);',1,'','2022-01-01 00:00:00'), + ('add index alert state','CREATE INDEX `IDX_alert_state` ON `alert` (`state`);',1,'','2022-01-01 00:00:00'), + ('add index alert dashboard_id','CREATE INDEX `IDX_alert_dashboard_id` ON `alert` (`dashboard_id`);',1,'','2022-01-01 00:00:00'), + ('Create alert_rule_tag table v1','CREATE TABLE IF NOT EXISTS `alert_rule_tag` (\n`alert_id` BIGINT(20) NOT NULL\n, `tag_id` BIGINT(20) NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('Add unique index alert_rule_tag.alert_id_tag_id','CREATE UNIQUE INDEX `UQE_alert_rule_tag_alert_id_tag_id` ON `alert_rule_tag` (`alert_id`,`tag_id`);',1,'','2022-01-01 00:00:00'), + ('drop index UQE_alert_rule_tag_alert_id_tag_id - v1','DROP INDEX `UQE_alert_rule_tag_alert_id_tag_id` ON `alert_rule_tag`',1,'','2022-01-01 00:00:00'), + ('Rename table alert_rule_tag to alert_rule_tag_v1 - v1','ALTER TABLE `alert_rule_tag` RENAME TO `alert_rule_tag_v1`',1,'','2022-01-01 00:00:00'), + ('Create alert_rule_tag table v2','CREATE TABLE IF NOT EXISTS `alert_rule_tag` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `alert_id` BIGINT(20) NOT NULL\n, `tag_id` BIGINT(20) NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('create index UQE_alert_rule_tag_alert_id_tag_id - Add unique index alert_rule_tag.alert_id_tag_id V2','CREATE UNIQUE INDEX `UQE_alert_rule_tag_alert_id_tag_id` ON `alert_rule_tag` (`alert_id`,`tag_id`);',1,'','2022-01-01 00:00:00'), + ('copy alert_rule_tag v1 to v2','INSERT INTO `alert_rule_tag` (`alert_id`\n, `tag_id`)\nSELECT `alert_id`\n, `tag_id`\nFROM `alert_rule_tag_v1`',1,'','2022-01-01 00:00:00'), + ('drop table alert_rule_tag_v1','DROP TABLE IF EXISTS `alert_rule_tag_v1`',1,'','2022-01-01 00:00:00'), + ('create alert_notification table v1','CREATE TABLE IF NOT EXISTS `alert_notification` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `org_id` BIGINT(20) NOT NULL\n, `name` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `type` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `settings` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `created` DATETIME NOT NULL\n, `updated` DATETIME NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('Add column is_default','alter table `alert_notification` ADD COLUMN `is_default` TINYINT(1) NOT NULL DEFAULT 0 ',1,'','2022-01-01 00:00:00'), + ('Add column frequency','alter table `alert_notification` ADD COLUMN `frequency` BIGINT(20) NULL ',1,'','2022-01-01 00:00:00'), + ('Add column send_reminder','alter table `alert_notification` ADD COLUMN `send_reminder` TINYINT(1) NULL DEFAULT 0 ',1,'','2022-01-01 00:00:00'), + ('Add column disable_resolve_message','alter table `alert_notification` ADD COLUMN `disable_resolve_message` TINYINT(1) NOT NULL DEFAULT 0 ',1,'','2022-01-01 00:00:00'), + ('add index alert_notification org_id & name','CREATE UNIQUE INDEX `UQE_alert_notification_org_id_name` ON `alert_notification` (`org_id`,`name`);',1,'','2022-01-01 00:00:00'), + ('Update alert table charset','ALTER TABLE `alert` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, MODIFY `name` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL , MODIFY `message` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL , MODIFY `state` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL , MODIFY `settings` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL , MODIFY `severity` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL , MODIFY `execution_error` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL , MODIFY `eval_data` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ;',1,'','2022-01-01 00:00:00'), + ('Update alert_notification table charset','ALTER TABLE `alert_notification` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, MODIFY `name` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL , MODIFY `type` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL , MODIFY `settings` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL ;',1,'','2022-01-01 00:00:00'), + ('create notification_journal table v1','CREATE TABLE IF NOT EXISTS `alert_notification_journal` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `org_id` BIGINT(20) NOT NULL\n, `alert_id` BIGINT(20) NOT NULL\n, `notifier_id` BIGINT(20) NOT NULL\n, `sent_at` BIGINT(20) NOT NULL\n, `success` TINYINT(1) NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('add index notification_journal org_id & alert_id & notifier_id','CREATE INDEX `IDX_alert_notification_journal_org_id_alert_id_notifier_id` ON `alert_notification_journal` (`org_id`,`alert_id`,`notifier_id`);',1,'','2022-01-01 00:00:00'), + ('drop alert_notification_journal','DROP TABLE IF EXISTS `alert_notification_journal`',1,'','2022-01-01 00:00:00'), + ('create alert_notification_state table v1','CREATE TABLE IF NOT EXISTS `alert_notification_state` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `org_id` BIGINT(20) NOT NULL\n, `alert_id` BIGINT(20) NOT NULL\n, `notifier_id` BIGINT(20) NOT NULL\n, `state` VARCHAR(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `version` BIGINT(20) NOT NULL\n, `updated_at` BIGINT(20) NOT NULL\n, `alert_rule_state_updated_version` BIGINT(20) NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('add index alert_notification_state org_id & alert_id & notifier_id','CREATE UNIQUE INDEX `UQE_alert_notification_state_org_id_alert_id_notifier_id` ON `alert_notification_state` (`org_id`,`alert_id`,`notifier_id`);',1,'','2022-01-01 00:00:00'), + ('Add for to alert table','alter table `alert` ADD COLUMN `for` BIGINT(20) NULL ',1,'','2022-01-01 00:00:00'), + ('Add column uid in alert_notification','alter table `alert_notification` ADD COLUMN `uid` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('Update uid column values in alert_notification','UPDATE alert_notification SET uid=lpad(id,9,\'0\') WHERE uid IS NULL;',1,'','2022-01-01 00:00:00'), + ('Add unique index alert_notification_org_id_uid','CREATE UNIQUE INDEX `UQE_alert_notification_org_id_uid` ON `alert_notification` (`org_id`,`uid`);',1,'','2022-01-01 00:00:00'), + ('Remove unique index org_id_name','DROP INDEX `UQE_alert_notification_org_id_name` ON `alert_notification`',1,'','2022-01-01 00:00:00'), + ('Add column secure_settings in alert_notification','alter table `alert_notification` ADD COLUMN `secure_settings` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('alter alert.settings to mediumtext','ALTER TABLE alert MODIFY settings MEDIUMTEXT;',1,'','2022-01-01 00:00:00'), + ('Add non-unique index alert_notification_state_alert_id','CREATE INDEX `IDX_alert_notification_state_alert_id` ON `alert_notification_state` (`alert_id`);',1,'','2022-01-01 00:00:00'), + ('Add non-unique index alert_rule_tag_alert_id','CREATE INDEX `IDX_alert_rule_tag_alert_id` ON `alert_rule_tag` (`alert_id`);',1,'','2022-01-01 00:00:00'), + ('Drop old annotation table v4','DROP TABLE IF EXISTS `annotation`',1,'','2022-01-01 00:00:00'), + ('create annotation table v5','CREATE TABLE IF NOT EXISTS `annotation` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `org_id` BIGINT(20) NOT NULL\n, `alert_id` BIGINT(20) NULL\n, `user_id` BIGINT(20) NULL\n, `dashboard_id` BIGINT(20) NULL\n, `panel_id` BIGINT(20) NULL\n, `category_id` BIGINT(20) NULL\n, `type` VARCHAR(25) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `title` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `text` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `metric` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `prev_state` VARCHAR(25) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `new_state` VARCHAR(25) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `data` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `epoch` BIGINT(20) NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('add index annotation 0 v3','CREATE INDEX `IDX_annotation_org_id_alert_id` ON `annotation` (`org_id`,`alert_id`);',1,'','2022-01-01 00:00:00'), + ('add index annotation 1 v3','CREATE INDEX `IDX_annotation_org_id_type` ON `annotation` (`org_id`,`type`);',1,'','2022-01-01 00:00:00'), + ('add index annotation 2 v3','CREATE INDEX `IDX_annotation_org_id_category_id` ON `annotation` (`org_id`,`category_id`);',1,'','2022-01-01 00:00:00'), + ('add index annotation 3 v3','CREATE INDEX `IDX_annotation_org_id_dashboard_id_panel_id_epoch` ON `annotation` (`org_id`,`dashboard_id`,`panel_id`,`epoch`);',1,'','2022-01-01 00:00:00'), + ('add index annotation 4 v3','CREATE INDEX `IDX_annotation_org_id_epoch` ON `annotation` (`org_id`,`epoch`);',1,'','2022-01-01 00:00:00'), + ('Update annotation table charset','ALTER TABLE `annotation` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, MODIFY `type` VARCHAR(25) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL , MODIFY `title` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL , MODIFY `text` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL , MODIFY `metric` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL , MODIFY `prev_state` VARCHAR(25) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL , MODIFY `new_state` VARCHAR(25) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL , MODIFY `data` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL ;',1,'','2022-01-01 00:00:00'), + ('Add column region_id to annotation table','alter table `annotation` ADD COLUMN `region_id` BIGINT(20) NULL DEFAULT 0 ',1,'','2022-01-01 00:00:00'), + ('Drop category_id index','DROP INDEX `IDX_annotation_org_id_category_id` ON `annotation`',1,'','2022-01-01 00:00:00'), + ('Add column tags to annotation table','alter table `annotation` ADD COLUMN `tags` VARCHAR(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('Create annotation_tag table v2','CREATE TABLE IF NOT EXISTS `annotation_tag` (\n`annotation_id` BIGINT(20) NOT NULL\n, `tag_id` BIGINT(20) NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('Add unique index annotation_tag.annotation_id_tag_id','CREATE UNIQUE INDEX `UQE_annotation_tag_annotation_id_tag_id` ON `annotation_tag` (`annotation_id`,`tag_id`);',1,'','2022-01-01 00:00:00'), + ('drop index UQE_annotation_tag_annotation_id_tag_id - v2','DROP INDEX `UQE_annotation_tag_annotation_id_tag_id` ON `annotation_tag`',1,'','2022-01-01 00:00:00'), + ('Rename table annotation_tag to annotation_tag_v2 - v2','ALTER TABLE `annotation_tag` RENAME TO `annotation_tag_v2`',1,'','2022-01-01 00:00:00'), + ('Create annotation_tag table v3','CREATE TABLE IF NOT EXISTS `annotation_tag` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `annotation_id` BIGINT(20) NOT NULL\n, `tag_id` BIGINT(20) NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('create index UQE_annotation_tag_annotation_id_tag_id - Add unique index annotation_tag.annotation_id_tag_id V3','CREATE UNIQUE INDEX `UQE_annotation_tag_annotation_id_tag_id` ON `annotation_tag` (`annotation_id`,`tag_id`);',1,'','2022-01-01 00:00:00'), + ('copy annotation_tag v2 to v3','INSERT INTO `annotation_tag` (`annotation_id`\n, `tag_id`)\nSELECT `annotation_id`\n, `tag_id`\nFROM `annotation_tag_v2`',1,'','2022-01-01 00:00:00'), + ('drop table annotation_tag_v2','DROP TABLE IF EXISTS `annotation_tag_v2`',1,'','2022-01-01 00:00:00'), + ('Update alert annotations and set TEXT to empty','UPDATE annotation SET TEXT = \'\' WHERE alert_id > 0',1,'','2022-01-01 00:00:00'), + ('Add created time to annotation table','alter table `annotation` ADD COLUMN `created` BIGINT(20) NULL DEFAULT 0 ',1,'','2022-01-01 00:00:00'), + ('Add updated time to annotation table','alter table `annotation` ADD COLUMN `updated` BIGINT(20) NULL DEFAULT 0 ',1,'','2022-01-01 00:00:00'), + ('Add index for created in annotation table','CREATE INDEX `IDX_annotation_org_id_created` ON `annotation` (`org_id`,`created`);',1,'','2022-01-01 00:00:00'), + ('Add index for updated in annotation table','CREATE INDEX `IDX_annotation_org_id_updated` ON `annotation` (`org_id`,`updated`);',1,'','2022-01-01 00:00:00'), + ('Convert existing annotations from seconds to milliseconds','UPDATE annotation SET epoch = (epoch*1000) where epoch < 9999999999',1,'','2022-01-01 00:00:00'), + ('Add epoch_end column','alter table `annotation` ADD COLUMN `epoch_end` BIGINT(20) NOT NULL DEFAULT 0 ',1,'','2022-01-01 00:00:00'), + ('Add index for epoch_end','CREATE INDEX `IDX_annotation_org_id_epoch_epoch_end` ON `annotation` (`org_id`,`epoch`,`epoch_end`);',1,'','2022-01-01 00:00:00'), + ('Make epoch_end the same as epoch','UPDATE annotation SET epoch_end = epoch',1,'','2022-01-01 00:00:00'), + ('Move region to single row','code migration',1,'','2022-01-01 00:00:00'), + ('Remove index org_id_epoch from annotation table','DROP INDEX `IDX_annotation_org_id_epoch` ON `annotation`',1,'','2022-01-01 00:00:00'), + ('Remove index org_id_dashboard_id_panel_id_epoch from annotation table','DROP INDEX `IDX_annotation_org_id_dashboard_id_panel_id_epoch` ON `annotation`',1,'','2022-01-01 00:00:00'), + ('Add index for org_id_dashboard_id_epoch_end_epoch on annotation table','CREATE INDEX `IDX_annotation_org_id_dashboard_id_epoch_end_epoch` ON `annotation` (`org_id`,`dashboard_id`,`epoch_end`,`epoch`);',1,'','2022-01-01 00:00:00'), + ('Add index for org_id_epoch_end_epoch on annotation table','CREATE INDEX `IDX_annotation_org_id_epoch_end_epoch` ON `annotation` (`org_id`,`epoch_end`,`epoch`);',1,'','2022-01-01 00:00:00'), + ('Remove index org_id_epoch_epoch_end from annotation table','DROP INDEX `IDX_annotation_org_id_epoch_epoch_end` ON `annotation`',1,'','2022-01-01 00:00:00'), + ('Add index for alert_id on annotation table','CREATE INDEX `IDX_annotation_alert_id` ON `annotation` (`alert_id`);',1,'','2022-01-01 00:00:00'), + ('Increase tags column to length 4096','ALTER TABLE annotation MODIFY tags VARCHAR(4096);',1,'','2022-01-01 00:00:00'), + ('Increase prev_state column to length 40 not null','ALTER TABLE annotation MODIFY prev_state VARCHAR(40) NOT NULL;',1,'','2022-01-01 00:00:00'), + ('Increase new_state column to length 40 not null','ALTER TABLE annotation MODIFY new_state VARCHAR(40) NOT NULL;',1,'','2022-01-01 00:00:00'), + ('Add dashboard_uid column to annotation table','alter table `annotation` ADD COLUMN `dashboard_uid` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('Add missing dashboard_uid to annotation table','code migration',1,'','2022-01-01 00:00:00'), + ('create test_data table','CREATE TABLE IF NOT EXISTS `test_data` (\n`id` INT PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `metric1` VARCHAR(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `metric2` VARCHAR(150) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `value_big_int` BIGINT(20) NULL\n, `value_double` DOUBLE NULL\n, `value_float` FLOAT NULL\n, `value_int` INT NULL\n, `time_epoch` BIGINT(20) NOT NULL\n, `time_date_time` DATETIME NOT NULL\n, `time_time_stamp` TIMESTAMP NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('create dashboard_version table v1','CREATE TABLE IF NOT EXISTS `dashboard_version` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `dashboard_id` BIGINT(20) NOT NULL\n, `parent_version` INT NOT NULL\n, `restored_from` INT NOT NULL\n, `version` INT NOT NULL\n, `created` DATETIME NOT NULL\n, `created_by` BIGINT(20) NOT NULL\n, `message` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `data` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('add index dashboard_version.dashboard_id','CREATE INDEX `IDX_dashboard_version_dashboard_id` ON `dashboard_version` (`dashboard_id`);',1,'','2022-01-01 00:00:00'), + ('add unique index dashboard_version.dashboard_id and dashboard_version.version','CREATE UNIQUE INDEX `UQE_dashboard_version_dashboard_id_version` ON `dashboard_version` (`dashboard_id`,`version`);',1,'','2022-01-01 00:00:00'), + ('Set dashboard version to 1 where 0','UPDATE dashboard SET version = 1 WHERE version = 0',1,'','2022-01-01 00:00:00'), + ('save existing dashboard data in dashboard_version table v1','INSERT INTO dashboard_version\n(\n dashboard_id,\n version,\n parent_version,\n restored_from,\n created,\n created_by,\n message,\n data\n)\nSELECT\n dashboard.id,\n dashboard.version,\n dashboard.version,\n dashboard.version,\n dashboard.updated,\n COALESCE(dashboard.updated_by, -1),\n \'\',\n dashboard.data\nFROM dashboard;',1,'','2022-01-01 00:00:00'), + ('alter dashboard_version.data to mediumtext v1','ALTER TABLE dashboard_version MODIFY data MEDIUMTEXT;',1,'','2022-01-01 00:00:00'), + ('Add apiVersion for dashboard_version','alter table `dashboard_version` ADD COLUMN `api_version` VARCHAR(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('create team table','CREATE TABLE IF NOT EXISTS `team` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `name` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `org_id` BIGINT(20) NOT NULL\n, `created` DATETIME NOT NULL\n, `updated` DATETIME NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('add index team.org_id','CREATE INDEX `IDX_team_org_id` ON `team` (`org_id`);',1,'','2022-01-01 00:00:00'), + ('add unique index team_org_id_name','CREATE UNIQUE INDEX `UQE_team_org_id_name` ON `team` (`org_id`,`name`);',1,'','2022-01-01 00:00:00'), + ('Add column uid in team','alter table `team` ADD COLUMN `uid` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('Update uid column values in team','UPDATE team SET uid=concat(\'t\',lpad(id,9,\'0\')) WHERE uid IS NULL;',1,'','2022-01-01 00:00:00'), + ('Add unique index team_org_id_uid','CREATE UNIQUE INDEX `UQE_team_org_id_uid` ON `team` (`org_id`,`uid`);',1,'','2022-01-01 00:00:00'), + ('Add column external_uid in team','alter table `team` ADD COLUMN `external_uid` VARCHAR(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('Add column is_provisioned in team','alter table `team` ADD COLUMN `is_provisioned` TINYINT(1) NULL ',1,'','2022-01-01 00:00:00'), + ('create team member table','CREATE TABLE IF NOT EXISTS `team_member` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `org_id` BIGINT(20) NOT NULL\n, `team_id` BIGINT(20) NOT NULL\n, `user_id` BIGINT(20) NOT NULL\n, `created` DATETIME NOT NULL\n, `updated` DATETIME NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('add index team_member.org_id','CREATE INDEX `IDX_team_member_org_id` ON `team_member` (`org_id`);',1,'','2022-01-01 00:00:00'), + ('add unique index team_member_org_id_team_id_user_id','CREATE UNIQUE INDEX `UQE_team_member_org_id_team_id_user_id` ON `team_member` (`org_id`,`team_id`,`user_id`);',1,'','2022-01-01 00:00:00'), + ('add index team_member.team_id','CREATE INDEX `IDX_team_member_team_id` ON `team_member` (`team_id`);',1,'','2022-01-01 00:00:00'), + ('Add column email to team table','alter table `team` ADD COLUMN `email` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('Add column external to team_member table','alter table `team_member` ADD COLUMN `external` TINYINT(1) NULL ',1,'','2022-01-01 00:00:00'), + ('Add column permission to team_member table','alter table `team_member` ADD COLUMN `permission` SMALLINT NULL ',1,'','2022-01-01 00:00:00'), + ('add unique index team_member_user_id_org_id','CREATE INDEX `IDX_team_member_user_id_org_id` ON `team_member` (`user_id`,`org_id`);',1,'','2022-01-01 00:00:00'), + ('Add column uid in team_member','alter table `team_member` ADD COLUMN `uid` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('Update uid column values in team_member','UPDATE team_member SET uid=concat(\'tm\',lpad(id,9,\'0\')) WHERE uid IS NULL OR uid = \'\';',1,'','2022-01-01 00:00:00'), + ('Add unique index team_member_uid','CREATE UNIQUE INDEX `UQE_team_member_uid` ON `team_member` (`uid`);',1,'','2022-01-01 00:00:00'), + ('create dashboard acl table','CREATE TABLE IF NOT EXISTS `dashboard_acl` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `org_id` BIGINT(20) NOT NULL\n, `dashboard_id` BIGINT(20) NOT NULL\n, `user_id` BIGINT(20) NULL\n, `team_id` BIGINT(20) NULL\n, `permission` SMALLINT NOT NULL DEFAULT 4\n, `role` VARCHAR(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `created` DATETIME NOT NULL\n, `updated` DATETIME NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('add index dashboard_acl_dashboard_id','CREATE INDEX `IDX_dashboard_acl_dashboard_id` ON `dashboard_acl` (`dashboard_id`);',1,'','2022-01-01 00:00:00'), + ('add unique index dashboard_acl_dashboard_id_user_id','CREATE UNIQUE INDEX `UQE_dashboard_acl_dashboard_id_user_id` ON `dashboard_acl` (`dashboard_id`,`user_id`);',1,'','2022-01-01 00:00:00'), + ('add unique index dashboard_acl_dashboard_id_team_id','CREATE UNIQUE INDEX `UQE_dashboard_acl_dashboard_id_team_id` ON `dashboard_acl` (`dashboard_id`,`team_id`);',1,'','2022-01-01 00:00:00'), + ('add index dashboard_acl_user_id','CREATE INDEX `IDX_dashboard_acl_user_id` ON `dashboard_acl` (`user_id`);',1,'','2022-01-01 00:00:00'), + ('add index dashboard_acl_team_id','CREATE INDEX `IDX_dashboard_acl_team_id` ON `dashboard_acl` (`team_id`);',1,'','2022-01-01 00:00:00'), + ('add index dashboard_acl_org_id_role','CREATE INDEX `IDX_dashboard_acl_org_id_role` ON `dashboard_acl` (`org_id`,`role`);',1,'','2022-01-01 00:00:00'), + ('add index dashboard_permission','CREATE INDEX `IDX_dashboard_acl_permission` ON `dashboard_acl` (`permission`);',1,'','2022-01-01 00:00:00'), + ('save default acl rules in dashboard_acl table','\nINSERT INTO dashboard_acl\n (\n org_id,\n dashboard_id,\n permission,\n role,\n created,\n updated\n )\n VALUES\n (-1,-1, 1,\'Viewer\',\'2017-06-20\',\'2017-06-20\'),\n (-1,-1, 2,\'Editor\',\'2017-06-20\',\'2017-06-20\')\n ',1,'','2022-01-01 00:00:00'), + ('delete acl rules for deleted dashboards and folders','DELETE FROM dashboard_acl WHERE dashboard_id NOT IN (SELECT id FROM dashboard) AND dashboard_id != -1',1,'','2022-01-01 00:00:00'), + ('create tag table','CREATE TABLE IF NOT EXISTS `tag` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `key` VARCHAR(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `value` VARCHAR(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('add index tag.key_value','CREATE UNIQUE INDEX `UQE_tag_key_value` ON `tag` (`key`,`value`);',1,'','2022-01-01 00:00:00'), + ('create login attempt table','CREATE TABLE IF NOT EXISTS `login_attempt` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `username` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `ip_address` VARCHAR(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `created` DATETIME NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('add index login_attempt.username','CREATE INDEX `IDX_login_attempt_username` ON `login_attempt` (`username`);',1,'','2022-01-01 00:00:00'), + ('drop index IDX_login_attempt_username - v1','DROP INDEX `IDX_login_attempt_username` ON `login_attempt`',1,'','2022-01-01 00:00:00'), + ('Rename table login_attempt to login_attempt_tmp_qwerty - v1','ALTER TABLE `login_attempt` RENAME TO `login_attempt_tmp_qwerty`',1,'','2022-01-01 00:00:00'), + ('create login_attempt v2','CREATE TABLE IF NOT EXISTS `login_attempt` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `username` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `ip_address` VARCHAR(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `created` INT NOT NULL DEFAULT 0\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('create index IDX_login_attempt_username - v2','CREATE INDEX `IDX_login_attempt_username` ON `login_attempt` (`username`);',1,'','2022-01-01 00:00:00'), + ('copy login_attempt v1 to v2','INSERT INTO `login_attempt` (`id`\n, `username`\n, `ip_address`)\nSELECT `id`\n, `username`\n, `ip_address`\nFROM `login_attempt_tmp_qwerty`',1,'','2022-01-01 00:00:00'), + ('drop login_attempt_tmp_qwerty','DROP TABLE IF EXISTS `login_attempt_tmp_qwerty`',1,'','2022-01-01 00:00:00'), + ('increase login_attempt.ip_address column length for IPv6 support','ALTER TABLE login_attempt MODIFY ip_address VARCHAR(50);',1,'','2022-01-01 00:00:00'), + ('alter table login_attempt alter column created type to bigint','ALTER TABLE login_attempt MODIFY created BIGINT;',1,'','2022-01-01 00:00:00'), + ('create user auth table','CREATE TABLE IF NOT EXISTS `user_auth` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `user_id` BIGINT(20) NOT NULL\n, `auth_module` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `auth_id` VARCHAR(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `created` DATETIME NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('create index IDX_user_auth_auth_module_auth_id - v1','CREATE INDEX `IDX_user_auth_auth_module_auth_id` ON `user_auth` (`auth_module`,`auth_id`);',1,'','2022-01-01 00:00:00'), + ('alter user_auth.auth_id to length 190','ALTER TABLE user_auth MODIFY auth_id VARCHAR(190);',1,'','2022-01-01 00:00:00'), + ('Add OAuth access token to user_auth','alter table `user_auth` ADD COLUMN `o_auth_access_token` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('Add OAuth refresh token to user_auth','alter table `user_auth` ADD COLUMN `o_auth_refresh_token` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('Add OAuth token type to user_auth','alter table `user_auth` ADD COLUMN `o_auth_token_type` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('Add OAuth expiry to user_auth','alter table `user_auth` ADD COLUMN `o_auth_expiry` DATETIME NULL ',1,'','2022-01-01 00:00:00'), + ('Add index to user_id column in user_auth','CREATE INDEX `IDX_user_auth_user_id` ON `user_auth` (`user_id`);',1,'','2022-01-01 00:00:00'), + ('Add OAuth ID token to user_auth','alter table `user_auth` ADD COLUMN `o_auth_id_token` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('Add user_unique_id to user_auth','alter table `user_auth` ADD COLUMN `external_uid` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('create server_lock table','CREATE TABLE IF NOT EXISTS `server_lock` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `operation_uid` VARCHAR(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `version` BIGINT(20) NOT NULL\n, `last_execution` BIGINT(20) NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('add index server_lock.operation_uid','CREATE UNIQUE INDEX `UQE_server_lock_operation_uid` ON `server_lock` (`operation_uid`);',1,'','2022-01-01 00:00:00'), + ('create user auth token table','CREATE TABLE IF NOT EXISTS `user_auth_token` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `user_id` BIGINT(20) NOT NULL\n, `auth_token` VARCHAR(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `prev_auth_token` VARCHAR(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `user_agent` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `client_ip` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `auth_token_seen` TINYINT(1) NOT NULL\n, `seen_at` INT NULL\n, `rotated_at` INT NOT NULL\n, `created_at` INT NOT NULL\n, `updated_at` INT NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('add unique index user_auth_token.auth_token','CREATE UNIQUE INDEX `UQE_user_auth_token_auth_token` ON `user_auth_token` (`auth_token`);',1,'','2022-01-01 00:00:00'), + ('add unique index user_auth_token.prev_auth_token','CREATE UNIQUE INDEX `UQE_user_auth_token_prev_auth_token` ON `user_auth_token` (`prev_auth_token`);',1,'','2022-01-01 00:00:00'), + ('add index user_auth_token.user_id','CREATE INDEX `IDX_user_auth_token_user_id` ON `user_auth_token` (`user_id`);',1,'','2022-01-01 00:00:00'), + ('Add revoked_at to the user auth token','alter table `user_auth_token` ADD COLUMN `revoked_at` INT NULL ',1,'','2022-01-01 00:00:00'), + ('add index user_auth_token.revoked_at','CREATE INDEX `IDX_user_auth_token_revoked_at` ON `user_auth_token` (`revoked_at`);',1,'','2022-01-01 00:00:00'), + ('add external_session_id to user_auth_token','alter table `user_auth_token` ADD COLUMN `external_session_id` BIGINT(20) NULL ',1,'','2022-01-01 00:00:00'), + ('create cache_data table','CREATE TABLE IF NOT EXISTS `cache_data` (\n`cache_key` VARCHAR(168) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci PRIMARY KEY NOT NULL\n, `data` BLOB NOT NULL\n, `expires` INTEGER(255) NOT NULL\n, `created_at` INTEGER(255) NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('add unique index cache_data.cache_key','CREATE UNIQUE INDEX `UQE_cache_data_cache_key` ON `cache_data` (`cache_key`);',1,'','2022-01-01 00:00:00'), + ('create short_url table v1','CREATE TABLE IF NOT EXISTS `short_url` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `org_id` BIGINT(20) NOT NULL\n, `uid` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `path` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `created_by` INT NOT NULL\n, `created_at` INT NOT NULL\n, `last_seen_at` INT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('add index short_url.org_id-uid','CREATE UNIQUE INDEX `UQE_short_url_org_id_uid` ON `short_url` (`org_id`,`uid`);',1,'','2022-01-01 00:00:00'), + ('alter table short_url alter column created_by type to bigint','ALTER TABLE short_url MODIFY created_by BIGINT;',1,'','2022-01-01 00:00:00'), + ('delete alert_definition table','DROP TABLE IF EXISTS `alert_definition`',1,'','2022-01-01 00:00:00'), + ('recreate alert_definition table','CREATE TABLE IF NOT EXISTS `alert_definition` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `org_id` BIGINT(20) NOT NULL\n, `title` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `condition` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `data` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `updated` DATETIME NOT NULL\n, `interval_seconds` BIGINT(20) NOT NULL DEFAULT 60\n, `version` INT NOT NULL DEFAULT 0\n, `uid` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 0\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('add index in alert_definition on org_id and title columns','CREATE INDEX `IDX_alert_definition_org_id_title` ON `alert_definition` (`org_id`,`title`);',1,'','2022-01-01 00:00:00'), + ('add index in alert_definition on org_id and uid columns','CREATE INDEX `IDX_alert_definition_org_id_uid` ON `alert_definition` (`org_id`,`uid`);',1,'','2022-01-01 00:00:00'), + ('alter alert_definition table data column to mediumtext in mysql','ALTER TABLE alert_definition MODIFY data MEDIUMTEXT;',1,'','2022-01-01 00:00:00'), + ('drop index in alert_definition on org_id and title columns','DROP INDEX `IDX_alert_definition_org_id_title` ON `alert_definition`',1,'','2022-01-01 00:00:00'), + ('drop index in alert_definition on org_id and uid columns','DROP INDEX `IDX_alert_definition_org_id_uid` ON `alert_definition`',1,'','2022-01-01 00:00:00'), + ('add unique index in alert_definition on org_id and title columns','CREATE UNIQUE INDEX `UQE_alert_definition_org_id_title` ON `alert_definition` (`org_id`,`title`);',1,'','2022-01-01 00:00:00'), + ('add unique index in alert_definition on org_id and uid columns','CREATE UNIQUE INDEX `UQE_alert_definition_org_id_uid` ON `alert_definition` (`org_id`,`uid`);',1,'','2022-01-01 00:00:00'), + ('Add column paused in alert_definition','alter table `alert_definition` ADD COLUMN `paused` TINYINT(1) NOT NULL DEFAULT 0 ',1,'','2022-01-01 00:00:00'), + ('drop alert_definition table','DROP TABLE IF EXISTS `alert_definition`',1,'','2022-01-01 00:00:00'), + ('delete alert_definition_version table','DROP TABLE IF EXISTS `alert_definition_version`',1,'','2022-01-01 00:00:00'), + ('recreate alert_definition_version table','CREATE TABLE IF NOT EXISTS `alert_definition_version` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `alert_definition_id` BIGINT(20) NOT NULL\n, `alert_definition_uid` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 0\n, `parent_version` INT NOT NULL\n, `restored_from` INT NOT NULL\n, `version` INT NOT NULL\n, `created` DATETIME NOT NULL\n, `title` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `condition` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `data` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `interval_seconds` BIGINT(20) NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('add index in alert_definition_version table on alert_definition_id and version columns','CREATE UNIQUE INDEX `UQE_alert_definition_version_alert_definition_id_version` ON `alert_definition_version` (`alert_definition_id`,`version`);',1,'','2022-01-01 00:00:00'), + ('add index in alert_definition_version table on alert_definition_uid and version columns','CREATE UNIQUE INDEX `UQE_alert_definition_version_alert_definition_uid_version` ON `alert_definition_version` (`alert_definition_uid`,`version`);',1,'','2022-01-01 00:00:00'), + ('alter alert_definition_version table data column to mediumtext in mysql','ALTER TABLE alert_definition_version MODIFY data MEDIUMTEXT;',1,'','2022-01-01 00:00:00'), + ('drop alert_definition_version table','DROP TABLE IF EXISTS `alert_definition_version`',1,'','2022-01-01 00:00:00'), + ('create alert_instance table','CREATE TABLE IF NOT EXISTS `alert_instance` (\n`def_org_id` BIGINT(20) NOT NULL\n, `def_uid` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 0\n, `labels` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `labels_hash` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `current_state` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `current_state_since` BIGINT(20) NOT NULL\n, `last_eval_time` BIGINT(20) NOT NULL\n, PRIMARY KEY ( `def_org_id`,`def_uid`,`labels_hash` )) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('add index in alert_instance table on def_org_id, def_uid and current_state columns','CREATE INDEX `IDX_alert_instance_def_org_id_def_uid_current_state` ON `alert_instance` (`def_org_id`,`def_uid`,`current_state`);',1,'','2022-01-01 00:00:00'), + ('add index in alert_instance table on def_org_id, current_state columns','CREATE INDEX `IDX_alert_instance_def_org_id_current_state` ON `alert_instance` (`def_org_id`,`current_state`);',1,'','2022-01-01 00:00:00'), + ('add column current_state_end to alert_instance','alter table `alert_instance` ADD COLUMN `current_state_end` BIGINT(20) NOT NULL DEFAULT 0 ',1,'','2022-01-01 00:00:00'), + ('remove index def_org_id, def_uid, current_state on alert_instance','DROP INDEX `IDX_alert_instance_def_org_id_def_uid_current_state` ON `alert_instance`',1,'','2022-01-01 00:00:00'), + ('remove index def_org_id, current_state on alert_instance','DROP INDEX `IDX_alert_instance_def_org_id_current_state` ON `alert_instance`',1,'','2022-01-01 00:00:00'), + ('rename def_org_id to rule_org_id in alert_instance','ALTER TABLE alert_instance CHANGE def_org_id rule_org_id BIGINT;',1,'','2022-01-01 00:00:00'), + ('rename def_uid to rule_uid in alert_instance','ALTER TABLE alert_instance CHANGE def_uid rule_uid VARCHAR(40);',1,'','2022-01-01 00:00:00'), + ('add index rule_org_id, rule_uid, current_state on alert_instance','CREATE INDEX `IDX_alert_instance_rule_org_id_rule_uid_current_state` ON `alert_instance` (`rule_org_id`,`rule_uid`,`current_state`);',1,'','2022-01-01 00:00:00'), + ('add index rule_org_id, current_state on alert_instance','CREATE INDEX `IDX_alert_instance_rule_org_id_current_state` ON `alert_instance` (`rule_org_id`,`current_state`);',1,'','2022-01-01 00:00:00'), + ('add current_reason column related to current_state','alter table `alert_instance` ADD COLUMN `current_reason` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('add result_fingerprint column to alert_instance','alter table `alert_instance` ADD COLUMN `result_fingerprint` VARCHAR(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('create alert_rule table','CREATE TABLE IF NOT EXISTS `alert_rule` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `org_id` BIGINT(20) NOT NULL\n, `title` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `condition` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `data` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `updated` DATETIME NOT NULL\n, `interval_seconds` BIGINT(20) NOT NULL DEFAULT 60\n, `version` INT NOT NULL DEFAULT 0\n, `uid` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 0\n, `namespace_uid` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `rule_group` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `no_data_state` VARCHAR(15) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT \'NoData\'\n, `exec_err_state` VARCHAR(15) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT \'Alerting\'\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('add index in alert_rule on org_id and title columns','CREATE UNIQUE INDEX `UQE_alert_rule_org_id_title` ON `alert_rule` (`org_id`,`title`);',1,'','2022-01-01 00:00:00'), + ('add index in alert_rule on org_id and uid columns','CREATE UNIQUE INDEX `UQE_alert_rule_org_id_uid` ON `alert_rule` (`org_id`,`uid`);',1,'','2022-01-01 00:00:00'), + ('add index in alert_rule on org_id, namespace_uid, group_uid columns','CREATE INDEX `IDX_alert_rule_org_id_namespace_uid_rule_group` ON `alert_rule` (`org_id`,`namespace_uid`,`rule_group`);',1,'','2022-01-01 00:00:00'), + ('alter alert_rule table data column to mediumtext in mysql','ALTER TABLE alert_rule MODIFY data MEDIUMTEXT;',1,'','2022-01-01 00:00:00'), + ('add column for to alert_rule','alter table `alert_rule` ADD COLUMN `for` BIGINT(20) NOT NULL DEFAULT 0 ',1,'','2022-01-01 00:00:00'), + ('add column annotations to alert_rule','alter table `alert_rule` ADD COLUMN `annotations` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('add column labels to alert_rule','alter table `alert_rule` ADD COLUMN `labels` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('remove unique index from alert_rule on org_id, title columns','DROP INDEX `UQE_alert_rule_org_id_title` ON `alert_rule`',1,'','2022-01-01 00:00:00'), + ('add index in alert_rule on org_id, namespase_uid and title columns','CREATE UNIQUE INDEX `UQE_alert_rule_org_id_namespace_uid_title` ON `alert_rule` (`org_id`,`namespace_uid`,`title`);',1,'','2022-01-01 00:00:00'), + ('add dashboard_uid column to alert_rule','alter table `alert_rule` ADD COLUMN `dashboard_uid` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('add panel_id column to alert_rule','alter table `alert_rule` ADD COLUMN `panel_id` BIGINT(20) NULL ',1,'','2022-01-01 00:00:00'), + ('add index in alert_rule on org_id, dashboard_uid and panel_id columns','CREATE INDEX `IDX_alert_rule_org_id_dashboard_uid_panel_id` ON `alert_rule` (`org_id`,`dashboard_uid`,`panel_id`);',1,'','2022-01-01 00:00:00'), + ('add rule_group_idx column to alert_rule','alter table `alert_rule` ADD COLUMN `rule_group_idx` INT NOT NULL DEFAULT 1 ',1,'','2022-01-01 00:00:00'), + ('add is_paused column to alert_rule table','alter table `alert_rule` ADD COLUMN `is_paused` TINYINT(1) NOT NULL DEFAULT 0 ',1,'','2022-01-01 00:00:00'), + ('fix is_paused column for alert_rule table','',1,'','2022-01-01 00:00:00'), + ('alter table alert_rule alter column rule_group_idx type to bigint','ALTER TABLE alert_rule MODIFY rule_group_idx BIGINT;',1,'','2022-01-01 00:00:00'), + ('create alert_rule_version table','CREATE TABLE IF NOT EXISTS `alert_rule_version` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `rule_org_id` BIGINT(20) NOT NULL\n, `rule_uid` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 0\n, `rule_namespace_uid` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `rule_group` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `parent_version` INT NOT NULL\n, `restored_from` INT NOT NULL\n, `version` INT NOT NULL\n, `created` DATETIME NOT NULL\n, `title` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `condition` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `data` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `interval_seconds` BIGINT(20) NOT NULL\n, `no_data_state` VARCHAR(15) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT \'NoData\'\n, `exec_err_state` VARCHAR(15) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT \'Alerting\'\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('add index in alert_rule_version table on rule_org_id, rule_uid and version columns','CREATE UNIQUE INDEX `UQE_alert_rule_version_rule_org_id_rule_uid_version` ON `alert_rule_version` (`rule_org_id`,`rule_uid`,`version`);',1,'','2022-01-01 00:00:00'), + ('add index in alert_rule_version table on rule_org_id, rule_namespace_uid and rule_group columns','CREATE INDEX `IDX_alert_rule_version_rule_org_id_rule_namespace_uid_rule_group` ON `alert_rule_version` (`rule_org_id`,`rule_namespace_uid`,`rule_group`);',1,'','2022-01-01 00:00:00'), + ('alter alert_rule_version table data column to mediumtext in mysql','ALTER TABLE alert_rule_version MODIFY data MEDIUMTEXT;',1,'','2022-01-01 00:00:00'), + ('add column for to alert_rule_version','alter table `alert_rule_version` ADD COLUMN `for` BIGINT(20) NOT NULL DEFAULT 0 ',1,'','2022-01-01 00:00:00'), + ('add column annotations to alert_rule_version','alter table `alert_rule_version` ADD COLUMN `annotations` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('add column labels to alert_rule_version','alter table `alert_rule_version` ADD COLUMN `labels` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('add rule_group_idx column to alert_rule_version','alter table `alert_rule_version` ADD COLUMN `rule_group_idx` INT NOT NULL DEFAULT 1 ',1,'','2022-01-01 00:00:00'), + ('add is_paused column to alert_rule_versions table','alter table `alert_rule_version` ADD COLUMN `is_paused` TINYINT(1) NOT NULL DEFAULT 0 ',1,'','2022-01-01 00:00:00'), + ('fix is_paused column for alert_rule_version table','',1,'','2022-01-01 00:00:00'), + ('alter table alert_rule_version alter column rule_group_idx type to bigint','ALTER TABLE alert_rule_version MODIFY rule_group_idx BIGINT;',1,'','2022-01-01 00:00:00'), + ('create_alert_configuration_table','CREATE TABLE IF NOT EXISTS `alert_configuration` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `alertmanager_configuration` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `configuration_version` VARCHAR(3) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `created_at` INT NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('Add column default in alert_configuration','alter table `alert_configuration` ADD COLUMN `default` TINYINT(1) NOT NULL DEFAULT 0 ',1,'','2022-01-01 00:00:00'), + ('alert alert_configuration alertmanager_configuration column from TEXT to MEDIUMTEXT if mysql','ALTER TABLE alert_configuration MODIFY alertmanager_configuration MEDIUMTEXT;',1,'','2022-01-01 00:00:00'), + ('add column org_id in alert_configuration','alter table `alert_configuration` ADD COLUMN `org_id` BIGINT(20) NOT NULL DEFAULT 0 ',1,'','2022-01-01 00:00:00'), + ('add index in alert_configuration table on org_id column','CREATE INDEX `IDX_alert_configuration_org_id` ON `alert_configuration` (`org_id`);',1,'','2022-01-01 00:00:00'), + ('add configuration_hash column to alert_configuration','alter table `alert_configuration` ADD COLUMN `configuration_hash` VARCHAR(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT \'not-yet-calculated\' ',1,'','2022-01-01 00:00:00'), + ('create_ngalert_configuration_table','CREATE TABLE IF NOT EXISTS `ngalert_configuration` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `org_id` BIGINT(20) NOT NULL\n, `alertmanagers` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `created_at` INT NOT NULL\n, `updated_at` INT NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('add index in ngalert_configuration on org_id column','CREATE UNIQUE INDEX `UQE_ngalert_configuration_org_id` ON `ngalert_configuration` (`org_id`);',1,'','2022-01-01 00:00:00'), + ('add column send_alerts_to in ngalert_configuration','alter table `ngalert_configuration` ADD COLUMN `send_alerts_to` SMALLINT NOT NULL DEFAULT 0 ',1,'','2022-01-01 00:00:00'), + ('create provenance_type table','CREATE TABLE IF NOT EXISTS `provenance_type` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `org_id` BIGINT(20) NOT NULL\n, `record_key` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `record_type` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `provenance` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('add index to uniquify (record_key, record_type, org_id) columns','CREATE UNIQUE INDEX `UQE_provenance_type_record_type_record_key_org_id` ON `provenance_type` (`record_type`,`record_key`,`org_id`);',1,'','2022-01-01 00:00:00'), + ('create alert_image table','CREATE TABLE IF NOT EXISTS `alert_image` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `token` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `path` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `url` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `created_at` DATETIME NOT NULL\n, `expires_at` DATETIME NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('add unique index on token to alert_image table','CREATE UNIQUE INDEX `UQE_alert_image_token` ON `alert_image` (`token`);',1,'','2022-01-01 00:00:00'), + ('support longer URLs in alert_image table','ALTER TABLE alert_image MODIFY url VARCHAR(2048) NOT NULL;',1,'','2022-01-01 00:00:00'), + ('create_alert_configuration_history_table','CREATE TABLE IF NOT EXISTS `alert_configuration_history` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `org_id` BIGINT(20) NOT NULL DEFAULT 0\n, `alertmanager_configuration` MEDIUMTEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `configuration_hash` VARCHAR(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT \'not-yet-calculated\'\n, `configuration_version` VARCHAR(3) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `created_at` INT NOT NULL\n, `default` TINYINT(1) NOT NULL DEFAULT 0\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('drop non-unique orgID index on alert_configuration','DROP INDEX `IDX_alert_configuration_org_id` ON `alert_configuration`',1,'','2022-01-01 00:00:00'), + ('drop unique orgID index on alert_configuration if exists','DROP INDEX `UQE_alert_configuration_org_id` ON `alert_configuration`',1,'','2022-01-01 00:00:00'), + ('extract alertmanager configuration history to separate table','code migration',1,'','2022-01-01 00:00:00'), + ('add unique index on orgID to alert_configuration','CREATE UNIQUE INDEX `UQE_alert_configuration_org_id` ON `alert_configuration` (`org_id`);',1,'','2022-01-01 00:00:00'), + ('add last_applied column to alert_configuration_history','alter table `alert_configuration_history` ADD COLUMN `last_applied` INT NOT NULL DEFAULT 0 ',1,'','2022-01-01 00:00:00'), + ('add message column to alert_rule_version','alter table `alert_rule_version` ADD COLUMN `message` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('create library_element table v1','CREATE TABLE IF NOT EXISTS `library_element` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `org_id` BIGINT(20) NOT NULL\n, `folder_id` BIGINT(20) NOT NULL\n, `uid` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `name` VARCHAR(150) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `kind` BIGINT(20) NOT NULL\n, `type` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `description` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `model` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `created` DATETIME NOT NULL\n, `created_by` BIGINT(20) NOT NULL\n, `updated` DATETIME NOT NULL\n, `updated_by` BIGINT(20) NOT NULL\n, `version` BIGINT(20) NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('add index library_element org_id-folder_id-name-kind','CREATE UNIQUE INDEX `UQE_library_element_org_id_folder_id_name_kind` ON `library_element` (`org_id`,`folder_id`,`name`,`kind`);',1,'','2022-01-01 00:00:00'), + ('create library_element_connection table v1','CREATE TABLE IF NOT EXISTS `library_element_connection` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `element_id` BIGINT(20) NOT NULL\n, `kind` BIGINT(20) NOT NULL\n, `connection_id` BIGINT(20) NOT NULL\n, `created` DATETIME NOT NULL\n, `created_by` BIGINT(20) NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('add index library_element_connection element_id-kind-connection_id','CREATE UNIQUE INDEX `UQE_library_element_connection_element_id_kind_connection_id` ON `library_element_connection` (`element_id`,`kind`,`connection_id`);',1,'','2022-01-01 00:00:00'), + ('add unique index library_element org_id_uid','CREATE UNIQUE INDEX `UQE_library_element_org_id_uid` ON `library_element` (`org_id`,`uid`);',1,'','2022-01-01 00:00:00'), + ('increase max description length to 2048','ALTER TABLE `library_element` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, MODIFY `description` VARCHAR(2048) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL ;',1,'','2022-01-01 00:00:00'), + ('alter library_element model to mediumtext','ALTER TABLE library_element MODIFY model MEDIUMTEXT NOT NULL;',1,'','2022-01-01 00:00:00'), + ('add library_element folder uid','alter table `library_element` ADD COLUMN `folder_uid` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('populate library_element folder_uid','UPDATE library_element\n SET folder_uid = (\n SELECT dashboard.uid\n FROM dashboard\n WHERE library_element.folder_id = dashboard.id AND library_element.org_id = dashboard.org_id\n )',1,'','2022-01-01 00:00:00'), + ('add index library_element org_id-folder_uid-name-kind','CREATE UNIQUE INDEX `UQE_library_element_org_id_folder_uid_name_kind` ON `library_element` (`org_id`,`folder_uid`,`name`,`kind`);',1,'','2022-01-01 00:00:00'), + ('drop unique name in folder index (id)','DROP INDEX `UQE_library_element_org_id_folder_id_name_kind` ON `library_element`',1,'','2022-01-01 00:00:00'), + ('drop unique name in folder index','DROP INDEX `UQE_library_element_org_id_folder_uid_name_kind` ON `library_element`',1,'','2022-01-01 00:00:00'), + ('clone move dashboard alerts to unified alerting','code migration',1,'','2022-01-01 00:00:00'), + ('create data_keys table','CREATE TABLE IF NOT EXISTS `data_keys` (\n`name` VARCHAR(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci PRIMARY KEY NOT NULL\n, `active` TINYINT(1) NOT NULL\n, `scope` VARCHAR(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `provider` VARCHAR(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `encrypted_data` BLOB NOT NULL\n, `created` DATETIME NOT NULL\n, `updated` DATETIME NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('create secrets table','CREATE TABLE IF NOT EXISTS `secrets` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `org_id` BIGINT(20) NOT NULL\n, `namespace` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `type` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `value` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `created` DATETIME NOT NULL\n, `updated` DATETIME NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('rename data_keys name column to id','ALTER TABLE `data_keys` CHANGE `name` `id` VARCHAR(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci',1,'','2022-01-01 00:00:00'), + ('add name column into data_keys','alter table `data_keys` ADD COLUMN `name` VARCHAR(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT \'\' ',1,'','2022-01-01 00:00:00'), + ('copy data_keys id column values into name','UPDATE data_keys SET name = id',1,'','2022-01-01 00:00:00'), + ('rename data_keys name column to label','ALTER TABLE `data_keys` CHANGE `name` `label` VARCHAR(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci',1,'','2022-01-01 00:00:00'), + ('rename data_keys id column back to name','ALTER TABLE `data_keys` CHANGE `id` `name` VARCHAR(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci',1,'','2022-01-01 00:00:00'), + ('create kv_store table v1','CREATE TABLE IF NOT EXISTS `kv_store` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `org_id` BIGINT(20) NOT NULL\n, `namespace` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `key` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `value` MEDIUMTEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `created` DATETIME NOT NULL\n, `updated` DATETIME NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('add index kv_store.org_id-namespace-key','CREATE UNIQUE INDEX `UQE_kv_store_org_id_namespace_key` ON `kv_store` (`org_id`,`namespace`,`key`);',1,'','2022-01-01 00:00:00'), + ('update dashboard_uid and panel_id from existing annotations','set dashboard_uid and panel_id migration',1,'','2022-01-01 00:00:00'), + ('create permission table','CREATE TABLE IF NOT EXISTS `permission` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `role_id` BIGINT(20) NOT NULL\n, `action` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `scope` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `created` DATETIME NOT NULL\n, `updated` DATETIME NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('add unique index permission.role_id','CREATE INDEX `IDX_permission_role_id` ON `permission` (`role_id`);',1,'','2022-01-01 00:00:00'), + ('add unique index role_id_action_scope','CREATE UNIQUE INDEX `UQE_permission_role_id_action_scope` ON `permission` (`role_id`,`action`,`scope`);',1,'','2022-01-01 00:00:00'), + ('create role table','CREATE TABLE IF NOT EXISTS `role` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `name` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `description` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `version` BIGINT(20) NOT NULL\n, `org_id` BIGINT(20) NOT NULL\n, `uid` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `created` DATETIME NOT NULL\n, `updated` DATETIME NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('add column display_name','alter table `role` ADD COLUMN `display_name` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('add column group_name','alter table `role` ADD COLUMN `group_name` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('add index role.org_id','CREATE INDEX `IDX_role_org_id` ON `role` (`org_id`);',1,'','2022-01-01 00:00:00'), + ('add unique index role_org_id_name','CREATE UNIQUE INDEX `UQE_role_org_id_name` ON `role` (`org_id`,`name`);',1,'','2022-01-01 00:00:00'), + ('add index role_org_id_uid','CREATE UNIQUE INDEX `UQE_role_org_id_uid` ON `role` (`org_id`,`uid`);',1,'','2022-01-01 00:00:00'), + ('create team role table','CREATE TABLE IF NOT EXISTS `team_role` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `org_id` BIGINT(20) NOT NULL\n, `team_id` BIGINT(20) NOT NULL\n, `role_id` BIGINT(20) NOT NULL\n, `created` DATETIME NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('add index team_role.org_id','CREATE INDEX `IDX_team_role_org_id` ON `team_role` (`org_id`);',1,'','2022-01-01 00:00:00'), + ('add unique index team_role_org_id_team_id_role_id','CREATE UNIQUE INDEX `UQE_team_role_org_id_team_id_role_id` ON `team_role` (`org_id`,`team_id`,`role_id`);',1,'','2022-01-01 00:00:00'), + ('add index team_role.team_id','CREATE INDEX `IDX_team_role_team_id` ON `team_role` (`team_id`);',1,'','2022-01-01 00:00:00'), + ('create user role table','CREATE TABLE IF NOT EXISTS `user_role` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `org_id` BIGINT(20) NOT NULL\n, `user_id` BIGINT(20) NOT NULL\n, `role_id` BIGINT(20) NOT NULL\n, `created` DATETIME NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('add index user_role.org_id','CREATE INDEX `IDX_user_role_org_id` ON `user_role` (`org_id`);',1,'','2022-01-01 00:00:00'), + ('add unique index user_role_org_id_user_id_role_id','CREATE UNIQUE INDEX `UQE_user_role_org_id_user_id_role_id` ON `user_role` (`org_id`,`user_id`,`role_id`);',1,'','2022-01-01 00:00:00'), + ('add index user_role.user_id','CREATE INDEX `IDX_user_role_user_id` ON `user_role` (`user_id`);',1,'','2022-01-01 00:00:00'), + ('create builtin role table','CREATE TABLE IF NOT EXISTS `builtin_role` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `role` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `role_id` BIGINT(20) NOT NULL\n, `created` DATETIME NOT NULL\n, `updated` DATETIME NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('add index builtin_role.role_id','CREATE INDEX `IDX_builtin_role_role_id` ON `builtin_role` (`role_id`);',1,'','2022-01-01 00:00:00'), + ('add index builtin_role.name','CREATE INDEX `IDX_builtin_role_role` ON `builtin_role` (`role`);',1,'','2022-01-01 00:00:00'), + ('Add column org_id to builtin_role table','alter table `builtin_role` ADD COLUMN `org_id` BIGINT(20) NOT NULL DEFAULT 0 ',1,'','2022-01-01 00:00:00'), + ('add index builtin_role.org_id','CREATE INDEX `IDX_builtin_role_org_id` ON `builtin_role` (`org_id`);',1,'','2022-01-01 00:00:00'), + ('add unique index builtin_role_org_id_role_id_role','CREATE UNIQUE INDEX `UQE_builtin_role_org_id_role_id_role` ON `builtin_role` (`org_id`,`role_id`,`role`);',1,'','2022-01-01 00:00:00'), + ('Remove unique index role_org_id_uid','DROP INDEX `UQE_role_org_id_uid` ON `role`',1,'','2022-01-01 00:00:00'), + ('add unique index role.uid','CREATE UNIQUE INDEX `UQE_role_uid` ON `role` (`uid`);',1,'','2022-01-01 00:00:00'), + ('create seed assignment table','CREATE TABLE IF NOT EXISTS `seed_assignment` (\n`builtin_role` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `role_name` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('add unique index builtin_role_role_name','CREATE UNIQUE INDEX `UQE_seed_assignment_builtin_role_role_name` ON `seed_assignment` (`builtin_role`,`role_name`);',1,'','2022-01-01 00:00:00'), + ('add column hidden to role table','alter table `role` ADD COLUMN `hidden` TINYINT(1) NOT NULL DEFAULT 0 ',1,'','2022-01-01 00:00:00'), + ('permission kind migration','alter table `permission` ADD COLUMN `kind` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT \'\' ',1,'','2022-01-01 00:00:00'), + ('permission attribute migration','alter table `permission` ADD COLUMN `attribute` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT \'\' ',1,'','2022-01-01 00:00:00'), + ('permission identifier migration','alter table `permission` ADD COLUMN `identifier` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT \'\' ',1,'','2022-01-01 00:00:00'), + ('add permission identifier index','CREATE INDEX `IDX_permission_identifier` ON `permission` (`identifier`);',1,'','2022-01-01 00:00:00'), + ('add permission action scope role_id index','CREATE UNIQUE INDEX `UQE_permission_action_scope_role_id` ON `permission` (`action`,`scope`,`role_id`);',1,'','2022-01-01 00:00:00'), + ('remove permission role_id action scope index','DROP INDEX `UQE_permission_role_id_action_scope` ON `permission`',1,'','2022-01-01 00:00:00'), + ('add group mapping UID column to user_role table','alter table `user_role` ADD COLUMN `group_mapping_uid` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT \'\' ',1,'','2022-01-01 00:00:00'), + ('add user_role org ID, user ID, role ID, group mapping UID index','CREATE UNIQUE INDEX `UQE_user_role_org_id_user_id_role_id_group_mapping_uid` ON `user_role` (`org_id`,`user_id`,`role_id`,`group_mapping_uid`);',1,'','2022-01-01 00:00:00'), + ('remove user_role org ID, user ID, role ID index','DROP INDEX `UQE_user_role_org_id_user_id_role_id` ON `user_role`',1,'','2022-01-01 00:00:00'), + ('add permission role_id action index','CREATE INDEX `IDX_permission_role_id_action` ON `permission` (`role_id`,`action`);',1,'','2022-01-01 00:00:00'), + ('Remove permission role_id index','DROP INDEX `IDX_permission_role_id` ON `permission`',1,'','2022-01-01 00:00:00'), + ('create query_history table v1','CREATE TABLE IF NOT EXISTS `query_history` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `uid` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `org_id` BIGINT(20) NOT NULL\n, `datasource_uid` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `created_by` INT NOT NULL\n, `created_at` INT NOT NULL\n, `comment` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `queries` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('add index query_history.org_id-created_by-datasource_uid','CREATE INDEX `IDX_query_history_org_id_created_by_datasource_uid` ON `query_history` (`org_id`,`created_by`,`datasource_uid`);',1,'','2022-01-01 00:00:00'), + ('alter table query_history alter column created_by type to bigint','ALTER TABLE query_history MODIFY created_by BIGINT;',1,'','2022-01-01 00:00:00'), + ('create query_history_details table v1','CREATE TABLE IF NOT EXISTS `query_history_details` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `query_history_item_uid` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `datasource_uid` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('rbac disabled migrator','code migration',1,'','2022-01-01 00:00:00'), + ('teams permissions migration','code migration',1,'','2022-01-01 00:00:00'), + ('dashboard permissions','code migration',1,'','2022-01-01 00:00:00'), + ('dashboard permissions uid scopes','code migration',1,'','2022-01-01 00:00:00'), + ('drop managed folder create actions','code migration',1,'','2022-01-01 00:00:00'), + ('alerting notification permissions','code migration',1,'','2022-01-01 00:00:00'), + ('create query_history_star table v1','CREATE TABLE IF NOT EXISTS `query_history_star` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `query_uid` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `user_id` INT NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('add index query_history.user_id-query_uid','CREATE UNIQUE INDEX `UQE_query_history_star_user_id_query_uid` ON `query_history_star` (`user_id`,`query_uid`);',1,'','2022-01-01 00:00:00'), + ('add column org_id in query_history_star','alter table `query_history_star` ADD COLUMN `org_id` BIGINT(20) NOT NULL DEFAULT 1 ',1,'','2022-01-01 00:00:00'), + ('alter table query_history_star_mig column user_id type to bigint','ALTER TABLE query_history_star MODIFY user_id BIGINT;',1,'','2022-01-01 00:00:00'), + ('create correlation table v1','CREATE TABLE IF NOT EXISTS `correlation` (\n`uid` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `source_uid` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `target_uid` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `label` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `description` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, PRIMARY KEY ( `uid`,`source_uid` )) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('add index correlations.uid','CREATE INDEX `IDX_correlation_uid` ON `correlation` (`uid`);',1,'','2022-01-01 00:00:00'), + ('add index correlations.source_uid','CREATE INDEX `IDX_correlation_source_uid` ON `correlation` (`source_uid`);',1,'','2022-01-01 00:00:00'), + ('add correlation config column','alter table `correlation` ADD COLUMN `config` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('drop index IDX_correlation_uid - v1','DROP INDEX `IDX_correlation_uid` ON `correlation`',1,'','2022-01-01 00:00:00'), + ('drop index IDX_correlation_source_uid - v1','DROP INDEX `IDX_correlation_source_uid` ON `correlation`',1,'','2022-01-01 00:00:00'), + ('Rename table correlation to correlation_tmp_qwerty - v1','ALTER TABLE `correlation` RENAME TO `correlation_tmp_qwerty`',1,'','2022-01-01 00:00:00'), + ('create correlation v2','CREATE TABLE IF NOT EXISTS `correlation` (\n`uid` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `org_id` BIGINT(20) NOT NULL DEFAULT 0\n, `source_uid` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `target_uid` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `label` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `description` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `config` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, PRIMARY KEY ( `uid`,`org_id`,`source_uid` )) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('create index IDX_correlation_uid - v2','CREATE INDEX `IDX_correlation_uid` ON `correlation` (`uid`);',1,'','2022-01-01 00:00:00'), + ('create index IDX_correlation_source_uid - v2','CREATE INDEX `IDX_correlation_source_uid` ON `correlation` (`source_uid`);',1,'','2022-01-01 00:00:00'), + ('create index IDX_correlation_org_id - v2','CREATE INDEX `IDX_correlation_org_id` ON `correlation` (`org_id`);',1,'','2022-01-01 00:00:00'), + ('copy correlation v1 to v2','INSERT INTO `correlation` (`target_uid`\n, `label`\n, `description`\n, `config`\n, `uid`\n, `source_uid`)\nSELECT `target_uid`\n, `label`\n, `description`\n, `config`\n, `uid`\n, `source_uid`\nFROM `correlation_tmp_qwerty`',1,'','2022-01-01 00:00:00'), + ('drop correlation_tmp_qwerty','DROP TABLE IF EXISTS `correlation_tmp_qwerty`',1,'','2022-01-01 00:00:00'), + ('add provisioning column','alter table `correlation` ADD COLUMN `provisioned` TINYINT(1) NOT NULL DEFAULT 0 ',1,'','2022-01-01 00:00:00'), + ('add type column','alter table `correlation` ADD COLUMN `type` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT \'query\' ',1,'','2022-01-01 00:00:00'), + ('create entity_events table','CREATE TABLE IF NOT EXISTS `entity_event` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `entity_id` VARCHAR(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `event_type` VARCHAR(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `created` BIGINT(20) NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('create dashboard public config v1','CREATE TABLE IF NOT EXISTS `dashboard_public_config` (\n`uid` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci PRIMARY KEY NOT NULL\n, `dashboard_uid` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `org_id` BIGINT(20) NOT NULL\n, `time_settings` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `refresh_rate` INT NOT NULL DEFAULT 30\n, `template_variables` MEDIUMTEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('drop index UQE_dashboard_public_config_uid - v1','DROP INDEX `UQE_dashboard_public_config_uid` ON `dashboard_public_config`',1,'','2022-01-01 00:00:00'), + ('drop index IDX_dashboard_public_config_org_id_dashboard_uid - v1','DROP INDEX `IDX_dashboard_public_config_org_id_dashboard_uid` ON `dashboard_public_config`',1,'','2022-01-01 00:00:00'), + ('Drop old dashboard public config table','DROP TABLE IF EXISTS `dashboard_public_config`',1,'','2022-01-01 00:00:00'), + ('recreate dashboard public config v1','CREATE TABLE IF NOT EXISTS `dashboard_public_config` (\n`uid` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci PRIMARY KEY NOT NULL\n, `dashboard_uid` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `org_id` BIGINT(20) NOT NULL\n, `time_settings` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `refresh_rate` INT NOT NULL DEFAULT 30\n, `template_variables` MEDIUMTEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('create index UQE_dashboard_public_config_uid - v1','CREATE UNIQUE INDEX `UQE_dashboard_public_config_uid` ON `dashboard_public_config` (`uid`);',1,'','2022-01-01 00:00:00'), + ('create index IDX_dashboard_public_config_org_id_dashboard_uid - v1','CREATE INDEX `IDX_dashboard_public_config_org_id_dashboard_uid` ON `dashboard_public_config` (`org_id`,`dashboard_uid`);',1,'','2022-01-01 00:00:00'), + ('drop index UQE_dashboard_public_config_uid - v2','DROP INDEX `UQE_dashboard_public_config_uid` ON `dashboard_public_config`',1,'','2022-01-01 00:00:00'), + ('drop index IDX_dashboard_public_config_org_id_dashboard_uid - v2','DROP INDEX `IDX_dashboard_public_config_org_id_dashboard_uid` ON `dashboard_public_config`',1,'','2022-01-01 00:00:00'), + ('Drop public config table','DROP TABLE IF EXISTS `dashboard_public_config`',1,'','2022-01-01 00:00:00'), + ('Recreate dashboard public config v2','CREATE TABLE IF NOT EXISTS `dashboard_public_config` (\n`uid` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci PRIMARY KEY NOT NULL\n, `dashboard_uid` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `org_id` BIGINT(20) NOT NULL\n, `time_settings` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `template_variables` MEDIUMTEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `access_token` VARCHAR(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `created_by` INT NOT NULL\n, `updated_by` INT NULL\n, `created_at` DATETIME NOT NULL\n, `updated_at` DATETIME NULL\n, `is_enabled` TINYINT(1) NOT NULL DEFAULT 0\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('create index UQE_dashboard_public_config_uid - v2','CREATE UNIQUE INDEX `UQE_dashboard_public_config_uid` ON `dashboard_public_config` (`uid`);',1,'','2022-01-01 00:00:00'), + ('create index IDX_dashboard_public_config_org_id_dashboard_uid - v2','CREATE INDEX `IDX_dashboard_public_config_org_id_dashboard_uid` ON `dashboard_public_config` (`org_id`,`dashboard_uid`);',1,'','2022-01-01 00:00:00'), + ('create index UQE_dashboard_public_config_access_token - v2','CREATE UNIQUE INDEX `UQE_dashboard_public_config_access_token` ON `dashboard_public_config` (`access_token`);',1,'','2022-01-01 00:00:00'), + ('Rename table dashboard_public_config to dashboard_public - v2','ALTER TABLE `dashboard_public_config` RENAME TO `dashboard_public`',1,'','2022-01-01 00:00:00'), + ('add annotations_enabled column','alter table `dashboard_public` ADD COLUMN `annotations_enabled` TINYINT(1) NOT NULL DEFAULT 0 ',1,'','2022-01-01 00:00:00'), + ('add time_selection_enabled column','alter table `dashboard_public` ADD COLUMN `time_selection_enabled` TINYINT(1) NOT NULL DEFAULT 0 ',1,'','2022-01-01 00:00:00'), + ('delete orphaned public dashboards','DELETE FROM dashboard_public WHERE dashboard_uid NOT IN (SELECT uid FROM dashboard)',1,'','2022-01-01 00:00:00'), + ('add share column','alter table `dashboard_public` ADD COLUMN `share` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT \'public\' ',1,'','2022-01-01 00:00:00'), + ('backfill empty share column fields with default of public','UPDATE dashboard_public SET share=\'public\' WHERE share=\'\'',1,'','2022-01-01 00:00:00'), + ('create file table','CREATE TABLE IF NOT EXISTS `file` (\n`path` VARCHAR(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `path_hash` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `parent_folder_path_hash` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `contents` BLOB NOT NULL\n, `etag` VARCHAR(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `cache_control` VARCHAR(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `content_disposition` VARCHAR(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `updated` DATETIME NOT NULL\n, `created` DATETIME NOT NULL\n, `size` BIGINT(20) NOT NULL\n, `mime_type` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('file table idx: path natural pk','CREATE UNIQUE INDEX `UQE_file_path_hash` ON `file` (`path_hash`);',1,'','2022-01-01 00:00:00'), + ('file table idx: parent_folder_path_hash fast folder retrieval','CREATE INDEX `IDX_file_parent_folder_path_hash` ON `file` (`parent_folder_path_hash`);',1,'','2022-01-01 00:00:00'), + ('create file_meta table','CREATE TABLE IF NOT EXISTS `file_meta` (\n`path_hash` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `key` VARCHAR(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `value` VARCHAR(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('file table idx: path key','CREATE UNIQUE INDEX `UQE_file_meta_path_hash_key` ON `file_meta` (`path_hash`,`key`);',1,'','2022-01-01 00:00:00'), + ('set path collation in file table','',1,'','2022-01-01 00:00:00'), + ('migrate contents column to mediumblob for MySQL','ALTER TABLE file MODIFY contents MEDIUMBLOB;',1,'','2022-01-01 00:00:00'), + ('drop my_row_id and add primary key to file table if my_row_id exists (auto-generated mysql column)','\n ALTER TABLE file\n DROP PRIMARY KEY,\n DROP COLUMN my_row_id,\n DROP INDEX UQE_file_path_hash,\n ADD PRIMARY KEY (path_hash);\n ',1,'','2022-01-01 00:00:00'), + ('drop file_path unique index from file table if it exists (mysql)','ALTER TABLE file DROP INDEX UQE_file_path_hash',1,'','2022-01-01 00:00:00'), + ('add primary key to file table if it doesn\'t exist (mysql)','ALTER TABLE file ADD PRIMARY KEY (path_hash);',1,'','2022-01-01 00:00:00'), + ('add primary key to file table (postgres and sqlite)','',1,'','2022-01-01 00:00:00'), + ('drop my_row_id and add primary key to file_meta table if my_row_id exists (auto-generated mysql column)','\n ALTER TABLE file_meta\n DROP PRIMARY KEY,\n DROP COLUMN my_row_id,\n DROP INDEX UQE_file_meta_path_hash_key,\n ADD PRIMARY KEY (path_hash, `key`);\n ',1,'','2022-01-01 00:00:00'), + ('drop file_path unique index from file_meta table if it exists (mysql)','ALTER TABLE file_meta DROP INDEX UQE_file_meta_path_hash_key',1,'','2022-01-01 00:00:00'), + ('add primary key to file_meta table if it doesn\'t exist (mysql)','ALTER TABLE file_meta ADD PRIMARY KEY (path_hash, `key`);',1,'','2022-01-01 00:00:00'), + ('add primary key to file_meta table (postgres and sqlite)','',1,'','2022-01-01 00:00:00'), + ('managed permissions migration','code migration',1,'','2022-01-01 00:00:00'), + ('managed folder permissions alert actions migration','code migration',1,'','2022-01-01 00:00:00'), + ('RBAC action name migrator','code migration',1,'','2022-01-01 00:00:00'), + ('Add UID column to playlist','alter table `playlist` ADD COLUMN `uid` VARCHAR(80) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 0 ',1,'','2022-01-01 00:00:00'), + ('Update uid column values in playlist','UPDATE playlist SET uid=id;',1,'','2022-01-01 00:00:00'), + ('Add index for uid in playlist','CREATE UNIQUE INDEX `UQE_playlist_org_id_uid` ON `playlist` (`org_id`,`uid`);',1,'','2022-01-01 00:00:00'), + ('update group index for alert rules','code migration',1,'','2022-01-01 00:00:00'), + ('managed folder permissions alert actions repeated migration','code migration',1,'','2022-01-01 00:00:00'), + ('admin only folder/dashboard permission','code migration',1,'','2022-01-01 00:00:00'), + ('add action column to seed_assignment','alter table `seed_assignment` ADD COLUMN `action` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('add scope column to seed_assignment','alter table `seed_assignment` ADD COLUMN `scope` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('remove unique index builtin_role_role_name before nullable update','DROP INDEX `UQE_seed_assignment_builtin_role_role_name` ON `seed_assignment`',1,'','2022-01-01 00:00:00'), + ('update seed_assignment role_name column to nullable','ALTER TABLE seed_assignment MODIFY role_name VARCHAR(190) DEFAULT NULL;',1,'','2022-01-01 00:00:00'), + ('add unique index builtin_role_name back','CREATE UNIQUE INDEX `UQE_seed_assignment_builtin_role_role_name` ON `seed_assignment` (`builtin_role`,`role_name`);',1,'','2022-01-01 00:00:00'), + ('add unique index builtin_role_action_scope','CREATE UNIQUE INDEX `UQE_seed_assignment_builtin_role_action_scope` ON `seed_assignment` (`builtin_role`,`action`,`scope`);',1,'','2022-01-01 00:00:00'), + ('add primary key to seed_assigment','code migration',1,'','2022-01-01 00:00:00'), + ('add origin column to seed_assignment','alter table `seed_assignment` ADD COLUMN `origin` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('add origin to plugin seed_assignment','code migration',1,'','2022-01-01 00:00:00'), + ('prevent seeding OnCall access','code migration',1,'','2022-01-01 00:00:00'), + ('managed folder permissions alert actions repeated fixed migration','code migration',1,'','2022-01-01 00:00:00'), + ('managed folder permissions library panel actions migration','code migration',1,'','2022-01-01 00:00:00'), + ('migrate external alertmanagers to datsourcse','migrate external alertmanagers to datasource',1,'','2022-01-01 00:00:00'), + ('create folder table','CREATE TABLE IF NOT EXISTS `folder` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `uid` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `org_id` BIGINT(20) NOT NULL\n, `title` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `description` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `parent_uid` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `created` DATETIME NOT NULL\n, `updated` DATETIME NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('Add index for parent_uid','CREATE INDEX `IDX_folder_parent_uid_org_id` ON `folder` (`parent_uid`,`org_id`);',1,'','2022-01-01 00:00:00'), + ('Add unique index for folder.uid and folder.org_id','CREATE UNIQUE INDEX `UQE_folder_uid_org_id` ON `folder` (`uid`,`org_id`);',1,'','2022-01-01 00:00:00'), + ('Update folder title length','ALTER TABLE `folder` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, MODIFY `title` VARCHAR(189) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL ;',1,'','2022-01-01 00:00:00'), + ('Add unique index for folder.title and folder.parent_uid','CREATE UNIQUE INDEX `UQE_folder_title_parent_uid` ON `folder` (`title`,`parent_uid`);',1,'','2022-01-01 00:00:00'), + ('Remove unique index for folder.title and folder.parent_uid','DROP INDEX `UQE_folder_title_parent_uid` ON `folder`',1,'','2022-01-01 00:00:00'), + ('Add unique index for title, parent_uid, and org_id','CREATE UNIQUE INDEX `UQE_folder_title_parent_uid_org_id` ON `folder` (`title`,`parent_uid`,`org_id`);',1,'','2022-01-01 00:00:00'), + ('Sync dashboard and folder table','\n INSERT INTO folder (uid, org_id, title, created, updated)\n SELECT * FROM (SELECT uid, org_id, title, created, updated FROM dashboard WHERE is_folder = 1) AS derived\n ON DUPLICATE KEY UPDATE title=derived.title, updated=derived.updated\n ',1,'','2022-01-01 00:00:00'), + ('Remove ghost folders from the folder table','\n DELETE FROM folder WHERE NOT EXISTS\n (SELECT 1 FROM dashboard WHERE dashboard.uid = folder.uid AND dashboard.org_id = folder.org_id AND dashboard.is_folder = true)\n ',1,'','2022-01-01 00:00:00'), + ('Remove unique index UQE_folder_uid_org_id','DROP INDEX `UQE_folder_uid_org_id` ON `folder`',1,'','2022-01-01 00:00:00'), + ('Add unique index UQE_folder_org_id_uid','CREATE UNIQUE INDEX `UQE_folder_org_id_uid` ON `folder` (`org_id`,`uid`);',1,'','2022-01-01 00:00:00'), + ('Remove unique index UQE_folder_title_parent_uid_org_id','DROP INDEX `UQE_folder_title_parent_uid_org_id` ON `folder`',1,'','2022-01-01 00:00:00'), + ('Add unique index UQE_folder_org_id_parent_uid_title','CREATE UNIQUE INDEX `UQE_folder_org_id_parent_uid_title` ON `folder` (`org_id`,`parent_uid`,`title`);',1,'','2022-01-01 00:00:00'), + ('Remove index IDX_folder_parent_uid_org_id','DROP INDEX `IDX_folder_parent_uid_org_id` ON `folder`',1,'','2022-01-01 00:00:00'), + ('Remove unique index UQE_folder_org_id_parent_uid_title','DROP INDEX `UQE_folder_org_id_parent_uid_title` ON `folder`',1,'','2022-01-01 00:00:00'), + ('Add index IDX_folder_org_id_parent_uid','CREATE INDEX `IDX_folder_org_id_parent_uid` ON `folder` (`org_id`,`parent_uid`);',1,'','2022-01-01 00:00:00'), + ('create anon_device table','CREATE TABLE IF NOT EXISTS `anon_device` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `client_ip` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `created_at` DATETIME NOT NULL\n, `device_id` VARCHAR(127) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `updated_at` DATETIME NOT NULL\n, `user_agent` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('add unique index anon_device.device_id','CREATE UNIQUE INDEX `UQE_anon_device_device_id` ON `anon_device` (`device_id`);',1,'','2022-01-01 00:00:00'), + ('add index anon_device.updated_at','CREATE INDEX `IDX_anon_device_updated_at` ON `anon_device` (`updated_at`);',1,'','2022-01-01 00:00:00'), + ('create signing_key table','CREATE TABLE IF NOT EXISTS `signing_key` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `key_id` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `private_key` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `added_at` DATETIME NOT NULL\n, `expires_at` DATETIME NULL\n, `alg` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('add unique index signing_key.key_id','CREATE UNIQUE INDEX `UQE_signing_key_key_id` ON `signing_key` (`key_id`);',1,'','2022-01-01 00:00:00'), + ('set legacy alert migration status in kvstore','code migration',1,'','2022-01-01 00:00:00'), + ('migrate record of created folders during legacy migration to kvstore','code migration',1,'','2022-01-01 00:00:00'), + ('Add folder_uid for dashboard','alter table `dashboard` ADD COLUMN `folder_uid` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('Populate dashboard folder_uid column','code migration',1,'','2022-01-01 00:00:00'), + ('Add unique index for dashboard_org_id_folder_uid_title','code migration',1,'','2022-01-01 00:00:00'), + ('Delete unique index for dashboard_org_id_folder_id_title','DROP INDEX `UQE_dashboard_org_id_folder_id_title` ON `dashboard`',1,'','2022-01-01 00:00:00'), + ('Delete unique index for dashboard_org_id_folder_uid_title','code migration',1,'','2022-01-01 00:00:00'), + ('Add unique index for dashboard_org_id_folder_uid_title_is_folder','CREATE UNIQUE INDEX `UQE_dashboard_org_id_folder_uid_title_is_folder` ON `dashboard` (`org_id`,`folder_uid`,`title`,`is_folder`);',1,'','2022-01-01 00:00:00'), + ('Restore index for dashboard_org_id_folder_id_title','CREATE INDEX `IDX_dashboard_org_id_folder_id_title` ON `dashboard` (`org_id`,`folder_id`,`title`);',1,'','2022-01-01 00:00:00'), + ('Remove unique index for dashboard_org_id_folder_uid_title_is_folder','DROP INDEX `UQE_dashboard_org_id_folder_uid_title_is_folder` ON `dashboard`',1,'','2022-01-01 00:00:00'), + ('create sso_setting table','CREATE TABLE IF NOT EXISTS `sso_setting` (\n`id` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci PRIMARY KEY NOT NULL\n, `provider` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `settings` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `created` DATETIME NOT NULL\n, `updated` DATETIME NOT NULL\n, `is_deleted` TINYINT(1) NOT NULL DEFAULT 0\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('update settings column to MEDIUMTEXT','ALTER TABLE sso_setting MODIFY COLUMN settings MEDIUMTEXT NOT NULL;',1,'','2022-01-01 00:00:00'), + ('copy kvstore migration status to each org','code migration',1,'','2022-01-01 00:00:00'), + ('add back entry for orgid=0 migrated status','code migration',1,'','2022-01-01 00:00:00'), + ('managed dashboard permissions annotation actions migration','code migration',1,'','2022-01-01 00:00:00'), + ('create cloud_migration table v1','CREATE TABLE IF NOT EXISTS `cloud_migration` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `auth_token` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `stack` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `created` DATETIME NOT NULL\n, `updated` DATETIME NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('create cloud_migration_run table v1','CREATE TABLE IF NOT EXISTS `cloud_migration_run` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `cloud_migration_uid` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `result` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `created` DATETIME NOT NULL\n, `updated` DATETIME NOT NULL\n, `finished` DATETIME NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('add stack_id column','alter table `cloud_migration` ADD COLUMN `stack_id` BIGINT(20) NOT NULL ',1,'','2022-01-01 00:00:00'), + ('add region_slug column','alter table `cloud_migration` ADD COLUMN `region_slug` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL ',1,'','2022-01-01 00:00:00'), + ('add cluster_slug column','alter table `cloud_migration` ADD COLUMN `cluster_slug` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL ',1,'','2022-01-01 00:00:00'), + ('add migration uid column','alter table `cloud_migration` ADD COLUMN `uid` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('Update uid column values for migration','UPDATE cloud_migration SET uid=concat(\'u\',lpad(id,9,\'0\')) WHERE uid IS NULL;',1,'','2022-01-01 00:00:00'), + ('Add unique index migration_uid','CREATE UNIQUE INDEX `UQE_cloud_migration_uid` ON `cloud_migration` (`uid`);',1,'','2022-01-01 00:00:00'), + ('add migration run uid column','alter table `cloud_migration_run` ADD COLUMN `uid` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('Update uid column values for migration run','UPDATE cloud_migration_run SET uid=concat(\'u\',lpad(id,9,\'0\')) WHERE uid IS NULL;',1,'','2022-01-01 00:00:00'), + ('Add unique index migration_run_uid','CREATE UNIQUE INDEX `UQE_cloud_migration_run_uid` ON `cloud_migration_run` (`uid`);',1,'','2022-01-01 00:00:00'), + ('Rename table cloud_migration to cloud_migration_session_tmp_qwerty - v1','ALTER TABLE `cloud_migration` RENAME TO `cloud_migration_session_tmp_qwerty`',1,'','2022-01-01 00:00:00'), + ('create cloud_migration_session v2','CREATE TABLE IF NOT EXISTS `cloud_migration_session` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `uid` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `auth_token` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `slug` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `stack_id` BIGINT(20) NOT NULL\n, `region_slug` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `cluster_slug` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `created` DATETIME NOT NULL\n, `updated` DATETIME NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('create index UQE_cloud_migration_session_uid - v2','CREATE UNIQUE INDEX `UQE_cloud_migration_session_uid` ON `cloud_migration_session` (`uid`);',1,'','2022-01-01 00:00:00'), + ('copy cloud_migration_session v1 to v2','INSERT INTO `cloud_migration_session` (`id`\n, `auth_token`\n, `stack_id`\n, `cluster_slug`\n, `updated`\n, `uid`\n, `slug`\n, `region_slug`\n, `created`)\nSELECT `id`\n, `auth_token`\n, `stack_id`\n, `cluster_slug`\n, `updated`\n, `uid`\n, `stack`\n, `region_slug`\n, `created`\nFROM `cloud_migration_session_tmp_qwerty`',1,'','2022-01-01 00:00:00'), + ('drop cloud_migration_session_tmp_qwerty','DROP TABLE IF EXISTS `cloud_migration_session_tmp_qwerty`',1,'','2022-01-01 00:00:00'), + ('Rename table cloud_migration_run to cloud_migration_snapshot_tmp_qwerty - v1','ALTER TABLE `cloud_migration_run` RENAME TO `cloud_migration_snapshot_tmp_qwerty`',1,'','2022-01-01 00:00:00'), + ('create cloud_migration_snapshot v2','CREATE TABLE IF NOT EXISTS `cloud_migration_snapshot` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `uid` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `session_uid` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `result` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `created` DATETIME NOT NULL\n, `updated` DATETIME NOT NULL\n, `finished` DATETIME NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('create index UQE_cloud_migration_snapshot_uid - v2','CREATE UNIQUE INDEX `UQE_cloud_migration_snapshot_uid` ON `cloud_migration_snapshot` (`uid`);',1,'','2022-01-01 00:00:00'), + ('copy cloud_migration_snapshot v1 to v2','INSERT INTO `cloud_migration_snapshot` (`created`\n, `updated`\n, `finished`\n, `id`\n, `uid`\n, `session_uid`\n, `result`)\nSELECT `created`\n, `updated`\n, `finished`\n, `id`\n, `uid`\n, `cloud_migration_uid`\n, `result`\nFROM `cloud_migration_snapshot_tmp_qwerty`',1,'','2022-01-01 00:00:00'), + ('drop cloud_migration_snapshot_tmp_qwerty','DROP TABLE IF EXISTS `cloud_migration_snapshot_tmp_qwerty`',1,'','2022-01-01 00:00:00'), + ('add snapshot upload_url column','alter table `cloud_migration_snapshot` ADD COLUMN `upload_url` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('add snapshot status column','alter table `cloud_migration_snapshot` ADD COLUMN `status` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL ',1,'','2022-01-01 00:00:00'), + ('add snapshot local_directory column','alter table `cloud_migration_snapshot` ADD COLUMN `local_directory` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('add snapshot gms_snapshot_uid column','alter table `cloud_migration_snapshot` ADD COLUMN `gms_snapshot_uid` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('add snapshot encryption_key column','alter table `cloud_migration_snapshot` ADD COLUMN `encryption_key` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('add snapshot error_string column','alter table `cloud_migration_snapshot` ADD COLUMN `error_string` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('create cloud_migration_resource table v1','CREATE TABLE IF NOT EXISTS `cloud_migration_resource` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `uid` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `resource_type` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `resource_uid` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `status` VARCHAR(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `error_string` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `snapshot_uid` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('delete cloud_migration_snapshot.result column','ALTER TABLE cloud_migration_snapshot DROP COLUMN result',1,'','2022-01-01 00:00:00'), + ('add cloud_migration_resource.name column','alter table `cloud_migration_resource` ADD COLUMN `name` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('add cloud_migration_resource.parent_name column','alter table `cloud_migration_resource` ADD COLUMN `parent_name` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('add cloud_migration_session.org_id column','alter table `cloud_migration_session` ADD COLUMN `org_id` BIGINT(20) NOT NULL DEFAULT 1 ',1,'','2022-01-01 00:00:00'), + ('add cloud_migration_resource.error_code column','alter table `cloud_migration_resource` ADD COLUMN `error_code` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('increase resource_uid column length','ALTER TABLE cloud_migration_resource MODIFY resource_uid NVARCHAR(255);',1,'','2022-01-01 00:00:00'), + ('create cloud_migration_snapshot_partition table v1','CREATE TABLE IF NOT EXISTS `cloud_migration_snapshot_partition` (\n`snapshot_uid` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `partition_number` INT NOT NULL\n, `resource_type` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `data` LONGBLOB NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('add cloud_migration_snapshot_partition srp_unique index','CREATE UNIQUE INDEX `UQE_cloud_migration_snapshot_partition_srp_unique` ON `cloud_migration_snapshot_partition` (`snapshot_uid`,`resource_type`,`partition_number`);',1,'','2022-01-01 00:00:00'), + ('add resource_storage_type column to cloud_migration_snapshot table','alter table `cloud_migration_snapshot` ADD COLUMN `resource_storage_type` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('add encryption_algo column to cloud_migration_snapshot table','alter table `cloud_migration_snapshot` ADD COLUMN `encryption_algo` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('add metadata column to cloud_migration_snapshot table','alter table `cloud_migration_snapshot` ADD COLUMN `metadata` BLOB NULL ',1,'','2022-01-01 00:00:00'), + ('add public_key column to cloud_migration_snapshot table','alter table `cloud_migration_snapshot` ADD COLUMN `public_key` BLOB NULL ',1,'','2022-01-01 00:00:00'), + ('drop my_row_id and add primary key with columns snapshot_uid,resource_type,partition_number to table cloud_migration_snapshot_partition if my_row_id exists (auto-generated mysql column)','\n ALTER TABLE cloud_migration_snapshot_partition\n DROP PRIMARY KEY,\n DROP COLUMN my_row_id,\n DROP INDEX UQE_cloud_migration_snapshot_partition_srp_unique,\n ADD PRIMARY KEY (`snapshot_uid`,`resource_type`,`partition_number`);\n ',1,'','2022-01-01 00:00:00'), + ('drop unique index UQE_cloud_migration_snapshot_partition_srp_unique from cloud_migration_snapshot_partition table if it exists (mysql)','ALTER TABLE cloud_migration_snapshot_partition DROP INDEX UQE_cloud_migration_snapshot_partition_srp_unique',1,'','2022-01-01 00:00:00'), + ('add primary key with columns snapshot_uid,resource_type,partition_number to table cloud_migration_snapshot_partition if it doesn\'t exist (mysql)','ALTER TABLE cloud_migration_snapshot_partition ADD PRIMARY KEY (`snapshot_uid`,`resource_type`,`partition_number`)',1,'','2022-01-01 00:00:00'), + ('add primary key with columns snapshot_uid,resource_type,partition_number to table cloud_migration_snapshot_partition (postgres and sqlite)','',1,'','2022-01-01 00:00:00'), + ('alter kv_store.value to longtext','ALTER TABLE kv_store MODIFY value LONGTEXT NOT NULL;',1,'','2022-01-01 00:00:00'), + ('add notification_settings column to alert_rule table','alter table `alert_rule` ADD COLUMN `notification_settings` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('add notification_settings column to alert_rule_version table','alter table `alert_rule_version` ADD COLUMN `notification_settings` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('removing scope from alert.instances:read action migration','code migration',1,'','2022-01-01 00:00:00'), + ('managed folder permissions alerting silences actions migration','code migration',1,'','2022-01-01 00:00:00'), + ('add record column to alert_rule table','alter table `alert_rule` ADD COLUMN `record` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('add record column to alert_rule_version table','alter table `alert_rule_version` ADD COLUMN `record` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('add resolved_at column to alert_instance table','alter table `alert_instance` ADD COLUMN `resolved_at` BIGINT(20) NULL ',1,'','2022-01-01 00:00:00'), + ('add last_sent_at column to alert_instance table','alter table `alert_instance` ADD COLUMN `last_sent_at` BIGINT(20) NULL ',1,'','2022-01-01 00:00:00'), + ('Add scope to alert.notifications.receivers:read and alert.notifications.receivers.secrets:read','code migration',1,'','2022-01-01 00:00:00'), + ('add metadata column to alert_rule table','alter table `alert_rule` ADD COLUMN `metadata` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('add metadata column to alert_rule_version table','alter table `alert_rule_version` ADD COLUMN `metadata` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('delete orphaned service account permissions','code migration',1,'','2022-01-01 00:00:00'), + ('adding action set permissions','code migration',1,'','2022-01-01 00:00:00'), + ('create user_external_session table','CREATE TABLE IF NOT EXISTS `user_external_session` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `user_auth_id` BIGINT(20) NOT NULL\n, `user_id` BIGINT(20) NOT NULL\n, `auth_module` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `access_token` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `id_token` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `refresh_token` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `session_id` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `session_id_hash` CHAR(44) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `name_id` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `name_id_hash` CHAR(44) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `expires_at` DATETIME NULL\n, `created_at` DATETIME NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('increase name_id column length to 1024','ALTER TABLE user_external_session MODIFY name_id NVARCHAR(1024);',1,'','2022-01-01 00:00:00'), + ('increase session_id column length to 1024','ALTER TABLE user_external_session MODIFY session_id NVARCHAR(1024);',1,'','2022-01-01 00:00:00'), + ('remove scope from alert.notifications.receivers:create','code migration',1,'','2022-01-01 00:00:00'), + ('add created_by column to alert_rule_version table','alter table `alert_rule_version` ADD COLUMN `created_by` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('add updated_by column to alert_rule table','alter table `alert_rule` ADD COLUMN `updated_by` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('add alert_rule_state table','CREATE TABLE IF NOT EXISTS `alert_rule_state` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `org_id` BIGINT(20) NOT NULL\n, `rule_uid` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `data` LONGBLOB NOT NULL\n, `updated_at` DATETIME NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('add index to alert_rule_state on org_id and rule_uid columns','CREATE UNIQUE INDEX `UQE_alert_rule_state_org_id_rule_uid` ON `alert_rule_state` (`org_id`,`rule_uid`);',1,'','2022-01-01 00:00:00'), + ('add guid column to alert_rule table','alter table `alert_rule` ADD COLUMN `guid` VARCHAR(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT \'\' ',1,'','2022-01-01 00:00:00'), + ('add rule_guid column to alert_rule_version table','alter table `alert_rule_version` ADD COLUMN `rule_guid` VARCHAR(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT \'\' ',1,'','2022-01-01 00:00:00'), + ('cleanup alert_rule_version table','code migration',1,'','2022-01-01 00:00:00'), + ('populate rule guid in alert rule table','code migration',1,'','2022-01-01 00:00:00'), + ('drop index in alert_rule_version table on rule_org_id, rule_uid and version columns','DROP INDEX `UQE_alert_rule_version_rule_org_id_rule_uid_version` ON `alert_rule_version`',1,'','2022-01-01 00:00:00'), + ('add index in alert_rule_version table on rule_org_id, rule_uid, rule_guid and version columns','CREATE UNIQUE INDEX `UQE_alert_rule_version_rule_org_id_rule_uid_rule_guid_version` ON `alert_rule_version` (`rule_org_id`,`rule_uid`,`rule_guid`,`version`);',1,'','2022-01-01 00:00:00'), + ('add index in alert_rule_version table on rule_guid and version columns','CREATE UNIQUE INDEX `UQE_alert_rule_version_rule_guid_version` ON `alert_rule_version` (`rule_guid`,`version`);',1,'','2022-01-01 00:00:00'), + ('add index in alert_rule table on guid columns','CREATE UNIQUE INDEX `UQE_alert_rule_guid` ON `alert_rule` (`guid`);',1,'','2022-01-01 00:00:00'), + ('add keep_firing_for column to alert_rule','alter table `alert_rule` ADD COLUMN `keep_firing_for` BIGINT(20) NOT NULL DEFAULT 0 ',1,'','2022-01-01 00:00:00'), + ('add keep_firing_for column to alert_rule_version','alter table `alert_rule_version` ADD COLUMN `keep_firing_for` BIGINT(20) NOT NULL DEFAULT 0 ',1,'','2022-01-01 00:00:00'), + ('add missing_series_evals_to_resolve column to alert_rule','alter table `alert_rule` ADD COLUMN `missing_series_evals_to_resolve` SMALLINT NULL ',1,'','2022-01-01 00:00:00'), + ('add missing_series_evals_to_resolve column to alert_rule_version','alter table `alert_rule_version` ADD COLUMN `missing_series_evals_to_resolve` SMALLINT NULL ',1,'','2022-01-01 00:00:00'), + ('remove the datasources:drilldown action','code migration',1,'','2022-01-01 00:00:00'), + ('remove title in folder unique index','DROP INDEX `UQE_alert_rule_org_id_namespace_uid_title` ON `alert_rule`',1,'','2022-01-01 00:00:00'), + ('add fired_at column to alert_instance table','alter table `alert_instance` ADD COLUMN `fired_at` BIGINT(20) NULL ',1,'','2022-01-01 00:00:00'), + ('ensure rule_group column is case sensitive in returned results','ALTER TABLE alert_rule MODIFY rule_group VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_as_cs NOT NULL;',1,'','2022-01-01 00:00:00'), + ('expand created_by in alert_rule_version table','ALTER TABLE `alert_rule_version` MODIFY created_by VARCHAR(190);',1,'','2022-01-01 00:00:00'), + ('expand updated_by in alert_rule table','ALTER TABLE `alert_rule` MODIFY updated_by VARCHAR(190);',1,'','2022-01-01 00:00:00'), + ('add index in alert_rule on org_id, namespace_uid, rule_group and rule_group_idx columns','CREATE INDEX `IDX_alert_rule_org_id_namespace_uid_rule_group_rule_group_idx` ON `alert_rule` (`org_id`,`namespace_uid`,`rule_group`,`rule_group_idx`);',1,'','2022-01-01 00:00:00'), + ('add annotations column to alert_instance table','alter table `alert_instance` ADD COLUMN `annotations` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('ensure namespace_uid column sorts the same way as golang','ALTER TABLE alert_rule MODIFY namespace_uid VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;',1,'','2022-01-01 00:00:00'), + ('ensure rule_group column sorts the same way as golang','ALTER TABLE alert_rule MODIFY rule_group VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;',1,'','2022-01-01 00:00:00'), + ('add \'alert.notifications.receivers.protected:write\' to receiver admins','code migration',1,'','2022-01-01 00:00:00'), + ('create data_source_usage_by_day table','CREATE TABLE IF NOT EXISTS `data_source_usage_by_day` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `data_source_id` BIGINT(20) NOT NULL\n, `day` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `queries` BIGINT(20) NOT NULL\n, `errors` BIGINT(20) NOT NULL\n, `load_duration_ms` BIGINT(20) NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('create data_source_usage_by_day(data_source_id) index','CREATE INDEX `IDX_data_source_usage_by_day_data_source_id` ON `data_source_usage_by_day` (`data_source_id`);',1,'','2022-01-01 00:00:00'), + ('create data_source_usage_by_day(data_source_id, day) unique index','CREATE UNIQUE INDEX `UQE_data_source_usage_by_day_data_source_id_day` ON `data_source_usage_by_day` (`data_source_id`,`day`);',1,'','2022-01-01 00:00:00'), + ('create dashboard_usage_by_day table','CREATE TABLE IF NOT EXISTS `dashboard_usage_by_day` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `dashboard_id` BIGINT(20) NOT NULL\n, `day` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `views` BIGINT(20) NOT NULL\n, `queries` BIGINT(20) NOT NULL\n, `errors` BIGINT(20) NOT NULL\n, `load_duration` FLOAT NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('create dashboard_usage_sums table','CREATE TABLE IF NOT EXISTS `dashboard_usage_sums` (\n`dashboard_id` BIGINT(20) PRIMARY KEY NOT NULL\n, `updated` DATETIME NOT NULL\n, `views_last_1_days` BIGINT(20) NOT NULL\n, `views_last_7_days` BIGINT(20) NOT NULL\n, `views_last_30_days` BIGINT(20) NOT NULL\n, `views_total` BIGINT(20) NOT NULL\n, `queries_last_1_days` BIGINT(20) NOT NULL\n, `queries_last_7_days` BIGINT(20) NOT NULL\n, `queries_last_30_days` BIGINT(20) NOT NULL\n, `queries_total` BIGINT(20) NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('create dashboard_usage_by_day(dashboard_id) index','CREATE INDEX `IDX_dashboard_usage_by_day_dashboard_id` ON `dashboard_usage_by_day` (`dashboard_id`);',1,'','2022-01-01 00:00:00'), + ('create dashboard_usage_by_day(dashboard_id, day) index','CREATE UNIQUE INDEX `UQE_dashboard_usage_by_day_dashboard_id_day` ON `dashboard_usage_by_day` (`dashboard_id`,`day`);',1,'','2022-01-01 00:00:00'), + ('add column errors_last_1_days to dashboard_usage_sums','alter table `dashboard_usage_sums` ADD COLUMN `errors_last_1_days` BIGINT(20) NOT NULL DEFAULT 0 ',1,'','2022-01-01 00:00:00'), + ('add column errors_last_7_days to dashboard_usage_sums','alter table `dashboard_usage_sums` ADD COLUMN `errors_last_7_days` BIGINT(20) NOT NULL DEFAULT 0 ',1,'','2022-01-01 00:00:00'), + ('add column errors_last_30_days to dashboard_usage_sums','alter table `dashboard_usage_sums` ADD COLUMN `errors_last_30_days` BIGINT(20) NOT NULL DEFAULT 0 ',1,'','2022-01-01 00:00:00'), + ('add column errors_total to dashboard_usage_sums','alter table `dashboard_usage_sums` ADD COLUMN `errors_total` BIGINT(20) NOT NULL DEFAULT 0 ',1,'','2022-01-01 00:00:00'), + ('create dashboard_public_usage_by_day table','CREATE TABLE IF NOT EXISTS `dashboard_public_usage_by_day` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `public_dashboard_uid` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `day` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `views` BIGINT(20) NOT NULL\n, `queries` BIGINT(20) NOT NULL\n, `errors` BIGINT(20) NOT NULL\n, `load_duration` FLOAT NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('add column cached_queries to dashboard_usage_by_day table','alter table `dashboard_usage_by_day` ADD COLUMN `cached_queries` BIGINT(20) NOT NULL DEFAULT 0 ',1,'','2022-01-01 00:00:00'), + ('add column cached_queries to dashboard_public_usage_by_day table','alter table `dashboard_public_usage_by_day` ADD COLUMN `cached_queries` BIGINT(20) NOT NULL DEFAULT 0 ',1,'','2022-01-01 00:00:00'), + ('add column dashboard_uid to dashboard_usage_sums','alter table `dashboard_usage_sums` ADD COLUMN `dashboard_uid` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('add column org_id to dashboard_usage_sums','alter table `dashboard_usage_sums` ADD COLUMN `org_id` BIGINT(20) NULL DEFAULT 1 ',1,'','2022-01-01 00:00:00'), + ('add column dashboard_uid to dashboard_usage_by_day','alter table `dashboard_usage_by_day` ADD COLUMN `dashboard_uid` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('add column org_id to dashboard_usage_by_day','alter table `dashboard_usage_by_day` ADD COLUMN `org_id` BIGINT(20) NULL DEFAULT 1 ',1,'','2022-01-01 00:00:00'), + ('create dashboard_usage_by_day(dashboard_uid, org_id, day) unique index','CREATE UNIQUE INDEX `UQE_dashboard_usage_by_day_dashboard_uid_org_id_day` ON `dashboard_usage_by_day` (`dashboard_uid`,`org_id`,`day`);',1,'','2022-01-01 00:00:00'), + ('Add missing dashboard_uid and org_id to dashboard_usage_by_day and dashboard_usage_sums','code migration',1,'','2022-01-01 00:00:00'), + ('Add dashboard_usage_sums(org_id, dashboard_uid) index','CREATE UNIQUE INDEX `UQE_dashboard_usage_sums_org_id_dashboard_uid` ON `dashboard_usage_sums` (`org_id`,`dashboard_uid`);',1,'','2022-01-01 00:00:00'), + ('create user_dashboard_views table','CREATE TABLE IF NOT EXISTS `user_dashboard_views` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `user_id` BIGINT(20) NOT NULL\n, `dashboard_id` BIGINT(20) NOT NULL\n, `viewed` DATETIME NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('add index user_dashboard_views.user_id','CREATE INDEX `IDX_user_dashboard_views_user_id` ON `user_dashboard_views` (`user_id`);',1,'','2022-01-01 00:00:00'), + ('add index user_dashboard_views.dashboard_id','CREATE INDEX `IDX_user_dashboard_views_dashboard_id` ON `user_dashboard_views` (`dashboard_id`);',1,'','2022-01-01 00:00:00'), + ('add unique index user_dashboard_views_user_id_dashboard_id','CREATE UNIQUE INDEX `UQE_user_dashboard_views_user_id_dashboard_id` ON `user_dashboard_views` (`user_id`,`dashboard_id`);',1,'','2022-01-01 00:00:00'), + ('add org_id column to user_dashboard_views','alter table `user_dashboard_views` ADD COLUMN `org_id` BIGINT(20) NULL ',1,'','2022-01-01 00:00:00'), + ('add dashboard_uid column to user_dashboard_views','alter table `user_dashboard_views` ADD COLUMN `dashboard_uid` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('add unique index user_dashboard_views_org_id_dashboard_uid','CREATE INDEX `IDX_user_dashboard_views_org_id_dashboard_uid` ON `user_dashboard_views` (`org_id`,`dashboard_uid`);',1,'','2022-01-01 00:00:00'), + ('add unique index user_dashboard_views_org_id_user_id_dashboard_uid','CREATE UNIQUE INDEX `UQE_user_dashboard_views_user_id_org_id_dashboard_uid` ON `user_dashboard_views` (`user_id`,`org_id`,`dashboard_uid`);',1,'','2022-01-01 00:00:00'), + ('populate user_dashboard_views.dashboard_uid and user_dashboard_views.org_id from dashboard table','views migration',1,'','2022-01-01 00:00:00'), + ('delete views where dashboard does not exist','DELETE FROM user_dashboard_views WHERE (dashboard_uid IS NULL OR org_id IS NULL) AND NOT EXISTS (SELECT 1 FROM dashboard WHERE dashboard.id = user_dashboard_views.dashboard_id)',1,'','2022-01-01 00:00:00'), + ('create user_stats table','CREATE TABLE IF NOT EXISTS `user_stats` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `user_id` BIGINT(20) NOT NULL\n, `billing_role` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `created` DATETIME NOT NULL\n, `updated` DATETIME NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('add unique index user_stats(user_id)','CREATE UNIQUE INDEX `UQE_user_stats_user_id` ON `user_stats` (`user_id`);',1,'','2022-01-01 00:00:00'), + ('create data_source_cache table','CREATE TABLE IF NOT EXISTS `data_source_cache` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `data_source_id` BIGINT(20) NOT NULL\n, `enabled` TINYINT(1) NOT NULL\n, `ttl_ms` BIGINT(20) NOT NULL\n, `created` DATETIME NOT NULL\n, `updated` DATETIME NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('add index data_source_cache.data_source_id','CREATE INDEX `IDX_data_source_cache_data_source_id` ON `data_source_cache` (`data_source_id`);',1,'','2022-01-01 00:00:00'), + ('add use_default_ttl column','alter table `data_source_cache` ADD COLUMN `use_default_ttl` TINYINT(1) NOT NULL DEFAULT 1 ',1,'','2022-01-01 00:00:00'), + ('add data_source_cache.data_source_uid column','alter table `data_source_cache` ADD COLUMN `data_source_uid` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 0 ',1,'','2022-01-01 00:00:00'), + ('remove abandoned data_source_cache records','DELETE FROM data_source_cache WHERE NOT EXISTS (SELECT 1 FROM data_source WHERE id = data_source_cache.data_source_id);',1,'','2022-01-01 00:00:00'), + ('update data_source_cache.data_source_uid value','UPDATE data_source_cache JOIN data_source ON data_source_cache.data_source_id = data_source.id SET data_source_cache.data_source_uid = data_source.uid;',1,'','2022-01-01 00:00:00'), + ('add index data_source_cache.data_source_uid','CREATE INDEX `IDX_data_source_cache_data_source_uid` ON `data_source_cache` (`data_source_uid`);',1,'','2022-01-01 00:00:00'), + ('add data_source_cache.ttl_resources_ms column','alter table `data_source_cache` ADD COLUMN `ttl_resources_ms` BIGINT(20) NOT NULL DEFAULT 300000 ',1,'','2022-01-01 00:00:00'), + ('update data_source_cache.ttl_resources_ms to have the same value as ttl_ms','UPDATE data_source_cache SET ttl_resources_ms = ttl_ms;',1,'','2022-01-01 00:00:00'), + ('create data_source_acl table','CREATE TABLE IF NOT EXISTS `data_source_acl` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `org_id` BIGINT(20) NOT NULL\n, `data_source_id` BIGINT(20) NOT NULL\n, `team_id` BIGINT(20) NOT NULL\n, `user_id` BIGINT(20) NOT NULL\n, `permission` SMALLINT NOT NULL\n, `created` DATETIME NOT NULL\n, `updated` DATETIME NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('add index data_source_acl.data_source_id','CREATE INDEX `IDX_data_source_acl_data_source_id` ON `data_source_acl` (`data_source_id`);',1,'','2022-01-01 00:00:00'), + ('add unique index datasource_acl.unique','CREATE UNIQUE INDEX `UQE_data_source_acl_data_source_id_team_id_user_id` ON `data_source_acl` (`data_source_id`,`team_id`,`user_id`);',1,'','2022-01-01 00:00:00'), + ('create license_token table','CREATE TABLE IF NOT EXISTS `license_token` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `token` LONGTEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `created` DATETIME NOT NULL\n, `updated` DATETIME NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('drop recorded_queries table v14','DROP TABLE IF EXISTS `recorded_queries`',1,'','2022-01-01 00:00:00'), + ('drop recording_rules table v14','DROP TABLE IF EXISTS `recording_rules`',1,'','2022-01-01 00:00:00'), + ('create recording_rules table v14','CREATE TABLE IF NOT EXISTS `recording_rules` (\n`id` VARCHAR(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `target_ref_id` VARCHAR(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `name` VARCHAR(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `description` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `org_id` BIGINT(20) NOT NULL\n, `interval` BIGINT(20) NOT NULL\n, `range` BIGINT(20) NOT NULL\n, `active` TINYINT(1) NOT NULL DEFAULT 0\n, `count` TINYINT(1) NOT NULL DEFAULT 0\n, `queries` BLOB NOT NULL\n, `created_at` DATETIME NOT NULL\n, PRIMARY KEY ( `id`,`target_ref_id` )) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('create remote_write_targets table v1','CREATE TABLE IF NOT EXISTS `remote_write_targets` (\n`id` VARCHAR(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `data_source_uid` VARCHAR(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `write_path` VARCHAR(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `org_id` INT NOT NULL\n, PRIMARY KEY ( `id`,`data_source_uid`,`write_path` )) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('Add prom_name to recording_rules table','alter table `recording_rules` ADD COLUMN `prom_name` VARCHAR(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('ensure remote_write_targets table','CREATE TABLE IF NOT EXISTS `remote_write_targets` (\n`id` VARCHAR(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `data_source_uid` VARCHAR(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `write_path` VARCHAR(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `org_id` INT NOT NULL\n, PRIMARY KEY ( `id`,`data_source_uid`,`write_path` )) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('create report config table v1','CREATE TABLE IF NOT EXISTS `report` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `user_id` BIGINT(20) NOT NULL\n, `org_id` BIGINT(20) NOT NULL\n, `dashboard_id` BIGINT(20) NOT NULL\n, `name` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `recipients` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `reply_to` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `message` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `schedule_frequency` VARCHAR(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `schedule_day` VARCHAR(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `schedule_hour` BIGINT(20) NOT NULL\n, `schedule_minute` BIGINT(20) NOT NULL\n, `created` DATETIME NOT NULL\n, `updated` DATETIME NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('Add index report.user_id','CREATE INDEX `IDX_report_user_id` ON `report` (`user_id`);',1,'','2022-01-01 00:00:00'), + ('add index to dashboard_id','CREATE INDEX `IDX_report_dashboard_id` ON `report` (`dashboard_id`);',1,'','2022-01-01 00:00:00'), + ('add index to org_id','CREATE INDEX `IDX_report_org_id` ON `report` (`org_id`);',1,'','2022-01-01 00:00:00'), + ('Add timezone to the report','alter table `report` ADD COLUMN `schedule_timezone` VARCHAR(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT \'Europe/Stockholm\' ',1,'','2022-01-01 00:00:00'), + ('Add time_from to the report','alter table `report` ADD COLUMN `time_from` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('Add time_to to the report','alter table `report` ADD COLUMN `time_to` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('Add PDF landscape option to the report','alter table `report` ADD COLUMN `pdf_landscape` TINYINT(1) NULL ',1,'','2022-01-01 00:00:00'), + ('Add monthly day scheduling option to the report','alter table `report` ADD COLUMN `schedule_day_of_month` VARCHAR(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('Add PDF layout option to the report','alter table `report` ADD COLUMN `pdf_layout` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('Add PDF orientation option to the report','alter table `report` ADD COLUMN `pdf_orientation` VARCHAR(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('Update report pdf_orientation from pdf_landscape','UPDATE report SET pdf_orientation = \'landscape\' WHERE pdf_landscape = 1',1,'','2022-01-01 00:00:00'), + ('create report settings table','CREATE TABLE IF NOT EXISTS `report_settings` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `user_id` BIGINT(20) NOT NULL\n, `org_id` BIGINT(20) NOT NULL\n, `branding_report_logo_url` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `branding_email_logo_url` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `branding_email_footer_link` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `branding_email_footer_text` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `branding_email_footer_mode` VARCHAR(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('Add dashboard_uid field to the report','alter table `report` ADD COLUMN `dashboard_uid` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('Add template_vars field to the report','alter table `report` ADD COLUMN `template_vars` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('Add option to include dashboard url in the report','alter table `report` ADD COLUMN `enable_dashboard_url` TINYINT(1) NULL ',1,'','2022-01-01 00:00:00'), + ('Add state field to the report','alter table `report` ADD COLUMN `state` VARCHAR(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('Add option to add CSV files to the report','alter table `report` ADD COLUMN `enable_csv` TINYINT(1) NULL ',1,'','2022-01-01 00:00:00'), + ('Add scheduling start date','alter table `report` ADD COLUMN `schedule_start` INT NULL ',1,'','2022-01-01 00:00:00'), + ('Add missing schedule_start date for old reports','code migration',1,'','2022-01-01 00:00:00'), + ('Add scheduling end date','alter table `report` ADD COLUMN `schedule_end` INT NULL ',1,'','2022-01-01 00:00:00'), + ('Add schedulinng custom interval frequency','alter table `report` ADD COLUMN `schedule_interval_frequency` VARCHAR(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('Add scheduling custom interval amount','alter table `report` ADD COLUMN `schedule_interval_amount` BIGINT(20) NULL ',1,'','2022-01-01 00:00:00'), + ('Add workdays only flag to report','alter table `report` ADD COLUMN `schedule_workdays_only` TINYINT(1) NULL ',1,'','2022-01-01 00:00:00'), + ('create report dashboards table','CREATE TABLE IF NOT EXISTS `report_dashboards` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `report_id` BIGINT(20) NOT NULL\n, `dashboard_uid` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT \'\'\n, `report_variables` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `time_to` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n, `time_from` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('Add index report_dashboards.report_id','CREATE INDEX `IDX_report_dashboards_report_id` ON `report_dashboards` (`report_id`);',1,'','2022-01-01 00:00:00'), + ('Migrate report fields into report_dashboards','INSERT INTO report_dashboards (report_id, dashboard_uid, report_variables, time_to, time_from) SELECT id, CASE WHEN dashboard_uid IS NULL THEN \'\' ELSE dashboard_uid END, template_vars, time_to, time_from FROM report',1,'','2022-01-01 00:00:00'), + ('Add formats option to the report','alter table `report` ADD COLUMN `formats` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT \'[\"pdf\"]\' ',1,'','2022-01-01 00:00:00'), + ('Migrate reports with csv enabled','UPDATE report SET formats=\'[\"pdf\",\"csv\"]\' WHERE enable_csv IS TRUE;',1,'','2022-01-01 00:00:00'), + ('Migrate ancient reports','code migration',1,'','2022-01-01 00:00:00'), + ('Add created column in report_dashboards','alter table `report_dashboards` ADD COLUMN `created` DATETIME NULL ',1,'','2022-01-01 00:00:00'), + ('Add scale_factor to the report','alter table `report` ADD COLUMN `scale_factor` TINYINT NOT NULL DEFAULT 2 ',1,'','2022-01-01 00:00:00'), + ('Alter scale_factor from TINYINT to SMALLINT','ALTER TABLE report MODIFY scale_factor SMALLINT NOT NULL DEFAULT 2',1,'','2022-01-01 00:00:00'), + ('Add uid column to report','alter table `report` ADD COLUMN `uid` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('Add unique index reports_org_id_uid','CREATE UNIQUE INDEX `UQE_report_org_id_uid` ON `report` (`org_id`,`uid`);',1,'','2022-01-01 00:00:00'), + ('Add pdf show template variable values to the report','alter table `report` ADD COLUMN `pdf_show_template_variables` TINYINT(1) NOT NULL DEFAULT 0 ',1,'','2022-01-01 00:00:00'), + ('Add pdf combine in one file','alter table `report` ADD COLUMN `pdf_combine_one_file` TINYINT(1) NOT NULL DEFAULT 1 ',1,'','2022-01-01 00:00:00'), + ('Add pdf theme to report settings table','alter table `report_settings` ADD COLUMN `pdf_theme` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT \'light\' ',1,'','2022-01-01 00:00:00'), + ('Add email subject to the report','alter table `report` ADD COLUMN `subject` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('Populate email subject with report name','UPDATE report SET subject = name WHERE subject IS NULL',1,'','2022-01-01 00:00:00'), + ('Add embedded image theme to report settings table','alter table `report_settings` ADD COLUMN `embedded_image_theme` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT \'dark\' ',1,'','2022-01-01 00:00:00'), + ('create team group table','CREATE TABLE IF NOT EXISTS `team_group` (\n`id` BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL\n, `org_id` BIGINT(20) NOT NULL\n, `team_id` BIGINT(20) NOT NULL\n, `group_id` VARCHAR(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `created` DATETIME NOT NULL\n, `updated` DATETIME NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('add index team_group.org_id','CREATE INDEX `IDX_team_group_org_id` ON `team_group` (`org_id`);',1,'','2022-01-01 00:00:00'), + ('add unique index team_group.org_id_team_id_group_id','CREATE UNIQUE INDEX `UQE_team_group_org_id_team_id_group_id` ON `team_group` (`org_id`,`team_id`,`group_id`);',1,'','2022-01-01 00:00:00'), + ('add index team_group.group_id','CREATE INDEX `IDX_team_group_group_id` ON `team_group` (`group_id`);',1,'','2022-01-01 00:00:00'), + ('Add column uid in team_group','alter table `team_group` ADD COLUMN `uid` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('Update uid column values in team_group','UPDATE team_group SET uid=concat(\'tg\',lpad(id,9,\'0\')) WHERE uid IS NULL OR uid = \'\';',1,'','2022-01-01 00:00:00'), + ('Add unique index team_group_uid','CREATE UNIQUE INDEX `UQE_team_group_uid` ON `team_group` (`uid`);',1,'','2022-01-01 00:00:00'), + ('create settings table','CREATE TABLE IF NOT EXISTS `setting` (\n`section` VARCHAR(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `key` VARCHAR(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `value` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('add unique index settings.section_key','CREATE UNIQUE INDEX `UQE_setting_section_key` ON `setting` (`section`,`key`);',1,'','2022-01-01 00:00:00'), + ('add setting.encrypted_value','alter table `setting` ADD COLUMN `encrypted_value` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL ',1,'','2022-01-01 00:00:00'), + ('drop my_row_id and add primary key to setting table if my_row_id exists (auto-generated mysql column)','\n ALTER TABLE setting\n DROP PRIMARY KEY,\n DROP COLUMN my_row_id,\n DROP INDEX UQE_setting_section_key,\n ADD PRIMARY KEY (section, `key`);\n ',1,'','2022-01-01 00:00:00'), + ('drop setting_section unique index from setting table if it exists (mysql)','ALTER TABLE setting DROP INDEX UQE_setting_section_key',1,'','2022-01-01 00:00:00'), + ('add primary key to setting table if it doesn\'t exist (mysql)','ALTER TABLE setting ADD PRIMARY KEY (section, `key`);',1,'','2022-01-01 00:00:00'), + ('add primary key to setting table (postgres and sqlite)','',1,'','2022-01-01 00:00:00'), + ('migrate role names','code migration',1,'','2022-01-01 00:00:00'), + ('rename orgs roles','code migration',1,'','2022-01-01 00:00:00'), + ('remove duplicated org role','code migration',1,'','2022-01-01 00:00:00'), + ('migrate alerting role names','code migration',1,'','2022-01-01 00:00:00'), + ('data source permissions','code migration',1,'','2022-01-01 00:00:00'), + ('data source uid permissions','code migration',1,'','2022-01-01 00:00:00'), + ('rename permissions:delegate scope','UPDATE permission SET scope = \'permissions:type:delegate\' WHERE scope = \'permissions:delegate\'',1,'','2022-01-01 00:00:00'), + ('remove invalid managed permissions','code migration',1,'','2022-01-01 00:00:00'), + ('builtin role migration','code migration',1,'','2022-01-01 00:00:00'), + ('seed permissions migration','code migration',1,'','2022-01-01 00:00:00'), + ('managed permissions migration enterprise','code migration',1,'','2022-01-01 00:00:00'), + ('create table dashboard_public_email_share','CREATE TABLE IF NOT EXISTS `dashboard_public_email_share` (\n`uid` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci PRIMARY KEY NOT NULL\n, `public_dashboard_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `recipient` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `type` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT \'email\'\n, `created_at` DATETIME NOT NULL\n, `updated_at` DATETIME NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('create table dashboard_public_magic_link','CREATE TABLE IF NOT EXISTS `dashboard_public_magic_link` (\n`uid` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci PRIMARY KEY NOT NULL\n, `token_uuid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `public_dashboard_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `email` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `created_at` DATETIME NOT NULL\n, `updated_at` DATETIME NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('create table dashboard_public_session','CREATE TABLE IF NOT EXISTS `dashboard_public_session` (\n`uid` VARCHAR(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci PRIMARY KEY NOT NULL\n, `cookie_uuid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `public_dashboard_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `email` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL\n, `created_at` DATETIME NOT NULL\n, `updated_at` DATETIME NOT NULL\n) ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;',1,'','2022-01-01 00:00:00'), + ('add last_seen_at column','alter table `dashboard_public_session` ADD COLUMN `last_seen_at` DATETIME NULL ',1,'','2022-01-01 00:00:00'); +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; + diff --git a/pkg/services/sqlstore/migrator/testdata/sqlite_file_migration_statement.sql b/pkg/services/sqlstore/migrator/testdata/sqlite_file_migration_statement.sql new file mode 100644 index 00000000000..2f37839d842 --- /dev/null +++ b/pkg/services/sqlstore/migrator/testdata/sqlite_file_migration_statement.sql @@ -0,0 +1,23 @@ +CREATE TABLE IF NOT EXISTS `file_new` ( + `path` TEXT NOT NULL + , `path_hash` TEXT NOT NULL + , `parent_folder_path_hash` TEXT NOT NULL + , `contents` BLOB NOT NULL + , `etag` TEXT NOT NULL + , PRIMARY KEY ( `path_hash`,`etag` )); + +INSERT INTO `file_new` (`path` + , `path_hash` + , `parent_folder_path_hash` + , `contents` + , `etag`) +SELECT `path` + , `path_hash` + , `parent_folder_path_hash` + , `contents` + , `etag` +FROM `file`; + +DROP TABLE IF EXISTS `file`; +ALTER TABLE `file_new` RENAME TO `file`; +CREATE INDEX `IDX_file_parent_folder_path_hash` ON `file` (`parent_folder_path_hash`); diff --git a/pkg/services/sqlstore/migrator/testing.go b/pkg/services/sqlstore/migrator/testing.go new file mode 100644 index 00000000000..cfe7849c79e --- /dev/null +++ b/pkg/services/sqlstore/migrator/testing.go @@ -0,0 +1,51 @@ +package migrator + +import ( + "fmt" + "strings" +) + +type ExpectedMigration struct { + Id string + SQL string +} + +// CheckExpectedMigrations verifies that given migrations exist in migrator after running addMigrations function, +// that they are in the same order and have expected SQL. +func CheckExpectedMigrations(dialectName string, expected []ExpectedMigration, addMigrations func(migrator *Migrator)) error { + d := NewDialect(dialectName) + mg := newMigrator(nil, nil, "", d) + addMigrations(mg) + + migrations := mg.migrations + migrationNames := make([]string, 0, len(migrations)) + for _, m := range expected { + for ; len(migrations) > 0 && migrations[0].Id() != m.Id; migrations = migrations[1:] { + migrationNames = append(migrationNames, migrations[0].Id()) + } + + if len(migrations) == 0 { + return fmt.Errorf("migration `%s` not found, existing migrations:\n%s", m.Id, strings.Join(migrationNames, "\n")) + } + + sql := migrations[0].SQL(d) + if normalizeLines(m.SQL) != normalizeLines(sql) { + return fmt.Errorf("migration `%s` has wrong SQL:\nexpected:\n%s\nactual:\n%s", m.Id, m.SQL, sql) + } + } + return nil +} + +func normalizeLines(sql string) string { + lines := strings.Split(sql, "\n") + result := strings.Builder{} + for _, l := range lines { + l := strings.TrimSpace(l) + if l == "" { + continue + } + result.WriteString(l) + result.WriteString("\n") + } + return result.String() +} diff --git a/pkg/setting/setting.go b/pkg/setting/setting.go index 8e309433032..995a01ad825 100644 --- a/pkg/setting/setting.go +++ b/pkg/setting/setting.go @@ -414,6 +414,7 @@ type Cfg struct { RudderstackDataPlaneURL string RudderstackWriteKey string RudderstackSDKURL string + RudderstackV3SDKURL string RudderstackConfigURL string RudderstackIntegrationsURL string IntercomSecret string @@ -632,6 +633,9 @@ type UnifiedStorageConfig struct { DataSyncerInterval time.Duration // DataSyncerRecordsLimit defines how many records will be processed at max during a sync invocation. DataSyncerRecordsLimit int + // EnableMigration indicates whether migration is enabled for the resource. + // If not set, will use the default from MigratedUnifiedResources. + EnableMigration bool } type InstallPlugin struct { @@ -1278,6 +1282,7 @@ func (cfg *Cfg) parseINIFile(iniFile *ini.File) error { cfg.RudderstackWriteKey = analytics.Key("rudderstack_write_key").String() cfg.RudderstackDataPlaneURL = analytics.Key("rudderstack_data_plane_url").String() cfg.RudderstackSDKURL = analytics.Key("rudderstack_sdk_url").String() + cfg.RudderstackV3SDKURL = analytics.Key("rudderstack_v3_sdk_url").String() cfg.RudderstackConfigURL = analytics.Key("rudderstack_config_url").String() cfg.RudderstackIntegrationsURL = analytics.Key("rudderstack_integrations_url").String() cfg.IntercomSecret = analytics.Key("intercom_secret").String() @@ -2162,7 +2167,7 @@ func (cfg *Cfg) readProvisioningSettings(iniFile *ini.File) error { } cfg.ProvisioningAllowedTargets = iniFile.Section("provisioning").Key("allowed_targets").Strings("|") if len(cfg.ProvisioningAllowedTargets) == 0 { - cfg.ProvisioningAllowedTargets = []string{"instance", "folder"} + cfg.ProvisioningAllowedTargets = []string{"folder"} } cfg.ProvisioningAllowImageRendering = iniFile.Section("provisioning").Key("allow_image_rendering").MustBool(true) cfg.ProvisioningMinSyncInterval = iniFile.Section("provisioning").Key("min_sync_interval").MustDuration(10 * time.Second) diff --git a/pkg/setting/setting_unified_storage.go b/pkg/setting/setting_unified_storage.go index 72e01ce6ce9..8086151c40a 100644 --- a/pkg/setting/setting_unified_storage.go +++ b/pkg/setting/setting_unified_storage.go @@ -8,10 +8,17 @@ import ( "github.com/grafana/grafana/pkg/util/osutil" ) -var MigratedUnifiedResources = []string{ - "playlists.playlist.grafana.app", - "folders.folder.grafana.app", - "dashboards.dashboard.grafana.app", +const ( + PlaylistResource = "playlists.playlist.grafana.app" + FolderResource = "folders.folder.grafana.app" + DashboardResource = "dashboards.dashboard.grafana.app" +) + +// MigratedUnifiedResources maps resources to a boolean indicating if migration is enabled by default +var MigratedUnifiedResources = map[string]bool{ + PlaylistResource: true, // enabled by default + FolderResource: false, + DashboardResource: false, } // read storage configs from ini file. They look like: @@ -46,12 +53,19 @@ func (cfg *Cfg) setUnifiedStorageConfig() { // parse dataSyncerInterval from resource section dataSyncerInterval := section.Key("dataSyncerInterval").MustDuration(time.Hour) + // parse EnableMigration from resource section + enableMigration := MigratedUnifiedResources[resourceName] + if section.HasKey("enableMigration") { + enableMigration = section.Key("enableMigration").MustBool(MigratedUnifiedResources[resourceName]) + } + storageConfig[resourceName] = UnifiedStorageConfig{ DualWriterMode: rest.DualWriterMode(dualWriterMode), DualWriterPeriodicDataSyncJobEnabled: dualWriterPeriodicDataSyncJobEnabled, DualWriterMigrationDataSyncDisabled: dualWriterMigrationDataSyncDisabled, DataSyncerRecordsLimit: dataSyncerRecordsLimit, DataSyncerInterval: dataSyncerInterval, + EnableMigration: enableMigration, } } cfg.UnifiedStorage = storageConfig @@ -61,8 +75,8 @@ func (cfg *Cfg) setUnifiedStorageConfig() { cfg.DisableDataMigrations = section.Key("disable_data_migrations").MustBool(false) if !cfg.DisableDataMigrations && cfg.getUnifiedStorageType() == "unified" { // Helper log to find instances running migrations in the future - cfg.Logger.Info("Unified migration configs not yet enforced") - // cfg.enforceMigrationToUnifiedConfigs() // TODO: uncomment when ready for release + cfg.Logger.Info("Unified migration configs enforced") + cfg.enforceMigrationToUnifiedConfigs() } else { // Helper log to find instances disabling migration cfg.Logger.Info("Unified migration configs enforcement disabled", "storage_type", cfg.getUnifiedStorageType(), "disable_data_migrations", cfg.DisableDataMigrations) @@ -107,7 +121,6 @@ func (cfg *Cfg) setUnifiedStorageConfig() { cfg.MinFileIndexBuildVersion = section.Key("min_file_index_build_version").MustString("") } -// nolint:unused // enforceMigrationToUnifiedConfigs enforces configurations required to run migrated resources in mode 5 // All migrated resources in MigratedUnifiedResources are set to mode 5 and unified search is enabled func (cfg *Cfg) enforceMigrationToUnifiedConfigs() { @@ -118,14 +131,22 @@ func (cfg *Cfg) enforceMigrationToUnifiedConfigs() { section.Key("enable_search").SetValue("true") cfg.EnableSearch = true } - for _, resource := range MigratedUnifiedResources { - cfg.Logger.Info("Enforcing mode 5 for resource in unified storage", "resource", resource) - if oldCfg, ok := cfg.UnifiedStorage[resource]; ok { - cfg.Logger.Info("Overriding unified storage config for migrated resource", "resource", resource, "old_config", oldCfg) + for resource, enabledByDefault := range MigratedUnifiedResources { + resourceCfg, ok := cfg.UnifiedStorage[resource] + if ok { + if !resourceCfg.EnableMigration { + cfg.Logger.Info("Resource migration disabled", "resource", resource) + continue + } + cfg.Logger.Info("Overriding unified storage config for migrated resource", "resource", resource, "old_config", resourceCfg) + } else if !enabledByDefault { + continue } + cfg.Logger.Info("Enforcing mode 5 for resource in unified storage", "resource", resource) cfg.UnifiedStorage[resource] = UnifiedStorageConfig{ DualWriterMode: 5, DualWriterMigrationDataSyncDisabled: true, + EnableMigration: true, } } } diff --git a/pkg/setting/setting_unified_storage_test.go b/pkg/setting/setting_unified_storage_test.go index 094033a4244..c112dc85962 100644 --- a/pkg/setting/setting_unified_storage_test.go +++ b/pkg/setting/setting_unified_storage_test.go @@ -4,6 +4,7 @@ import ( "testing" "time" + "github.com/grafana/grafana/pkg/apiserver/rest" "github.com/stretchr/testify/assert" ) @@ -13,31 +14,56 @@ func TestCfg_setUnifiedStorageConfig(t *testing.T) { err := cfg.Load(CommandLineArgs{HomePath: "../../", Config: "../../conf/defaults.ini"}) assert.NoError(t, err) - s, err := cfg.Raw.NewSection("unified_storage.playlists.playlist.grafana.app") - assert.NoError(t, err) + setSectionKey := func(sectionName, key, value string) { + section := cfg.Raw.Section(sectionName) // Gets existing or creates new + _, err := section.NewKey(key, value) + assert.NoError(t, err) + } - _, err = s.NewKey("dualWriterMode", "2") - assert.NoError(t, err) + setMigratedResourceKey := func(key, value string) { + for migratedResource := range MigratedUnifiedResources { + setSectionKey("unified_storage."+migratedResource, key, value) + } + } - _, err = s.NewKey("dualWriterPeriodicDataSyncJobEnabled", "true") - assert.NoError(t, err) + validateMigratedResources := func(optIn bool) { + for migratedResource, enabled := range MigratedUnifiedResources { + resourceCfg, exists := cfg.UnifiedStorage[migratedResource] - _, err = s.NewKey("dataSyncerRecordsLimit", "1001") - assert.NoError(t, err) + isEnabled := enabled + if optIn { + isEnabled = true + } - _, err = s.NewKey("dataSyncerInterval", "10m") - assert.NoError(t, err) + if !isEnabled { + if exists { + assert.Equal(t, rest.DualWriterMode(1), resourceCfg.DualWriterMode, migratedResource) + } + continue + } + assert.Equal(t, exists, true, migratedResource) + + assert.Equal(t, UnifiedStorageConfig{ + DualWriterMode: 5, + DualWriterMigrationDataSyncDisabled: true, + EnableMigration: isEnabled, + }, resourceCfg, migratedResource) + } + } + + setMigratedResourceKey("dualWriterMode", "1") // migrated resources enabled by default will change to 5 in setUnifiedStorageConfig + + setSectionKey("unified_storage.resource.not_migrated.grafana.app", "dualWriterMode", "2") + setSectionKey("unified_storage.resource.not_migrated.grafana.app", "dualWriterPeriodicDataSyncJobEnabled", "true") + setSectionKey("unified_storage.resource.not_migrated.grafana.app", "dataSyncerRecordsLimit", "1001") + setSectionKey("unified_storage.resource.not_migrated.grafana.app", "dataSyncerInterval", "10m") // Add unified_storage section for index settings - unifiedStorageSection, err := cfg.Raw.NewSection("unified_storage") - assert.NoError(t, err) - - _, err = unifiedStorageSection.NewKey("index_min_count", "5") - assert.NoError(t, err) + setSectionKey("unified_storage", "index_min_count", "5") cfg.setUnifiedStorageConfig() - value, exists := cfg.UnifiedStorage["playlists.playlist.grafana.app"] + value, exists := cfg.UnifiedStorage["resource.not_migrated.grafana.app"] assert.Equal(t, exists, true) assert.Equal(t, value, UnifiedStorageConfig{ @@ -47,6 +73,14 @@ func TestCfg_setUnifiedStorageConfig(t *testing.T) { DataSyncerInterval: time.Minute * 10, }) + validateMigratedResources(false) + + setMigratedResourceKey("enableMigration", "true") // will be changed to 5 in setUnifiedStorageConfig + + cfg.setUnifiedStorageConfig() + + validateMigratedResources(true) + // Test that index settings are correctly parsed assert.Equal(t, 5, cfg.IndexMinCount) }) diff --git a/pkg/storage/secret/migrator/migrator.go b/pkg/storage/secret/migrator/migrator.go index 215020561a2..f2a4525c082 100644 --- a/pkg/storage/secret/migrator/migrator.go +++ b/pkg/storage/secret/migrator/migrator.go @@ -224,4 +224,23 @@ func (*SecretDB) AddMigration(mg *migrator.Migrator) { mg.AddMigration("set secret_secure_value.keeper to 'system' where keeper is null in "+TableNameSecureValue, migrator.NewRawSQLMigration( fmt.Sprintf("UPDATE %s SET keeper = '%s' WHERE keeper IS NULL", TableNameSecureValue, contracts.SystemKeeperName), )) + + encryptedValueTableUniqueKey := migrator.Index{Cols: []string{"namespace", "name", "version"}, Type: migrator.UniqueIndex} + updatedEncryptedValueTable := migrator.Table{ + Name: TableNameEncryptedValue, + Columns: []*migrator.Column{ + {Name: "namespace", Type: migrator.DB_NVarchar, Length: 253, Nullable: false, IsPrimaryKey: true}, // Limit enforced by K8s. + {Name: "name", Type: migrator.DB_NVarchar, Length: 253, Nullable: false, IsPrimaryKey: true}, + {Name: "version", Type: migrator.DB_BigInt, Nullable: false, IsPrimaryKey: true}, + {Name: "encrypted_data", Type: migrator.DB_Blob, Nullable: false}, + {Name: "created", Type: migrator.DB_BigInt, Nullable: false}, + {Name: "updated", Type: migrator.DB_BigInt, Nullable: false}, + {Name: "data_key_id", Type: migrator.DB_NVarchar, Length: 100, Nullable: false, Default: "''"}, + }, + PrimaryKeys: []string{"namespace", "name", "version"}, + Indices: []*migrator.Index{ + {Cols: []string{"data_key_id"}}, + }, + } + migrator.ConvertUniqueKeyToPrimaryKey(mg, encryptedValueTableUniqueKey, updatedEncryptedValueTable) } diff --git a/pkg/storage/unified/apistore/prepare_test.go b/pkg/storage/unified/apistore/prepare_test.go index 0b36f71117a..a35c2398736 100644 --- a/pkg/storage/unified/apistore/prepare_test.go +++ b/pkg/storage/unified/apistore/prepare_test.go @@ -2,6 +2,7 @@ package apistore import ( "context" + "encoding/json" "math/rand/v2" "strings" "testing" @@ -19,6 +20,7 @@ import ( authlib "github.com/grafana/authlib/types" dashv1 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v1beta1" + "github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1" "github.com/grafana/grafana/pkg/apimachinery/identity" "github.com/grafana/grafana/pkg/apimachinery/utils" ) @@ -195,6 +197,42 @@ func TestPrepareObjectForStorage(t *testing.T) { require.Equal(t, int64(2), meta2.GetGeneration()) }) + t.Run("Update should skip incrementing generation when content is unchanged", func(t *testing.T) { + dashboard := dashv1.Dashboard{ + ObjectMeta: v1.ObjectMeta{ + Name: "test", + Generation: 123, + Annotations: map[string]string{ + "A": "B", + utils.AnnoKeyUpdatedTimestamp: "2025-12-17T01:01:00Z", + }, + UID: "XXX", + }, + Spec: v0alpha1.Unstructured{ + Object: map[string]any{ + "hello": "world", + }, + }, + } + dashboard.Name = "test-name" + obj := dashboard.DeepCopyObject() + tmp, err := utils.MetaAccessor(obj) + tmp.SetGeneration(2) + tmp.SetUpdatedTimestampMillis(12345) + require.NoError(t, err) + + v, err := s.prepareObjectForUpdate(ctx, obj, &dashboard) + require.NoError(t, err) + require.False(t, v.hasChanged, "no changes") + + out := &unstructured.Unstructured{} + err = json.Unmarshal(v.raw.Bytes(), out) + require.NoError(t, err) + + require.Equal(t, int64(123), tmp.GetGeneration()) + require.Equal(t, "2025-12-17T01:01:00Z", tmp.GetAnnotation(utils.AnnoKeyUpdatedTimestamp)) + }) + s.opts.RequireDeprecatedInternalID = true t.Run("Should generate internal id", func(t *testing.T) { dashboard := dashv1.Dashboard{} diff --git a/pkg/storage/unified/migrations/migrator_test.go b/pkg/storage/unified/migrations/migrator_test.go index 92afe698a98..8552092d066 100644 --- a/pkg/storage/unified/migrations/migrator_test.go +++ b/pkg/storage/unified/migrations/migrator_test.go @@ -162,14 +162,49 @@ func runMigrationTestSuite(t *testing.T, testCases []resourceMigratorTestCase) { } }) - t.Run("Step 3: verify data is migrated to unified storage", func(t *testing.T) { - // Migrations will run automatically at startup and mode 5 is enforced by the config + t.Run("Step 3: verify that opted-out resources are not migrated", func(t *testing.T) { + // Build unified storage config for Mode5 + unifiedConfig := make(map[string]setting.UnifiedStorageConfig) + for _, tc := range testCases { + for _, gvr := range tc.resources() { + resourceKey := fmt.Sprintf("%s.%s", gvr.Resource, gvr.Group) + unifiedConfig[resourceKey] = setting.UnifiedStorageConfig{ + DualWriterMode: grafanarest.Mode5, + EnableMigration: false, + } + } + } + + helper := apis.NewK8sTestHelperWithOpts(t, apis.K8sTestHelperOpts{ + GrafanaOpts: testinfra.GrafanaOpts{ + AppModeProduction: true, + DisableAnonymous: true, + DisableDBCleanup: true, + APIServerStorageType: "unified", + UnifiedStorageConfig: unifiedConfig, + }, + Org1Users: org1, + OrgBUsers: orgB, + }) + t.Cleanup(helper.Shutdown) + + for _, state := range testStates { + t.Run(state.tc.name(), func(t *testing.T) { + // Verify resources don't exist in unified storage yet + state.tc.verify(t, helper, false) + }) + } + verifyRegisteredMigrations(t, helper, false, true) + }) + + t.Run("Step 4: verify data is migrated to unified storage", func(t *testing.T) { + // Migrations enabled by default will run automatically at startup and mode 5 is enforced by the config helper := apis.NewK8sTestHelperWithOpts(t, apis.K8sTestHelperOpts{ GrafanaOpts: testinfra.GrafanaOpts{ - // EnableLog: true, AppModeProduction: true, DisableAnonymous: true, DisableDataMigrations: false, // Run migrations at startup + DisableDBCleanup: true, APIServerStorageType: "unified", }, Org1Users: org1, @@ -183,7 +218,89 @@ func runMigrationTestSuite(t *testing.T, testCases []resourceMigratorTestCase) { state.tc.verify(t, helper, true) }) } + + t.Logf("Verifying migrations are correctly registered") + verifyRegisteredMigrations(t, helper, true, false) }) + + t.Run("Step 5: verify data is migrated for all migrations", func(t *testing.T) { + // Trigger migrations that are not enabled by default + unifiedConfig := make(map[string]setting.UnifiedStorageConfig) + for _, tc := range testCases { + for _, gvr := range tc.resources() { + resourceKey := fmt.Sprintf("%s.%s", gvr.Resource, gvr.Group) + unifiedConfig[resourceKey] = setting.UnifiedStorageConfig{ + EnableMigration: true, + } + } + } + helper := apis.NewK8sTestHelperWithOpts(t, apis.K8sTestHelperOpts{ + GrafanaOpts: testinfra.GrafanaOpts{ + // EnableLog: true, + AppModeProduction: true, + DisableAnonymous: true, + DisableDataMigrations: false, + APIServerStorageType: "unified", + UnifiedStorageConfig: unifiedConfig, + }, + Org1Users: org1, + OrgBUsers: orgB, + }) + t.Cleanup(helper.Shutdown) + + for _, state := range testStates { + t.Run(state.tc.name(), func(t *testing.T) { + // Verify resources still exist in unified storage after restart + state.tc.verify(t, helper, true) + }) + } + + t.Logf("Verifying migrations are correctly registered") + verifyRegisteredMigrations(t, helper, false, false) + }) +} + +const ( + migrationScope = "unifiedstorage" + migrationTable = migrationScope + "_migration_log" + + playlistsID = "playlists migration" + foldersAndDashboardsID = "folders and dashboards migration" +) + +var migrationIDsToDefault = map[string]bool{ + playlistsID: true, + foldersAndDashboardsID: false, +} + +func verifyRegisteredMigrations(t *testing.T, helper *apis.K8sTestHelper, onlyDefault bool, optOut bool) { + getMigrationsQuery := fmt.Sprintf("SELECT migration_id FROM %s", migrationTable) + createTableMigrationID := fmt.Sprintf("create %s table", migrationTable) + expectedMigrationIDs := []string{createTableMigrationID} + for id, enabled := range migrationIDsToDefault { + if onlyDefault && !enabled { + continue + } + if optOut { + continue + } + expectedMigrationIDs = append(expectedMigrationIDs, id) + } + rows, err := helper.GetEnv().SQLStore.GetEngine().DB().Query(getMigrationsQuery) + require.NoError(t, err) + defer func() { + require.NoError(t, rows.Close()) + }() + + migrationIDs := make(map[string]struct{}) + for rows.Next() { + var migrationID string + require.NoError(t, rows.Scan(&migrationID)) + require.Contains(t, expectedMigrationIDs, migrationID) + migrationIDs[migrationID] = struct{}{} + } + require.NoError(t, rows.Err()) + require.Len(t, migrationIDs, len(expectedMigrationIDs)) } // verifyResourceCount verifies that the expected number of resources exist in K8s storage diff --git a/pkg/storage/unified/migrations/resources.go b/pkg/storage/unified/migrations/resources.go index 0a4dcc7766e..ea32bb54322 100644 --- a/pkg/storage/unified/migrations/resources.go +++ b/pkg/storage/unified/migrations/resources.go @@ -7,7 +7,9 @@ import ( folders "github.com/grafana/grafana/apps/folder/pkg/apis/folder/v1beta1" playlists "github.com/grafana/grafana/apps/playlist/pkg/apis/playlist/v0alpha1" "github.com/grafana/grafana/pkg/registry/apis/dashboard/legacy" + sqlstoremigrator "github.com/grafana/grafana/pkg/services/sqlstore/migrator" "github.com/grafana/grafana/pkg/setting" + "github.com/grafana/grafana/pkg/storage/unified/resource" "github.com/grafana/grafana/pkg/storage/unified/resourcepb" "k8s.io/apimachinery/pkg/runtime/schema" ) @@ -17,7 +19,13 @@ type ResourceDefinition struct { MigratorFunc string // Name of the method: "MigrateFolders", "MigrateDashboards", etc. } -var registeredResources = []ResourceDefinition{ +type migrationDefinition struct { + name string + resources []string + registerFunc func(mg *sqlstoremigrator.Migrator, migrator UnifiedMigrator, client resource.ResourceClient) +} + +var resourceRegistry = []ResourceDefinition{ { GroupResource: schema.GroupResource{Group: folders.GROUP, Resource: folders.RESOURCE}, MigratorFunc: "MigrateFolders", @@ -36,9 +44,50 @@ var registeredResources = []ResourceDefinition{ }, } +var migrationRegistry = []migrationDefinition{ + { + name: "playlists", + resources: []string{setting.PlaylistResource}, + registerFunc: registerPlaylistMigration, + }, + { + name: "folders and dashboards", + resources: []string{setting.FolderResource, setting.DashboardResource}, + registerFunc: registerDashboardAndFolderMigration, + }, +} + +func registerMigrations(cfg *setting.Cfg, mg *sqlstoremigrator.Migrator, migrator UnifiedMigrator, client resource.ResourceClient) error { + for _, migration := range migrationRegistry { + var ( + hasValue bool + allEnabled bool + ) + + for _, res := range migration.resources { + enabled := cfg.UnifiedStorage[res].EnableMigration + if !hasValue { + allEnabled = enabled + hasValue = true + continue + } + if enabled != allEnabled { + return fmt.Errorf("cannot migrate resources separately: %v migration must be either all enabled or all disabled", migration.resources) + } + } + + if !allEnabled { + logger.Info("Migration is disabled in config, skipping", "migration", migration.name) + continue + } + migration.registerFunc(mg, migrator, client) + } + return nil +} + func getResourceDefinition(group, resource string) *ResourceDefinition { - for i := range registeredResources { - r := ®isteredResources[i] + for i := range resourceRegistry { + r := &resourceRegistry[i] if r.GroupResource.Group == group && r.GroupResource.Resource == resource { return r } @@ -80,13 +129,13 @@ func getMigratorFunc(accessor legacy.MigrationDashboardAccessor, group, resource func validateRegisteredResources() error { registeredMap := make(map[string]bool) - for _, gr := range registeredResources { + for _, gr := range resourceRegistry { key := fmt.Sprintf("%s.%s", gr.GroupResource.Resource, gr.GroupResource.Group) registeredMap[key] = true } var missing []string - for _, expected := range setting.MigratedUnifiedResources { + for expected := range setting.MigratedUnifiedResources { if !registeredMap[expected] { missing = append(missing, expected) } diff --git a/pkg/storage/unified/migrations/resources_test.go b/pkg/storage/unified/migrations/resources_test.go new file mode 100644 index 00000000000..5a519e9ad62 --- /dev/null +++ b/pkg/storage/unified/migrations/resources_test.go @@ -0,0 +1,92 @@ +package migrations + +import ( + "testing" + + sqlstoremigrator "github.com/grafana/grafana/pkg/services/sqlstore/migrator" + "github.com/grafana/grafana/pkg/setting" + "github.com/grafana/grafana/pkg/storage/unified/resource" + "github.com/stretchr/testify/require" +) + +// TestRegisterMigrations exercises registerMigrations with various EnableMigration configs using a table-driven test. +func TestRegisterMigrations(t *testing.T) { + origRegistry := migrationRegistry + t.Cleanup(func() { migrationRegistry = origRegistry }) + + // helper to build a fake registry with custom register funcs that bump counters + makeFakeRegistry := func(migrationCalls map[string]int) []migrationDefinition { + return []migrationDefinition{ + { + name: "playlists", + resources: []string{setting.PlaylistResource}, + registerFunc: func(mg *sqlstoremigrator.Migrator, migrator UnifiedMigrator, client resource.ResourceClient) { + migrationCalls["playlists"]++ + }, + }, + { + name: "folders and dashboards", + resources: []string{setting.FolderResource, setting.DashboardResource}, + registerFunc: func(mg *sqlstoremigrator.Migrator, migrator UnifiedMigrator, client resource.ResourceClient) { + migrationCalls["folders and dashboards"]++ + }, + }, + } + } + + // Build a minimal cfg with UnifiedStorage entries used by registerMigrations + makeCfg := func(vals map[string]bool) *setting.Cfg { + cfg := &setting.Cfg{UnifiedStorage: make(map[string]setting.UnifiedStorageConfig)} + for k, v := range vals { + cfg.UnifiedStorage[k] = setting.UnifiedStorageConfig{EnableMigration: v} + } + return cfg + } + + // Table of scenarios + tests := []struct { + name string + enablePlaylist bool + enableFolder bool + enableDashboard bool + wantPlaylistCalls int + wantFDCalls int + wantErr bool + }{ + {name: "playlists enabled", enablePlaylist: true, wantPlaylistCalls: 1}, + {name: "playlists disabled", enablePlaylist: false, wantPlaylistCalls: 0}, + {name: "folders+dashboards both enabled", enableFolder: true, enableDashboard: true, wantFDCalls: 1}, + {name: "folders enabled, dashboards disabled (mismatch)", enableFolder: true, enableDashboard: false, wantFDCalls: 0, wantErr: true}, + {name: "folders disabled, dashboards enabled (mismatch)", enableFolder: false, enableDashboard: true, wantFDCalls: 0, wantErr: true}, + {name: "folders+dashboards both disabled", enableFolder: false, enableDashboard: false, wantFDCalls: 0}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + migrationCalls := map[string]int{ + "playlists": 0, + "folders and dashboards": 0, + } + + migrationRegistry = makeFakeRegistry(migrationCalls) + + cfg := makeCfg(map[string]bool{ + setting.PlaylistResource: tt.enablePlaylist, + setting.FolderResource: tt.enableFolder, + setting.DashboardResource: tt.enableDashboard, + }) + + // We pass nils for migrator dependencies because our fake registerFuncs don't use them + err := registerMigrations(cfg, nil, nil, nil) + + if tt.wantErr { + require.Error(t, err, "expected error for mismatched enablement") + } else { + require.NoError(t, err, "unexpected error") + } + + require.Equal(t, tt.wantPlaylistCalls, migrationCalls["playlists"], "playlists register call count") + require.Equal(t, tt.wantFDCalls, migrationCalls["folders and dashboards"], "folders+dashboards register call count") + }) + } +} diff --git a/pkg/storage/unified/migrations/service.go b/pkg/storage/unified/migrations/service.go index 1fda9b42593..4ac9cdad218 100644 --- a/pkg/storage/unified/migrations/service.go +++ b/pkg/storage/unified/migrations/service.go @@ -3,7 +3,6 @@ package migrations import ( "context" "fmt" - "os" "github.com/grafana/grafana/pkg/infra/db" "github.com/grafana/grafana/pkg/infra/kvstore" @@ -49,34 +48,25 @@ func ProvideUnifiedStorageMigrationService( } func (p *UnifiedStorageMigrationServiceImpl) Run(ctx context.Context) error { - // TODO: temporary skip migrations in test environments to prevent integration test timeouts. - if os.Getenv("GRAFANA_TEST_DB") != "" { - return nil - } - // skip migrations if disabled in config if p.cfg.DisableDataMigrations { metrics.MUnifiedStorageMigrationStatus.Set(1) logger.Info("Data migrations are disabled, skipping") return nil - } else { - metrics.MUnifiedStorageMigrationStatus.Set(2) - logger.Info("Data migrations not yet enforced, skipping") } - - // TODO: Re-enable once migrations are ready - // TODO: add guarantee that this only runs once - // return RegisterMigrations(p.migrator, p.cfg, p.sqlStore, p.client) - return nil + logger.Info("Running migrations for unified storage") + metrics.MUnifiedStorageMigrationStatus.Set(3) + return RegisterMigrations(ctx, p.migrator, p.cfg, p.sqlStore, p.client) } func RegisterMigrations( + ctx context.Context, migrator UnifiedMigrator, cfg *setting.Cfg, sqlStore db.DB, client resource.ResourceClient, ) error { - ctx, span := tracer.Start(context.Background(), "storage.unified.RegisterMigrations") + ctx, span := tracer.Start(ctx, "storage.unified.RegisterMigrations") defer span.End() mg := sqlstoremigrator.NewScopedMigrator(sqlStore.GetEngine(), cfg, "unifiedstorage") mg.AddCreateMigration() @@ -89,12 +79,19 @@ func RegisterMigrations( return err } - // Register resource migrations - registerDashboardAndFolderMigration(mg, migrator, client) - registerPlaylistMigration(mg, migrator, client) + if err := registerMigrations(cfg, mg, migrator, client); err != nil { + return err + } // Run all registered migrations (blocking) sec := cfg.Raw.Section("database") + db := mg.DBEngine.DB().DB + maxOpenConns := db.Stats().MaxOpenConnections + if maxOpenConns <= 2 { + // migrations require at least 3 connections due to extra GRPC connections + db.SetMaxOpenConns(3) + defer db.SetMaxOpenConns(maxOpenConns) + } if err := mg.RunMigrations(ctx, sec.Key("migration_locking").MustBool(true), sec.Key("locking_attempt_timeout_sec").MustInt()); err != nil { diff --git a/pkg/storage/unified/resource/data/sqlkv_batch_delete.sql b/pkg/storage/unified/resource/data/sqlkv_batch_delete.sql new file mode 100644 index 00000000000..c165007d23d --- /dev/null +++ b/pkg/storage/unified/resource/data/sqlkv_batch_delete.sql @@ -0,0 +1,7 @@ +DELETE +FROM {{ .TableName }} +WHERE {{ .Ident "key_path" }} IN ( + {{ range $id, $key_path := .KeyPaths }} + {{ if ne $id 0 }}, {{ end }}{{ $.Arg $key_path }} + {{ end }} +); diff --git a/pkg/storage/unified/resource/data/sqlkv_batch_get.sql b/pkg/storage/unified/resource/data/sqlkv_batch_get.sql new file mode 100644 index 00000000000..0babcb36970 --- /dev/null +++ b/pkg/storage/unified/resource/data/sqlkv_batch_get.sql @@ -0,0 +1,12 @@ +SELECT r.{{ .Ident "key_path" }}, r.{{ .Ident "value" }} +FROM ( +{{ range $id, $key_path := .KeyPaths }} + {{ if eq $id 0 }} + SELECT {{ $.Arg $id }} AS idx, {{ $.Arg $key_path }} AS key_path + {{ else }} + UNION ALL SELECT {{ $.Arg $id }}, {{ $.Arg $key_path }} + {{ end }} +{{ end }} +) AS requested_keys +INNER JOIN {{ .TableName }} r ON r.{{ .Ident "key_path" }} = requested_keys.{{ .Ident "key_path" }} +ORDER BY requested_keys.{{ .Ident "idx" }}; diff --git a/pkg/storage/unified/resource/data/sqlkv_delete.sql b/pkg/storage/unified/resource/data/sqlkv_delete.sql new file mode 100644 index 00000000000..60a60746993 --- /dev/null +++ b/pkg/storage/unified/resource/data/sqlkv_delete.sql @@ -0,0 +1,3 @@ +DELETE +FROM {{ .Ident .TableName }} +WHERE {{ .Ident "key_path" }} = {{ .Arg .KeyPath }}; diff --git a/pkg/storage/unified/resource/data/sqlkv_delete_legacy_resource.sql b/pkg/storage/unified/resource/data/sqlkv_delete_legacy_resource.sql new file mode 100644 index 00000000000..e27ee578a41 --- /dev/null +++ b/pkg/storage/unified/resource/data/sqlkv_delete_legacy_resource.sql @@ -0,0 +1,5 @@ +DELETE FROM {{ .Ident "resource" }} +WHERE {{ .Ident "group" }} = {{ .Arg .Group }} +AND {{ .Ident "resource" }} = {{ .Arg .Resource }} +AND {{ .Ident "namespace" }} = {{ .Arg .Namespace }} +AND {{ .Ident "name" }} = {{ .Arg .Name }}; diff --git a/pkg/storage/unified/resource/data/sqlkv_get.sql b/pkg/storage/unified/resource/data/sqlkv_get.sql new file mode 100644 index 00000000000..48c83cf0450 --- /dev/null +++ b/pkg/storage/unified/resource/data/sqlkv_get.sql @@ -0,0 +1,3 @@ +SELECT {{ .Ident "value" | .Into .Value }} +FROM {{ .Ident .TableName }} +WHERE {{ .Ident "key_path" }} = {{ .Arg .KeyPath }}; diff --git a/pkg/storage/unified/resource/data/sqlkv_insert_datastore.sql b/pkg/storage/unified/resource/data/sqlkv_insert_datastore.sql new file mode 100644 index 00000000000..8372eb73463 --- /dev/null +++ b/pkg/storage/unified/resource/data/sqlkv_insert_datastore.sql @@ -0,0 +1,21 @@ +INSERT INTO {{ .Ident .TableName }} +( + {{ .Ident "guid" }}, + {{ .Ident "key_path" }}, + {{ .Ident "value" }}, + {{ .Ident "group" }}, + {{ .Ident "resource" }}, + {{ .Ident "namespace" }}, + {{ .Ident "name" }}, + {{ .Ident "action" }} +) +VALUES ( + {{ .Arg .GUID }}, + {{ .Arg .KeyPath }}, + COALESCE({{ .Arg .Value }}, ""), + {{ .Arg .Group }}, + {{ .Arg .Resource }}, + {{ .Arg .Namespace }}, + {{ .Arg .Name }}, + {{ .Arg .Action }} +); diff --git a/pkg/storage/unified/resource/data/sqlkv_insert_legacy_resource.sql b/pkg/storage/unified/resource/data/sqlkv_insert_legacy_resource.sql new file mode 100644 index 00000000000..1f58bd28b43 --- /dev/null +++ b/pkg/storage/unified/resource/data/sqlkv_insert_legacy_resource.sql @@ -0,0 +1,31 @@ +INSERT INTO {{ .Ident "resource" }} +( + {{ .Ident "value" }}, + {{ .Ident "guid" }}, + {{ .Ident "group" }}, + {{ .Ident "resource" }}, + {{ .Ident "namespace" }}, + {{ .Ident "name" }}, + {{ .Ident "action" }}, + {{ .Ident "folder" }}, + {{ .Ident "previous_resource_version" }} +) +VALUES ( + COALESCE({{ .Arg .Value }}, ""), + {{ .Arg .GUID }}, + {{ .Arg .Group }}, + {{ .Arg .Resource }}, + {{ .Arg .Namespace }}, + {{ .Arg .Name }}, + {{ .Arg .Action }}, + {{ .Arg .Folder }}, + CASE WHEN {{ .Arg .Action }} = 1 THEN 0 ELSE ( + SELECT {{ .Ident "resource_version" }} + FROM {{ .Ident "resource" }} + WHERE {{ .Ident "group" }} = {{ .Arg .Group }} + AND {{ .Ident "resource" }} = {{ .Arg .Resource }} + AND {{ .Ident "namespace" }} = {{ .Arg .Namespace }} + AND {{ .Ident "name" }} = {{ .Arg .Name }} + ORDER BY {{ .Ident "resource_version" }} DESC LIMIT 1 + ) END +); diff --git a/pkg/storage/unified/resource/data/sqlkv_insert_legacy_resource_history.sql b/pkg/storage/unified/resource/data/sqlkv_insert_legacy_resource_history.sql new file mode 100644 index 00000000000..d52aac5063d --- /dev/null +++ b/pkg/storage/unified/resource/data/sqlkv_insert_legacy_resource_history.sql @@ -0,0 +1,44 @@ +INSERT INTO {{ .Ident "resource_history" }} +( + {{ .Ident "value" }}, + {{ .Ident "guid" }}, + {{ .Ident "group" }}, + {{ .Ident "resource" }}, + {{ .Ident "namespace" }}, + {{ .Ident "name" }}, + {{ .Ident "action" }}, + {{ .Ident "folder" }}, + {{ .Ident "previous_resource_version" }}, + {{ .Ident "generation" }} +) +VALUES ( + COALESCE({{ .Arg .Value }}, ""), + {{ .Arg .GUID }}, + {{ .Arg .Group }}, + {{ .Arg .Resource }}, + {{ .Arg .Namespace }}, + {{ .Arg .Name }}, + {{ .Arg .Action }}, + {{ .Arg .Folder }}, + CASE WHEN {{ .Arg .Action }} = 1 THEN 0 ELSE ( + SELECT {{ .Ident "resource_version" }} + FROM {{ .Ident "resource_history" }} + WHERE {{ .Ident "group" }} = {{ .Arg .Group }} + AND {{ .Ident "resource" }} = {{ .Arg .Resource }} + AND {{ .Ident "namespace" }} = {{ .Arg .Namespace }} + AND {{ .Ident "name" }} = {{ .Arg .Name }} + ORDER BY {{ .Ident "resource_version" }} DESC LIMIT 1 + ) END, + CASE + WHEN {{ .Arg .Action }} = 1 THEN 1 + WHEN {{ .Arg .Action }} = 3 THEN 0 + ELSE 1 + ( + SELECT COUNT(1) + FROM {{ .Ident "resource_history" }} + WHERE {{ .Ident "group" }} = {{ .Arg .Group }} + AND {{ .Ident "resource" }} = {{ .Arg .Resource }} + AND {{ .Ident "namespace" }} = {{ .Arg .Namespace }} + AND {{ .Ident "name" }} = {{ .Arg .Name }} + ) + END +); diff --git a/pkg/storage/unified/resource/data/sqlkv_keys.sql b/pkg/storage/unified/resource/data/sqlkv_keys.sql new file mode 100644 index 00000000000..36b7bfbe01c --- /dev/null +++ b/pkg/storage/unified/resource/data/sqlkv_keys.sql @@ -0,0 +1,9 @@ +SELECT {{ .Ident "key_path" }} +FROM {{ .TableName }} +WHERE {{ .Ident "key_path" }} >= {{ .Arg .StartKey }} + AND {{ .Ident "key_path" }} < {{ .Arg .EndKey }} +ORDER BY {{ .Ident "key_path" }} {{ if .SortAscending }}ASC{{ else }}DESC{{ end }} +{{ if .Options.Limit }} +LIMIT {{ .Options.Limit }} +{{ end }} +; diff --git a/pkg/storage/unified/resource/data/sqlkv_save_event.sql b/pkg/storage/unified/resource/data/sqlkv_save_event.sql new file mode 100644 index 00000000000..669497dbb19 --- /dev/null +++ b/pkg/storage/unified/resource/data/sqlkv_save_event.sql @@ -0,0 +1,15 @@ +INSERT INTO {{ .Ident .TableName }} +( + {{ .Ident "key_path" }}, + {{ .Ident "value" }} +) +VALUES ( + {{ .Arg .KeyPath }}, + COALESCE({{ .Arg .Value }}, "") +) +{{- if eq .DialectName "mysql" }} +ON DUPLICATE KEY UPDATE {{ .Ident "value" }} = {{ .Arg .Value }} +{{- else }} +ON CONFLICT ({{ .Ident "key_path" }}) DO UPDATE SET {{ .Ident "value" }} = {{ .Arg .Value }} +{{- end }} +; diff --git a/pkg/storage/unified/resource/data/sqlkv_update_datastore.sql b/pkg/storage/unified/resource/data/sqlkv_update_datastore.sql new file mode 100644 index 00000000000..677666e00a4 --- /dev/null +++ b/pkg/storage/unified/resource/data/sqlkv_update_datastore.sql @@ -0,0 +1,3 @@ +UPDATE {{ .Ident .TableName }} +SET {{ .Ident "value" }} = {{ .Arg .Value }} +WHERE {{ .Ident "key_path" }} = {{ .Arg .KeyPath }}; diff --git a/pkg/storage/unified/resource/data/sqlkv_update_legacy_resource.sql b/pkg/storage/unified/resource/data/sqlkv_update_legacy_resource.sql new file mode 100644 index 00000000000..1565d0894a4 --- /dev/null +++ b/pkg/storage/unified/resource/data/sqlkv_update_legacy_resource.sql @@ -0,0 +1,9 @@ +UPDATE {{ .Ident "resource" }} +SET + {{ .Ident "value" }} = {{ .Arg .Value }}, + {{ .Ident "action" }} = {{ .Arg .Action }}, + {{ .Ident "folder" }} = {{ .Arg .Folder }} +WHERE {{ .Ident "group" }} = {{ .Arg .Group }} +AND {{ .Ident "resource" }} = {{ .Arg .Resource }} +AND {{ .Ident "namespace" }} = {{ .Arg .Namespace }} +AND {{ .Ident "name" }} = {{ .Arg .Name }}; diff --git a/pkg/storage/unified/resource/datastore.go b/pkg/storage/unified/resource/datastore.go index 8a930492420..7a1b614323e 100644 --- a/pkg/storage/unified/resource/datastore.go +++ b/pkg/storage/unified/resource/datastore.go @@ -49,6 +49,9 @@ type DataKey struct { ResourceVersion int64 Action DataAction Folder string + + // needed to maintain backwards compatibility with unified/sql + GUID string } // GroupResource represents a unique group/resource combination @@ -61,6 +64,12 @@ func (k DataKey) String() string { return fmt.Sprintf("%s/%s/%s/%s/%d~%s~%s", k.Group, k.Resource, k.Namespace, k.Name, k.ResourceVersion, k.Action, k.Folder) } +// Temporary while we need to support unified/sql/backend compatibility +// Remove once we stop using RvManager in storage_backend.go +func (k DataKey) StringWithGUID() string { + return fmt.Sprintf("%s/%s/%s/%s/%d~%s~%s~%s", k.Group, k.Resource, k.Namespace, k.Name, k.ResourceVersion, k.Action, k.Folder, k.GUID) +} + func (k DataKey) Equals(other DataKey) bool { return k.Group == other.Group && k.Resource == other.Resource && k.Namespace == other.Namespace && k.Name == other.Name && k.ResourceVersion == other.ResourceVersion && k.Action == other.Action && k.Folder == other.Folder } @@ -516,7 +525,13 @@ func (d *dataStore) Save(ctx context.Context, key DataKey, value io.Reader) erro return fmt.Errorf("invalid data key: %w", err) } - writer, err := d.kv.Save(ctx, dataSection, key.String()) + var writer io.WriteCloser + var err error + if key.GUID != "" { + writer, err = d.kv.Save(ctx, dataSection, key.StringWithGUID()) + } else { + writer, err = d.kv.Save(ctx, dataSection, key.String()) + } if err != nil { return err } @@ -583,6 +598,33 @@ func ParseKey(key string) (DataKey, error) { }, nil } +// Temporary while we need to support unified/sql/backend compatibility +// Remove once we stop using RvManager in storage_backend.go +func ParseKeyWithGUID(key string) (DataKey, error) { + parts := strings.Split(key, "/") + if len(parts) != 5 { + return DataKey{}, fmt.Errorf("invalid key: %s", key) + } + rvActionFolderGUIDParts := strings.Split(parts[4], "~") + if len(rvActionFolderGUIDParts) != 4 { + return DataKey{}, fmt.Errorf("invalid key: %s", key) + } + rv, err := strconv.ParseInt(rvActionFolderGUIDParts[0], 10, 64) + if err != nil { + return DataKey{}, fmt.Errorf("invalid resource version '%s' in key %s: %w", rvActionFolderGUIDParts[0], key, err) + } + return DataKey{ + Group: parts[0], + Resource: parts[1], + Namespace: parts[2], + Name: parts[3], + ResourceVersion: rv, + Action: DataAction(rvActionFolderGUIDParts[1]), + Folder: rvActionFolderGUIDParts[2], + GUID: rvActionFolderGUIDParts[3], + }, nil +} + // SameResource checks if this key represents the same resource as another key. // It compares the identifying fields: Group, Resource, Namespace, and Name. // ResourceVersion, Action, and Folder are ignored as they don't identify the resource itself. diff --git a/pkg/storage/unified/resource/eventstore.go b/pkg/storage/unified/resource/eventstore.go index 7f80fb6b87a..e0c01afb550 100644 --- a/pkg/storage/unified/resource/eventstore.go +++ b/pkg/storage/unified/resource/eventstore.go @@ -32,6 +32,7 @@ type EventKey struct { ResourceVersion int64 Action DataAction Folder string + GUID string } func (k EventKey) String() string { diff --git a/pkg/storage/unified/resource/kv.go b/pkg/storage/unified/resource/kv.go index 043ea45f695..0bd413254a4 100644 --- a/pkg/storage/unified/resource/kv.go +++ b/pkg/storage/unified/resource/kv.go @@ -87,6 +87,9 @@ func (k *badgerKV) Get(ctx context.Context, section string, key string) (io.Read if section == "" { return nil, fmt.Errorf("section is required") } + if key == "" { + return nil, fmt.Errorf("key is required") + } key = section + "/" + key @@ -225,6 +228,9 @@ func (k *badgerKV) Delete(ctx context.Context, section string, key string) error if section == "" { return fmt.Errorf("section is required") } + if key == "" { + return fmt.Errorf("key is required") + } txn := k.db.NewTransaction(true) defer txn.Discard() diff --git a/pkg/storage/unified/resource/sqlkv.go b/pkg/storage/unified/resource/sqlkv.go index f6e8d0698f3..9cc2cc32dd0 100644 --- a/pkg/storage/unified/resource/sqlkv.go +++ b/pkg/storage/unified/resource/sqlkv.go @@ -1,19 +1,222 @@ package resource import ( + "bytes" "context" + "database/sql" + "embed" + "errors" "fmt" "io" "iter" + "strings" + "text/template" + "github.com/google/uuid" "github.com/grafana/grafana/pkg/storage/unified/sql/db" + "github.com/grafana/grafana/pkg/storage/unified/sql/dbutil" + "github.com/grafana/grafana/pkg/storage/unified/sql/rvmanager" + "github.com/grafana/grafana/pkg/storage/unified/sql/sqltemplate" ) +// Templates setup. +var ( + //go:embed data/*.sql + sqlTemplatesFS embed.FS + + sqlTemplates = template.Must(template.New("sql").ParseFS(sqlTemplatesFS, `data/*.sql`)) +) + +func mustTemplate(filename string) *template.Template { + if t := sqlTemplates.Lookup(filename); t != nil { + return t + } + panic(fmt.Sprintf("template file not found: %s", filename)) +} + +// Templates. +var ( + sqlKVKeys = mustTemplate("sqlkv_keys.sql") + sqlKVGet = mustTemplate("sqlkv_get.sql") + sqlKVBatchGet = mustTemplate("sqlkv_batch_get.sql") + sqlKVSaveEvent = mustTemplate("sqlkv_save_event.sql") + sqlKVInsertData = mustTemplate("sqlkv_insert_datastore.sql") + sqlKVUpdateData = mustTemplate("sqlkv_update_datastore.sql") + sqlKVInsertLegacyResourceHistory = mustTemplate("sqlkv_insert_legacy_resource_history.sql") + sqlKVInsertLegacyResource = mustTemplate("sqlkv_insert_legacy_resource.sql") + sqlKVUpdateLegacyResource = mustTemplate("sqlkv_update_legacy_resource.sql") + sqlKVDeleteLegacyResource = mustTemplate("sqlkv_delete_legacy_resource.sql") + sqlKVDelete = mustTemplate("sqlkv_delete.sql") + sqlKVBatchDelete = mustTemplate("sqlkv_batch_delete.sql") +) + +// sqlKVSection can be embedded in structs used when rendering query templates +// for queries that reference a particular section. The section will be validated, +// and the template can directly reference the `TableName`. +type sqlKVSection struct { + Section string +} + +func (req sqlKVSection) Validate() error { + if req.Section == "" { + return fmt.Errorf("section is required") + } + + if req.Section != dataSection && req.Section != eventsSection { + return fmt.Errorf("invalid section: %s", req.Section) + } + + return nil +} + +func (req sqlKVSection) TableName() string { + if req.Section == dataSection { + return "resource_history" + } + + return "resource_events" +} + +// sqlKVSectionKey can be embedded in structs used when rendering query templates +// for queries that reference both a section and a particular key. The `key` is +// validated, and the template can reference the corresponding `KeyPath`. +type sqlKVSectionKey struct { + sqlKVSection + Key string +} + +func (req sqlKVSectionKey) Validate() error { + if err := req.sqlKVSection.Validate(); err != nil { + return err + } + if req.Key == "" { + return fmt.Errorf("key is required") + } + + return nil +} + +func (req sqlKVSectionKey) KeyPath() string { + return req.Section + "/" + req.Key +} + +type sqlKVGetRequest struct { + sqltemplate.SQLTemplate + sqlKVSectionKey + *sqlKVGetResponse +} + +type sqlKVGetResponse struct { + Value []byte +} + +func (req sqlKVGetRequest) Validate() error { + return req.sqlKVSectionKey.Validate() +} + +func (req sqlKVGetRequest) Results() ([]byte, error) { + return req.Value, nil +} + +type sqlKVBatchRequest struct { + sqltemplate.SQLTemplate + sqlKVSection + Keys []string +} + +func (req sqlKVBatchRequest) Validate() error { + return req.sqlKVSection.Validate() +} + +func (req sqlKVBatchRequest) KeyPaths() []string { + result := make([]string, 0, len(req.Keys)) + for _, key := range req.Keys { + result = append(result, req.Section+"/"+key) + } + + return result +} + +type sqlKVSaveRequest struct { + sqltemplate.SQLTemplate + sqlKVSectionKey + Value []byte + + // old fields that can be removed once we prune resource_history + GUID string + Group string + Resource string + Namespace string + Name string + Action int64 + Folder string +} + +func (req sqlKVSaveRequest) Validate() error { + return req.sqlKVSectionKey.Validate() +} + +type sqlKVLegacySaveRequest struct { + sqltemplate.SQLTemplate + Value []byte + GUID string + Group string + Resource string + Namespace string + Name string + Action int64 + Folder string +} + +func (req sqlKVLegacySaveRequest) Validate() error { + return nil +} + +func (req sqlKVLegacySaveRequest) Results() ([]byte, error) { + return req.Value, nil +} + +type sqlKVKeysRequest struct { + sqltemplate.SQLTemplate + sqlKVSection + Options ListOptions +} + +func (req sqlKVKeysRequest) Validate() error { + return req.sqlKVSection.Validate() +} + +func (req sqlKVKeysRequest) StartKey() string { + return req.Section + "/" + req.Options.StartKey +} + +func (req sqlKVKeysRequest) EndKey() string { + if req.Options.EndKey == "" { + req.Options.EndKey = PrefixRangeEnd(req.Section + "/") + } + + return req.Section + "/" + req.Options.EndKey +} + +func (req sqlKVKeysRequest) SortAscending() bool { + return req.Options.Sort != SortOrderDesc +} + +type sqlKVDeleteRequest struct { + sqltemplate.SQLTemplate + sqlKVSectionKey +} + +func (req sqlKVDeleteRequest) Validate() error { + return req.sqlKVSectionKey.Validate() +} + var _ KV = &sqlKV{} type sqlKV struct { dbProvider db.DBProvider db db.DB + dialect sqltemplate.Dialect } func NewSQLKV(dbProvider db.DBProvider) (KV, error) { @@ -27,9 +230,15 @@ func NewSQLKV(dbProvider db.DBProvider) (KV, error) { return nil, fmt.Errorf("error initializing DB: %w", err) } + dialect := sqltemplate.DialectForDriver(dbConn.DriverName()) + if dialect == nil { + return nil, fmt.Errorf("unsupported database driver: %s", dbConn.DriverName()) + } + return &sqlKV{ dbProvider: dbProvider, db: dbConn, + dialect: dialect, }, nil } @@ -39,32 +248,320 @@ func (k *sqlKV) Ping(ctx context.Context) error { func (k *sqlKV) Keys(ctx context.Context, section string, opt ListOptions) iter.Seq2[string, error] { return func(yield func(string, error) bool) { - panic("not implemented!") + rows, err := dbutil.QueryRows(ctx, k.db, sqlKVKeys, sqlKVKeysRequest{ + SQLTemplate: sqltemplate.New(k.dialect), + sqlKVSection: sqlKVSection{section}, + Options: opt, + }) + if err != nil { + yield("", err) + return + } + defer closeRows(rows, yield) + + for rows.Next() { + var key string + if err := rows.Scan(&key); err != nil { + yield("", fmt.Errorf("error reading row: %w", err)) + return + } + + if !yield(strings.TrimPrefix(key, section+"/"), nil) { + return + } + } + + if err := rows.Err(); err != nil { + yield("", fmt.Errorf("failed to read rows: %w", err)) + } } } func (k *sqlKV) Get(ctx context.Context, section string, key string) (io.ReadCloser, error) { - panic("not implemented!") + value, err := dbutil.QueryRow(ctx, k.db, sqlKVGet, sqlKVGetRequest{ + SQLTemplate: sqltemplate.New(k.dialect), + sqlKVSectionKey: sqlKVSectionKey{sqlKVSection{section}, key}, + sqlKVGetResponse: new(sqlKVGetResponse), + }) + if err != nil { + if errors.Is(err, sql.ErrNoRows) { + return nil, ErrNotFound + } + return nil, fmt.Errorf("failed to get key: %w", err) + } + + return io.NopCloser(bytes.NewReader(value)), nil } func (k *sqlKV) BatchGet(ctx context.Context, section string, keys []string) iter.Seq2[KeyValue, error] { return func(yield func(KeyValue, error) bool) { - panic("not implemented!") + if len(keys) == 0 { + return + } + + rows, err := dbutil.QueryRows(ctx, k.db, sqlKVBatchGet, sqlKVBatchRequest{ + SQLTemplate: sqltemplate.New(k.dialect), + sqlKVSection: sqlKVSection{section}, + Keys: keys, + }) + if err != nil { + yield(KeyValue{}, err) + return + } + defer closeRows(rows, yield) + + for rows.Next() { + var key string + var value []byte + if err := rows.Scan(&key, &value); err != nil { + yield(KeyValue{}, fmt.Errorf("error reading row: %w", err)) + return + } + + kv := KeyValue{ + Key: strings.TrimPrefix(key, section+"/"), + Value: io.NopCloser(bytes.NewReader(value)), + } + if !yield(kv, nil) { + return + } + } + + if err := rows.Err(); err != nil { + yield(KeyValue{}, fmt.Errorf("failed to read rows: %w", err)) + } } } func (k *sqlKV) Save(ctx context.Context, section string, key string) (io.WriteCloser, error) { - panic("not implemented!") + sectionKey := sqlKVSectionKey{sqlKVSection{section}, key} + if err := sectionKey.Validate(); err != nil { + return nil, err + } + + return &sqlWriteCloser{ + kv: k, + ctx: ctx, + sectionKey: sectionKey, + buf: &bytes.Buffer{}, + closed: false, + }, nil +} + +type sqlWriteCloser struct { + kv *sqlKV + ctx context.Context + sectionKey sqlKVSectionKey + buf *bytes.Buffer + closed bool +} + +func (w *sqlWriteCloser) Write(value []byte) (int, error) { + if w.closed { + return 0, errors.New("write to closed writer") + } + + return w.buf.Write(value) +} + +func (w *sqlWriteCloser) Close() error { + if w.closed { + return nil + } + + w.closed = true + + // do regular kv save: simple key_path + value insert with conflict check. + // can only do this on resource_events for now, until we drop the columns in resource_history + if w.sectionKey.Section == eventsSection { + _, err := dbutil.Exec(w.ctx, w.kv.db, sqlKVSaveEvent, sqlKVSaveRequest{ + SQLTemplate: sqltemplate.New(w.kv.dialect), + sqlKVSectionKey: w.sectionKey, + Value: w.buf.Bytes(), + }) + + if err != nil { + return fmt.Errorf("failed to save: %w", err) + } + + return nil + } + + // if storage_backend is running with an RvManager, it will inject a transaction into the context + // used to keep backwards compatibility between sql-based kvstore and unified/sql/backend + tx, ok := rvmanager.TxFromCtx(w.ctx) + if !ok { + // temporary save for dataStore without rvmanager + // we can use the same template as the event one after we: + // - move PK from GUID to key_path + // - remove all unnecessary columns (or at least their NOT NULL constraints) + _, err := w.kv.Get(w.ctx, w.sectionKey.Section, w.sectionKey.Key) + if errors.Is(err, ErrNotFound) { + _, err := dbutil.Exec(w.ctx, w.kv.db, sqlKVInsertData, sqlKVSaveRequest{ + SQLTemplate: sqltemplate.New(w.kv.dialect), + sqlKVSectionKey: w.sectionKey, + GUID: uuid.New().String(), + Value: w.buf.Bytes(), + }) + + if err != nil { + return fmt.Errorf("failed to insert to datastore: %w", err) + } + + return nil + } + + if err != nil { + return fmt.Errorf("failed to get for save: %w", err) + } + + _, err = dbutil.Exec(w.ctx, w.kv.db, sqlKVUpdateData, sqlKVSaveRequest{ + SQLTemplate: sqltemplate.New(w.kv.dialect), + sqlKVSectionKey: w.sectionKey, + Value: w.buf.Bytes(), + }) + + if err != nil { + return fmt.Errorf("failed to update to datastore: %w", err) + } + + return nil + } + + // special, temporary save that includes all the fields in resource_history that are not relevant for the kvstore, + // as well as the resource table. This is only called if an RvManager was passed to storage_backend, as that + // component will be responsible for populating the resource_version and key_path columns + // note that we are not touching resource_version table, neither the resource_version columns or the key_path column + // as the RvManager will be responsible for this + dataKey, err := ParseKeyWithGUID(w.sectionKey.Key) + if err != nil { + return fmt.Errorf("failed to parse key: %w", err) + } + + var action int64 + switch dataKey.Action { + case DataActionCreated: + action = 1 + case DataActionUpdated: + action = 2 + case DataActionDeleted: + action = 3 + default: + return fmt.Errorf("failed to parse key: %w", err) + } + + _, err = dbutil.Exec(w.ctx, tx, sqlKVInsertLegacyResourceHistory, sqlKVSaveRequest{ + SQLTemplate: sqltemplate.New(w.kv.dialect), + sqlKVSectionKey: w.sectionKey, + Value: w.buf.Bytes(), + GUID: dataKey.GUID, + Group: dataKey.Group, + Resource: dataKey.Resource, + Namespace: dataKey.Namespace, + Name: dataKey.Name, + Action: action, + Folder: dataKey.Folder, + }) + + if err != nil { + return fmt.Errorf("failed to save to resource_history: %w", err) + } + + switch dataKey.Action { + case DataActionCreated: + _, err = dbutil.Exec(w.ctx, tx, sqlKVInsertLegacyResource, sqlKVLegacySaveRequest{ + SQLTemplate: sqltemplate.New(w.kv.dialect), + Value: w.buf.Bytes(), + GUID: dataKey.GUID, + Group: dataKey.Group, + Resource: dataKey.Resource, + Namespace: dataKey.Namespace, + Name: dataKey.Name, + Action: action, + Folder: dataKey.Folder, + }) + + if err != nil { + return fmt.Errorf("failed to insert to resource: %w", err) + } + case DataActionUpdated: + _, err = dbutil.Exec(w.ctx, tx, sqlKVUpdateLegacyResource, sqlKVLegacySaveRequest{ + SQLTemplate: sqltemplate.New(w.kv.dialect), + Value: w.buf.Bytes(), + Group: dataKey.Group, + Resource: dataKey.Resource, + Namespace: dataKey.Namespace, + Name: dataKey.Name, + Action: action, + Folder: dataKey.Folder, + }) + + if err != nil { + return fmt.Errorf("failed to update resource: %w", err) + } + case DataActionDeleted: + _, err = dbutil.Exec(w.ctx, tx, sqlKVDeleteLegacyResource, sqlKVLegacySaveRequest{ + SQLTemplate: sqltemplate.New(w.kv.dialect), + Group: dataKey.Group, + Resource: dataKey.Resource, + Namespace: dataKey.Namespace, + Name: dataKey.Name, + }) + + if err != nil { + return fmt.Errorf("failed to delete from resource: %w", err) + } + } + + return nil } func (k *sqlKV) Delete(ctx context.Context, section string, key string) error { - panic("not implemented!") + res, err := dbutil.Exec(ctx, k.db, sqlKVDelete, sqlKVDeleteRequest{ + SQLTemplate: sqltemplate.New(k.dialect), + sqlKVSectionKey: sqlKVSectionKey{sqlKVSection{section}, key}, + }) + if err != nil { + return fmt.Errorf("failed to delete key: %w", err) + } + + rows, err := res.RowsAffected() + if err != nil { + return fmt.Errorf("failed to validate delete: %w", err) + } + + if rows == 0 { + return ErrNotFound + } + + // TODO reflect change to resource table + + return nil } func (k *sqlKV) BatchDelete(ctx context.Context, section string, keys []string) error { - panic("not implemented!") + if len(keys) == 0 { + return nil + } + + if _, err := dbutil.Exec(ctx, k.db, sqlKVBatchDelete, sqlKVBatchRequest{ + SQLTemplate: sqltemplate.New(k.dialect), + sqlKVSection: sqlKVSection{section}, + Keys: keys, + }); err != nil { + return fmt.Errorf("failed to batch delete keys: %w", err) + } + + return nil } func (k *sqlKV) UnixTimestamp(ctx context.Context) (int64, error) { panic("not implemented!") } + +func closeRows[T any](rows db.Rows, yield func(T, error) bool) { + if err := rows.Close(); err != nil { + var zero T + yield(zero, fmt.Errorf("error closing rows: %w", err)) + } +} diff --git a/pkg/storage/unified/resource/storage_backend.go b/pkg/storage/unified/resource/storage_backend.go index b0f51702775..13f2b9d6159 100644 --- a/pkg/storage/unified/resource/storage_backend.go +++ b/pkg/storage/unified/resource/storage_backend.go @@ -14,6 +14,7 @@ import ( "time" "github.com/bwmarrin/snowflake" + "github.com/google/uuid" "github.com/grafana/grafana-app-sdk/logging" "github.com/prometheus/client_golang/prometheus" "go.opentelemetry.io/otel/trace" @@ -22,6 +23,8 @@ import ( "github.com/grafana/grafana/pkg/apimachinery/utils" "github.com/grafana/grafana/pkg/storage/unified/resourcepb" + "github.com/grafana/grafana/pkg/storage/unified/sql/db" + "github.com/grafana/grafana/pkg/storage/unified/sql/rvmanager" "github.com/grafana/grafana/pkg/util/debouncer" ) @@ -68,6 +71,8 @@ type kvStorageBackend struct { withExperimentalClusterScope bool //tracer trace.Tracer //reg prometheus.Registerer + + rvManager *rvmanager.ResourceVersionManager } var _ KVBackend = &kvStorageBackend{} @@ -85,6 +90,10 @@ type KVBackendOptions struct { EventPruningInterval time.Duration // How often to run the event pruning (default: 5 minutes) Tracer trace.Tracer // TODO add tracing Reg prometheus.Registerer // TODO add metrics + + // Adding RvManager overrides the RV generated with snowflake in order to keep backwards compatibility with + // unified/sql + RvManager *rvmanager.ResourceVersionManager } func NewKVStorageBackend(opts KVBackendOptions) (KVBackend, error) { @@ -119,6 +128,7 @@ func NewKVStorageBackend(opts KVBackendOptions) (KVBackend, error) { eventRetentionPeriod: eventRetentionPeriod, eventPruningInterval: eventPruningInterval, withExperimentalClusterScope: opts.WithExperimentalClusterScope, + rvManager: opts.RvManager, } err = backend.initPruner(ctx) if err != nil { @@ -317,9 +327,28 @@ func (k *kvStorageBackend) WriteEvent(ctx context.Context, event WriteEvent) (in Action: action, Folder: obj.GetFolder(), } - err := k.dataStore.Save(ctx, dataKey, bytes.NewReader(event.Value)) - if err != nil { - return 0, fmt.Errorf("failed to write data: %w", err) + + if k.rvManager != nil { + dataKey.GUID = uuid.New().String() + var err error + rv, err = k.rvManager.ExecWithRV(ctx, event.Key, func(tx db.Tx) (string, error) { + err := k.dataStore.Save(rvmanager.ContextWithTx(ctx, tx), dataKey, bytes.NewReader(event.Value)) + if err != nil { + return "", fmt.Errorf("failed to write data: %w", err) + } + + return dataKey.GUID, nil + }) + if err != nil { + return 0, fmt.Errorf("failed to write data: %w", err) + } + + dataKey.ResourceVersion = rv + } else { + err := k.dataStore.Save(ctx, dataKey, bytes.NewReader(event.Value)) + if err != nil { + return 0, fmt.Errorf("failed to write data: %w", err) + } } // Optimistic concurrency control to verify our write is the latest version @@ -340,14 +369,22 @@ func (k *kvStorageBackend) WriteEvent(ctx context.Context, event WriteEvent) (in } // Check if the RV we just wrote is the latest. If not, a concurrent write with higher RV happened - if latestKey.ResourceVersion != rv { + if !rvmanager.IsRvEqual(latestKey.ResourceVersion, rv) { // Delete the data we just wrote since it's not the latest + // if we're running with rvManager, convert the ResourceVersion back to snowflake to delete + if k.rvManager != nil { + dataKey.ResourceVersion = rvmanager.SnowflakeFromRv(dataKey.ResourceVersion) + } _ = k.dataStore.Delete(ctx, dataKey) return 0, fmt.Errorf("optimistic locking failed: concurrent modification detected") } - if prevKey.ResourceVersion != event.PreviousRV { + if !rvmanager.IsRvEqual(prevKey.ResourceVersion, event.PreviousRV) { // Another concurrent write happened between our read and write + // if we're running with rvManager, convert the ResourceVersion back to snowflake to delete + if k.rvManager != nil { + dataKey.ResourceVersion = rvmanager.SnowflakeFromRv(dataKey.ResourceVersion) + } _ = k.dataStore.Delete(ctx, dataKey) return 0, fmt.Errorf("optimistic locking failed: resource was modified concurrently (expected previous RV %d, found %d)", event.PreviousRV, prevKey.ResourceVersion) } @@ -366,8 +403,12 @@ func (k *kvStorageBackend) WriteEvent(ctx context.Context, event WriteEvent) (in } // Check if the RV we just wrote is the latest. If not, a concurrent create with higher RV happened - if latestKey.ResourceVersion != rv { + if !rvmanager.IsRvEqual(latestKey.ResourceVersion, rv) { // Delete the data we just wrote since it's not the latest + // if we're running with rvManager, convert the ResourceVersion back to snowflake to delete + if k.rvManager != nil { + dataKey.ResourceVersion = rvmanager.SnowflakeFromRv(dataKey.ResourceVersion) + } _ = k.dataStore.Delete(ctx, dataKey) return 0, fmt.Errorf("optimistic locking failed: concurrent create detected") } @@ -375,6 +416,10 @@ func (k *kvStorageBackend) WriteEvent(ctx context.Context, event WriteEvent) (in // Verify that the immediate predecessor is not a create if prevKey.Action == DataActionCreated { // Another concurrent create happened - delete our write and return error + // if we're running with rvManager, convert the ResourceVersion back to snowflake to delete + if k.rvManager != nil { + dataKey.ResourceVersion = rvmanager.SnowflakeFromRv(dataKey.ResourceVersion) + } _ = k.dataStore.Delete(ctx, dataKey) return 0, fmt.Errorf("optimistic locking failed: concurrent create detected") } @@ -391,7 +436,7 @@ func (k *kvStorageBackend) WriteEvent(ctx context.Context, event WriteEvent) (in Folder: obj.GetFolder(), PreviousRV: event.PreviousRV, } - err = k.eventStore.Save(ctx, eventData) + err := k.eventStore.Save(ctx, eventData) if err != nil { // Clean up the data we wrote since event save failed _ = k.dataStore.Delete(ctx, dataKey) diff --git a/pkg/storage/unified/search/builders/team_search.go b/pkg/storage/unified/search/builders/team_search.go index 4b09074b3dc..3dcf3cfdc95 100644 --- a/pkg/storage/unified/search/builders/team_search.go +++ b/pkg/storage/unified/search/builders/team_search.go @@ -46,8 +46,8 @@ func GetTeamSearchBuilder() (resource.DocumentBuilderInfo, error) { return resource.DocumentBuilderInfo{ GroupResource: schema.GroupResource{ - Group: "iam.grafana.app", - Resource: "searchTeams", + Group: v0alpha1.TeamResourceInfo.GroupResource().Group, + Resource: v0alpha1.TeamResourceInfo.GroupResource().Resource, }, Fields: fields, Builder: new(teamSearchBuilder), diff --git a/pkg/storage/unified/sql/backend.go b/pkg/storage/unified/sql/backend.go index ebd04ce4a30..a129a01727a 100644 --- a/pkg/storage/unified/sql/backend.go +++ b/pkg/storage/unified/sql/backend.go @@ -31,6 +31,7 @@ import ( "github.com/grafana/grafana/pkg/storage/unified/resourcepb" "github.com/grafana/grafana/pkg/storage/unified/sql/db" "github.com/grafana/grafana/pkg/storage/unified/sql/dbutil" + "github.com/grafana/grafana/pkg/storage/unified/sql/rvmanager" "github.com/grafana/grafana/pkg/storage/unified/sql/sqltemplate" "github.com/grafana/grafana/pkg/util/debouncer" ) @@ -126,7 +127,7 @@ type backend struct { notifier eventNotifier // resource version manager - rvManager *resourceVersionManager + rvManager *rvmanager.ResourceVersionManager // testing simulatedNetworkLatency time.Duration @@ -163,7 +164,7 @@ func (b *backend) initLocked(ctx context.Context) error { } // Initialize ResourceVersionManager - rvManager, err := NewResourceVersionManager(ResourceManagerOptions{ + rvManager, err := rvmanager.NewResourceVersionManager(rvmanager.ResourceManagerOptions{ Dialect: b.dialect, DB: b.db, }) @@ -928,12 +929,12 @@ func (b *backend) listLatestRVs(ctx context.Context) (groupResourceRV, error) { func (b *backend) fetchLatestRV(ctx context.Context, x db.ContextExecer, d sqltemplate.Dialect, group, resource string) (int64, error) { ctx, span := tracer.Start(ctx, "sql.backend.fetchLatestRV") defer span.End() - res, err := dbutil.QueryRow(ctx, x, sqlResourceVersionGet, sqlResourceVersionGetRequest{ + res, err := dbutil.QueryRow(ctx, x, rvmanager.SqlResourceVersionGet, rvmanager.SqlResourceVersionGetRequest{ SQLTemplate: sqltemplate.New(d), Group: group, Resource: resource, ReadOnly: true, - Response: new(resourceVersionResponse), + Response: new(rvmanager.ResourceVersionResponse), }) if errors.Is(err, sql.ErrNoRows) { return 1, nil diff --git a/pkg/storage/unified/sql/backend_test.go b/pkg/storage/unified/sql/backend_test.go index f7ecd755f32..2f8f9fcb060 100644 --- a/pkg/storage/unified/sql/backend_test.go +++ b/pkg/storage/unified/sql/backend_test.go @@ -40,6 +40,26 @@ type testBackend struct { test.TestDBProvider } +func expectSuccessfulResourceVersionLock(t *testing.T, dbp test.TestDBProvider, rv int64, timestamp int64) { + dbp.SQLMock.ExpectQuery("select resource_version, unix_timestamp for update"). + WillReturnRows(sqlmock.NewRows([]string{"resource_version", "unix_timestamp"}). + AddRow(rv, timestamp)) +} + +func expectSuccessfulResourceVersionSaveRV(t *testing.T, dbp test.TestDBProvider) { + dbp.SQLMock.ExpectExec("update resource set resource_version").WillReturnResult(sqlmock.NewResult(1, 1)) + dbp.SQLMock.ExpectExec("update resource_history set resource_version").WillReturnResult(sqlmock.NewResult(1, 1)) + dbp.SQLMock.ExpectExec("update resource_version set resource_version").WillReturnResult(sqlmock.NewResult(1, 1)) +} + +func expectSuccessfulResourceVersionExec(t *testing.T, dbp test.TestDBProvider, cbs ...func()) { + for _, cb := range cbs { + cb() + } + expectSuccessfulResourceVersionLock(t, dbp, 100, 200) + expectSuccessfulResourceVersionSaveRV(t, dbp) +} + func (b testBackend) ExecWithResult(expectedSQL string, lastInsertID int64, rowsAffected int64) { b.SQLMock.ExpectExec(expectedSQL).WillReturnResult(sqlmock.NewResult(lastInsertID, rowsAffected)) } diff --git a/pkg/storage/unified/sql/bulk.go b/pkg/storage/unified/sql/bulk.go index 6580975a764..4037c74f0dd 100644 --- a/pkg/storage/unified/sql/bulk.go +++ b/pkg/storage/unified/sql/bulk.go @@ -281,13 +281,13 @@ func (b *backend) processBulkWithTx(ctx context.Context, tx db.Tx, setting resou } if b.dialect.DialectName() == "sqlite" { - nextRV, err := b.rvManager.lock(ctx, tx, key.Group, key.Resource) + nextRV, err := b.rvManager.Lock(ctx, tx, key.Group, key.Resource) if err != nil { b.log.Error("error locking RV", "error", err, "key", resource.NSGR(key)) } else { b.log.Info("successfully locked RV", "nextRV", nextRV, "key", resource.NSGR(key)) // Save the incremented RV - if err := b.rvManager.saveRV(ctx, tx, key.Group, key.Resource, nextRV); err != nil { + if err := b.rvManager.SaveRV(ctx, tx, key.Group, key.Resource, nextRV); err != nil { b.log.Error("error saving RV", "error", err, "key", resource.NSGR(key)) } else { b.log.Info("successfully saved RV", "rv", nextRV, "key", resource.NSGR(key)) diff --git a/pkg/storage/unified/sql/db/migrations/resource_mig.go b/pkg/storage/unified/sql/db/migrations/resource_mig.go index fbbfe32d4a6..0f19ae01d93 100644 --- a/pkg/storage/unified/sql/db/migrations/resource_mig.go +++ b/pkg/storage/unified/sql/db/migrations/resource_mig.go @@ -204,5 +204,18 @@ func initResourceTables(mg *migrator.Migrator) string { Name: "IDX_resource_history_key_path", })) + oldResourceVersionUniqueKey := migrator.Index{Cols: []string{"group", "resource"}, Type: migrator.UniqueIndex} + updatedResourceVersionTable := migrator.Table{ + Name: "resource_version", + Columns: []*migrator.Column{ + {Name: "group", Type: migrator.DB_NVarchar, Length: 190, Nullable: false, IsPrimaryKey: true}, + {Name: "resource", Type: migrator.DB_NVarchar, Length: 190, Nullable: false, IsPrimaryKey: true}, + {Name: "resource_version", Type: migrator.DB_BigInt, Nullable: false}, + }, + PrimaryKeys: []string{"group", "resource"}, + } + + migrator.ConvertUniqueKeyToPrimaryKey(mg, oldResourceVersionUniqueKey, updatedResourceVersionTable) + return marker } diff --git a/pkg/storage/unified/sql/list_iterator_test.go b/pkg/storage/unified/sql/list_iterator_test.go index 3b567ca0f3e..e049e06525e 100644 --- a/pkg/storage/unified/sql/list_iterator_test.go +++ b/pkg/storage/unified/sql/list_iterator_test.go @@ -17,6 +17,7 @@ import ( dbsql "github.com/grafana/grafana/pkg/storage/unified/sql/db" "github.com/grafana/grafana/pkg/storage/unified/sql/db/dbimpl" "github.com/grafana/grafana/pkg/storage/unified/sql/dbutil" + "github.com/grafana/grafana/pkg/storage/unified/sql/rvmanager" "github.com/grafana/grafana/pkg/storage/unified/sql/sqltemplate" "github.com/grafana/grafana/pkg/tests/testsuite" "github.com/grafana/grafana/pkg/util/testutil" @@ -94,7 +95,7 @@ func TestIntegrationListIter(t *testing.T) { return fmt.Errorf("failed to insert test data: %w", err) } - if _, err = dbutil.Exec(ctx, tx, sqlResourceUpdateRV, sqlResourceUpdateRVRequest{ + if _, err = dbutil.Exec(ctx, tx, rvmanager.SqlResourceUpdateRV, rvmanager.SqlResourceUpdateRVRequest{ SQLTemplate: sqltemplate.New(dialect), GUIDToRV: map[string]int64{ item.guid: item.resourceVersion, diff --git a/pkg/storage/unified/sql/queries.go b/pkg/storage/unified/sql/queries.go index 5b9a177e17c..725c4617403 100644 --- a/pkg/storage/unified/sql/queries.go +++ b/pkg/storage/unified/sql/queries.go @@ -38,10 +38,8 @@ var ( sqlResourceList = mustTemplate("resource_list.sql") sqlResourceHistoryList = mustTemplate("resource_history_list.sql") sqlResourceHistoryListModifiedSince = mustTemplate("resource_history_list_since_modified.sql") - sqlResourceUpdateRV = mustTemplate("resource_update_rv.sql") sqlResourceHistoryRead = mustTemplate("resource_history_read.sql") sqlResourceHistoryReadLatestRV = mustTemplate("resource_history_read_latest_rv.sql") - sqlResourceHistoryUpdateRV = mustTemplate("resource_history_update_rv.sql") sqlResourceHistoryInsert = mustTemplate("resource_history_insert.sql") sqlResourceHistoryPoll = mustTemplate("resource_history_poll.sql") sqlResourceHistoryGet = mustTemplate("resource_history_get.sql") @@ -51,10 +49,7 @@ var ( sqlResourceInsertFromHistory = mustTemplate("resource_insert_from_history.sql") // sqlResourceLabelsInsert = mustTemplate("resource_labels_insert.sql") - sqlResourceVersionGet = mustTemplate("resource_version_get.sql") - sqlResourceVersionUpdate = mustTemplate("resource_version_update.sql") - sqlResourceVersionInsert = mustTemplate("resource_version_insert.sql") - sqlResourceVersionList = mustTemplate("resource_version_list.sql") + sqlResourceVersionList = mustTemplate("resource_version_list.sql") sqlResourceBlobInsert = mustTemplate("resource_blob_insert.sql") sqlResourceBlobQuery = mustTemplate("resource_blob_query.sql") @@ -365,76 +360,11 @@ func (r sqlResourceBlobQueryRequest) Validate() error { return nil } -// update RV - -type sqlResourceUpdateRVRequest struct { - sqltemplate.SQLTemplate - GUIDToRV map[string]int64 - GUIDToSnowflakeRV map[string]int64 -} - -func (r sqlResourceUpdateRVRequest) Validate() error { - return nil // TODO -} - -func (r sqlResourceUpdateRVRequest) SlashFunc() string { - if r.DialectName() == "postgres" { - return "CHR(47)" - } - - return "CHAR(47)" -} - -func (r sqlResourceUpdateRVRequest) TildeFunc() string { - if r.DialectName() == "postgres" { - return "CHR(126)" - } - - return "CHAR(126)" -} - -// resource_version table requests. -type resourceVersionResponse struct { - ResourceVersion int64 - CurrentEpoch int64 -} - -func (r *resourceVersionResponse) Results() (*resourceVersionResponse, error) { - return r, nil -} - type groupResourceVersion struct { Group, Resource string ResourceVersion int64 } -type sqlResourceVersionUpsertRequest struct { - sqltemplate.SQLTemplate - Group, Resource string - ResourceVersion int64 -} - -func (r sqlResourceVersionUpsertRequest) Validate() error { - return nil // TODO -} - -type sqlResourceVersionGetRequest struct { - sqltemplate.SQLTemplate - Group, Resource string - ReadOnly bool - Response *resourceVersionResponse -} - -func (r sqlResourceVersionGetRequest) Validate() error { - return nil // TODO -} -func (r sqlResourceVersionGetRequest) Results() (*resourceVersionResponse, error) { - return &resourceVersionResponse{ - ResourceVersion: r.Response.ResourceVersion, - CurrentEpoch: r.Response.CurrentEpoch, - }, nil -} - type sqlResourceVersionListRequest struct { sqltemplate.SQLTemplate *groupResourceVersion diff --git a/pkg/storage/unified/sql/queries_test.go b/pkg/storage/unified/sql/queries_test.go index 5673bfad1e8..93e9b1f5af4 100644 --- a/pkg/storage/unified/sql/queries_test.go +++ b/pkg/storage/unified/sql/queries_test.go @@ -8,6 +8,7 @@ import ( "github.com/grafana/grafana/pkg/apimachinery/utils" "github.com/grafana/grafana/pkg/storage/unified/resource" "github.com/grafana/grafana/pkg/storage/unified/resourcepb" + "github.com/grafana/grafana/pkg/storage/unified/sql/rvmanager" "github.com/grafana/grafana/pkg/storage/unified/sql/sqltemplate/mocks" ) @@ -162,10 +163,10 @@ func TestUnifiedStorageQueries(t *testing.T) { }, }, - sqlResourceUpdateRV: { + rvmanager.SqlResourceUpdateRV: { { Name: "single path", - Data: &sqlResourceUpdateRVRequest{ + Data: &rvmanager.SqlResourceUpdateRVRequest{ SQLTemplate: mocks.NewTestingSQLTemplate(), GUIDToRV: map[string]int64{ "guid1": 123, @@ -228,10 +229,10 @@ func TestUnifiedStorageQueries(t *testing.T) { }, }, - sqlResourceHistoryUpdateRV: { + rvmanager.SqlResourceHistoryUpdateRV: { { Name: "single path", - Data: &sqlResourceUpdateRVRequest{ + Data: &rvmanager.SqlResourceUpdateRVRequest{ SQLTemplate: mocks.NewTestingSQLTemplate(), GUIDToRV: map[string]int64{ "guid1": 123, @@ -334,23 +335,23 @@ func TestUnifiedStorageQueries(t *testing.T) { }, }, - sqlResourceVersionGet: { + rvmanager.SqlResourceVersionGet: { { Name: "single path", - Data: &sqlResourceVersionGetRequest{ + Data: &rvmanager.SqlResourceVersionGetRequest{ SQLTemplate: mocks.NewTestingSQLTemplate(), Resource: "resource", Group: "group", - Response: new(resourceVersionResponse), + Response: new(rvmanager.ResourceVersionResponse), ReadOnly: false, }, }, }, - sqlResourceVersionUpdate: { + rvmanager.SqlResourceVersionUpdate: { { Name: "increment resource version", - Data: &sqlResourceVersionUpsertRequest{ + Data: &rvmanager.SqlResourceVersionUpsertRequest{ SQLTemplate: mocks.NewTestingSQLTemplate(), Resource: "resource", Group: "group", @@ -359,10 +360,10 @@ func TestUnifiedStorageQueries(t *testing.T) { }, }, - sqlResourceVersionInsert: { + rvmanager.SqlResourceVersionInsert: { { Name: "single path", - Data: &sqlResourceVersionUpsertRequest{ + Data: &rvmanager.SqlResourceVersionUpsertRequest{ SQLTemplate: mocks.NewTestingSQLTemplate(), ResourceVersion: int64(12354), }, diff --git a/pkg/storage/unified/sql/data/resource_history_update_rv.sql b/pkg/storage/unified/sql/rvmanager/data/resource_history_update_rv.sql similarity index 100% rename from pkg/storage/unified/sql/data/resource_history_update_rv.sql rename to pkg/storage/unified/sql/rvmanager/data/resource_history_update_rv.sql diff --git a/pkg/storage/unified/sql/data/resource_update_rv.sql b/pkg/storage/unified/sql/rvmanager/data/resource_update_rv.sql similarity index 100% rename from pkg/storage/unified/sql/data/resource_update_rv.sql rename to pkg/storage/unified/sql/rvmanager/data/resource_update_rv.sql diff --git a/pkg/storage/unified/sql/data/resource_version_get.sql b/pkg/storage/unified/sql/rvmanager/data/resource_version_get.sql similarity index 100% rename from pkg/storage/unified/sql/data/resource_version_get.sql rename to pkg/storage/unified/sql/rvmanager/data/resource_version_get.sql diff --git a/pkg/storage/unified/sql/data/resource_version_insert.sql b/pkg/storage/unified/sql/rvmanager/data/resource_version_insert.sql similarity index 100% rename from pkg/storage/unified/sql/data/resource_version_insert.sql rename to pkg/storage/unified/sql/rvmanager/data/resource_version_insert.sql diff --git a/pkg/storage/unified/sql/data/resource_version_update.sql b/pkg/storage/unified/sql/rvmanager/data/resource_version_update.sql similarity index 100% rename from pkg/storage/unified/sql/data/resource_version_update.sql rename to pkg/storage/unified/sql/rvmanager/data/resource_version_update.sql diff --git a/pkg/storage/unified/sql/rvmanager/queries.go b/pkg/storage/unified/sql/rvmanager/queries.go new file mode 100644 index 00000000000..c0411cdf704 --- /dev/null +++ b/pkg/storage/unified/sql/rvmanager/queries.go @@ -0,0 +1,84 @@ +package rvmanager + +import ( + "github.com/grafana/grafana/pkg/storage/unified/sql/sqltemplate" +) + +type SqlResourceUpdateRVRequest struct { + sqltemplate.SQLTemplate + GUIDToRV map[string]int64 + GUIDToSnowflakeRV map[string]int64 +} + +func (r SqlResourceUpdateRVRequest) Validate() error { + return nil // TODO +} + +func (r SqlResourceUpdateRVRequest) SlashFunc() string { + if r.DialectName() == "postgres" { + return "CHR(47)" + } + + return "CHAR(47)" +} + +func (r SqlResourceUpdateRVRequest) TildeFunc() string { + if r.DialectName() == "postgres" { + return "CHR(126)" + } + + return "CHAR(126)" +} + +type ResourceVersionResponse struct { + ResourceVersion int64 + CurrentEpoch int64 +} + +func (r *ResourceVersionResponse) Results() (*ResourceVersionResponse, error) { + return r, nil +} + +type sqlResourceVersionGetRequest struct { + sqltemplate.SQLTemplate + Group, Resource string + ReadOnly bool + Response *ResourceVersionResponse +} + +func (r sqlResourceVersionGetRequest) Validate() error { + return nil // TODO +} +func (r sqlResourceVersionGetRequest) Results() (*ResourceVersionResponse, error) { + return &ResourceVersionResponse{ + ResourceVersion: r.Response.ResourceVersion, + CurrentEpoch: r.Response.CurrentEpoch, + }, nil +} + +type SqlResourceVersionUpsertRequest struct { + sqltemplate.SQLTemplate + Group, Resource string + ResourceVersion int64 +} + +func (r SqlResourceVersionUpsertRequest) Validate() error { + return nil // TODO +} + +type SqlResourceVersionGetRequest struct { + sqltemplate.SQLTemplate + Group, Resource string + ReadOnly bool + Response *ResourceVersionResponse +} + +func (r SqlResourceVersionGetRequest) Validate() error { + return nil // TODO +} +func (r SqlResourceVersionGetRequest) Results() (*ResourceVersionResponse, error) { + return &ResourceVersionResponse{ + ResourceVersion: r.Response.ResourceVersion, + CurrentEpoch: r.Response.CurrentEpoch, + }, nil +} diff --git a/pkg/storage/unified/sql/rv_manager.go b/pkg/storage/unified/sql/rvmanager/rv_manager.go similarity index 85% rename from pkg/storage/unified/sql/rv_manager.go rename to pkg/storage/unified/sql/rvmanager/rv_manager.go index 858345b1fc2..b10685f22ad 100644 --- a/pkg/storage/unified/sql/rv_manager.go +++ b/pkg/storage/unified/sql/rvmanager/rv_manager.go @@ -1,4 +1,4 @@ -package sql +package rvmanager import ( "context" @@ -11,6 +11,7 @@ import ( "github.com/bwmarrin/snowflake" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" + "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/trace" @@ -20,6 +21,21 @@ import ( "github.com/grafana/grafana/pkg/storage/unified/sql/sqltemplate" ) +type contextKey string + +const txKey contextKey = "rvmanager_db_tx" + +func ContextWithTx(ctx context.Context, tx db.Tx) context.Context { + return context.WithValue(ctx, txKey, tx) +} + +func TxFromCtx(ctx context.Context) (db.Tx, bool) { + tx, ok := ctx.Value(txKey).(db.Tx) + return tx, ok +} + +var tracer = otel.Tracer("github.com/grafana/grafana/pkg/storage/unified/sql/rvmanager") + var ( rvmWriteDuration = promauto.NewHistogramVec(prometheus.HistogramOpts{ Name: "rvmanager_write_duration_seconds", @@ -62,8 +78,8 @@ const ( defaultBatchTimeout = 5 * time.Second ) -// resourceVersionManager handles resource version operations -type resourceVersionManager struct { +// ResourceVersionManager handles resource version operations +type ResourceVersionManager struct { dialect sqltemplate.Dialect db db.DB batchMu sync.RWMutex @@ -100,7 +116,7 @@ type ResourceManagerOptions struct { } // NewResourceVersionManager creates a new ResourceVersionManager -func NewResourceVersionManager(opts ResourceManagerOptions) (*resourceVersionManager, error) { +func NewResourceVersionManager(opts ResourceManagerOptions) (*ResourceVersionManager, error) { if opts.MaxBatchSize == 0 { opts.MaxBatchSize = defaultMaxBatchSize } @@ -113,7 +129,7 @@ func NewResourceVersionManager(opts ResourceManagerOptions) (*resourceVersionMan if opts.DB == nil { return nil, errors.New("db is required") } - return &resourceVersionManager{ + return &ResourceVersionManager{ dialect: opts.Dialect, db: opts.DB, batchChMap: make(map[string]chan *writeOp), @@ -123,7 +139,7 @@ func NewResourceVersionManager(opts ResourceManagerOptions) (*resourceVersionMan } // ExecWithRV executes the given function with an incremented resource version -func (m *resourceVersionManager) ExecWithRV(ctx context.Context, key *resourcepb.ResourceKey, fn WriteEventFunc) (rv int64, err error) { +func (m *ResourceVersionManager) ExecWithRV(ctx context.Context, key *resourcepb.ResourceKey, fn WriteEventFunc) (rv int64, err error) { rvmInflightWrites.WithLabelValues(key.Group, key.Resource).Inc() defer rvmInflightWrites.WithLabelValues(key.Group, key.Resource).Dec() @@ -179,7 +195,7 @@ func (m *resourceVersionManager) ExecWithRV(ctx context.Context, key *resourcepb } // startBatchProcessor is responsible for processing batches of write operations -func (m *resourceVersionManager) startBatchProcessor(group, resource string) { +func (m *ResourceVersionManager) startBatchProcessor(group, resource string) { ctx := context.TODO() batchKey := fmt.Sprintf("%s/%s", group, resource) @@ -216,7 +232,11 @@ func (m *resourceVersionManager) startBatchProcessor(group, resource string) { } } -func (m *resourceVersionManager) execBatch(ctx context.Context, group, resource string, batch []writeOp) { +var readCommitted = &sql.TxOptions{ + Isolation: sql.LevelReadCommitted, +} + +func (m *ResourceVersionManager) execBatch(ctx context.Context, group, resource string, batch []writeOp) { ctx, span := tracer.Start(ctx, "sql.resourceVersionManager.execBatch") defer span.End() @@ -245,7 +265,7 @@ func (m *resourceVersionManager) execBatch(ctx context.Context, group, resource guids := make([]string, len(batch)) // The GUIDs of the created resources in the same order as the batch rvs := make([]int64, len(batch)) // The RVs of the created resources in the same order as the batch - err = m.db.WithTx(ctx, ReadCommitted, func(ctx context.Context, tx db.Tx) error { + err = m.db.WithTx(ctx, readCommitted, func(ctx context.Context, tx db.Tx) error { span.AddEvent("starting_batch_transaction") writeTimer := prometheus.NewTimer(prometheus.ObserverFunc(func(v float64) { @@ -268,7 +288,7 @@ func (m *resourceVersionManager) execBatch(ctx context.Context, group, resource lockTimer := prometheus.NewTimer(prometheus.ObserverFunc(func(v float64) { rvmExecBatchPhaseDuration.WithLabelValues(group, resource, "waiting_for_lock").Observe(v) })) - rv, err := m.lock(ctx, tx, group, resource) + rv, err := m.Lock(ctx, tx, group, resource) lockTimer.ObserveDuration() if err != nil { span.AddEvent("resource_version_lock_failed", trace.WithAttributes( @@ -287,12 +307,12 @@ func (m *resourceVersionManager) execBatch(ctx context.Context, group, resource // Allocate the RVs for i, guid := range guids { guidToRV[guid] = rv - guidToSnowflakeRV[guid] = snowflakeFromRv(rv) + guidToSnowflakeRV[guid] = SnowflakeFromRv(rv) rvs[i] = rv rv++ } // Update the resource version for the created resources in both the resource and the resource history - if _, err := dbutil.Exec(ctx, tx, sqlResourceUpdateRV, sqlResourceUpdateRVRequest{ + if _, err := dbutil.Exec(ctx, tx, SqlResourceUpdateRV, SqlResourceUpdateRVRequest{ SQLTemplate: sqltemplate.New(m.dialect), GUIDToRV: guidToRV, }); err != nil { @@ -303,7 +323,7 @@ func (m *resourceVersionManager) execBatch(ctx context.Context, group, resource } span.AddEvent("resource_versions_updated") - if _, err := dbutil.Exec(ctx, tx, sqlResourceHistoryUpdateRV, sqlResourceUpdateRVRequest{ + if _, err := dbutil.Exec(ctx, tx, SqlResourceHistoryUpdateRV, SqlResourceUpdateRVRequest{ SQLTemplate: sqltemplate.New(m.dialect), GUIDToRV: guidToRV, GUIDToSnowflakeRV: guidToSnowflakeRV, @@ -316,7 +336,7 @@ func (m *resourceVersionManager) execBatch(ctx context.Context, group, resource span.AddEvent("resource_history_versions_updated") // Record the latest RV in the resource version table - err = m.saveRV(ctx, tx, group, resource, rv) + err = m.SaveRV(ctx, tx, group, resource, rv) if err != nil { span.AddEvent("save_rv_failed", trace.WithAttributes( attribute.String("error", err.Error()), @@ -346,24 +366,34 @@ func (m *resourceVersionManager) execBatch(ctx context.Context, group, resource // takes a unix microsecond rv and transforms into a snowflake format. The timestamp is converted from microsecond to // millisecond (the integer division) and the remainder is saved in the stepbits section. machine id is always 0 -func snowflakeFromRv(rv int64) int64 { +func SnowflakeFromRv(rv int64) int64 { return (((rv / 1000) - snowflake.Epoch) << (snowflake.NodeBits + snowflake.StepBits)) + (rv % 1000) } -// lock locks the resource version for the given key -func (m *resourceVersionManager) lock(ctx context.Context, x db.ContextExecer, group, resource string) (nextRV int64, err error) { +// helper utility to compare two RVs. The first RV must be in snowflake format. Will convert rv2 to snowflake and retry +// if comparison fails +func IsRvEqual(rv1, rv2 int64) bool { + if rv1 == rv2 { + return true + } + + return rv1 == SnowflakeFromRv(rv2) +} + +// Lock locks the resource version for the given key +func (m *ResourceVersionManager) Lock(ctx context.Context, x db.ContextExecer, group, resource string) (nextRV int64, err error) { // 1. Lock the row and prevent concurrent updates until the transaction is committed - res, err := dbutil.QueryRow(ctx, x, sqlResourceVersionGet, sqlResourceVersionGetRequest{ + res, err := dbutil.QueryRow(ctx, x, SqlResourceVersionGet, sqlResourceVersionGetRequest{ SQLTemplate: sqltemplate.New(m.dialect), Group: group, Resource: resource, - Response: new(resourceVersionResponse), + Response: new(ResourceVersionResponse), ReadOnly: false, // Lock the row for update }) if errors.Is(err, sql.ErrNoRows) { // If there wasn't a row for this resource, create it - if _, err = dbutil.Exec(ctx, x, sqlResourceVersionInsert, sqlResourceVersionUpsertRequest{ + if _, err = dbutil.Exec(ctx, x, SqlResourceVersionInsert, SqlResourceVersionUpsertRequest{ SQLTemplate: sqltemplate.New(m.dialect), Group: group, Resource: resource, @@ -372,11 +402,11 @@ func (m *resourceVersionManager) lock(ctx context.Context, x db.ContextExecer, g } // Fetch the newly created resource version - res, err = dbutil.QueryRow(ctx, x, sqlResourceVersionGet, sqlResourceVersionGetRequest{ + res, err = dbutil.QueryRow(ctx, x, SqlResourceVersionGet, sqlResourceVersionGetRequest{ SQLTemplate: sqltemplate.New(m.dialect), Group: group, Resource: resource, - Response: new(resourceVersionResponse), + Response: new(ResourceVersionResponse), ReadOnly: true, }) if err != nil { @@ -390,8 +420,8 @@ func (m *resourceVersionManager) lock(ctx context.Context, x db.ContextExecer, g return max(res.CurrentEpoch, res.ResourceVersion+1), nil } -func (m *resourceVersionManager) saveRV(ctx context.Context, x db.ContextExecer, group, resource string, rv int64) error { - _, err := dbutil.Exec(ctx, x, sqlResourceVersionUpdate, sqlResourceVersionUpsertRequest{ +func (m *ResourceVersionManager) SaveRV(ctx context.Context, x db.ContextExecer, group, resource string, rv int64) error { + _, err := dbutil.Exec(ctx, x, SqlResourceVersionUpdate, SqlResourceVersionUpsertRequest{ SQLTemplate: sqltemplate.New(m.dialect), Group: group, Resource: resource, diff --git a/pkg/storage/unified/sql/rv_manager_test.go b/pkg/storage/unified/sql/rvmanager/rv_manager_test.go similarity index 99% rename from pkg/storage/unified/sql/rv_manager_test.go rename to pkg/storage/unified/sql/rvmanager/rv_manager_test.go index 46d23d26a59..9a2e105aa2f 100644 --- a/pkg/storage/unified/sql/rv_manager_test.go +++ b/pkg/storage/unified/sql/rvmanager/rv_manager_test.go @@ -1,4 +1,4 @@ -package sql +package rvmanager import ( "testing" diff --git a/pkg/storage/unified/sql/rvmanager/templates.go b/pkg/storage/unified/sql/rvmanager/templates.go new file mode 100644 index 00000000000..65c91a273af --- /dev/null +++ b/pkg/storage/unified/sql/rvmanager/templates.go @@ -0,0 +1,30 @@ +package rvmanager + +import ( + "embed" + "fmt" + "text/template" +) + +// Templates setup. +var ( + //go:embed data/*.sql + sqlTemplatesFS embed.FS + + sqlTemplates = template.Must(template.New("sql").ParseFS(sqlTemplatesFS, `data/*.sql`)) +) + +func mustTemplate(filename string) *template.Template { + if t := sqlTemplates.Lookup(filename); t != nil { + return t + } + panic(fmt.Sprintf("template file not found: %s", filename)) +} + +var ( + SqlResourceUpdateRV = mustTemplate("resource_update_rv.sql") + SqlResourceHistoryUpdateRV = mustTemplate("resource_history_update_rv.sql") + SqlResourceVersionGet = mustTemplate("resource_version_get.sql") + SqlResourceVersionUpdate = mustTemplate("resource_version_update.sql") + SqlResourceVersionInsert = mustTemplate("resource_version_insert.sql") +) diff --git a/pkg/storage/unified/sql/server.go b/pkg/storage/unified/sql/server.go index 84eda71ca20..f4a1ee3ce77 100644 --- a/pkg/storage/unified/sql/server.go +++ b/pkg/storage/unified/sql/server.go @@ -20,6 +20,8 @@ import ( "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/storage/unified/resource" "github.com/grafana/grafana/pkg/storage/unified/sql/db/dbimpl" + "github.com/grafana/grafana/pkg/storage/unified/sql/rvmanager" + "github.com/grafana/grafana/pkg/storage/unified/sql/sqltemplate" ) type QOSEnqueueDequeuer interface { @@ -103,11 +105,34 @@ func NewResourceServer(opts ServerOptions) (resource.ResourceServer, error) { return nil, fmt.Errorf("error creating sqlkv: %s", err) } - kvBackend, err := resource.NewKVStorageBackend(resource.KVBackendOptions{ + kvBackendOpts := resource.KVBackendOptions{ KvStore: sqlkv, Tracer: opts.Tracer, Reg: opts.Reg, + } + + ctx := context.Background() + dbConn, err := eDB.Init(ctx) + if err != nil { + return nil, fmt.Errorf("error initializing DB: %w", err) + } + + dialect := sqltemplate.DialectForDriver(dbConn.DriverName()) + if dialect == nil { + return nil, fmt.Errorf("unsupported database driver: %s", dbConn.DriverName()) + } + + rvManager, err := rvmanager.NewResourceVersionManager(rvmanager.ResourceManagerOptions{ + Dialect: dialect, + DB: dbConn, }) + if err != nil { + return nil, fmt.Errorf("failed to create resource version manager: %w", err) + } + + // TODO add config to decide whether to pass RvManager or not + kvBackendOpts.RvManager = rvManager + kvBackend, err := resource.NewKVStorageBackend(kvBackendOpts) if err != nil { return nil, fmt.Errorf("error creating kv backend: %s", err) } diff --git a/pkg/storage/unified/testing/kv.go b/pkg/storage/unified/testing/kv.go index f30f1d761d7..d1900c7a46e 100644 --- a/pkg/storage/unified/testing/kv.go +++ b/pkg/storage/unified/testing/kv.go @@ -5,6 +5,8 @@ import ( "context" "fmt" "io" + "maps" + "slices" "strings" "testing" "time" @@ -28,6 +30,10 @@ const ( TestKVUnixTimestamp = "unix timestamp" TestKVBatchGet = "batch get operations" TestKVBatchDelete = "batch delete operations" + + // Use `eventsSection` as the section for the tests, as the sqlkv implementation + // needs a real section to determine which table to use. + testSection = "unified/events" ) // NewKVFunc is a function that creates a new KV instance for testing @@ -84,17 +90,31 @@ func RunKVTest(t *testing.T, newKV NewKVFunc, opts *KVTestOptions) { } } +func namespacedKeys(nsPrefix string, keys []string) []string { + prefixed := make([]string, 0, len(keys)) + for _, k := range keys { + prefixed = append(prefixed, nsPrefix+"/"+k) + } + + return prefixed +} + +func namespacedKey(nsPrefix, key string) string { + return namespacedKeys(nsPrefix, []string{key})[0] +} + func runTestKVGet(t *testing.T, kv resource.KV, nsPrefix string) { ctx := testutil.NewTestContext(t, time.Now().Add(30*time.Second)) - section := nsPrefix + "-get" + nsPrefix += "-get" t.Run("get existing key", func(t *testing.T) { // First save a key + existingKey := namespacedKey(nsPrefix, "existing-key") testValue := "test value for get" - saveKVHelper(t, kv, ctx, section, "existing-key", strings.NewReader(testValue)) + saveKVHelper(t, kv, ctx, testSection, existingKey, strings.NewReader(testValue)) // Now get it - reader, err := kv.Get(ctx, section, "existing-key") + reader, err := kv.Get(ctx, testSection, existingKey) require.NoError(t, err) // Read the value @@ -108,28 +128,33 @@ func runTestKVGet(t *testing.T, kv resource.KV, nsPrefix string) { }) t.Run("get non-existent key", func(t *testing.T) { - _, err := kv.Get(ctx, section, "non-existent-key") + _, err := kv.Get(ctx, testSection, namespacedKey(nsPrefix, "non-existent-key")) assert.Error(t, err) assert.Equal(t, resource.ErrNotFound, err) }) t.Run("get with empty section", func(t *testing.T) { - _, err := kv.Get(ctx, "", "some-key") + _, err := kv.Get(ctx, "", namespacedKey(nsPrefix, "some-key")) assert.Error(t, err) assert.Contains(t, err.Error(), "section is required") }) + + t.Run("get with empty key", func(t *testing.T) { + _, err := kv.Get(ctx, testSection, "") + assert.Error(t, err) + assert.Contains(t, err.Error(), "key is required") + }) } func runTestKVSave(t *testing.T, kv resource.KV, nsPrefix string) { ctx := testutil.NewTestContext(t, time.Now().Add(30*time.Second)) - section := nsPrefix + "-save" t.Run("save new key", func(t *testing.T) { testValue := "new test value" - saveKVHelper(t, kv, ctx, section, "new-key", strings.NewReader(testValue)) + saveKVHelper(t, kv, ctx, testSection, "new-key", strings.NewReader(testValue)) // Verify it was saved - reader, err := kv.Get(ctx, section, "new-key") + reader, err := kv.Get(ctx, testSection, "new-key") require.NoError(t, err) value, err := io.ReadAll(reader) @@ -140,6 +165,26 @@ func runTestKVSave(t *testing.T, kv resource.KV, nsPrefix string) { }) t.Run("save overwrite existing key", func(t *testing.T) { + // First save + saveKVHelper(t, kv, ctx, testSection, "overwrite-key", strings.NewReader("old value")) + + // Overwrite + newValue := "new value" + saveKVHelper(t, kv, ctx, testSection, "overwrite-key", strings.NewReader(newValue)) + + // Verify it was updated + reader, err := kv.Get(ctx, testSection, "overwrite-key") + require.NoError(t, err) + + value, err := io.ReadAll(reader) + require.NoError(t, err) + assert.Equal(t, newValue, string(value)) + err = reader.Close() + require.NoError(t, err) + }) + + t.Run("save overwrite existing key (datastore)", func(t *testing.T) { + section := "unified/data" // First save saveKVHelper(t, kv, ctx, section, "overwrite-key", strings.NewReader("old value")) @@ -166,10 +211,10 @@ func runTestKVSave(t *testing.T, kv resource.KV, nsPrefix string) { t.Run("save binary data", func(t *testing.T) { binaryData := []byte{0x00, 0x01, 0x02, 0x03, 0xFF, 0xFE, 0xFD} - saveKVHelper(t, kv, ctx, section, "binary-key", bytes.NewReader(binaryData)) + saveKVHelper(t, kv, ctx, testSection, "binary-key", bytes.NewReader(binaryData)) // Verify binary data - reader, err := kv.Get(ctx, section, "binary-key") + reader, err := kv.Get(ctx, testSection, "binary-key") require.NoError(t, err) value, err := io.ReadAll(reader) @@ -181,10 +226,10 @@ func runTestKVSave(t *testing.T, kv resource.KV, nsPrefix string) { t.Run("save key with no data", func(t *testing.T) { // Save a key with empty data - saveKVHelper(t, kv, ctx, section, "empty-key", strings.NewReader("")) + saveKVHelper(t, kv, ctx, testSection, "empty-key", strings.NewReader("")) // Verify it was saved with empty data - reader, err := kv.Get(ctx, section, "empty-key") + reader, err := kv.Get(ctx, testSection, "empty-key") require.NoError(t, err) value, err := io.ReadAll(reader) @@ -198,52 +243,59 @@ func runTestKVSave(t *testing.T, kv resource.KV, nsPrefix string) { func runTestKVDelete(t *testing.T, kv resource.KV, nsPrefix string) { ctx := testutil.NewTestContext(t, time.Now().Add(30*time.Second)) - section := nsPrefix + "-delete" + nsPrefix += "-delete" t.Run("delete existing key", func(t *testing.T) { // First create a key - saveKVHelper(t, kv, ctx, section, "delete-key", strings.NewReader("delete me")) + deleteKey := namespacedKey(nsPrefix, "delete-key") + saveKVHelper(t, kv, ctx, testSection, deleteKey, strings.NewReader("delete me")) // Verify it exists - _, err := kv.Get(ctx, section, "delete-key") + _, err := kv.Get(ctx, testSection, deleteKey) require.NoError(t, err) // Delete it - err = kv.Delete(ctx, section, "delete-key") + err = kv.Delete(ctx, testSection, deleteKey) require.NoError(t, err) // Verify it's gone - _, err = kv.Get(ctx, section, "delete-key") + _, err = kv.Get(ctx, testSection, deleteKey) assert.Error(t, err) assert.Equal(t, resource.ErrNotFound, err) }) t.Run("delete non-existent key", func(t *testing.T) { - err := kv.Delete(ctx, section, "non-existent-delete-key") + err := kv.Delete(ctx, testSection, namespacedKey(nsPrefix, "non-existent-delete-key")) assert.Error(t, err) assert.Equal(t, resource.ErrNotFound, err) }) t.Run("delete with empty section", func(t *testing.T) { - err := kv.Delete(ctx, "", "some-key") + err := kv.Delete(ctx, "", namespacedKey(nsPrefix, "some-key")) assert.Error(t, err) assert.Contains(t, err.Error(), "section is required") }) + + t.Run("delete with empty key", func(t *testing.T) { + err := kv.Delete(ctx, testSection, "") + assert.Error(t, err) + assert.Contains(t, err.Error(), "key is required") + }) } func runTestKVKeys(t *testing.T, kv resource.KV, nsPrefix string) { ctx := testutil.NewTestContext(t, time.Now().Add(30*time.Second)) - section := nsPrefix + "-keys" + nsPrefix += "-keys" // Setup test data - testKeys := []string{"a1", "a2", "b1", "b2", "c1"} + testKeys := namespacedKeys(nsPrefix, []string{"a1", "a2", "b1", "b2", "c1"}) for _, key := range testKeys { - saveKVHelper(t, kv, ctx, section, key, strings.NewReader("value"+key)) + saveKVHelper(t, kv, ctx, testSection, key, strings.NewReader("value"+key)) } t.Run("list all keys", func(t *testing.T) { var keys []string - for k, err := range kv.Keys(ctx, section, resource.ListOptions{}) { + for k, err := range kv.Keys(ctx, testSection, resource.ListOptions{}) { require.NoError(t, err) keys = append(keys, k) } @@ -256,134 +308,188 @@ func runTestKVKeys(t *testing.T, kv resource.KV, nsPrefix string) { for k, err := range kv.Keys(ctx, "", resource.ListOptions{}) { if err != nil { errors = append(errors, err) - break + continue } keys = append(keys, k) } - assert.Len(t, errors, 1) + require.Len(t, errors, 1) assert.Contains(t, errors[0].Error(), "section is required") assert.Empty(t, keys) }) + t.Run("invalid sort option, defaults to asc", func(t *testing.T) { + var keys []string + var errors []error + for k, err := range kv.Keys(ctx, testSection, resource.ListOptions{ + Sort: resource.SortOrder(100), + }) { + if err != nil { + errors = append(errors, err) + continue + } + keys = append(keys, k) + } + assert.Empty(t, errors) + assert.Equal(t, testKeys, keys) + }) + + t.Run("list keys with end key < start key", func(t *testing.T) { + var keys []string + var errors []error + for k, err := range kv.Keys(ctx, testSection, resource.ListOptions{ + StartKey: namespacedKey(nsPrefix, "c"), + EndKey: namespacedKey(nsPrefix, "a"), + }) { + if err != nil { + errors = append(errors, err) + continue + } + keys = append(keys, k) + } + // Nothing is yielded + assert.Empty(t, errors) + assert.Empty(t, keys) + }) + t.Run("list keys returns 0 keys", func(t *testing.T) { - // Use a different section with no keys - emptySection := nsPrefix + "-empty-keys" + // Use a key range with no keys. + startKey, endKey := "aaaaa", "aaaaz" var keys []string - for k, err := range kv.Keys(ctx, emptySection, resource.ListOptions{}) { + for k, err := range kv.Keys(ctx, testSection, resource.ListOptions{ + StartKey: startKey, + EndKey: endKey, + }) { require.NoError(t, err) keys = append(keys, k) } assert.Empty(t, keys) assert.Len(t, keys, 0) }) + + t.Run("interrupting the iterator", func(t *testing.T) { + var keys []string + for k, err := range kv.Keys(ctx, testSection, resource.ListOptions{}) { + require.NoError(t, err) + keys = append(keys, k) + + if len(keys) == 2 { + break + } + } + + assert.Equal(t, namespacedKeys(nsPrefix, []string{"a1", "a2"}), keys) + }) } func runTestKVKeysWithLimits(t *testing.T, kv resource.KV, nsPrefix string) { ctx := testutil.NewTestContext(t, time.Now().Add(30*time.Second)) - section := nsPrefix + "-keys-limits" + nsPrefix += "-keys-with-limits" // Setup test data - testKeys := []string{"a1", "a2", "b1", "b2", "c1", "c2", "d1", "d2"} + testKeys := namespacedKeys(nsPrefix, []string{"a1", "a2", "b1", "b2", "c1", "c2", "d1", "d2"}) for _, key := range testKeys { - saveKVHelper(t, kv, ctx, section, key, strings.NewReader("value"+key)) + saveKVHelper(t, kv, ctx, testSection, key, strings.NewReader("value"+key)) } t.Run("keys with limit", func(t *testing.T) { var keys []string - for k, err := range kv.Keys(ctx, section, resource.ListOptions{Limit: 3}) { + for k, err := range kv.Keys(ctx, testSection, resource.ListOptions{Limit: 3}) { require.NoError(t, err) keys = append(keys, k) } - assert.Equal(t, []string{"a1", "a2", "b1"}, keys) + assert.Equal(t, namespacedKeys(nsPrefix, []string{"a1", "a2", "b1"}), keys) }) t.Run("keys with range", func(t *testing.T) { var keys []string - for k, err := range kv.Keys(ctx, section, resource.ListOptions{StartKey: "b", EndKey: "d"}) { - require.NoError(t, err) - keys = append(keys, k) - } - assert.Equal(t, []string{"b1", "b2", "c1", "c2"}, keys) - }) - - t.Run("keys with prefix", func(t *testing.T) { - var keys []string - for k, err := range kv.Keys(ctx, section, resource.ListOptions{ - StartKey: "c", - EndKey: resource.PrefixRangeEnd("c"), + for k, err := range kv.Keys(ctx, testSection, resource.ListOptions{ + StartKey: namespacedKey(nsPrefix, "b"), + EndKey: namespacedKey(nsPrefix, "d"), }) { require.NoError(t, err) keys = append(keys, k) } - assert.Equal(t, []string{"c1", "c2"}, keys) + assert.Equal(t, namespacedKeys(nsPrefix, []string{"b1", "b2", "c1", "c2"}), keys) + }) + + t.Run("keys with prefix", func(t *testing.T) { + var keys []string + for k, err := range kv.Keys(ctx, testSection, resource.ListOptions{ + StartKey: namespacedKey(nsPrefix, "c"), + EndKey: namespacedKey(nsPrefix, resource.PrefixRangeEnd("c")), + }) { + require.NoError(t, err) + keys = append(keys, k) + } + assert.Equal(t, namespacedKeys(nsPrefix, []string{"c1", "c2"}), keys) }) t.Run("keys with limit and range", func(t *testing.T) { var keys []string - for k, err := range kv.Keys(ctx, section, resource.ListOptions{ - StartKey: "a", - EndKey: "c", + for k, err := range kv.Keys(ctx, testSection, resource.ListOptions{ + StartKey: namespacedKey(nsPrefix, "a"), + EndKey: namespacedKey(nsPrefix, "c"), Limit: 2, }) { require.NoError(t, err) keys = append(keys, k) } - assert.Equal(t, []string{"a1", "a2"}, keys) + assert.Equal(t, namespacedKeys(nsPrefix, []string{"a1", "a2"}), keys) }) } func runTestKVKeysWithSort(t *testing.T, kv resource.KV, nsPrefix string) { ctx := testutil.NewTestContext(t, time.Now().Add(30*time.Second)) - section := nsPrefix + "-keys-sort" + nsPrefix += "-keys-with-sort" // Setup test data - testKeys := []string{"a1", "a2", "b1", "b2", "c1"} + testKeys := namespacedKeys(nsPrefix, []string{"a1", "a2", "b1", "b2", "c1"}) for _, key := range testKeys { - saveKVHelper(t, kv, ctx, section, key, strings.NewReader("value"+key)) + saveKVHelper(t, kv, ctx, testSection, key, strings.NewReader("value"+key)) } t.Run("keys in ascending order (default)", func(t *testing.T) { var keys []string - for k, err := range kv.Keys(ctx, section, resource.ListOptions{Sort: resource.SortOrderAsc}) { + for k, err := range kv.Keys(ctx, testSection, resource.ListOptions{Sort: resource.SortOrderAsc}) { require.NoError(t, err) keys = append(keys, k) } - assert.Equal(t, []string{"a1", "a2", "b1", "b2", "c1"}, keys) + assert.Equal(t, namespacedKeys(nsPrefix, []string{"a1", "a2", "b1", "b2", "c1"}), keys) }) t.Run("keys in descending order", func(t *testing.T) { var keys []string - for k, err := range kv.Keys(ctx, section, resource.ListOptions{Sort: resource.SortOrderDesc}) { + for k, err := range kv.Keys(ctx, testSection, resource.ListOptions{Sort: resource.SortOrderDesc}) { require.NoError(t, err) keys = append(keys, k) } - assert.Equal(t, []string{"c1", "b2", "b1", "a2", "a1"}, keys) + assert.Equal(t, namespacedKeys(nsPrefix, []string{"c1", "b2", "b1", "a2", "a1"}), keys) }) t.Run("keys descending with prefix", func(t *testing.T) { var keys []string - for k, err := range kv.Keys(ctx, section, resource.ListOptions{ - StartKey: "a", - EndKey: resource.PrefixRangeEnd("a"), + for k, err := range kv.Keys(ctx, testSection, resource.ListOptions{ + StartKey: namespacedKey(nsPrefix, "a"), + EndKey: namespacedKey(nsPrefix, resource.PrefixRangeEnd("a")), Sort: resource.SortOrderDesc, }) { require.NoError(t, err) keys = append(keys, k) } - assert.Equal(t, []string{"a2", "a1"}, keys) + assert.Equal(t, namespacedKeys(nsPrefix, []string{"a2", "a1"}), keys) }) t.Run("keys descending with limit", func(t *testing.T) { var keys []string - for k, err := range kv.Keys(ctx, section, resource.ListOptions{ + for k, err := range kv.Keys(ctx, testSection, resource.ListOptions{ Sort: resource.SortOrderDesc, Limit: 3, }) { require.NoError(t, err) keys = append(keys, k) } - assert.Equal(t, []string{"c1", "b2", "b1"}, keys) + assert.Equal(t, namespacedKeys(nsPrefix, []string{"c1", "b2", "b1"}), keys) }) } @@ -539,29 +645,29 @@ func runTestKVUnixTimestamp(t *testing.T, kv resource.KV, nsPrefix string) { func runTestKVBatchGet(t *testing.T, kv resource.KV, nsPrefix string) { ctx := testutil.NewTestContext(t, time.Now().Add(30*time.Second)) - section := nsPrefix + "-batchget" + nsPrefix += "-batchget" t.Run("batch get existing keys", func(t *testing.T) { // Setup test data testData := map[string]string{ - "key1": "value1", - "key2": "value2", - "key3": "value3", + namespacedKey(nsPrefix, "key1"): "value1", + namespacedKey(nsPrefix, "key2"): "value2", + namespacedKey(nsPrefix, "key3"): "value3", } // Save test data for key, value := range testData { - saveKVHelper(t, kv, ctx, section, key, strings.NewReader(value)) + saveKVHelper(t, kv, ctx, testSection, key, strings.NewReader(value)) } // Batch get all keys - keys := []string{"key1", "key2", "key3"} + keys := namespacedKeys(nsPrefix, []string{"key1", "key2", "key3"}) type result struct { key string value string } var results []result - for kv, err := range kv.BatchGet(ctx, section, keys) { + for kv, err := range kv.BatchGet(ctx, testSection, keys) { require.NoError(t, err) value, err := io.ReadAll(kv.Value) require.NoError(t, err) @@ -571,10 +677,10 @@ func runTestKVBatchGet(t *testing.T, kv resource.KV, nsPrefix string) { } // Verify results - assert.Len(t, results, 3) + require.Len(t, results, 3) // Check that all keys are present and in order - expectedKeys := []string{"key1", "key2", "key3"} + expectedKeys := namespacedKeys(nsPrefix, []string{"key1", "key2", "key3"}) actualKeys := make([]string, len(results)) for i, r := range results { actualKeys[i] = r.key @@ -583,22 +689,40 @@ func runTestKVBatchGet(t *testing.T, kv resource.KV, nsPrefix string) { // Verify values for _, r := range results { - assert.Equal(t, testData[r.key], r.value) + assert.Equal(t, testData[r.key], r.value, "key = %s", r.key) } }) + t.Run("batch get with empty section", func(t *testing.T) { + var kvs []resource.KeyValue + var errs []error + keys := namespacedKeys(nsPrefix, []string{"key1", "key2", "key3"}) + for kv, err := range kv.BatchGet(ctx, "", keys) { + if err != nil { + errs = append(errs, err) + continue + } + + kvs = append(kvs, kv) + } + + require.Len(t, errs, 1) + assert.Contains(t, errs[0].Error(), "section is required") + assert.Empty(t, kvs) + }) + t.Run("batch get with non-existent keys", func(t *testing.T) { // Setup some test data - saveKVHelper(t, kv, ctx, section, "existing-key", strings.NewReader("existing-value")) + saveKVHelper(t, kv, ctx, testSection, namespacedKey(nsPrefix, "existing-key"), strings.NewReader("existing-value")) // Batch get with mix of existing and non-existent keys - keys := []string{"existing-key", "non-existent-1", "non-existent-2"} + keys := namespacedKeys(nsPrefix, []string{"existing-key", "non-existent-1", "non-existent-2"}) type result struct { key string value string } var results []result - for kv, err := range kv.BatchGet(ctx, section, keys) { + for kv, err := range kv.BatchGet(ctx, testSection, keys) { require.NoError(t, err) value, err := io.ReadAll(kv.Value) require.NoError(t, err) @@ -608,15 +732,15 @@ func runTestKVBatchGet(t *testing.T, kv resource.KV, nsPrefix string) { } // Should only return the existing key - assert.Len(t, results, 1) - assert.Equal(t, "existing-key", results[0].key) + require.Len(t, results, 1) + assert.Equal(t, namespacedKey(nsPrefix, "existing-key"), results[0].key) assert.Equal(t, "existing-value", results[0].value) }) t.Run("batch get with all non-existent keys", func(t *testing.T) { - keys := []string{"non-existent-1", "non-existent-2", "non-existent-3"} + keys := namespacedKeys(nsPrefix, []string{"non-existent-1", "non-existent-2", "non-existent-3"}) var results []resource.KeyValue - for kv, err := range kv.BatchGet(ctx, section, keys) { + for kv, err := range kv.BatchGet(ctx, testSection, keys) { require.NoError(t, err) results = append(results, kv) } @@ -628,7 +752,7 @@ func runTestKVBatchGet(t *testing.T, kv resource.KV, nsPrefix string) { t.Run("batch get with empty keys list", func(t *testing.T) { keys := []string{} var results []resource.KeyValue - for kv, err := range kv.BatchGet(ctx, section, keys) { + for kv, err := range kv.BatchGet(ctx, testSection, keys) { require.NoError(t, err) results = append(results, kv) } @@ -638,16 +762,16 @@ func runTestKVBatchGet(t *testing.T, kv resource.KV, nsPrefix string) { }) t.Run("batch get with empty section", func(t *testing.T) { - keys := []string{"some-key"} + keys := namespacedKeys(nsPrefix, []string{"some-key"}) var errors []error for kv, err := range kv.BatchGet(ctx, "", keys) { if err != nil { errors = append(errors, err) - break + continue } _ = kv // unused } - assert.Len(t, errors, 1) + require.Len(t, errors, 1) assert.Contains(t, errors[0].Error(), "section is required") }) @@ -661,13 +785,13 @@ func runTestKVBatchGet(t *testing.T, kv resource.KV, nsPrefix string) { // Save test data for key, value := range testData { - saveKVHelper(t, kv, ctx, section, key, strings.NewReader(value)) + saveKVHelper(t, kv, ctx, testSection, namespacedKey(nsPrefix, key), strings.NewReader(value)) } // Batch get in specific order - keys := []string{"z-key", "a-key", "m-key"} + keys := namespacedKeys(nsPrefix, []string{"z-key", "invalid-key1", "a-key", "invalid-key2", "m-key", "invalid-key3"}) var results []string - for kv, err := range kv.BatchGet(ctx, section, keys) { + for kv, err := range kv.BatchGet(ctx, testSection, keys) { require.NoError(t, err) err = kv.Value.Close() require.NoError(t, err) @@ -675,43 +799,43 @@ func runTestKVBatchGet(t *testing.T, kv resource.KV, nsPrefix string) { } // Verify order is preserved - assert.Len(t, results, 3) - expectedOrder := []string{"z-key", "a-key", "m-key"} + require.Len(t, results, 3) + expectedOrder := namespacedKeys(nsPrefix, []string{"z-key", "a-key", "m-key"}) assert.Equal(t, expectedOrder, results) }) } func runTestKVBatchDelete(t *testing.T, kv resource.KV, nsPrefix string) { ctx := testutil.NewTestContext(t, time.Now().Add(30*time.Second)) - section := nsPrefix + "-batchdelete" + nsPrefix += "-batchdelete" t.Run("batch delete existing keys", func(t *testing.T) { // Setup test data testData := map[string]string{ - "key1": "value1", - "key2": "value2", - "key3": "value3", + namespacedKey(nsPrefix, "key1"): "value1", + namespacedKey(nsPrefix, "key2"): "value2", + namespacedKey(nsPrefix, "key3"): "value3", } // Save test data for key, value := range testData { - saveKVHelper(t, kv, ctx, section, key, strings.NewReader(value)) + saveKVHelper(t, kv, ctx, testSection, key, strings.NewReader(value)) } // Verify keys exist before deletion for key := range testData { - _, err := kv.Get(ctx, section, key) + _, err := kv.Get(ctx, testSection, key) require.NoError(t, err) } // Batch delete all keys - keys := []string{"key1", "key2", "key3"} - err := kv.BatchDelete(ctx, section, keys) + keys := slices.Collect(maps.Keys(testData)) + err := kv.BatchDelete(ctx, testSection, keys) require.NoError(t, err) // Verify all keys are deleted for _, key := range keys { - _, err := kv.Get(ctx, section, key) + _, err := kv.Get(ctx, testSection, key) assert.Error(t, err) assert.Equal(t, resource.ErrNotFound, err) } @@ -719,39 +843,40 @@ func runTestKVBatchDelete(t *testing.T, kv resource.KV, nsPrefix string) { t.Run("batch delete with non-existent keys", func(t *testing.T) { // Setup some test data - saveKVHelper(t, kv, ctx, section, "existing-key-1", strings.NewReader("value1")) - saveKVHelper(t, kv, ctx, section, "existing-key-2", strings.NewReader("value2")) + key1, key2 := namespacedKey(nsPrefix, "existing-key-1"), namespacedKey(nsPrefix, "existing-key-2") + saveKVHelper(t, kv, ctx, testSection, key1, strings.NewReader("value1")) + saveKVHelper(t, kv, ctx, testSection, key2, strings.NewReader("value2")) // Batch delete with mix of existing and non-existent keys - keys := []string{"existing-key-1", "non-existent-1", "existing-key-2", "non-existent-2"} - err := kv.BatchDelete(ctx, section, keys) + keys := []string{key1, namespacedKey(nsPrefix, "non-existent-1"), key2, namespacedKey(nsPrefix, "non-existent-2")} + err := kv.BatchDelete(ctx, testSection, keys) require.NoError(t, err) // Verify existing keys are deleted - _, err = kv.Get(ctx, section, "existing-key-1") - assert.Error(t, err) + _, err = kv.Get(ctx, testSection, key1) + require.Error(t, err) assert.Equal(t, resource.ErrNotFound, err) - _, err = kv.Get(ctx, section, "existing-key-2") - assert.Error(t, err) + _, err = kv.Get(ctx, testSection, key2) + require.Error(t, err) assert.Equal(t, resource.ErrNotFound, err) }) t.Run("batch delete with all non-existent keys", func(t *testing.T) { // Batch delete keys that don't exist - keys := []string{"non-existent-1", "non-existent-2", "non-existent-3"} - err := kv.BatchDelete(ctx, section, keys) + keys := namespacedKeys(nsPrefix, []string{"non-existent-1", "non-existent-2", "non-existent-3"}) + err := kv.BatchDelete(ctx, testSection, keys) require.NoError(t, err) }) t.Run("batch delete with empty keys list", func(t *testing.T) { keys := []string{} - err := kv.BatchDelete(ctx, section, keys) + err := kv.BatchDelete(ctx, testSection, keys) require.NoError(t, err) }) t.Run("batch delete with empty section", func(t *testing.T) { - keys := []string{"some-key"} + keys := namespacedKeys(nsPrefix, []string{"some-key"}) err := kv.BatchDelete(ctx, "", keys) assert.Error(t, err) assert.Contains(t, err.Error(), "section is required") @@ -759,27 +884,27 @@ func runTestKVBatchDelete(t *testing.T, kv resource.KV, nsPrefix string) { t.Run("batch delete preserves other keys", func(t *testing.T) { // Setup test data - saveKVHelper(t, kv, ctx, section, "keep-key-1", strings.NewReader("keep-value-1")) - saveKVHelper(t, kv, ctx, section, "delete-key-1", strings.NewReader("delete-value-1")) - saveKVHelper(t, kv, ctx, section, "keep-key-2", strings.NewReader("keep-value-2")) - saveKVHelper(t, kv, ctx, section, "delete-key-2", strings.NewReader("delete-value-2")) + saveKVHelper(t, kv, ctx, testSection, namespacedKey(nsPrefix, "keep-key-1"), strings.NewReader("keep-value-1")) + saveKVHelper(t, kv, ctx, testSection, namespacedKey(nsPrefix, "delete-key-1"), strings.NewReader("delete-value-1")) + saveKVHelper(t, kv, ctx, testSection, namespacedKey(nsPrefix, "keep-key-2"), strings.NewReader("keep-value-2")) + saveKVHelper(t, kv, ctx, testSection, namespacedKey(nsPrefix, "delete-key-2"), strings.NewReader("delete-value-2")) // Batch delete specific keys - keys := []string{"delete-key-1", "delete-key-2"} - err := kv.BatchDelete(ctx, section, keys) + keys := namespacedKeys(nsPrefix, []string{"delete-key-1", "delete-key-2"}) + err := kv.BatchDelete(ctx, testSection, keys) require.NoError(t, err) // Verify deleted keys are gone - _, err = kv.Get(ctx, section, "delete-key-1") + _, err = kv.Get(ctx, testSection, namespacedKey(nsPrefix, "delete-key-1")) assert.Error(t, err) assert.Equal(t, resource.ErrNotFound, err) - _, err = kv.Get(ctx, section, "delete-key-2") + _, err = kv.Get(ctx, testSection, namespacedKey(nsPrefix, "delete-key-2")) assert.Error(t, err) assert.Equal(t, resource.ErrNotFound, err) // Verify kept keys still exist - reader, err := kv.Get(ctx, section, "keep-key-1") + reader, err := kv.Get(ctx, testSection, namespacedKey(nsPrefix, "keep-key-1")) require.NoError(t, err) value, err := io.ReadAll(reader) require.NoError(t, err) @@ -787,7 +912,7 @@ func runTestKVBatchDelete(t *testing.T, kv resource.KV, nsPrefix string) { err = reader.Close() require.NoError(t, err) - reader, err = kv.Get(ctx, section, "keep-key-2") + reader, err = kv.Get(ctx, testSection, namespacedKey(nsPrefix, "keep-key-2")) require.NoError(t, err) value, err = io.ReadAll(reader) require.NoError(t, err) @@ -800,6 +925,7 @@ func runTestKVBatchDelete(t *testing.T, kv resource.KV, nsPrefix string) { // saveKVHelper is a helper function to save data to KV store using the new WriteCloser interface func saveKVHelper(t *testing.T, kv resource.KV, ctx context.Context, section, key string, value io.Reader) { t.Helper() + writer, err := kv.Save(ctx, section, key) require.NoError(t, err) _, err = io.Copy(writer, value) diff --git a/pkg/storage/unified/testing/kv_test.go b/pkg/storage/unified/testing/kv_test.go index 4dbd27d5ec9..5e94ccd8a7f 100644 --- a/pkg/storage/unified/testing/kv_test.go +++ b/pkg/storage/unified/testing/kv_test.go @@ -47,16 +47,8 @@ func TestSQLKV(t *testing.T) { }, &KVTestOptions{ NSPrefix: "sql-kv-test", SkipTests: map[string]bool{ - TestKVGet: true, - TestKVSave: true, - TestKVDelete: true, - TestKVKeys: true, - TestKVKeysWithLimits: true, - TestKVKeysWithSort: true, - TestKVConcurrent: true, - TestKVUnixTimestamp: true, - TestKVBatchGet: true, - TestKVBatchDelete: true, + TestKVConcurrent: true, + TestKVUnixTimestamp: true, }, }) } diff --git a/pkg/tests/api/alerting/api_convert_prometheus_test.go b/pkg/tests/api/alerting/api_convert_prometheus_test.go index 4fc9151602f..f33ce55d851 100644 --- a/pkg/tests/api/alerting/api_convert_prometheus_test.go +++ b/pkg/tests/api/alerting/api_convert_prometheus_test.go @@ -1166,11 +1166,12 @@ func TestIntegrationConvertPrometheusEndpoints_Editor(t *testing.T) { testinfra.SQLiteIntegrationTest(t) dir, gpath := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{ - DisableLegacyAlerting: true, - EnableUnifiedAlerting: true, - DisableAnonymous: true, - AppModeProduction: true, - EnableRecordingRules: true, + DisableAuthZClientCache: true, + DisableLegacyAlerting: true, + EnableUnifiedAlerting: true, + DisableAnonymous: true, + AppModeProduction: true, + EnableRecordingRules: true, }) grafanaListedAddr, env := testinfra.StartGrafanaEnv(t, dir, gpath) diff --git a/pkg/tests/api/alerting/api_provisioning_test.go b/pkg/tests/api/alerting/api_provisioning_test.go index 20484a38bf4..e952740f2e6 100644 --- a/pkg/tests/api/alerting/api_provisioning_test.go +++ b/pkg/tests/api/alerting/api_provisioning_test.go @@ -1192,10 +1192,11 @@ func TestIntegrationExportFileProvisionContactPoints(t *testing.T) { func TestIntegrationFullpath(t *testing.T) { dir, p := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{ - DisableLegacyAlerting: true, - EnableUnifiedAlerting: true, - DisableAnonymous: true, - AppModeProduction: true, + DisableAuthZClientCache: true, + DisableLegacyAlerting: true, + EnableUnifiedAlerting: true, + DisableAnonymous: true, + AppModeProduction: true, }) grafanaListedAddr, env := testinfra.StartGrafanaEnv(t, dir, p) diff --git a/pkg/tests/api/alerting/api_ruler_test.go b/pkg/tests/api/alerting/api_ruler_test.go index 9e8855d8f19..a05829976f4 100644 --- a/pkg/tests/api/alerting/api_ruler_test.go +++ b/pkg/tests/api/alerting/api_ruler_test.go @@ -53,10 +53,11 @@ func TestIntegrationAlertRulePermissions(t *testing.T) { testinfra.SQLiteIntegrationTest(t) dir, p := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{ - DisableLegacyAlerting: true, - EnableUnifiedAlerting: true, - DisableAnonymous: true, - AppModeProduction: true, + DisableAuthZClientCache: true, + DisableLegacyAlerting: true, + EnableUnifiedAlerting: true, + DisableAnonymous: true, + AppModeProduction: true, }) grafanaListedAddr, env := testinfra.StartGrafanaEnv(t, dir, p) @@ -360,10 +361,11 @@ func TestIntegrationAlertRuleNestedPermissions(t *testing.T) { testinfra.SQLiteIntegrationTest(t) dir, p := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{ - DisableLegacyAlerting: true, - EnableUnifiedAlerting: true, - DisableAnonymous: true, - AppModeProduction: true, + DisableAuthZClientCache: true, + DisableLegacyAlerting: true, + EnableUnifiedAlerting: true, + DisableAnonymous: true, + AppModeProduction: true, }) grafanaListedAddr, env := testinfra.StartGrafanaEnv(t, dir, p) @@ -1429,10 +1431,11 @@ func TestIntegrationRuleGroupSequence(t *testing.T) { testinfra.SQLiteIntegrationTest(t) dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{ - DisableLegacyAlerting: true, - EnableUnifiedAlerting: true, - DisableAnonymous: true, - AppModeProduction: true, + DisableAuthZClientCache: true, + DisableLegacyAlerting: true, + EnableUnifiedAlerting: true, + DisableAnonymous: true, + AppModeProduction: true, }) grafanaListedAddr, env := testinfra.StartGrafanaEnv(t, dir, path) diff --git a/pkg/tests/api/alerting/test-data/alert-notifiers-v1-snapshot.json b/pkg/tests/api/alerting/test-data/alert-notifiers-v1-snapshot.json index 7bf5ff10535..b3dabb7cde2 100644 --- a/pkg/tests/api/alerting/test-data/alert-notifiers-v1-snapshot.json +++ b/pkg/tests/api/alerting/test-data/alert-notifiers-v1-snapshot.json @@ -82,6 +82,7 @@ "is": "" }, "required": true, + "protected": true, "validationRule": "", "secure": true, "dependsOn": "", @@ -208,6 +209,7 @@ "is": "" }, "required": true, + "protected": true, "validationRule": "", "secure": true, "dependsOn": "", @@ -352,6 +354,7 @@ "is": "" }, "required": true, + "protected": true, "validationRule": "", "secure": true, "dependsOn": "", @@ -451,6 +454,7 @@ "is": "" }, "required": true, + "protected": true, "validationRule": "", "secure": false, "dependsOn": "", @@ -748,6 +752,7 @@ "is": "" }, "required": true, + "protected": true, "validationRule": "", "secure": false, "dependsOn": "", @@ -910,6 +915,7 @@ "is": "" }, "required": true, + "protected": true, "validationRule": "", "secure": false, "dependsOn": "", @@ -1194,6 +1200,7 @@ "is": "" }, "required": true, + "protected": true, "validationRule": "", "secure": false, "dependsOn": "", @@ -1392,6 +1399,7 @@ "is": "" }, "required": true, + "protected": true, "validationRule": "", "secure": false, "dependsOn": "", @@ -1793,6 +1801,7 @@ "is": "" }, "required": false, + "protected": true, "validationRule": "", "secure": false, "dependsOn": "", @@ -1820,6 +1829,7 @@ "is": "" }, "required": true, + "protected": true, "validationRule": "", "secure": false, "dependsOn": "", @@ -2318,6 +2328,7 @@ "is": "" }, "required": true, + "protected": true, "validationRule": "", "secure": false, "dependsOn": "", @@ -2610,6 +2621,7 @@ "is": "" }, "required": true, + "protected": true, "validationRule": "", "secure": true, "dependsOn": "token", @@ -2628,6 +2640,7 @@ "is": "" }, "required": false, + "protected": true, "validationRule": "", "secure": false, "dependsOn": "", @@ -2953,6 +2966,7 @@ "is": "" }, "required": true, + "protected": true, "validationRule": "", "secure": false, "dependsOn": "", @@ -3303,6 +3317,7 @@ "is": "" }, "required": true, + "protected": true, "validationRule": "", "secure": true, "dependsOn": "", @@ -3393,6 +3408,7 @@ "is": "" }, "required": false, + "protected": true, "validationRule": "", "secure": false, "dependsOn": "", @@ -3474,6 +3490,7 @@ "is": "" }, "required": true, + "protected": true, "validationRule": "", "secure": false, "dependsOn": "", @@ -3916,6 +3933,7 @@ "is": "" }, "required": true, + "protected": true, "validationRule": "", "secure": false, "dependsOn": "", @@ -4114,6 +4132,7 @@ "is": "" }, "required": false, + "protected": true, "validationRule": "", "secure": false, "dependsOn": "", @@ -4201,6 +4220,7 @@ "is": "" }, "required": true, + "protected": true, "validationRule": "", "secure": true, "dependsOn": "secret", diff --git a/pkg/tests/api/annotations/annotations_test.go b/pkg/tests/api/annotations/annotations_test.go index 89e7131d4b5..6391d37d762 100644 --- a/pkg/tests/api/annotations/annotations_test.go +++ b/pkg/tests/api/annotations/annotations_test.go @@ -32,8 +32,9 @@ func TestIntegrationAnnotations(t *testing.T) { testutil.SkipIntegrationTestInShortMode(t) dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{ - DisableAnonymous: true, - EnableFeatureToggles: []string{featuremgmt.FlagAnnotationPermissionUpdate}, + DisableAuthZClientCache: true, + DisableAnonymous: true, + EnableFeatureToggles: []string{featuremgmt.FlagAnnotationPermissionUpdate}, }) grafanaListedAddr, env := testinfra.StartGrafanaEnv(t, dir, path) noneUserID := tests.CreateUser(t, env.SQLStore, env.Cfg, user.CreateUserCommand{ diff --git a/pkg/tests/api/dashboards/api_dashboards_test.go b/pkg/tests/api/dashboards/api_dashboards_test.go index fcfb09cb5ba..84ae8c62c62 100644 --- a/pkg/tests/api/dashboards/api_dashboards_test.go +++ b/pkg/tests/api/dashboards/api_dashboards_test.go @@ -12,6 +12,7 @@ import ( "testing" "time" + "github.com/grafana/grafana/pkg/setting" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -38,8 +39,15 @@ func TestMain(m *testing.M) { func TestIntegrationDashboardServiceValidation(t *testing.T) { testutil.SkipIntegrationTestInShortMode(t) + unifiedConfig := make(map[string]setting.UnifiedStorageConfig) + for _, resource := range []string{"folders.folder.grafana.app", "dashboards.dashboard.grafana.app"} { + unifiedConfig[resource] = setting.UnifiedStorageConfig{ + EnableMigration: true, + } + } dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{ - DisableAnonymous: true, + DisableAnonymous: true, + UnifiedStorageConfig: unifiedConfig, }) grafanaListedAddr, env := testinfra.StartGrafanaEnv(t, dir, path) @@ -218,11 +226,12 @@ func TestIntegrationDashboardServiceValidation(t *testing.T) { require.NoError(t, err) }) - t.Run("When updating uid with id", func(t *testing.T) { + dashboardWithDuplicatedLegacyAnnotation := "new-uid" + t.Run("When saving a dashboard with an already used legacy ID", func(t *testing.T) { resp, err := postDashboard(t, grafanaListedAddr, "admin", "admin", map[string]interface{}{ "dashboard": map[string]interface{}{ "id": savedDashInFolder.ID, // nolint:staticcheck - "uid": "new-uid", + "uid": dashboardWithDuplicatedLegacyAnnotation, "title": "Updated title", }, "folderUid": savedDashInFolder.FolderUID, @@ -234,7 +243,48 @@ func TestIntegrationDashboardServiceValidation(t *testing.T) { require.NoError(t, err) }) - t.Run("When updating uid with a dashboard already using that uid", func(t *testing.T) { + t.Run("When updating a dashboard with legacy ID in multiple dashboards", func(t *testing.T) { + resp, err := postDashboard(t, grafanaListedAddr, "admin", "admin", map[string]interface{}{ + "dashboard": map[string]interface{}{ + "id": savedDashInFolder.ID, // nolint:staticcheck + "uid": savedDashInGeneralFolder.UID, + "title": "Updated title", + }, + "folderUid": savedDashInFolder.FolderUID, + "overwrite": true, + }) + require.NoError(t, err) + assert.Equal(t, http.StatusInternalServerError, resp.StatusCode) + err = resp.Body.Close() + require.NoError(t, err) + // Delete the dashboard with duplicated legacy ID annotation + u := fmt.Sprintf("http://admin:admin@%s/api/dashboards/uid/%s", grafanaListedAddr, dashboardWithDuplicatedLegacyAnnotation) + req, err := http.NewRequest("DELETE", u, nil) + require.NoError(t, err) + resp, err = http.DefaultClient.Do(req) + require.NoError(t, err) + err = resp.Body.Close() + require.NoError(t, err) + assert.Equal(t, http.StatusOK, resp.StatusCode) + }) + + t.Run("When updating a dashboard already using that uid", func(t *testing.T) { + resp, err := postDashboard(t, grafanaListedAddr, "admin", "admin", map[string]interface{}{ + "dashboard": map[string]interface{}{ + "id": savedDashInFolder.ID, + "uid": savedDashInFolder.UID, + "title": "Dashboard with existing UID", + }, + "folderUid": savedDashInFolder.FolderUID, + "overwrite": true, + }) + require.NoError(t, err) + assert.Equal(t, http.StatusOK, resp.StatusCode) + err = resp.Body.Close() + require.NoError(t, err) + }) + + t.Run("When updating id with a dashboard already using that uid", func(t *testing.T) { resp, err := postDashboard(t, grafanaListedAddr, "admin", "admin", map[string]interface{}{ "dashboard": map[string]interface{}{ "id": savedDashInFolder.ID, // nolint:staticcheck @@ -268,8 +318,9 @@ func TestIntegrationDashboardServiceValidation(t *testing.T) { require.NoError(t, err) }) + // Obs: in legacy, the dashboard request would fail + // After the dashboard is created, the user can see that there is an error with the library panel and can remove them manually t.Run("When creating a dashboard that references a non-existent library panel", func(t *testing.T) { - originalCount := getDashboardCount(t, grafanaListedAddr, "admin", "admin") resp, err := postDashboard(t, grafanaListedAddr, "admin", "admin", map[string]interface{}{ "dashboard": map[string]interface{}{ "title": "Bad dashboard", @@ -285,15 +336,11 @@ func TestIntegrationDashboardServiceValidation(t *testing.T) { }, }) require.NoError(t, err) - assert.Equal(t, http.StatusInternalServerError, resp.StatusCode) - body, err := io.ReadAll(resp.Body) + assert.Equal(t, http.StatusOK, resp.StatusCode) + _, err = io.ReadAll(resp.Body) require.NoError(t, err) - require.Contains(t, string(body), "library element could not be found") err = resp.Body.Close() require.NoError(t, err) - - // A new dashboard is not created in this situation. - require.Equal(t, originalCount, getDashboardCount(t, grafanaListedAddr, "admin", "admin")) }) } @@ -332,7 +379,7 @@ func TestIntegrationDashboardQuota(t *testing.T) { dashboardDTO := &plugindashboards.PluginDashboard{} err = json.Unmarshal(b, dashboardDTO) require.NoError(t, err) - require.EqualValues(t, 1, dashboardDTO.DashboardId) + require.EqualValues(t, "just testing", dashboardDTO.Title) }) t.Run("when quota limit exceeds importing a dashboard should fail", func(t *testing.T) { @@ -421,7 +468,7 @@ providers: dashboardUID = d.UID dashboardID = d.ID // nolint:staticcheck } - assert.Equal(t, int64(1), dashboardID) + assert.Len(t, *dashboardList, 1) testCases := []struct { desc string @@ -781,7 +828,7 @@ func TestIntegrationImportDashboardWithLibraryPanels(t *testing.T) { }, { "id": 2, - "title": "Library Panel 2", + "title": "Library Panel 2", "type": "stat", "gridPos": {"h": 8, "w": 12, "x": 12, "y": 0}, "libraryPanel": { @@ -805,7 +852,7 @@ func TestIntegrationImportDashboardWithLibraryPanels(t *testing.T) { } }, "test-lib-panel-2": { - "uid": "test-lib-panel-2", + "uid": "test-lib-panel-2", "name": "Test Library Panel 2", "kind": 1, "type": "stat", @@ -1011,26 +1058,12 @@ func postDashboard(t *testing.T, grafanaListedAddr, user, password string, paylo return http.Post(u, "application/json", bytes.NewBuffer(payloadBytes)) // nolint:gosec } -func getDashboardCount(t *testing.T, grafanaListenAddr, user, password string) int { - endpoint := fmt.Sprintf("http://%s:%s@%s/apis/dashboard.grafana.app/v0alpha1/namespaces/default/search", user, password, grafanaListenAddr) - resp, err := http.Get(endpoint) //nolint:gosec - require.NoError(t, err) - - body, err := io.ReadAll(resp.Body) - require.NoError(t, err) - require.NoError(t, resp.Body.Close()) - - var payload map[string]any - require.NoError(t, json.Unmarshal(body, &payload)) - - return int(payload["totalHits"].(float64)) -} - func TestIntegrationDashboardServicePermissions(t *testing.T) { testutil.SkipIntegrationTestInShortMode(t) dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{ - DisableAnonymous: true, + DisableAnonymous: true, + DisableAuthZClientCache: true, }) grafanaListedAddr, env := testinfra.StartGrafanaEnv(t, dir, path) tests.CreateUser(t, env.SQLStore, env.Cfg, user.CreateUserCommand{ diff --git a/pkg/tests/apis/alerting/notifications/receivers/receiver_test.go b/pkg/tests/apis/alerting/notifications/receivers/receiver_test.go index 0f7b476ecad..5497c8f1685 100644 --- a/pkg/tests/apis/alerting/notifications/receivers/receiver_test.go +++ b/pkg/tests/apis/alerting/notifications/receivers/receiver_test.go @@ -143,7 +143,7 @@ func TestIntegrationResourcePermissions(t *testing.T) { adminClient := test_common.NewReceiverClient(t, admin) writeACMetadata := []string{"canWrite", "canDelete"} - allACMetadata := []string{"canWrite", "canDelete", "canReadSecrets", "canAdmin"} + allACMetadata := []string{"canWrite", "canDelete", "canReadSecrets", "canAdmin", "canModifyProtected"} mustID := func(user apis.User) int64 { id, err := user.Identity.GetInternalID() @@ -404,13 +404,14 @@ func TestIntegrationAccessControl(t *testing.T) { org1 := helper.Org1 type testCase struct { - user apis.User - canRead bool - canUpdate bool - canCreate bool - canDelete bool - canReadSecrets bool - canAdmin bool + user apis.User + canRead bool + canUpdate bool + canUpdateProtected bool + canCreate bool + canDelete bool + canReadSecrets bool + canAdmin bool } // region users unauthorized := helper.CreateUser("unauthorized", "Org1", org.RoleNone, []resourcepermissions.SetResourcePermissionCommand{}) @@ -473,20 +474,22 @@ func TestIntegrationAccessControl(t *testing.T) { testCases := []testCase{ { - user: unauthorized, - canRead: false, - canUpdate: false, - canCreate: false, - canDelete: false, + user: unauthorized, + canRead: false, + canUpdate: false, + canUpdateProtected: false, + canCreate: false, + canDelete: false, }, { - user: org1.Admin, - canRead: true, - canCreate: true, - canUpdate: true, - canDelete: true, - canAdmin: true, - canReadSecrets: true, + user: org1.Admin, + canRead: true, + canCreate: true, + canUpdate: true, + canUpdateProtected: true, + canDelete: true, + canAdmin: true, + canReadSecrets: true, }, { user: org1.Editor, @@ -535,22 +538,24 @@ func TestIntegrationAccessControl(t *testing.T) { canDelete: true, }, { - user: adminLikeUser, - canRead: true, - canCreate: true, - canUpdate: true, - canDelete: true, - canAdmin: true, - canReadSecrets: true, + user: adminLikeUser, + canRead: true, + canCreate: true, + canUpdate: true, + canUpdateProtected: true, + canDelete: true, + canAdmin: true, + canReadSecrets: true, }, { - user: adminLikeUserLongName, - canRead: true, - canCreate: true, - canUpdate: true, - canDelete: true, - canAdmin: true, - canReadSecrets: true, + user: adminLikeUserLongName, + canRead: true, + canCreate: true, + canUpdate: true, + canUpdateProtected: true, + canDelete: true, + canAdmin: true, + canReadSecrets: true, }, } @@ -609,6 +614,9 @@ func TestIntegrationAccessControl(t *testing.T) { if tc.canUpdate { expectedWithMetadata.SetAccessControl("canWrite") } + if tc.canUpdateProtected { + expectedWithMetadata.SetAccessControl("canModifyProtected") + } if tc.canDelete { expectedWithMetadata.SetAccessControl("canDelete") } @@ -672,6 +680,32 @@ func TestIntegrationAccessControl(t *testing.T) { require.Truef(t, errors.IsNotFound(err), "Should get NotFound error but got: %s", err) }) }) + + updatedExpected = expected.Copy().(*v0alpha1.Receiver) + updatedExpected.Spec.Integrations = []v0alpha1.ReceiverIntegration{ + createIntegration(t, "webhook"), + } + + expected, err = adminClient.Update(ctx, updatedExpected, v1.UpdateOptions{}) + require.NoErrorf(t, err, "Payload %s", string(d)) + require.NotNil(t, expected) + + updatedProtected := expected.Copy().(*v0alpha1.Receiver) + updatedProtected.Spec.Integrations[0].Settings["url"] = "http://localhost:8080/webhook" + + if tc.canUpdateProtected { + t.Run("should be able to update protected fields of the receiver", func(t *testing.T) { + updated, err := client.Update(ctx, updatedProtected, v1.UpdateOptions{}) + require.NoErrorf(t, err, "Payload %s", string(d)) + require.NotNil(t, updated) + expected = updated + }) + } else { + t.Run("should be forbidden to edit protected fields of the receiver", func(t *testing.T) { + _, err := client.Update(ctx, updatedProtected, v1.UpdateOptions{}) + require.Truef(t, errors.IsForbidden(err), "should get Forbidden error but got %s", err) + }) + } } else { t.Run("should be forbidden to update receiver", func(t *testing.T) { _, err := client.Update(ctx, updatedExpected, v1.UpdateOptions{}) @@ -684,6 +718,7 @@ func TestIntegrationAccessControl(t *testing.T) { require.Truef(t, errors.IsForbidden(err), "should get Forbidden error but got %s", err) }) }) + require.Falsef(t, tc.canUpdateProtected, "Invalid combination of assertions. CanUpdateProtected should be false") } deleteOptions := v1.DeleteOptions{Preconditions: &v1.Preconditions{ResourceVersion: util.Pointer(expected.ResourceVersion)}} @@ -1291,6 +1326,7 @@ func TestIntegrationCRUD(t *testing.T) { receiver.SetAccessControl("canDelete") receiver.SetAccessControl("canReadSecrets") receiver.SetAccessControl("canAdmin") + receiver.SetAccessControl("canModifyProtected") receiver.SetInUse(0, nil) receiver.SetCanUse(true) diff --git a/pkg/tests/apis/alerting/notifications/receivers/test-data/imported-expected-snapshot.json b/pkg/tests/apis/alerting/notifications/receivers/test-data/imported-expected-snapshot.json index 621f9c3af16..f092d8980f7 100644 --- a/pkg/tests/apis/alerting/notifications/receivers/test-data/imported-expected-snapshot.json +++ b/pkg/tests/apis/alerting/notifications/receivers/test-data/imported-expected-snapshot.json @@ -8,6 +8,7 @@ "annotations": { "grafana.com/access/canAdmin": "true", "grafana.com/access/canDelete": "true", + "grafana.com/access/canModifyProtected": "true", "grafana.com/access/canReadSecrets": "true", "grafana.com/access/canWrite": "true", "grafana.com/canUse": "true", @@ -40,6 +41,7 @@ "kind": "Receiver", "metadata": { "annotations": { + "grafana.com/access/canModifyProtected": "true", "grafana.com/access/canReadSecrets": "true", "grafana.com/canUse": "false", "grafana.com/inUse/routes": "0", @@ -61,6 +63,7 @@ "kind": "Receiver", "metadata": { "annotations": { + "grafana.com/access/canModifyProtected": "true", "grafana.com/access/canReadSecrets": "true", "grafana.com/canUse": "false", "grafana.com/inUse/routes": "0", @@ -105,6 +108,7 @@ "kind": "Receiver", "metadata": { "annotations": { + "grafana.com/access/canModifyProtected": "true", "grafana.com/access/canReadSecrets": "true", "grafana.com/canUse": "false", "grafana.com/inUse/routes": "0", @@ -153,6 +157,7 @@ "kind": "Receiver", "metadata": { "annotations": { + "grafana.com/access/canModifyProtected": "true", "grafana.com/access/canReadSecrets": "true", "grafana.com/canUse": "false", "grafana.com/inUse/routes": "0", @@ -211,6 +216,7 @@ "kind": "Receiver", "metadata": { "annotations": { + "grafana.com/access/canModifyProtected": "true", "grafana.com/access/canReadSecrets": "true", "grafana.com/canUse": "false", "grafana.com/inUse/routes": "0", @@ -256,6 +262,7 @@ "kind": "Receiver", "metadata": { "annotations": { + "grafana.com/access/canModifyProtected": "true", "grafana.com/access/canReadSecrets": "true", "grafana.com/canUse": "false", "grafana.com/inUse/routes": "0", @@ -317,6 +324,7 @@ "kind": "Receiver", "metadata": { "annotations": { + "grafana.com/access/canModifyProtected": "true", "grafana.com/access/canReadSecrets": "true", "grafana.com/canUse": "false", "grafana.com/inUse/routes": "1", @@ -388,6 +396,7 @@ "kind": "Receiver", "metadata": { "annotations": { + "grafana.com/access/canModifyProtected": "true", "grafana.com/access/canReadSecrets": "true", "grafana.com/canUse": "false", "grafana.com/inUse/routes": "0", @@ -441,6 +450,7 @@ "kind": "Receiver", "metadata": { "annotations": { + "grafana.com/access/canModifyProtected": "true", "grafana.com/access/canReadSecrets": "true", "grafana.com/canUse": "false", "grafana.com/inUse/routes": "0", @@ -525,6 +535,7 @@ "kind": "Receiver", "metadata": { "annotations": { + "grafana.com/access/canModifyProtected": "true", "grafana.com/access/canReadSecrets": "true", "grafana.com/canUse": "false", "grafana.com/inUse/routes": "0", @@ -579,6 +590,7 @@ "kind": "Receiver", "metadata": { "annotations": { + "grafana.com/access/canModifyProtected": "true", "grafana.com/access/canReadSecrets": "true", "grafana.com/canUse": "false", "grafana.com/inUse/routes": "0", @@ -625,6 +637,7 @@ "kind": "Receiver", "metadata": { "annotations": { + "grafana.com/access/canModifyProtected": "true", "grafana.com/access/canReadSecrets": "true", "grafana.com/canUse": "false", "grafana.com/inUse/routes": "0", @@ -674,6 +687,7 @@ "kind": "Receiver", "metadata": { "annotations": { + "grafana.com/access/canModifyProtected": "true", "grafana.com/access/canReadSecrets": "true", "grafana.com/canUse": "false", "grafana.com/inUse/routes": "0", @@ -722,6 +736,7 @@ "kind": "Receiver", "metadata": { "annotations": { + "grafana.com/access/canModifyProtected": "true", "grafana.com/access/canReadSecrets": "true", "grafana.com/canUse": "false", "grafana.com/inUse/routes": "1", @@ -767,6 +782,7 @@ "kind": "Receiver", "metadata": { "annotations": { + "grafana.com/access/canModifyProtected": "true", "grafana.com/access/canReadSecrets": "true", "grafana.com/canUse": "false", "grafana.com/inUse/routes": "0", diff --git a/pkg/tests/apis/alerting/notifications/templategroup/imported_test.go b/pkg/tests/apis/alerting/notifications/templategroup/imported_test.go new file mode 100644 index 00000000000..9a3e88f3e46 --- /dev/null +++ b/pkg/tests/apis/alerting/notifications/templategroup/imported_test.go @@ -0,0 +1,129 @@ +package templateGroup + +import ( + "context" + "embed" + "path" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.yaml.in/yaml/v3" + "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/grafana/grafana/apps/alerting/notifications/pkg/apis/alertingnotifications/v0alpha1" + "github.com/grafana/grafana/pkg/services/featuremgmt" + apimodels "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions" + "github.com/grafana/grafana/pkg/services/ngalert/models" + "github.com/grafana/grafana/pkg/tests/api/alerting" + "github.com/grafana/grafana/pkg/tests/apis" + "github.com/grafana/grafana/pkg/tests/apis/alerting/notifications/common" + "github.com/grafana/grafana/pkg/tests/testinfra" + "github.com/grafana/grafana/pkg/util/testutil" +) + +//go:embed test-data/*.* +var testData embed.FS + +func TestIntegrationImportedTemplates(t *testing.T) { + testutil.SkipIntegrationTestInShortMode(t) + + helper := apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{ + EnableFeatureToggles: []string{ + featuremgmt.FlagAlertingImportAlertmanagerAPI, + }, + }) + + client := common.NewTemplateGroupClient(t, helper.Org1.Admin) + + cliCfg := helper.Org1.Admin.NewRestConfig() + alertingApi := alerting.NewAlertingLegacyAPIClient(helper.GetEnv().Server.HTTPServer.Listener.Addr().String(), cliCfg.Username, cliCfg.Password) + + configYaml, err := testData.ReadFile(path.Join("test-data", "imported.yaml")) + require.NoError(t, err) + + identifier := "test-create-get-config" + mergeMatchers := "_imported=true" + + headers := map[string]string{ + "Content-Type": "application/yaml", + "X-Grafana-Alerting-Config-Identifier": identifier, + "X-Grafana-Alerting-Merge-Matchers": mergeMatchers, + } + var amConfig apimodels.AlertmanagerUserConfig + require.NoError(t, yaml.Unmarshal(configYaml, &amConfig)) + + response := alertingApi.ConvertPrometheusPostAlertmanagerConfig(t, amConfig, headers) + require.Equal(t, "success", response.Status) + + templates, err := client.List(context.Background(), metav1.ListOptions{}) + + require.NoError(t, err) + require.Len(t, templates.Items, 3) + + require.Equal(t, v0alpha1.DefaultTemplateTitle, templates.Items[0].Spec.Title) + require.Equal(t, "imported", templates.Items[1].Spec.Title) + require.Equal(t, "template", templates.Items[2].Spec.Title) + + t.Run("should be correct kind", func(t *testing.T) { + assert.Equal(t, + v0alpha1.TemplateGroupSpec{ + Title: "imported", + Content: amConfig.TemplateFiles["imported"], + Kind: v0alpha1.TemplateGroupTemplateKindMimir, + }, templates.Items[1].Spec) + assert.Equal(t, + v0alpha1.TemplateGroupSpec{ + Title: "template", + Content: amConfig.TemplateFiles["template"], + Kind: v0alpha1.TemplateGroupTemplateKindMimir, + }, templates.Items[2].Spec) + }) + + t.Run("should be provisioned", func(t *testing.T) { + for _, tpl := range templates.Items[1:] { + assert.EqualValues(t, models.ProvenanceConvertedPrometheus, tpl.GetProvenanceStatus()) + } + }) + + t.Run("should not be able to update", func(t *testing.T) { + tpl := templates.Items[1] + tpl.Spec.Content = "new content" + _, err := client.Update(context.Background(), &tpl, metav1.UpdateOptions{}) + require.Truef(t, errors.IsBadRequest(err), "expected bad request but got %s", err) + }) + + t.Run("should not be able to delete", func(t *testing.T) { + err := client.Delete(context.Background(), templates.Items[1].Name, metav1.DeleteOptions{}) + require.Truef(t, errors.IsBadRequest(err), "expected bad request but got %s", err) + }) + + t.Run("should not conflict with Grafana kind", func(t *testing.T) { + tpl := v0alpha1.TemplateGroup{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + }, + Spec: templates.Items[1].Spec, + } + tpl.Spec.Kind = v0alpha1.TemplateGroupTemplateKindGrafana + + created, err := client.Create(context.Background(), &tpl, metav1.CreateOptions{}) + require.NoError(t, err) + + assert.NotEqual(t, templates.Items[1].Name, created.Name) + }) + + t.Run("sort by kind and then name", func(t *testing.T) { + templates, err := client.List(context.Background(), metav1.ListOptions{}) + + require.NoError(t, err) + require.Len(t, templates.Items, 4) + assert.Equal(t, v0alpha1.DefaultTemplateTitle, templates.Items[0].Spec.Title) + assert.Equal(t, "imported", templates.Items[1].Spec.Title) + assert.Equal(t, v0alpha1.TemplateGroupTemplateKindGrafana, templates.Items[1].Spec.Kind) + assert.Equal(t, "imported", templates.Items[2].Spec.Title) + assert.Equal(t, v0alpha1.TemplateGroupTemplateKindMimir, templates.Items[2].Spec.Kind) + assert.Equal(t, "template", templates.Items[3].Spec.Title) + }) +} diff --git a/pkg/tests/apis/alerting/notifications/templategroup/templates_group_test.go b/pkg/tests/apis/alerting/notifications/templategroup/templates_group_test.go index 04d9e626ab7..146bccd5f11 100644 --- a/pkg/tests/apis/alerting/notifications/templategroup/templates_group_test.go +++ b/pkg/tests/apis/alerting/notifications/templategroup/templates_group_test.go @@ -54,6 +54,7 @@ func TestIntegrationResourceIdentifier(t *testing.T) { Spec: v0alpha1.TemplateGroupSpec{ Title: "templateGroup", Content: `{{ define "test" }} test {{ end }}`, + Kind: v0alpha1.TemplateGroupTemplateKindGrafana, }, } @@ -112,6 +113,7 @@ func TestIntegrationResourceIdentifier(t *testing.T) { require.Equal(t, v0alpha1.TemplateGroupSpec{ Title: v0alpha1.DefaultTemplateTitle, Content: defaultDefn.Template, + Kind: v0alpha1.TemplateGroupTemplateKindGrafana, }, actual.Spec) defaultTemplateGroup = actual }) @@ -226,6 +228,7 @@ func TestIntegrationAccessControl(t *testing.T) { Spec: v0alpha1.TemplateGroupSpec{ Title: fmt.Sprintf("template-group-1-%s", tc.user.Identity.GetLogin()), Content: `{{ define "test" }} test {{ end }}`, + Kind: v0alpha1.TemplateGroupTemplateKindGrafana, }, } expected.SetProvenanceStatus("") @@ -385,6 +388,7 @@ func TestIntegrationProvisioning(t *testing.T) { Spec: v0alpha1.TemplateGroupSpec{ Title: "template-group-1", Content: `{{ define "test" }} test {{ end }}`, + Kind: v0alpha1.TemplateGroupTemplateKindGrafana, }, }, v1.CreateOptions{}) require.NoError(t, err) @@ -428,6 +432,7 @@ func TestIntegrationOptimisticConcurrency(t *testing.T) { Spec: v0alpha1.TemplateGroupSpec{ Title: "template-group-1", Content: `{{ define "test" }} test {{ end }}`, + Kind: v0alpha1.TemplateGroupTemplateKindGrafana, }, } @@ -510,6 +515,7 @@ func TestIntegrationPatch(t *testing.T) { Spec: v0alpha1.TemplateGroupSpec{ Title: "template-group", Content: `{{ define "test" }} test {{ end }}`, + Kind: v0alpha1.TemplateGroupTemplateKindGrafana, }, } @@ -568,6 +574,7 @@ func TestIntegrationListSelector(t *testing.T) { Spec: v0alpha1.TemplateGroupSpec{ Title: "test1", Content: `{{ define "test1" }} test {{ end }}`, + Kind: v0alpha1.TemplateGroupTemplateKindGrafana, }, } template1, err := adminClient.Create(ctx, template1, v1.CreateOptions{}) @@ -580,6 +587,7 @@ func TestIntegrationListSelector(t *testing.T) { Spec: v0alpha1.TemplateGroupSpec{ Title: "test2", Content: `{{ define "test2" }} test {{ end }}`, + Kind: v0alpha1.TemplateGroupTemplateKindGrafana, }, } template2, err = adminClient.Create(ctx, template2, v1.CreateOptions{}) @@ -655,3 +663,37 @@ func TestIntegrationListSelector(t *testing.T) { require.NotEqualf(t, templates.DefaultTemplateName, list.Items[1].Name, "Expected non-default template but got %s", list.Items[1].Name) }) } + +func TestIntegrationKinds(t *testing.T) { + testutil.SkipIntegrationTestInShortMode(t) + + ctx := context.Background() + helper := getTestHelper(t) + client := common.NewTemplateGroupClient(t, helper.Org1.Admin) + + newTemplate := &v0alpha1.TemplateGroup{ + ObjectMeta: v1.ObjectMeta{ + Namespace: "default", + }, + Spec: v0alpha1.TemplateGroupSpec{ + Title: "templateGroup", + Content: `{{ define "test" }} test {{ end }}`, + Kind: v0alpha1.TemplateGroupTemplateKindMimir, + }, + } + + t.Run("should not let create Mimir template", func(t *testing.T) { + _, err := client.Create(ctx, newTemplate, v1.CreateOptions{}) + require.Truef(t, errors.IsBadRequest(err), "expected bad request but got %s", err) + }) + + t.Run("should not let change kind", func(t *testing.T) { + newTemplate.Spec.Kind = v0alpha1.TemplateGroupTemplateKindGrafana + created, err := client.Create(ctx, newTemplate, v1.CreateOptions{}) + require.NoError(t, err) + + created.Spec.Kind = v0alpha1.TemplateGroupTemplateKindMimir + _, err = client.Update(ctx, created, v1.UpdateOptions{}) + require.Truef(t, errors.IsBadRequest(err), "expected bad request but got %s", err) + }) +} diff --git a/pkg/tests/apis/alerting/notifications/templategroup/test-data/imported.yaml b/pkg/tests/apis/alerting/notifications/templategroup/test-data/imported.yaml new file mode 100644 index 00000000000..76e9a2c4b51 --- /dev/null +++ b/pkg/tests/apis/alerting/notifications/templategroup/test-data/imported.yaml @@ -0,0 +1,15 @@ +alertmanager_config: | + route: + receiver: sinkhole + group_by: + - alertname + receivers: + - name: sinkhole +template_files: + imported: | + {{ define "imported" }} + {{ end }} + template: | + {{ define "template" }} + {{ template "imported" . }} + {{ end }} diff --git a/pkg/tests/apis/collections/stars_test.go b/pkg/tests/apis/collections/stars_test.go index 573da05a00b..949e3d6c6ac 100644 --- a/pkg/tests/apis/collections/stars_test.go +++ b/pkg/tests/apis/collections/stars_test.go @@ -42,9 +42,10 @@ func TestIntegrationStars(t *testing.T) { } helper := apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{ - AppModeProduction: false, // required for experimental APIs - DisableAnonymous: true, - EnableFeatureToggles: flags, + DisableDataMigrations: true, + AppModeProduction: false, // required for experimental APIs + DisableAnonymous: true, + EnableFeatureToggles: flags, UnifiedStorageConfig: map[string]setting.UnifiedStorageConfig{ "dashboards.dashboard.grafana.app": { DualWriterMode: mode, diff --git a/pkg/tests/apis/config_test.go b/pkg/tests/apis/config_test.go index a9e8d87e0a0..665d79a5e50 100644 --- a/pkg/tests/apis/config_test.go +++ b/pkg/tests/apis/config_test.go @@ -51,7 +51,7 @@ const pluginsDiscoveryJSON = `[ "version": "" }, "scope": "Namespaced", - "singularResource": "plugins", + "singularResource": "plugin", "subresources": [ { "responseKind": { diff --git a/pkg/tests/apis/dashboard/dashboards_test.go b/pkg/tests/apis/dashboard/dashboards_test.go index 5d5d04aa535..5e34d28ba9f 100644 --- a/pkg/tests/apis/dashboard/dashboards_test.go +++ b/pkg/tests/apis/dashboard/dashboards_test.go @@ -37,7 +37,8 @@ func TestMain(m *testing.M) { func runDashboardTest(t *testing.T, mode rest.DualWriterMode, gvr schema.GroupVersionResource) { t.Run("simple crud+list", func(t *testing.T) { helper := apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{ - DisableAnonymous: true, + DisableAnonymous: true, + DisableDataMigrations: true, UnifiedStorageConfig: map[string]setting.UnifiedStorageConfig{ "dashboards.dashboard.grafana.app": { DualWriterMode: mode, @@ -194,7 +195,9 @@ func TestIntegrationLegacySupport(t *testing.T) { testutil.SkipIntegrationTestInShortMode(t) ctx := context.Background() - helper := apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{}) + helper := apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{ + DisableDataMigrations: true, + }) clientV0 := helper.GetResourceClient(apis.ResourceClientArgs{ User: helper.Org1.Admin, @@ -500,9 +503,10 @@ func runDashboardSearchTest(t *testing.T, mode rest.DualWriterMode) { ctx := context.Background() helper := apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{ - AppModeProduction: true, - DisableAnonymous: true, - APIServerStorageType: "unified", + AppModeProduction: true, + DisableDataMigrations: true, + DisableAnonymous: true, + APIServerStorageType: "unified", UnifiedStorageConfig: map[string]setting.UnifiedStorageConfig{ "dashboards.dashboard.grafana.app": {DualWriterMode: mode}, "folders.folder.grafana.app": {DualWriterMode: mode}, diff --git a/pkg/tests/apis/dashboard/integration/api_validation_test.go b/pkg/tests/apis/dashboard/integration/api_validation_test.go index 9e087cb76a6..36461ea910e 100644 --- a/pkg/tests/apis/dashboard/integration/api_validation_test.go +++ b/pkg/tests/apis/dashboard/integration/api_validation_test.go @@ -68,7 +68,8 @@ func TestIntegrationDashboardAPIValidation(t *testing.T) { t.Run(fmt.Sprintf("DualWriterMode %d", dualWriterMode), func(t *testing.T) { // Create a K8sTestHelper which will set up a real API server helper := apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{ - DisableAnonymous: true, + DisableDataMigrations: true, + DisableAnonymous: true, EnableFeatureToggles: []string{ featuremgmt.FlagKubernetesDashboards, // Enable FE-only dashboard feature flag }, @@ -105,7 +106,8 @@ func TestIntegrationDashboardAPIValidation(t *testing.T) { t.Run(fmt.Sprintf("DualWriterMode %d - kubernetesDashboards disabled", dualWriterMode), func(t *testing.T) { // Create a K8sTestHelper which will set up a real API server helper := apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{ - DisableAnonymous: true, + DisableDataMigrations: true, + DisableAnonymous: true, DisableFeatureToggles: []string{ featuremgmt.FlagKubernetesDashboards, }, @@ -138,7 +140,8 @@ func TestIntegrationDashboardAPIAuthorization(t *testing.T) { for _, dualWriterMode := range dualWriterModes { t.Run(fmt.Sprintf("DualWriterMode %d", dualWriterMode), func(t *testing.T) { helper := apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{ - DisableAnonymous: true, + DisableDataMigrations: true, + DisableAnonymous: true, UnifiedStorageConfig: map[string]setting.UnifiedStorageConfig{ "dashboards.dashboard.grafana.app": { DualWriterMode: dualWriterMode, @@ -185,7 +188,8 @@ func TestIntegrationDashboardAPI(t *testing.T) { t.Run(fmt.Sprintf("DualWriterMode %d", dualWriterMode), func(t *testing.T) { // Create a K8sTestHelper which will set up a real API server helper := apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{ - DisableAnonymous: true, + DisableDataMigrations: true, + DisableAnonymous: true, EnableFeatureToggles: []string{ featuremgmt.FlagKubernetesDashboards, }, diff --git a/pkg/tests/apis/dashboard/integration/library_panels_api_validation_test.go b/pkg/tests/apis/dashboard/integration/library_panels_api_validation_test.go index dd85fdb2400..32548d593ea 100644 --- a/pkg/tests/apis/dashboard/integration/library_panels_api_validation_test.go +++ b/pkg/tests/apis/dashboard/integration/library_panels_api_validation_test.go @@ -29,7 +29,8 @@ func TestIntegrationLibraryPanelConnections(t *testing.T) { for _, dualWriterMode := range dualWriterModes { t.Run(fmt.Sprintf("DualWriterMode %d", dualWriterMode), func(t *testing.T) { helper := apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{ - DisableAnonymous: true, + DisableDataMigrations: true, + DisableAnonymous: true, EnableFeatureToggles: []string{ "kubernetesLibraryPanels", }, @@ -93,7 +94,8 @@ func TestIntegrationLibraryElementPermissions(t *testing.T) { for _, dualWriterMode := range dualWriterModes { t.Run(fmt.Sprintf("DualWriterMode %d", dualWriterMode), func(t *testing.T) { helper := apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{ - DisableAnonymous: true, + DisableDataMigrations: true, + DisableAnonymous: true, EnableFeatureToggles: []string{ "kubernetesLibraryPanels", "grafanaAPIServerWithExperimentalAPIs", // needed until we move it to v0beta1 at least (currently v0alpha1) @@ -296,7 +298,8 @@ func TestIntegrationLibraryPanelConnectionsWithFolderAccess(t *testing.T) { for _, dualWriterMode := range dualWriterModes { t.Run(fmt.Sprintf("DualWriterMode %d", dualWriterMode), func(t *testing.T) { helper := apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{ - DisableAnonymous: true, + DisableDataMigrations: true, + DisableAnonymous: true, EnableFeatureToggles: []string{ "kubernetesLibraryPanels", }, diff --git a/pkg/tests/apis/dashboard/search_test.go b/pkg/tests/apis/dashboard/search_test.go index 09d23398c3f..3fe35c51b3a 100644 --- a/pkg/tests/apis/dashboard/search_test.go +++ b/pkg/tests/apis/dashboard/search_test.go @@ -37,9 +37,10 @@ func runSearchPermissionTest(t *testing.T, mode rest.DualWriterMode) { ctx := context.Background() helper := apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{ - AppModeProduction: true, - DisableAnonymous: true, - APIServerStorageType: "unified", + DisableDataMigrations: true, + AppModeProduction: true, + DisableAnonymous: true, + APIServerStorageType: "unified", UnifiedStorageConfig: map[string]setting.UnifiedStorageConfig{ "dashboards.dashboard.grafana.app": {DualWriterMode: mode}, "folders.folder.grafana.app": {DualWriterMode: mode}, diff --git a/pkg/tests/apis/folder/folder_tree_test.go b/pkg/tests/apis/folder/folder_tree_test.go index b1d38ab3918..1b3d5df37f2 100644 --- a/pkg/tests/apis/folder/folder_tree_test.go +++ b/pkg/tests/apis/folder/folder_tree_test.go @@ -48,9 +48,10 @@ func TestIntegrationFolderTree(t *testing.T) { for _, mode := range modes { t.Run(fmt.Sprintf("mode %d", mode), func(t *testing.T) { helper := apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{ - AppModeProduction: true, - DisableAnonymous: true, - APIServerStorageType: "unified", + DisableDataMigrations: true, + AppModeProduction: true, + DisableAnonymous: true, + APIServerStorageType: "unified", UnifiedStorageConfig: map[string]setting.UnifiedStorageConfig{ "dashboards.dashboard.grafana.app": { DualWriterMode: mode, diff --git a/pkg/tests/apis/folder/folders_test.go b/pkg/tests/apis/folder/folders_test.go index 1cc58c4bdbd..ce7dd5f6795 100644 --- a/pkg/tests/apis/folder/folders_test.go +++ b/pkg/tests/apis/folder/folders_test.go @@ -139,9 +139,10 @@ func TestIntegrationFoldersApp(t *testing.T) { t.Run(fmt.Sprintf("with dual write (unified storage, mode %v)", modeDw), func(t *testing.T) { doFolderTests(t, apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{ - AppModeProduction: true, - DisableAnonymous: true, - APIServerStorageType: "unified", + DisableDataMigrations: true, + AppModeProduction: true, + DisableAnonymous: true, + APIServerStorageType: "unified", UnifiedStorageConfig: map[string]setting.UnifiedStorageConfig{ folders.RESOURCEGROUP: { DualWriterMode: modeDw, @@ -153,9 +154,10 @@ func TestIntegrationFoldersApp(t *testing.T) { t.Run(fmt.Sprintf("with dual write (unified storage, mode %v, create nested folders)", modeDw), func(t *testing.T) { doNestedCreateTest(t, apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{ - AppModeProduction: true, - DisableAnonymous: true, - APIServerStorageType: "unified", + DisableDataMigrations: true, + AppModeProduction: true, + DisableAnonymous: true, + APIServerStorageType: "unified", UnifiedStorageConfig: map[string]setting.UnifiedStorageConfig{ folders.RESOURCEGROUP: { DualWriterMode: modeDw, @@ -166,9 +168,10 @@ func TestIntegrationFoldersApp(t *testing.T) { t.Run(fmt.Sprintf("with dual write (unified storage, mode %v, create existing folder)", modeDw), func(t *testing.T) { doCreateDuplicateFolderTest(t, apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{ - AppModeProduction: true, - DisableAnonymous: true, - APIServerStorageType: "unified", + DisableDataMigrations: true, + AppModeProduction: true, + DisableAnonymous: true, + APIServerStorageType: "unified", UnifiedStorageConfig: map[string]setting.UnifiedStorageConfig{ folders.RESOURCEGROUP: { DualWriterMode: modeDw, @@ -179,9 +182,10 @@ func TestIntegrationFoldersApp(t *testing.T) { t.Run(fmt.Sprintf("when creating a folder, mode %v, it should trim leading and trailing spaces", modeDw), func(t *testing.T) { doCreateEnsureTitleIsTrimmedTest(t, apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{ - AppModeProduction: true, - DisableAnonymous: true, - APIServerStorageType: "unified", + DisableDataMigrations: true, + AppModeProduction: true, + DisableAnonymous: true, + APIServerStorageType: "unified", UnifiedStorageConfig: map[string]setting.UnifiedStorageConfig{ folders.RESOURCEGROUP: { DualWriterMode: modeDw, @@ -192,9 +196,10 @@ func TestIntegrationFoldersApp(t *testing.T) { t.Run(fmt.Sprintf("with dual write (unified storage, mode %v, create circular reference folder)", modeDw), func(t *testing.T) { doCreateCircularReferenceFolderTest(t, apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{ - AppModeProduction: true, - DisableAnonymous: true, - APIServerStorageType: "unified", + DisableDataMigrations: true, + AppModeProduction: true, + DisableAnonymous: true, + APIServerStorageType: "unified", UnifiedStorageConfig: map[string]setting.UnifiedStorageConfig{ folders.RESOURCEGROUP: { DualWriterMode: modeDw, @@ -218,9 +223,10 @@ func TestIntegrationFoldersApp(t *testing.T) { for _, mode := range modes { t.Run(fmt.Sprintf("mode %d", mode), func(t *testing.T) { doListFoldersTest(t, apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{ - AppModeProduction: true, - DisableAnonymous: true, - APIServerStorageType: "unified", + DisableDataMigrations: true, + AppModeProduction: true, + DisableAnonymous: true, + APIServerStorageType: "unified", UnifiedStorageConfig: map[string]setting.UnifiedStorageConfig{ folders.RESOURCEGROUP: { DualWriterMode: mode, @@ -735,9 +741,10 @@ func TestIntegrationFolderCreatePermissions(t *testing.T) { t.Run(fmt.Sprintf("Mode_%d", mode), func(t *testing.T) { modeDw := grafanarest.DualWriterMode(mode) helper := apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{ - AppModeProduction: true, - DisableAnonymous: true, - APIServerStorageType: "unified", + DisableDataMigrations: true, + AppModeProduction: true, + DisableAnonymous: true, + APIServerStorageType: "unified", UnifiedStorageConfig: map[string]setting.UnifiedStorageConfig{ folders.RESOURCEGROUP: { DualWriterMode: modeDw, @@ -862,9 +869,10 @@ func TestIntegrationFolderGetPermissions(t *testing.T) { t.Run(fmt.Sprintf("Mode_%d", mode), func(t *testing.T) { modeDw := grafanarest.DualWriterMode(mode) helper := apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{ - AppModeProduction: true, - DisableAnonymous: true, - APIServerStorageType: "unified", + DisableDataMigrations: true, + AppModeProduction: true, + DisableAnonymous: true, + APIServerStorageType: "unified", UnifiedStorageConfig: map[string]setting.UnifiedStorageConfig{ folders.RESOURCEGROUP: { DualWriterMode: modeDw, @@ -1079,9 +1087,10 @@ func TestIntegrationFoldersCreateAPIEndpointK8S(t *testing.T) { for mode := 0; mode <= 4; mode++ { modeDw := grafanarest.DualWriterMode(mode) helper := apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{ - AppModeProduction: true, - DisableAnonymous: true, - APIServerStorageType: "unified", + DisableDataMigrations: true, + AppModeProduction: true, + DisableAnonymous: true, + APIServerStorageType: "unified", UnifiedStorageConfig: map[string]setting.UnifiedStorageConfig{ folders.RESOURCEGROUP: { DualWriterMode: modeDw, @@ -1254,9 +1263,10 @@ func TestIntegrationFoldersGetAPIEndpointK8S(t *testing.T) { modeDw := grafanarest.DualWriterMode(mode) helper := apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{ - AppModeProduction: true, - DisableAnonymous: true, - APIServerStorageType: "unified", + DisableDataMigrations: true, + AppModeProduction: true, + DisableAnonymous: true, + APIServerStorageType: "unified", UnifiedStorageConfig: map[string]setting.UnifiedStorageConfig{ folders.RESOURCEGROUP: { DualWriterMode: modeDw, @@ -1366,9 +1376,10 @@ func TestIntegrationFolderDeletionBlockedByLibraryElements(t *testing.T) { modeDw := grafanarest.DualWriterMode(mode) helper := apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{ - AppModeProduction: true, - DisableAnonymous: true, - APIServerStorageType: "unified", + DisableDataMigrations: true, + AppModeProduction: true, + DisableAnonymous: true, + APIServerStorageType: "unified", UnifiedStorageConfig: map[string]setting.UnifiedStorageConfig{ folders.RESOURCEGROUP: { DualWriterMode: modeDw, @@ -1446,9 +1457,10 @@ func TestIntegrationRootFolderDeletionBlockedByLibraryElementsInSubfolder(t *tes modeDw := grafanarest.DualWriterMode(mode) helper := apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{ - AppModeProduction: true, - DisableAnonymous: true, - APIServerStorageType: "unified", + DisableDataMigrations: true, + AppModeProduction: true, + DisableAnonymous: true, + APIServerStorageType: "unified", UnifiedStorageConfig: map[string]setting.UnifiedStorageConfig{ folders.RESOURCEGROUP: { DualWriterMode: modeDw, @@ -1542,9 +1554,10 @@ func TestIntegrationFolderDeletionBlockedByConnectedLibraryPanels(t *testing.T) modeDw := grafanarest.DualWriterMode(mode) helper := apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{ - AppModeProduction: true, - DisableAnonymous: true, - APIServerStorageType: "unified", + DisableDataMigrations: true, + AppModeProduction: true, + DisableAnonymous: true, + APIServerStorageType: "unified", UnifiedStorageConfig: map[string]setting.UnifiedStorageConfig{ folders.RESOURCEGROUP: { DualWriterMode: modeDw, @@ -1620,9 +1633,10 @@ func TestIntegrationFolderDeletionWithDanglingLibraryPanels(t *testing.T) { modeDw := grafanarest.DualWriterMode(mode) helper := apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{ - AppModeProduction: true, - DisableAnonymous: true, - APIServerStorageType: "unified", + DisableDataMigrations: true, + AppModeProduction: true, + DisableAnonymous: true, + APIServerStorageType: "unified", UnifiedStorageConfig: map[string]setting.UnifiedStorageConfig{ folders.RESOURCEGROUP: { DualWriterMode: modeDw, @@ -1901,9 +1915,10 @@ func TestIntegrationDeleteNestedFoldersPostorder(t *testing.T) { t.Run(fmt.Sprintf("Mode %d: Delete nested folder hierarchy in postorder", mode), func(t *testing.T) { modeDw := grafanarest.DualWriterMode(mode) helper := apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{ - AppModeProduction: true, - DisableAnonymous: true, - APIServerStorageType: "unified", + DisableDataMigrations: true, + AppModeProduction: true, + DisableAnonymous: true, + APIServerStorageType: "unified", UnifiedStorageConfig: map[string]setting.UnifiedStorageConfig{ folders.RESOURCEGROUP: { DualWriterMode: modeDw, @@ -2027,9 +2042,10 @@ func TestIntegrationDeleteFolderWithProvisionedDashboards(t *testing.T) { t.Run(fmt.Sprintf("Mode %d: Delete provisioned folders and dashboards", mode), func(t *testing.T) { modeDw := grafanarest.DualWriterMode(mode) ops := testinfra.GrafanaOpts{ - DisableAnonymous: true, - AppModeProduction: true, - APIServerStorageType: "unified", + DisableDataMigrations: true, + DisableAnonymous: true, + AppModeProduction: true, + APIServerStorageType: "unified", UnifiedStorageConfig: map[string]setting.UnifiedStorageConfig{ folders.RESOURCEGROUP: { DualWriterMode: modeDw, @@ -2131,11 +2147,14 @@ func TestIntegrationDeleteFolderWithProvisionedDashboards(t *testing.T) { // Test that folders created during provisioning using the dual writer have the // appropriate labels and annotations in unified storage. func TestIntegrationProvisionedFolderPropagatesLabelsAndAnnotations(t *testing.T) { + testutil.SkipIntegrationTestInShortMode(t) + mode3 := grafanarest.DualWriterMode(3) ops := testinfra.GrafanaOpts{ - DisableAnonymous: true, - AppModeProduction: true, - APIServerStorageType: "unified", + DisableDataMigrations: true, + DisableAnonymous: true, + AppModeProduction: true, + APIServerStorageType: "unified", UnifiedStorageConfig: map[string]setting.UnifiedStorageConfig{ folders.RESOURCEGROUP: { DualWriterMode: mode3, diff --git a/pkg/tests/apis/iam/team_search_integration_test.go b/pkg/tests/apis/iam/team_search_integration_test.go index c01ca9a641a..bf02f5718c9 100644 --- a/pkg/tests/apis/iam/team_search_integration_test.go +++ b/pkg/tests/apis/iam/team_search_integration_test.go @@ -21,8 +21,7 @@ import ( func TestIntegrationTeamSearch(t *testing.T) { testutil.SkipIntegrationTestInShortMode(t) - // TODO: Add rest.Mode3 and rest.Mode4 when they're supported - modes := []rest.DualWriterMode{rest.Mode0, rest.Mode1, rest.Mode2} + modes := []rest.DualWriterMode{rest.Mode0, rest.Mode1, rest.Mode2, rest.Mode3, rest.Mode4, rest.Mode5} for _, mode := range modes { t.Run(fmt.Sprintf("Team search with dual writer mode %d", mode), func(t *testing.T) { helper := apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{ @@ -38,6 +37,7 @@ func TestIntegrationTeamSearch(t *testing.T) { featuremgmt.FlagGrafanaAPIServerWithExperimentalAPIs, featuremgmt.FlagKubernetesAuthnMutation, }, + UnifiedStorageEnableSearch: true, }) doTeamSearchTests(t, helper) }) @@ -59,7 +59,6 @@ func doTeamSearchTests(t *testing.T, helper *apis.K8sTestHelper) { require.NoError(t, err) require.NotNil(t, team1) - // Create a second team with a different name team2YAML := helper.LoadYAMLOrJSONFile("testdata/team-test-create-v0.yaml") team2YAML.Object["metadata"].(map[string]interface{})["name"] = "testteam2" team2YAML.Object["spec"].(map[string]interface{})["title"] = "Another Team" diff --git a/pkg/tests/apis/openapi_snapshots/notifications.alerting.grafana.app-v0alpha1.json b/pkg/tests/apis/openapi_snapshots/notifications.alerting.grafana.app-v0alpha1.json index 2061616fc9a..4c7c45aad35 100644 --- a/pkg/tests/apis/openapi_snapshots/notifications.alerting.grafana.app-v0alpha1.json +++ b/pkg/tests/apis/openapi_snapshots/notifications.alerting.grafana.app-v0alpha1.json @@ -3783,18 +3783,29 @@ "type": "object", "required": [ "title", - "content" + "content", + "kind" ], "properties": { "content": { "type": "string" }, + "kind": { + "$ref": "#/components/schemas/com.github.grafana.grafana.apps.alerting.notifications.pkg.apis.alertingnotifications.v0alpha1.TemplateGroupTemplateKind" + }, "title": { "type": "string" } }, "additionalProperties": false }, + "com.github.grafana.grafana.apps.alerting.notifications.pkg.apis.alertingnotifications.v0alpha1.TemplateGroupTemplateKind": { + "type": "string", + "enum": [ + "grafana", + "mimir" + ] + }, "com.github.grafana.grafana.apps.alerting.notifications.pkg.apis.alertingnotifications.v0alpha1.TimeInterval": { "type": "object", "required": [ diff --git a/pkg/tests/apis/openapi_snapshots/playlist.grafana.app-v0alpha1.json b/pkg/tests/apis/openapi_snapshots/playlist.grafana.app-v0alpha1.json index dd1b486823e..dee1a56d6c0 100644 --- a/pkg/tests/apis/openapi_snapshots/playlist.grafana.app-v0alpha1.json +++ b/pkg/tests/apis/openapi_snapshots/playlist.grafana.app-v0alpha1.json @@ -40,7 +40,7 @@ "tags": [ "Playlist" ], - "description": "list objects of kind Playlist", + "description": "list or watch objects of kind Playlist", "operationId": "listPlaylist", "parameters": [ { @@ -1850,6 +1850,32 @@ "description": "Time is a wrapper around time.Time which supports correct marshaling to YAML and JSON. Wrappers are provided for many of the factory methods that the time package offers.", "type": "string", "format": "date-time" + }, + "io.k8s.apimachinery.pkg.apis.meta.v1.WatchEvent": { + "description": "Event represents a single event to a watched resource.", + "type": "object", + "required": [ + "type", + "object" + ], + "properties": { + "object": { + "description": "Object is:\n * If Type is Added or Modified: the new state of the object.\n * If Type is Deleted: the state of the object immediately before deletion.\n * If Type is Error: *Status is recommended; other types may make sense\n depending on context.", + "allOf": [ + { + "$ref": "#/components/schemas/io.k8s.apimachinery.pkg.runtime.RawExtension" + } + ] + }, + "type": { + "type": "string", + "default": "" + } + } + }, + "io.k8s.apimachinery.pkg.runtime.RawExtension": { + "description": "RawExtension is used to hold extensions in external versions.\n\nTo use this, make a field which has RawExtension as its type in your external, versioned struct, and Object in your internal struct. You also need to register your various plugin types.\n\n// Internal package:\n\n\ttype MyAPIObject struct {\n\t\truntime.TypeMeta `json:\",inline\"`\n\t\tMyPlugin runtime.Object `json:\"myPlugin\"`\n\t}\n\n\ttype PluginA struct {\n\t\tAOption string `json:\"aOption\"`\n\t}\n\n// External package:\n\n\ttype MyAPIObject struct {\n\t\truntime.TypeMeta `json:\",inline\"`\n\t\tMyPlugin runtime.RawExtension `json:\"myPlugin\"`\n\t}\n\n\ttype PluginA struct {\n\t\tAOption string `json:\"aOption\"`\n\t}\n\n// On the wire, the JSON will look something like this:\n\n\t{\n\t\t\"kind\":\"MyAPIObject\",\n\t\t\"apiVersion\":\"v1\",\n\t\t\"myPlugin\": {\n\t\t\t\"kind\":\"PluginA\",\n\t\t\t\"aOption\":\"foo\",\n\t\t},\n\t}\n\nSo what happens? Decode first uses json or yaml to unmarshal the serialized data into your external MyAPIObject. That causes the raw JSON to be stored, but not unpacked. The next step is to copy (using pkg/conversion) into the internal struct. The runtime package's DefaultScheme has conversion functions installed which will unpack the JSON stored in RawExtension, turning it into the correct object type, and storing it in the Object. (TODO: In the case where the object is of an unknown type, a runtime.Unknown object will be created and stored.)", + "type": "object" } } } diff --git a/pkg/tests/apis/openapi_snapshots/provisioning.grafana.app-v0alpha1.json b/pkg/tests/apis/openapi_snapshots/provisioning.grafana.app-v0alpha1.json index 0eeb7737af2..d4764b742f1 100644 --- a/pkg/tests/apis/openapi_snapshots/provisioning.grafana.app-v0alpha1.json +++ b/pkg/tests/apis/openapi_snapshots/provisioning.grafana.app-v0alpha1.json @@ -4409,6 +4409,18 @@ } ] }, + "com.github.grafana.grafana.apps.provisioning.pkg.apis.provisioning.v0alpha1.ConnectionInfo": { + "type": "object", + "required": [ + "name" + ], + "properties": { + "name": { + "type": "string", + "default": "" + } + } + }, "com.github.grafana.grafana.apps.provisioning.pkg.apis.provisioning.v0alpha1.ConnectionList": { "type": "object", "required": [ @@ -5283,10 +5295,6 @@ "com.github.grafana.grafana.apps.provisioning.pkg.apis.provisioning.v0alpha1.MigrateJobOptions": { "type": "object", "properties": { - "history": { - "description": "Preserve history (if possible)", - "type": "boolean" - }, "message": { "description": "Message to use when committing the changes in a single commit", "type": "string" @@ -5525,6 +5533,14 @@ } ] }, + "connection": { + "description": "The connection the repository references. This means the Repository is interacting with git via a Connection.", + "allOf": [ + { + "$ref": "#/components/schemas/com.github.grafana.grafana.apps.provisioning.pkg.apis.provisioning.v0alpha1.ConnectionInfo" + } + ] + }, "description": { "description": "Repository description", "type": "string" @@ -5808,10 +5824,6 @@ "kind": { "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" - }, - "legacyStorage": { - "description": "The backend is using legacy storage FIXME: Not sure where this should be exposed... but we need it somewhere The UI should force the onboarding workflow when this is true", - "type": "boolean" } } }, diff --git a/pkg/tests/apis/openapi_test.go b/pkg/tests/apis/openapi_test.go index b9d0283e37a..f9d5cdb70e5 100644 --- a/pkg/tests/apis/openapi_test.go +++ b/pkg/tests/apis/openapi_test.go @@ -10,7 +10,9 @@ import ( "k8s.io/apimachinery/pkg/util/version" "k8s.io/client-go/kubernetes" + "github.com/grafana/grafana/pkg/apiserver/rest" "github.com/grafana/grafana/pkg/services/featuremgmt" + "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/tests/testinfra" "github.com/grafana/grafana/pkg/tests/testsuite" "github.com/grafana/grafana/pkg/util/testutil" @@ -37,6 +39,11 @@ func TestIntegrationOpenAPIs(t *testing.T) { featuremgmt.FlagKubernetesAlertingHistorian, featuremgmt.FlagKubernetesLogsDrilldown, }, + // Explicitly configure with mode 5 the resources supported by provisioning. + UnifiedStorageConfig: map[string]setting.UnifiedStorageConfig{ + "dashboards.dashboard.grafana.app": {DualWriterMode: rest.Mode5}, + "folders.folder.grafana.app": {DualWriterMode: rest.Mode5}, + }, }) t.Run("check valid version response", func(t *testing.T) { diff --git a/pkg/tests/apis/playlist/playlist_test.go b/pkg/tests/apis/playlist/playlist_test.go index 057452eb7f9..2611624debb 100644 --- a/pkg/tests/apis/playlist/playlist_test.go +++ b/pkg/tests/apis/playlist/playlist_test.go @@ -54,47 +54,48 @@ func TestIntegrationPlaylist(t *testing.T) { require.NoError(t, err) // t.Logf("%s", disco) require.JSONEq(t, `[ - { - "version": "v0alpha1", - "freshness": "Current", - "resources": [ - { - "resource": "playlists", - "responseKind": { - "group": "", - "kind": "Playlist", - "version": "" - }, - "scope": "Namespaced", - "singularResource": "playlist", - "subresources": [ - { - "responseKind": { - "group": "", - "kind": "Playlist", - "version": "" - }, - "subresource": "status", - "verbs": [ - "get", - "patch", - "update" - ] - } - ], - "verbs": [ - "create", - "delete", - "deletecollection", - "get", - "list", - "patch", - "update" - ] - } - ] - } - ]`, disco) + { + "freshness": "Current", + "resources": [ + { + "resource": "playlists", + "responseKind": { + "group": "", + "kind": "Playlist", + "version": "" + }, + "scope": "Namespaced", + "singularResource": "playlist", + "subresources": [ + { + "responseKind": { + "group": "", + "kind": "Playlist", + "version": "" + }, + "subresource": "status", + "verbs": [ + "get", + "patch", + "update" + ] + } + ], + "verbs": [ + "create", + "delete", + "deletecollection", + "get", + "list", + "patch", + "update", + "watch" + ] + } + ], + "version": "v0alpha1" + } + ]`, disco) }) t.Run("with k8s api flag", func(t *testing.T) { @@ -106,9 +107,10 @@ func TestIntegrationPlaylist(t *testing.T) { t.Run("with dual write (file, mode 0)", func(t *testing.T) { doPlaylistTests(t, apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{ - AppModeProduction: true, - DisableAnonymous: true, - APIServerStorageType: "file", // write the files to disk + DisableDataMigrations: true, + AppModeProduction: true, + DisableAnonymous: true, + APIServerStorageType: "file", // write the files to disk UnifiedStorageConfig: map[string]setting.UnifiedStorageConfig{ RESOURCEGROUP: { DualWriterMode: grafanarest.Mode0, @@ -119,9 +121,10 @@ func TestIntegrationPlaylist(t *testing.T) { t.Run("with dual write (file, mode 1)", func(t *testing.T) { doPlaylistTests(t, apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{ - AppModeProduction: true, - DisableAnonymous: true, - APIServerStorageType: "file", // write the files to disk + DisableDataMigrations: true, + AppModeProduction: true, + DisableAnonymous: true, + APIServerStorageType: "file", // write the files to disk UnifiedStorageConfig: map[string]setting.UnifiedStorageConfig{ RESOURCEGROUP: { DualWriterMode: grafanarest.Mode1, @@ -132,9 +135,10 @@ func TestIntegrationPlaylist(t *testing.T) { t.Run("with dual write (file, mode 2)", func(t *testing.T) { doPlaylistTests(t, apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{ - AppModeProduction: true, - DisableAnonymous: true, - APIServerStorageType: "file", // write the files to disk + DisableDataMigrations: true, + AppModeProduction: true, + DisableAnonymous: true, + APIServerStorageType: "file", // write the files to disk UnifiedStorageConfig: map[string]setting.UnifiedStorageConfig{ RESOURCEGROUP: { DualWriterMode: grafanarest.Mode2, @@ -145,9 +149,10 @@ func TestIntegrationPlaylist(t *testing.T) { t.Run("with dual write (file, mode 3)", func(t *testing.T) { doPlaylistTests(t, apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{ - AppModeProduction: true, - DisableAnonymous: true, - APIServerStorageType: "file", // write the files to disk + DisableDataMigrations: true, + AppModeProduction: true, + DisableAnonymous: true, + APIServerStorageType: "file", // write the files to disk UnifiedStorageConfig: map[string]setting.UnifiedStorageConfig{ RESOURCEGROUP: { DualWriterMode: grafanarest.Mode3, @@ -158,9 +163,10 @@ func TestIntegrationPlaylist(t *testing.T) { t.Run("with dual write (file, mode 5)", func(t *testing.T) { helper := doPlaylistTests(t, apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{ - AppModeProduction: true, - DisableAnonymous: true, - APIServerStorageType: "file", // write the files to disk + DisableDataMigrations: true, + AppModeProduction: true, + DisableAnonymous: true, + APIServerStorageType: "file", // write the files to disk UnifiedStorageConfig: map[string]setting.UnifiedStorageConfig{ RESOURCEGROUP: { DualWriterMode: grafanarest.Mode5, @@ -198,9 +204,10 @@ func TestIntegrationPlaylist(t *testing.T) { t.Run("with dual write (unified storage, mode 0)", func(t *testing.T) { doPlaylistTests(t, apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{ - AppModeProduction: false, // required for unified storage - DisableAnonymous: true, - APIServerStorageType: options.StorageTypeUnified, // use the entity api tables + DisableDataMigrations: true, + AppModeProduction: false, // required for unified storage + DisableAnonymous: true, + APIServerStorageType: options.StorageTypeUnified, // use the entity api tables UnifiedStorageConfig: map[string]setting.UnifiedStorageConfig{ RESOURCEGROUP: { DualWriterMode: grafanarest.Mode0, @@ -211,18 +218,20 @@ func TestIntegrationPlaylist(t *testing.T) { t.Run("with dual write (unified storage, mode 1)", func(t *testing.T) { doPlaylistTests(t, apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{ - AppModeProduction: false, - DisableAnonymous: true, - APIServerStorageType: options.StorageTypeUnified, - EnableFeatureToggles: []string{}, + DisableDataMigrations: true, + AppModeProduction: false, + DisableAnonymous: true, + APIServerStorageType: options.StorageTypeUnified, + EnableFeatureToggles: []string{}, })) }) t.Run("with dual write (unified storage, mode 2)", func(t *testing.T) { doPlaylistTests(t, apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{ - AppModeProduction: false, // required for unified storage - DisableAnonymous: true, - APIServerStorageType: options.StorageTypeUnified, // use the entity api tables + DisableDataMigrations: true, + AppModeProduction: false, // required for unified storage + DisableAnonymous: true, + APIServerStorageType: options.StorageTypeUnified, // use the entity api tables UnifiedStorageConfig: map[string]setting.UnifiedStorageConfig{ RESOURCEGROUP: { DualWriterMode: grafanarest.Mode2, @@ -233,9 +242,10 @@ func TestIntegrationPlaylist(t *testing.T) { t.Run("with dual write (unified storage, mode 3)", func(t *testing.T) { doPlaylistTests(t, apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{ - AppModeProduction: false, // required for unified storage - DisableAnonymous: true, - APIServerStorageType: options.StorageTypeUnified, // use the entity api tables + DisableDataMigrations: true, + AppModeProduction: false, // required for unified storage + DisableAnonymous: true, + APIServerStorageType: options.StorageTypeUnified, // use the entity api tables UnifiedStorageConfig: map[string]setting.UnifiedStorageConfig{ RESOURCEGROUP: { DualWriterMode: grafanarest.Mode3, @@ -246,9 +256,10 @@ func TestIntegrationPlaylist(t *testing.T) { t.Run("with dual write (unified storage, mode 5)", func(t *testing.T) { doPlaylistTests(t, apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{ - AppModeProduction: false, // required for unified storage - DisableAnonymous: true, - APIServerStorageType: options.StorageTypeUnified, // use the entity api tables + DisableDataMigrations: true, + AppModeProduction: false, // required for unified storage + DisableAnonymous: true, + APIServerStorageType: options.StorageTypeUnified, // use the entity api tables UnifiedStorageConfig: map[string]setting.UnifiedStorageConfig{ RESOURCEGROUP: { DualWriterMode: grafanarest.Mode5, @@ -262,9 +273,10 @@ func TestIntegrationPlaylist(t *testing.T) { t.Skip("local etcd testing") helper := apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{ - AppModeProduction: true, - DisableAnonymous: true, - APIServerStorageType: options.StorageTypeEtcd, // requires etcd running on localhost:2379 + DisableDataMigrations: true, + AppModeProduction: true, + DisableAnonymous: true, + APIServerStorageType: options.StorageTypeEtcd, // requires etcd running on localhost:2379 UnifiedStorageConfig: map[string]setting.UnifiedStorageConfig{ RESOURCEGROUP: { DualWriterMode: grafanarest.Mode0, @@ -288,9 +300,10 @@ func TestIntegrationPlaylist(t *testing.T) { t.Skip("local etcd testing") helper := apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{ - AppModeProduction: true, - DisableAnonymous: true, - APIServerStorageType: options.StorageTypeEtcd, // requires etcd running on localhost:2379 + DisableDataMigrations: true, + AppModeProduction: true, + DisableAnonymous: true, + APIServerStorageType: options.StorageTypeEtcd, // requires etcd running on localhost:2379 UnifiedStorageConfig: map[string]setting.UnifiedStorageConfig{ RESOURCEGROUP: { DualWriterMode: grafanarest.Mode1, @@ -314,9 +327,10 @@ func TestIntegrationPlaylist(t *testing.T) { t.Skip("local etcd testing") helper := apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{ - AppModeProduction: true, - DisableAnonymous: true, - APIServerStorageType: options.StorageTypeEtcd, // requires etcd running on localhost:2379 + DisableDataMigrations: true, + AppModeProduction: true, + DisableAnonymous: true, + APIServerStorageType: options.StorageTypeEtcd, // requires etcd running on localhost:2379 UnifiedStorageConfig: map[string]setting.UnifiedStorageConfig{ RESOURCEGROUP: { DualWriterMode: grafanarest.Mode2, @@ -340,9 +354,10 @@ func TestIntegrationPlaylist(t *testing.T) { t.Skip("local etcd testing") helper := apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{ - AppModeProduction: true, - DisableAnonymous: true, - APIServerStorageType: options.StorageTypeEtcd, // requires etcd running on localhost:2379 + DisableDataMigrations: true, + AppModeProduction: true, + DisableAnonymous: true, + APIServerStorageType: options.StorageTypeEtcd, // requires etcd running on localhost:2379 UnifiedStorageConfig: map[string]setting.UnifiedStorageConfig{ RESOURCEGROUP: { DualWriterMode: grafanarest.Mode3, @@ -366,9 +381,10 @@ func TestIntegrationPlaylist(t *testing.T) { t.Skip("local etcd testing") helper := apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{ - AppModeProduction: true, - DisableAnonymous: true, - APIServerStorageType: options.StorageTypeEtcd, // requires etcd running on localhost:2379 + DisableDataMigrations: true, + AppModeProduction: true, + DisableAnonymous: true, + APIServerStorageType: options.StorageTypeEtcd, // requires etcd running on localhost:2379 UnifiedStorageConfig: map[string]setting.UnifiedStorageConfig{ RESOURCEGROUP: { DualWriterMode: grafanarest.Mode5, diff --git a/pkg/tests/apis/plugins/discovery_test.go b/pkg/tests/apis/plugins/discovery_test.go index 5e211cc45a1..1cbcfff487a 100644 --- a/pkg/tests/apis/plugins/discovery_test.go +++ b/pkg/tests/apis/plugins/discovery_test.go @@ -57,7 +57,7 @@ func TestIntegrationPluginsIntegrationDiscovery(t *testing.T) { "version": "" }, "scope": "Namespaced", - "singularResource": "plugins", + "singularResource": "plugin", "subresources": [ { "responseKind": { diff --git a/pkg/tests/apis/plugins/metas_test.go b/pkg/tests/apis/plugins/metas_test.go index c240d3fb91d..0132ee72173 100644 --- a/pkg/tests/apis/plugins/metas_test.go +++ b/pkg/tests/apis/plugins/metas_test.go @@ -28,7 +28,7 @@ func TestIntegrationPluginMeta(t *testing.T) { "apiVersion": "plugins.grafana.app/v0alpha1", "kind": "Plugin", "metadata": {"name": "%s"}, - "spec": {"id": "grafana-piechart-panel", "version": "1.0.0"} + "spec": {"id": "piechart", "version": "1.0.0"} }`, plugin1Name)) _, err := client.Resource.Create(ctx, plugin1, metav1.CreateOptions{}) require.NoError(t, err) @@ -38,7 +38,7 @@ func TestIntegrationPluginMeta(t *testing.T) { "apiVersion": "plugins.grafana.app/v0alpha1", "kind": "Plugin", "metadata": {"name": "%s"}, - "spec": {"id": "grafana-clock-panel", "version": "1.0.0"} + "spec": {"id": "table", "version": "1.0.0"} }`, plugin2Name)) _, err = client.Resource.Create(ctx, plugin2, metav1.CreateOptions{}) require.NoError(t, err) @@ -57,14 +57,14 @@ func TestIntegrationPluginMeta(t *testing.T) { foundIDs := make(map[string]bool) for _, item := range response.Result.Items { - require.NotNil(t, item.Spec.PluginJSON) - foundIDs[item.Spec.PluginJSON.Id] = true - require.NotEmpty(t, item.Spec.PluginJSON.Id) - require.NotEmpty(t, item.Spec.PluginJSON.Type) - require.NotEmpty(t, item.Spec.PluginJSON.Name) + require.NotNil(t, item.Spec.PluginJson) + foundIDs[item.Spec.PluginJson.Id] = true + require.NotEmpty(t, item.Spec.PluginJson.Id) + require.NotEmpty(t, item.Spec.PluginJson.Type) + require.NotEmpty(t, item.Spec.PluginJson.Name) } - require.True(t, foundIDs["grafana-piechart-panel"]) - require.True(t, foundIDs["grafana-clock-panel"]) + require.True(t, foundIDs["piechart"]) + require.True(t, foundIDs["table"]) }) t.Run("list plugin metas with no plugins", func(t *testing.T) { @@ -95,7 +95,7 @@ func TestIntegrationPluginMeta(t *testing.T) { "apiVersion": "plugins.grafana.app/v0alpha1", "kind": "Plugin", "metadata": {"name": "%s"}, - "spec": {"id": "grafana-piechart-panel", "version": "1.0.0"} + "spec": {"id": "piechart", "version": "1.0.0"} }`, pluginName)) _, err := client.Resource.Create(ctx, plugin, metav1.CreateOptions{}) require.NoError(t, err) @@ -109,10 +109,10 @@ func TestIntegrationPluginMeta(t *testing.T) { }, &pluginsv0alpha1.Meta{}) require.NotNil(t, response.Result) - require.NotNil(t, response.Result.Spec.PluginJSON) - require.Equal(t, "grafana-piechart-panel", response.Result.Spec.PluginJSON.Id) - require.NotEmpty(t, response.Result.Spec.PluginJSON.Name) - require.NotEmpty(t, response.Result.Spec.PluginJSON.Type) + require.NotNil(t, response.Result.Spec.PluginJson) + require.Equal(t, "piechart", response.Result.Spec.PluginJson.Id) + require.NotEmpty(t, response.Result.Spec.PluginJson.Name) + require.NotEmpty(t, response.Result.Spec.PluginJson.Type) }) t.Run("get plugin meta for non-existent plugin", func(t *testing.T) { diff --git a/pkg/tests/apis/provisioning/connection_status_auth_test.go b/pkg/tests/apis/provisioning/connection_status_auth_test.go new file mode 100644 index 00000000000..fbddd85999a --- /dev/null +++ b/pkg/tests/apis/provisioning/connection_status_auth_test.go @@ -0,0 +1,88 @@ +package provisioning + +import ( + "context" + "net/http" + "testing" + + "github.com/stretchr/testify/require" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + + "github.com/grafana/grafana/pkg/util/testutil" +) + +func TestIntegrationProvisioning_ConnectionStatusAuthorization(t *testing.T) { + testutil.SkipIntegrationTestInShortMode(t) + + helper := runGrafana(t) + ctx := context.Background() + createOptions := metav1.CreateOptions{FieldValidation: "Strict"} + + // Create a connection for testing + connection := &unstructured.Unstructured{Object: map[string]any{ + "apiVersion": "provisioning.grafana.app/v0alpha1", + "kind": "Connection", + "metadata": map[string]any{ + "name": "connection-status-test", + "namespace": "default", + }, + "spec": map[string]any{ + "type": "github", + "github": map[string]any{ + "appID": "123456", + "installationID": "454545", + }, + }, + "secure": map[string]any{ + "privateKey": map[string]any{ + "create": "someSecret", + }, + }, + }} + + _, err := helper.Connections.Resource.Create(ctx, connection, createOptions) + require.NoError(t, err, "failed to create connection") + + t.Run("admin can GET connection status", func(t *testing.T) { + var statusCode int + result := helper.AdminREST.Get(). + Namespace("default"). + Resource("connections"). + Name("connection-status-test"). + SubResource("status"). + Do(ctx).StatusCode(&statusCode) + + require.NoError(t, result.Error(), "admin should be able to GET connection status") + require.Equal(t, http.StatusOK, statusCode, "should return 200 OK") + }) + + t.Run("editor cannot GET connection status", func(t *testing.T) { + var statusCode int + result := helper.EditorREST.Get(). + Namespace("default"). + Resource("connections"). + Name("connection-status-test"). + SubResource("status"). + Do(ctx).StatusCode(&statusCode) + + require.Error(t, result.Error(), "editor should not be able to GET connection status") + require.Equal(t, http.StatusForbidden, statusCode, "should return 403 Forbidden") + require.True(t, apierrors.IsForbidden(result.Error()), "error should be forbidden") + }) + + t.Run("viewer cannot GET connection status", func(t *testing.T) { + var statusCode int + result := helper.ViewerREST.Get(). + Namespace("default"). + Resource("connections"). + Name("connection-status-test"). + SubResource("status"). + Do(ctx).StatusCode(&statusCode) + + require.Error(t, result.Error(), "viewer should not be able to GET connection status") + require.Equal(t, http.StatusForbidden, statusCode, "should return 403 Forbidden") + require.True(t, apierrors.IsForbidden(result.Error()), "error should be forbidden") + }) +} diff --git a/pkg/tests/apis/provisioning/exportjob_test.go b/pkg/tests/apis/provisioning/exportjob_test.go index 2218e87ef77..5d4348d23cb 100644 --- a/pkg/tests/apis/provisioning/exportjob_test.go +++ b/pkg/tests/apis/provisioning/exportjob_test.go @@ -44,6 +44,7 @@ func TestIntegrationProvisioning_ExportUnifiedToRepository(t *testing.T) { const repo = "local-repository" testRepo := TestRepo{ Name: repo, + Target: "instance", // Export is only supported for instance sync Copies: map[string]string{}, // No initial files needed for export test ExpectedDashboards: 4, // 4 dashboards created above (v0, v1, v2alpha1, v2beta1) ExpectedFolders: 0, // No folders expected after sync @@ -177,6 +178,7 @@ func TestIntegrationProvisioning_ExportDashboardsWithStoredVersions(t *testing.T const repo = "version-test-repository" testRepo := TestRepo{ Name: repo, + Target: "instance", // Export is only supported for instance sync Copies: map[string]string{}, ExpectedDashboards: len(tests), ExpectedFolders: 0, diff --git a/pkg/tests/apis/provisioning/files_test.go b/pkg/tests/apis/provisioning/files_test.go index 823241aa6b0..e31674be505 100644 --- a/pkg/tests/apis/provisioning/files_test.go +++ b/pkg/tests/apis/provisioning/files_test.go @@ -1,7 +1,9 @@ package provisioning import ( + "bytes" "context" + "encoding/json" "errors" "fmt" "io" @@ -11,6 +13,7 @@ import ( "testing" "github.com/grafana/grafana/pkg/apimachinery/utils" + "github.com/grafana/grafana/pkg/services/accesscontrol/resourcepermissions" "github.com/grafana/grafana/pkg/util/testutil" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -590,3 +593,390 @@ func TestIntegrationProvisioning_FilesOwnershipProtection(t *testing.T) { require.Equal(t, repo2, dashboard2.GetAnnotations()[utils.AnnoKeyManagerIdentity], "repo2's dashboard should still be owned by repo2") }) } + +func TestIntegrationProvisioning_FilesAuthorization(t *testing.T) { + testutil.SkipIntegrationTestInShortMode(t) + + helper := runGrafana(t) + ctx := context.Background() + + const repo = "auth-test-repo" + helper.CreateRepo(t, TestRepo{ + Name: repo, + Path: helper.ProvisioningPath, + Target: "instance", + Copies: map[string]string{ + "testdata/all-panels.json": "dashboard1.json", + }, + ExpectedDashboards: 1, + ExpectedFolders: 0, + }) + + // Wait for initial sync to complete + var dashboardUID string + require.EventuallyWithT(t, func(collect *assert.CollectT) { + dashboards, err := helper.DashboardsV1.Resource.List(t.Context(), metav1.ListOptions{}) + if err != nil { + collect.Errorf("could not list dashboards error: %s", err.Error()) + return + } + if len(dashboards.Items) != 1 { + collect.Errorf("should have the expected dashboards after sync. got: %d. expected: %d", len(dashboards.Items), 1) + return + } + assert.Len(collect, dashboards.Items, 1) + dashboardUID = dashboards.Items[0].GetName() + }, waitTimeoutDefault, waitIntervalDefault, "should have the expected dashboards after sync") + + // Grant permissions to Editor user for all dashboards using wildcard + // The access checker checks resource-level permissions, so we need to grant them + // Using wildcard "*" to grant permissions to all dashboards (including ones created during tests) + // Note: Viewer role gets permissions via HTTP API below, Editor gets them here via SetPermissions + helper.SetPermissions(helper.Org1.Editor, []resourcepermissions.SetResourcePermissionCommand{ + { + Actions: []string{"dashboards:read", "dashboards:write", "dashboards:delete"}, + Resource: "dashboards", + ResourceAttribute: "uid", + ResourceID: "*", + }, + }) + + // Grant view permission to Viewer role via HTTP API (for the initial dashboard) + // Note: This only grants permissions to the initial dashboard, but viewers should be able to read all + addr := helper.GetEnv().Server.HTTPServer.Listener.Addr().String() + setDashboardPermissions := func(permissions []map[string]interface{}) { + payload := map[string]interface{}{ + "items": permissions, + } + payloadBytes, err := json.Marshal(payload) + require.NoError(t, err) + url := fmt.Sprintf("http://admin:admin@%s/api/dashboards/uid/%s/permissions", addr, dashboardUID) + req, err := http.NewRequest(http.MethodPost, url, bytes.NewBuffer(payloadBytes)) + require.NoError(t, err) + req.Header.Set("Content-Type", "application/json") + resp, err := http.DefaultClient.Do(req) + require.NoError(t, err) + require.Equal(t, http.StatusOK, resp.StatusCode) + require.NoError(t, resp.Body.Close()) + } + + // Grant view permission to Viewer role for the initial dashboard + setDashboardPermissions([]map[string]interface{}{ + {"role": "Viewer", "permission": 1}, // View permission + }) + + t.Run("GET operations", func(t *testing.T) { + t.Run("viewer can GET files", func(t *testing.T) { + var statusCode int + result := helper.ViewerREST.Get(). + Namespace("default"). + Resource("repositories"). + Name(repo). + SubResource("files", "dashboard1.json"). + Do(ctx).StatusCode(&statusCode) + + require.NoError(t, result.Error(), "viewer should be able to GET files") + require.Equal(t, http.StatusOK, statusCode, "should return 200 OK") + }) + + t.Run("editor can GET files", func(t *testing.T) { + var statusCode int + result := helper.EditorREST.Get(). + Namespace("default"). + Resource("repositories"). + Name(repo). + SubResource("files", "dashboard1.json"). + Do(ctx).StatusCode(&statusCode) + + require.NoError(t, result.Error(), "editor should be able to GET files") + require.Equal(t, http.StatusOK, statusCode, "should return 200 OK") + }) + + t.Run("admin can GET files", func(t *testing.T) { + var statusCode int + result := helper.AdminREST.Get(). + Namespace("default"). + Resource("repositories"). + Name(repo). + SubResource("files", "dashboard1.json"). + Do(ctx).StatusCode(&statusCode) + + require.NoError(t, result.Error(), "admin should be able to GET files") + require.Equal(t, http.StatusOK, statusCode, "should return 200 OK") + }) + }) + + t.Run("POST operations", func(t *testing.T) { + t.Run("viewer cannot POST files", func(t *testing.T) { + var statusCode int + result := helper.ViewerREST.Post(). + Namespace("default"). + Resource("repositories"). + Name(repo). + SubResource("files", "viewer-test.json"). + Body(helper.LoadFile("testdata/text-options.json")). + SetHeader("Content-Type", "application/json"). + Do(ctx).StatusCode(&statusCode) + + require.Error(t, result.Error(), "viewer should not be able to POST files") + require.Equal(t, http.StatusForbidden, statusCode, "should return 403 Forbidden") + require.True(t, apierrors.IsForbidden(result.Error()), "error should be forbidden") + }) + + t.Run("editor can POST files", func(t *testing.T) { + var statusCode int + result := helper.EditorREST.Post(). + Namespace("default"). + Resource("repositories"). + Name(repo). + SubResource("files", "editor-test.json"). + Body(helper.LoadFile("testdata/text-options.json")). + SetHeader("Content-Type", "application/json"). + Do(ctx).StatusCode(&statusCode) + + require.NoError(t, result.Error(), "editor should be able to POST files") + require.Equal(t, http.StatusOK, statusCode, "should return 200 OK") + + // Clean up + helper.AdminREST.Delete(). + Namespace("default"). + Resource("repositories"). + Name(repo). + SubResource("files", "editor-test.json"). + Do(ctx) + }) + + t.Run("admin can POST files", func(t *testing.T) { + var statusCode int + result := helper.AdminREST.Post(). + Namespace("default"). + Resource("repositories"). + Name(repo). + SubResource("files", "admin-test.json"). + Body(helper.LoadFile("testdata/text-options.json")). + SetHeader("Content-Type", "application/json"). + Do(ctx).StatusCode(&statusCode) + + require.NoError(t, result.Error(), "admin should be able to POST files") + require.Equal(t, http.StatusOK, statusCode, "should return 200 OK") + + // Clean up + helper.AdminREST.Delete(). + Namespace("default"). + Resource("repositories"). + Name(repo). + SubResource("files", "admin-test.json"). + Do(ctx) + }) + }) + + t.Run("PUT operations", func(t *testing.T) { + // Create a test file first using admin + helper.AdminREST.Post(). + Namespace("default"). + Resource("repositories"). + Name(repo). + SubResource("files", "update-test.json"). + Body(helper.LoadFile("testdata/text-options.json")). + SetHeader("Content-Type", "application/json"). + Do(ctx) + + t.Run("viewer cannot PUT files", func(t *testing.T) { + var statusCode int + result := helper.ViewerREST.Put(). + Namespace("default"). + Resource("repositories"). + Name(repo). + SubResource("files", "update-test.json"). + Body(helper.LoadFile("testdata/timeline-demo.json")). + SetHeader("Content-Type", "application/json"). + Do(ctx).StatusCode(&statusCode) + + require.Error(t, result.Error(), "viewer should not be able to PUT files") + require.Equal(t, http.StatusForbidden, statusCode, "should return 403 Forbidden") + require.True(t, apierrors.IsForbidden(result.Error()), "error should be forbidden") + }) + + t.Run("editor can PUT files", func(t *testing.T) { + var statusCode int + result := helper.EditorREST.Put(). + Namespace("default"). + Resource("repositories"). + Name(repo). + SubResource("files", "update-test.json"). + Body(helper.LoadFile("testdata/timeline-demo.json")). + SetHeader("Content-Type", "application/json"). + Do(ctx).StatusCode(&statusCode) + + require.NoError(t, result.Error(), "editor should be able to PUT files") + require.Equal(t, http.StatusOK, statusCode, "should return 200 OK") + }) + + t.Run("admin can PUT files", func(t *testing.T) { + var statusCode int + result := helper.AdminREST.Put(). + Namespace("default"). + Resource("repositories"). + Name(repo). + SubResource("files", "update-test.json"). + Body(helper.LoadFile("testdata/text-options.json")). + SetHeader("Content-Type", "application/json"). + Do(ctx).StatusCode(&statusCode) + + require.NoError(t, result.Error(), "admin should be able to PUT files") + require.Equal(t, http.StatusOK, statusCode, "should return 200 OK") + }) + + // Clean up + helper.AdminREST.Delete(). + Namespace("default"). + Resource("repositories"). + Name(repo). + SubResource("files", "update-test.json"). + Do(ctx) + }) + + t.Run("DELETE operations", func(t *testing.T) { + // Create test files for deletion tests + helper.AdminREST.Post(). + Namespace("default"). + Resource("repositories"). + Name(repo). + SubResource("files", "delete-viewer-test.json"). + Body(helper.LoadFile("testdata/text-options.json")). + SetHeader("Content-Type", "application/json"). + Do(ctx) + + helper.AdminREST.Post(). + Namespace("default"). + Resource("repositories"). + Name(repo). + SubResource("files", "delete-editor-test.json"). + Body(helper.LoadFile("testdata/text-options.json")). + SetHeader("Content-Type", "application/json"). + Do(ctx) + + helper.AdminREST.Post(). + Namespace("default"). + Resource("repositories"). + Name(repo). + SubResource("files", "delete-admin-test.json"). + Body(helper.LoadFile("testdata/text-options.json")). + SetHeader("Content-Type", "application/json"). + Do(ctx) + + t.Run("viewer cannot DELETE files", func(t *testing.T) { + var statusCode int + result := helper.ViewerREST.Delete(). + Namespace("default"). + Resource("repositories"). + Name(repo). + SubResource("files", "delete-viewer-test.json"). + Do(ctx).StatusCode(&statusCode) + + require.Error(t, result.Error(), "viewer should not be able to DELETE files") + require.Equal(t, http.StatusForbidden, statusCode, "should return 403 Forbidden") + require.True(t, apierrors.IsForbidden(result.Error()), "error should be forbidden") + + // Verify file still exists + _, err := helper.Repositories.Resource.Get(ctx, repo, metav1.GetOptions{}, "files", "delete-viewer-test.json") + require.NoError(t, err, "file should still exist after failed delete") + }) + + t.Run("editor can DELETE files", func(t *testing.T) { + var statusCode int + result := helper.EditorREST.Delete(). + Namespace("default"). + Resource("repositories"). + Name(repo). + SubResource("files", "delete-editor-test.json"). + Do(ctx).StatusCode(&statusCode) + + require.NoError(t, result.Error(), "editor should be able to DELETE files") + require.Equal(t, http.StatusOK, statusCode, "should return 200 OK") + + // Verify file was deleted + _, err := helper.Repositories.Resource.Get(ctx, repo, metav1.GetOptions{}, "files", "delete-editor-test.json") + require.Error(t, err, "file should be deleted") + require.True(t, apierrors.IsNotFound(err), "should return NotFound for deleted file") + }) + + t.Run("admin can DELETE files", func(t *testing.T) { + var statusCode int + result := helper.AdminREST.Delete(). + Namespace("default"). + Resource("repositories"). + Name(repo). + SubResource("files", "delete-admin-test.json"). + Do(ctx).StatusCode(&statusCode) + + require.NoError(t, result.Error(), "admin should be able to DELETE files") + require.Equal(t, http.StatusOK, statusCode, "should return 200 OK") + + // Verify file was deleted + _, err := helper.Repositories.Resource.Get(ctx, repo, metav1.GetOptions{}, "files", "delete-admin-test.json") + require.Error(t, err, "file should be deleted") + require.True(t, apierrors.IsNotFound(err), "should return NotFound for deleted file") + }) + }) + + t.Run("folder operations", func(t *testing.T) { + t.Run("viewer cannot create folders", func(t *testing.T) { + // Create a folder by POSTing to a directory path + addr := helper.GetEnv().Server.HTTPServer.Listener.Addr().String() + url := fmt.Sprintf("http://viewer:viewer@%s/apis/provisioning.grafana.app/v0alpha1/namespaces/default/repositories/%s/files/test-folder/", addr, repo) + req, err := http.NewRequest(http.MethodPost, url, nil) + require.NoError(t, err) + resp, err := http.DefaultClient.Do(req) + require.NoError(t, err) + // nolint:errcheck + defer resp.Body.Close() + + require.Equal(t, http.StatusForbidden, resp.StatusCode, "viewer should not be able to create folders") + }) + + t.Run("editor can create folders", func(t *testing.T) { + addr := helper.GetEnv().Server.HTTPServer.Listener.Addr().String() + url := fmt.Sprintf("http://editor:editor@%s/apis/provisioning.grafana.app/v0alpha1/namespaces/default/repositories/%s/files/editor-folder/", addr, repo) + req, err := http.NewRequest(http.MethodPost, url, nil) + require.NoError(t, err) + resp, err := http.DefaultClient.Do(req) + require.NoError(t, err) + // nolint:errcheck + defer resp.Body.Close() + + require.Equal(t, http.StatusOK, resp.StatusCode, "editor should be able to create folders") + + // Clean up - delete folder + deleteURL := fmt.Sprintf("http://admin:admin@%s/apis/provisioning.grafana.app/v0alpha1/namespaces/default/repositories/%s/files/editor-folder/", addr, repo) + deleteReq, err := http.NewRequest(http.MethodDelete, deleteURL, nil) + require.NoError(t, err) + deleteResp, err := http.DefaultClient.Do(deleteReq) + require.NoError(t, err) + // nolint:errcheck + defer deleteResp.Body.Close() + }) + + t.Run("admin can create folders", func(t *testing.T) { + addr := helper.GetEnv().Server.HTTPServer.Listener.Addr().String() + url := fmt.Sprintf("http://admin:admin@%s/apis/provisioning.grafana.app/v0alpha1/namespaces/default/repositories/%s/files/admin-folder/", addr, repo) + req, err := http.NewRequest(http.MethodPost, url, nil) + require.NoError(t, err) + resp, err := http.DefaultClient.Do(req) + require.NoError(t, err) + // nolint:errcheck + defer resp.Body.Close() + + require.Equal(t, http.StatusOK, resp.StatusCode, "admin should be able to create folders") + + // Clean up - delete folder + deleteURL := fmt.Sprintf("http://admin:admin@%s/apis/provisioning.grafana.app/v0alpha1/namespaces/default/repositories/%s/files/admin-folder/", addr, repo) + deleteReq, err := http.NewRequest(http.MethodDelete, deleteURL, nil) + require.NoError(t, err) + deleteResp, err := http.DefaultClient.Do(deleteReq) + require.NoError(t, err) + // nolint:errcheck + defer deleteResp.Body.Close() + }) + }) +} diff --git a/pkg/tests/apis/provisioning/helper_test.go b/pkg/tests/apis/provisioning/helper_test.go index 5f2ec6a3985..791ac4b8a20 100644 --- a/pkg/tests/apis/provisioning/helper_test.go +++ b/pkg/tests/apis/provisioning/helper_test.go @@ -681,15 +681,23 @@ func runGrafana(t *testing.T, options ...grafanaOption) *provisioningTestHelper EnableFeatureToggles: []string{ featuremgmt.FlagProvisioning, }, + // Provisioning requires resources to be fully migrated to unified storage. + // Mode5 ensures reads/writes go to unified storage, and EnableMigration + // enables the data migration at startup to migrate legacy data. UnifiedStorageConfig: map[string]setting.UnifiedStorageConfig{ "dashboards.dashboard.grafana.app": { - DualWriterMode: grafanarest.Mode5, + DualWriterMode: grafanarest.Mode5, + EnableMigration: true, }, "folders.folder.grafana.app": { - DualWriterMode: grafanarest.Mode5, + DualWriterMode: grafanarest.Mode5, + EnableMigration: true, }, }, PermittedProvisioningPaths: ".|" + provisioningPath, + // Allow both folder and instance sync targets for tests + // (instance is needed for export jobs, folder for most operations) + ProvisioningAllowedTargets: []string{"folder", "instance"}, } for _, o := range options { o(&opts) diff --git a/pkg/tests/apis/provisioning/historicjobs_auth_test.go b/pkg/tests/apis/provisioning/historicjobs_auth_test.go new file mode 100644 index 00000000000..fc11f8d00b3 --- /dev/null +++ b/pkg/tests/apis/provisioning/historicjobs_auth_test.go @@ -0,0 +1,95 @@ +package provisioning + +import ( + "context" + "net/http" + "testing" + + "github.com/stretchr/testify/require" + apierrors "k8s.io/apimachinery/pkg/api/errors" + + provisioning "github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1" + "github.com/grafana/grafana/pkg/util/testutil" +) + +func TestIntegrationProvisioning_HistoricJobsAuthorization(t *testing.T) { + testutil.SkipIntegrationTestInShortMode(t) + + helper := runGrafana(t) + ctx := context.Background() + + const repo = "historicjobs-auth-test" + testRepo := TestRepo{ + Name: repo, + Target: "folder", + Copies: map[string]string{}, // No files needed for this test + ExpectedDashboards: 0, + ExpectedFolders: 1, // Repository creates a folder + } + helper.CreateRepo(t, testRepo) + + // Trigger a job to create a historic job entry + jobSpec := provisioning.JobSpec{ + Action: provisioning.JobActionPull, + Pull: &provisioning.SyncJobOptions{}, + } + body := asJSON(jobSpec) + + // Create a job as admin + var statusCode int + result := helper.AdminREST.Post(). + Namespace("default"). + Resource("repositories"). + Name(repo). + SubResource("jobs"). + Body(body). + SetHeader("Content-Type", "application/json"). + Do(ctx).StatusCode(&statusCode) + require.NoError(t, result.Error(), "should be able to create job") + require.Equal(t, http.StatusAccepted, statusCode) + + // Wait for job to complete and become historic + helper.AwaitJobs(t, repo) + historicJob := helper.AwaitLatestHistoricJob(t, repo) + require.NotNil(t, historicJob, "should have a historic job") + + historicJobName := historicJob.GetName() + + t.Run("admin can GET historic job", func(t *testing.T) { + var statusCode int + result := helper.AdminREST.Get(). + Namespace("default"). + Resource("historicjobs"). + Name(historicJobName). + Do(ctx).StatusCode(&statusCode) + + require.NoError(t, result.Error(), "admin should be able to GET historic job") + require.Equal(t, http.StatusOK, statusCode, "should return 200 OK") + }) + + t.Run("editor cannot GET historic job", func(t *testing.T) { + var statusCode int + result := helper.EditorREST.Get(). + Namespace("default"). + Resource("historicjobs"). + Name(historicJobName). + Do(ctx).StatusCode(&statusCode) + + require.Error(t, result.Error(), "editor should not be able to GET historic job") + require.Equal(t, http.StatusForbidden, statusCode, "should return 403 Forbidden") + require.True(t, apierrors.IsForbidden(result.Error()), "error should be forbidden") + }) + + t.Run("viewer cannot GET historic job", func(t *testing.T) { + var statusCode int + result := helper.ViewerREST.Get(). + Namespace("default"). + Resource("historicjobs"). + Name(historicJobName). + Do(ctx).StatusCode(&statusCode) + + require.Error(t, result.Error(), "viewer should not be able to GET historic job") + require.Equal(t, http.StatusForbidden, statusCode, "should return 403 Forbidden") + require.True(t, apierrors.IsForbidden(result.Error()), "error should be forbidden") + }) +} diff --git a/pkg/tests/apis/provisioning/job_validation_test.go b/pkg/tests/apis/provisioning/job_validation_test.go index c54ad58500c..4c1947693f1 100644 --- a/pkg/tests/apis/provisioning/job_validation_test.go +++ b/pkg/tests/apis/provisioning/job_validation_test.go @@ -24,10 +24,10 @@ func TestIntegrationProvisioning_JobValidation(t *testing.T) { const repo = "job-validation-test-repo" testRepo := TestRepo{ Name: repo, - Target: "instance", + Target: "folder", Copies: map[string]string{}, ExpectedDashboards: 0, - ExpectedFolders: 0, + ExpectedFolders: 1, // folder sync creates a folder } helper.CreateRepo(t, testRepo) diff --git a/pkg/tests/apis/provisioning/movejob_test.go b/pkg/tests/apis/provisioning/movejob_test.go index 85d227996fd..9cd298711a9 100644 --- a/pkg/tests/apis/provisioning/movejob_test.go +++ b/pkg/tests/apis/provisioning/movejob_test.go @@ -24,14 +24,15 @@ func TestIntegrationProvisioning_MoveJob(t *testing.T) { ctx := context.Background() const repo = "move-test-repo" testRepo := TestRepo{ - Name: repo, + Name: repo, + Target: "folder", Copies: map[string]string{ "testdata/all-panels.json": "dashboard1.json", "testdata/text-options.json": "dashboard2.json", "testdata/timeline-demo.json": "folder/dashboard3.json", }, ExpectedDashboards: 3, - ExpectedFolders: 1, + ExpectedFolders: 2, // folder sync creates a folder for the repo + one nested folder } helper.CreateRepo(t, testRepo) @@ -236,6 +237,7 @@ func TestIntegrationProvisioning_MoveJob(t *testing.T) { const refRepo = "move-ref-test-repo" helper.CreateRepo(t, TestRepo{ Name: refRepo, + Target: "folder", SkipResourceAssertions: true, // HACK: I am not sure why sometimes it's 6 or 3 dashbaords. }) diff --git a/pkg/tests/apis/provisioning/repository_subresources_auth_test.go b/pkg/tests/apis/provisioning/repository_subresources_auth_test.go new file mode 100644 index 00000000000..54a2f173b51 --- /dev/null +++ b/pkg/tests/apis/provisioning/repository_subresources_auth_test.go @@ -0,0 +1,236 @@ +package provisioning + +import ( + "context" + "encoding/json" + "net/http" + "testing" + + "github.com/stretchr/testify/require" + apierrors "k8s.io/apimachinery/pkg/api/errors" + + "github.com/grafana/grafana/pkg/util/testutil" +) + +func TestIntegrationProvisioning_RepositorySubresourcesAuthorization(t *testing.T) { + testutil.SkipIntegrationTestInShortMode(t) + + helper := runGrafana(t) + ctx := context.Background() + + const repo = "subresources-auth-test" + testRepo := TestRepo{ + Name: repo, + Target: "folder", + Copies: map[string]string{}, // No files needed for this test + ExpectedDashboards: 0, + ExpectedFolders: 1, // Repository creates a folder + } + helper.CreateRepo(t, testRepo) + + t.Run("test subresource", func(t *testing.T) { + newRepoConfig := map[string]any{ + "apiVersion": "provisioning.grafana.app/v0alpha1", + "kind": "Repository", + "spec": map[string]any{ + "title": "Test Configuration", + "type": "local", + "local": map[string]any{ + "path": helper.ProvisioningPath, + }, + "workflows": []string{"write"}, + "sync": map[string]any{ + "enabled": true, + "target": "folder", + "intervalSeconds": 10, + }, + }, + } + configBytes, err := json.Marshal(newRepoConfig) + require.NoError(t, err) + + t.Run("admin can POST test", func(t *testing.T) { + var statusCode int + result := helper.AdminREST.Post(). + Namespace("default"). + Resource("repositories"). + Name("test-config-auth"). + SubResource("test"). + Body(configBytes). + SetHeader("Content-Type", "application/json"). + Do(ctx).StatusCode(&statusCode) + + require.NoError(t, result.Error(), "admin should be able to POST test") + require.Equal(t, http.StatusOK, statusCode, "should return 200 OK") + }) + + t.Run("editor cannot POST test", func(t *testing.T) { + var statusCode int + result := helper.EditorREST.Post(). + Namespace("default"). + Resource("repositories"). + Name("test-config-auth"). + SubResource("test"). + Body(configBytes). + SetHeader("Content-Type", "application/json"). + Do(ctx).StatusCode(&statusCode) + + require.Error(t, result.Error(), "editor should not be able to POST test") + require.Equal(t, http.StatusForbidden, statusCode, "should return 403 Forbidden") + require.True(t, apierrors.IsForbidden(result.Error()), "error should be forbidden") + }) + + t.Run("viewer cannot POST test", func(t *testing.T) { + var statusCode int + result := helper.ViewerREST.Post(). + Namespace("default"). + Resource("repositories"). + Name("test-config-auth"). + SubResource("test"). + Body(configBytes). + SetHeader("Content-Type", "application/json"). + Do(ctx).StatusCode(&statusCode) + + require.Error(t, result.Error(), "viewer should not be able to POST test") + require.Equal(t, http.StatusForbidden, statusCode, "should return 403 Forbidden") + require.True(t, apierrors.IsForbidden(result.Error()), "error should be forbidden") + }) + }) + + t.Run("resources subresource", func(t *testing.T) { + t.Run("admin can GET resources", func(t *testing.T) { + var statusCode int + result := helper.AdminREST.Get(). + Namespace("default"). + Resource("repositories"). + Name(repo). + SubResource("resources"). + Do(ctx).StatusCode(&statusCode) + + require.NoError(t, result.Error(), "admin should be able to GET resources") + require.Equal(t, http.StatusOK, statusCode, "should return 200 OK") + }) + + t.Run("editor cannot GET resources", func(t *testing.T) { + var statusCode int + result := helper.EditorREST.Get(). + Namespace("default"). + Resource("repositories"). + Name(repo). + SubResource("resources"). + Do(ctx).StatusCode(&statusCode) + + require.Error(t, result.Error(), "editor should not be able to GET resources") + require.Equal(t, http.StatusForbidden, statusCode, "should return 403 Forbidden") + require.True(t, apierrors.IsForbidden(result.Error()), "error should be forbidden") + }) + + t.Run("viewer cannot GET resources", func(t *testing.T) { + var statusCode int + result := helper.ViewerREST.Get(). + Namespace("default"). + Resource("repositories"). + Name(repo). + SubResource("resources"). + Do(ctx).StatusCode(&statusCode) + + require.Error(t, result.Error(), "viewer should not be able to GET resources") + require.Equal(t, http.StatusForbidden, statusCode, "should return 403 Forbidden") + require.True(t, apierrors.IsForbidden(result.Error()), "error should be forbidden") + }) + }) + + t.Run("history subresource", func(t *testing.T) { + t.Run("admin can GET history (or BadRequest if not supported)", func(t *testing.T) { + var statusCode int + result := helper.AdminREST.Get(). + Namespace("default"). + Resource("repositories"). + Name(repo). + SubResource("history"). + Do(ctx).StatusCode(&statusCode) + + // Admin should pass authorization - may get BadRequest if repo doesn't support history + // but should NOT get Forbidden (which would indicate authorization failure) + if result.Error() != nil { + require.False(t, apierrors.IsForbidden(result.Error()), "admin should not get Forbidden error") + // Local repos don't support history, so BadRequest is expected + require.True(t, apierrors.IsBadRequest(result.Error()) || statusCode == http.StatusBadRequest, + "should get BadRequest if history not supported, not Forbidden") + } else { + require.Equal(t, http.StatusOK, statusCode, "should return 200 OK if history is supported") + } + }) + + t.Run("editor cannot GET history", func(t *testing.T) { + var statusCode int + result := helper.EditorREST.Get(). + Namespace("default"). + Resource("repositories"). + Name(repo). + SubResource("history"). + Do(ctx).StatusCode(&statusCode) + + require.Error(t, result.Error(), "editor should not be able to GET history") + require.Equal(t, http.StatusForbidden, statusCode, "should return 403 Forbidden") + require.True(t, apierrors.IsForbidden(result.Error()), "error should be forbidden") + }) + + t.Run("viewer cannot GET history", func(t *testing.T) { + var statusCode int + result := helper.ViewerREST.Get(). + Namespace("default"). + Resource("repositories"). + Name(repo). + SubResource("history"). + Do(ctx).StatusCode(&statusCode) + + require.Error(t, result.Error(), "viewer should not be able to GET history") + require.Equal(t, http.StatusForbidden, statusCode, "should return 403 Forbidden") + require.True(t, apierrors.IsForbidden(result.Error()), "error should be forbidden") + }) + }) + + t.Run("status subresource", func(t *testing.T) { + t.Run("admin can GET status", func(t *testing.T) { + var statusCode int + result := helper.AdminREST.Get(). + Namespace("default"). + Resource("repositories"). + Name(repo). + SubResource("status"). + Do(ctx).StatusCode(&statusCode) + + require.NoError(t, result.Error(), "admin should be able to GET status") + require.Equal(t, http.StatusOK, statusCode, "should return 200 OK") + }) + + t.Run("editor cannot GET status", func(t *testing.T) { + var statusCode int + result := helper.EditorREST.Get(). + Namespace("default"). + Resource("repositories"). + Name(repo). + SubResource("status"). + Do(ctx).StatusCode(&statusCode) + + require.Error(t, result.Error(), "editor should not be able to GET status") + require.Equal(t, http.StatusForbidden, statusCode, "should return 403 Forbidden") + require.True(t, apierrors.IsForbidden(result.Error()), "error should be forbidden") + }) + + t.Run("viewer cannot GET status", func(t *testing.T) { + var statusCode int + result := helper.ViewerREST.Get(). + Namespace("default"). + Resource("repositories"). + Name(repo). + SubResource("status"). + Do(ctx).StatusCode(&statusCode) + + require.Error(t, result.Error(), "viewer should not be able to GET status") + require.Equal(t, http.StatusForbidden, statusCode, "should return 403 Forbidden") + require.True(t, apierrors.IsForbidden(result.Error()), "error should be forbidden") + }) + }) +} diff --git a/pkg/tests/apis/provisioning/repository_test.go b/pkg/tests/apis/provisioning/repository_test.go index 877ed0d5f98..f2447e71d23 100644 --- a/pkg/tests/apis/provisioning/repository_test.go +++ b/pkg/tests/apis/provisioning/repository_test.go @@ -578,7 +578,13 @@ func TestIntegrationProvisioning_RunLocalRepository(t *testing.T) { const targetPath = "all-panels.json" // Set up the repository. - helper.CreateRepo(t, TestRepo{Name: repo}) + helper.CreateRepo(t, TestRepo{ + Name: repo, + Target: "folder", + ExpectedDashboards: 0, + ExpectedFolders: 1, // folder sync creates a folder for the repo + SkipResourceAssertions: false, + }) // Write a file -- this will create it *both* in the local file system, and in grafana t.Run("write all panels", func(t *testing.T) { @@ -744,10 +750,10 @@ func TestIntegrationProvisioning_ImportAllPanelsFromLocalRepository(t *testing.T // Set up the repository and the file to import. testRepo := TestRepo{ Name: repo, - Target: "instance", + Target: "folder", Copies: map[string]string{"testdata/all-panels.json": "all-panels.json"}, ExpectedDashboards: 1, - ExpectedFolders: 0, + ExpectedFolders: 1, // folder sync creates a folder } // We create the repository helper.CreateRepo(t, testRepo) @@ -950,3 +956,66 @@ func TestIntegrationProvisioning_JobPermissions(t *testing.T) { require.Equal(t, http.StatusAccepted, statusCode, "should return 202 Accepted") }) } + +func TestIntegrationProvisioning_RefsPermissions(t *testing.T) { + testutil.SkipIntegrationTestInShortMode(t) + + helper := runGrafana(t) + ctx := context.Background() + + const repo = "refs-permissions-test" + testRepo := TestRepo{ + Name: repo, + Template: "testdata/github-readonly.json.tmpl", + Target: "folder", + ExpectedDashboards: 3, + ExpectedFolders: 3, // Repository creates folders + } + helper.CreateRepo(t, testRepo) + + t.Run("editor can GET refs", func(t *testing.T) { + var statusCode int + result := helper.EditorREST.Get(). + Namespace("default"). + Resource("repositories"). + Name(repo). + SubResource("refs"). + Do(ctx).StatusCode(&statusCode) + + require.NoError(t, result.Error(), "editor should be able to GET refs") + require.Equal(t, http.StatusOK, statusCode, "should return 200 OK") + + // Verify we can parse the refs and it contains at least main branch + refs := &provisioning.RefList{} + err := result.Into(refs) + require.NoError(t, err, "should parse refs response") + require.NotEmpty(t, refs.Items, "should have at least one ref") + }) + + t.Run("viewer cannot GET refs", func(t *testing.T) { + var statusCode int + result := helper.ViewerREST.Get(). + Namespace("default"). + Resource("repositories"). + Name(repo). + SubResource("refs"). + Do(ctx).StatusCode(&statusCode) + + require.Error(t, result.Error(), "viewer should not be able to GET refs") + require.Equal(t, http.StatusForbidden, statusCode, "should return 403 Forbidden") + require.True(t, apierrors.IsForbidden(result.Error()), "error should be forbidden") + }) + + t.Run("admin can GET refs", func(t *testing.T) { + var statusCode int + result := helper.AdminREST.Get(). + Namespace("default"). + Resource("repositories"). + Name(repo). + SubResource("refs"). + Do(ctx).StatusCode(&statusCode) + + require.NoError(t, result.Error(), "admin should be able to GET refs") + require.Equal(t, http.StatusOK, statusCode, "should return 200 OK") + }) +} diff --git a/pkg/tests/apis/provisioning/settings_stats_auth_test.go b/pkg/tests/apis/provisioning/settings_stats_auth_test.go new file mode 100644 index 00000000000..d438066235a --- /dev/null +++ b/pkg/tests/apis/provisioning/settings_stats_auth_test.go @@ -0,0 +1,104 @@ +package provisioning + +import ( + "context" + "net/http" + "testing" + + "github.com/stretchr/testify/require" + apierrors "k8s.io/apimachinery/pkg/api/errors" + + "github.com/grafana/grafana/pkg/util/testutil" +) + +func TestIntegrationProvisioning_SettingsAuthorization(t *testing.T) { + testutil.SkipIntegrationTestInShortMode(t) + + helper := runGrafana(t) + ctx := context.Background() + + t.Run("viewer can GET settings", func(t *testing.T) { + var statusCode int + result := helper.ViewerREST.Get(). + Namespace("default"). + Resource("settings"). + Do(ctx).StatusCode(&statusCode) + + require.NoError(t, result.Error(), "viewer should be able to GET settings") + require.Equal(t, http.StatusOK, statusCode, "should return 200 OK") + }) + + t.Run("editor can GET settings", func(t *testing.T) { + var statusCode int + result := helper.EditorREST.Get(). + Namespace("default"). + Resource("settings"). + Do(ctx).StatusCode(&statusCode) + + require.NoError(t, result.Error(), "editor should be able to GET settings") + require.Equal(t, http.StatusOK, statusCode, "should return 200 OK") + }) + + t.Run("admin can GET settings", func(t *testing.T) { + var statusCode int + result := helper.AdminREST.Get(). + Namespace("default"). + Resource("settings"). + Do(ctx).StatusCode(&statusCode) + + require.NoError(t, result.Error(), "admin should be able to GET settings") + require.Equal(t, http.StatusOK, statusCode, "should return 200 OK") + }) +} + +func TestIntegrationProvisioning_StatsAuthorization(t *testing.T) { + testutil.SkipIntegrationTestInShortMode(t) + + helper := runGrafana(t) + ctx := context.Background() + + // Create a repository to ensure stats endpoint has data + const repo = "stats-auth-test" + helper.CreateRepo(t, TestRepo{ + Name: repo, + Target: "folder", + Copies: map[string]string{}, + ExpectedDashboards: 0, + ExpectedFolders: 1, + }) + + t.Run("admin can GET stats", func(t *testing.T) { + var statusCode int + result := helper.AdminREST.Get(). + Namespace("default"). + Resource("stats"). + Do(ctx).StatusCode(&statusCode) + + require.NoError(t, result.Error(), "admin should be able to GET stats") + require.Equal(t, http.StatusOK, statusCode, "should return 200 OK") + }) + + t.Run("editor cannot GET stats", func(t *testing.T) { + var statusCode int + result := helper.EditorREST.Get(). + Namespace("default"). + Resource("stats"). + Do(ctx).StatusCode(&statusCode) + + require.Error(t, result.Error(), "editor should not be able to GET stats") + require.Equal(t, http.StatusForbidden, statusCode, "should return 403 Forbidden") + require.True(t, apierrors.IsForbidden(result.Error()), "error should be forbidden") + }) + + t.Run("viewer cannot GET stats", func(t *testing.T) { + var statusCode int + result := helper.ViewerREST.Get(). + Namespace("default"). + Resource("stats"). + Do(ctx).StatusCode(&statusCode) + + require.Error(t, result.Error(), "viewer should not be able to GET stats") + require.Equal(t, http.StatusForbidden, statusCode, "should return 403 Forbidden") + require.True(t, apierrors.IsForbidden(result.Error()), "error should be forbidden") + }) +} diff --git a/pkg/tests/apis/provisioning/stats_test.go b/pkg/tests/apis/provisioning/stats_test.go index eae3cbf7531..25ecd5c8f7c 100644 --- a/pkg/tests/apis/provisioning/stats_test.go +++ b/pkg/tests/apis/provisioning/stats_test.go @@ -21,13 +21,14 @@ func TestIntegrationProvisioning_Stats(t *testing.T) { const repo = "stats-test-repo1" testRepo := TestRepo{ - Name: repo, + Name: repo, + Target: "folder", Copies: map[string]string{ "testdata/all-panels.json": "dashboard1.json", "testdata/text-options.json": "folder/dashboard2.json", }, ExpectedDashboards: 2, - ExpectedFolders: 1, + ExpectedFolders: 2, // folder sync creates a folder for the repo + one nested folder } helper.CreateRepo(t, testRepo) @@ -94,7 +95,7 @@ func TestIntegrationProvisioning_Stats(t *testing.T) { require.Equal(t, int64(2), count, "repo should manage 2 dashboards") } else if group == "folder.grafana.app" && resource == "folders" { count, _, _ := unstructured.NestedInt64(stat, "count") - require.Equal(t, int64(1), count, "repo should manage 1 folder") + require.Equal(t, int64(2), count, "repo should manage 2 folders (repo folder + nested folder)") } } } diff --git a/pkg/tests/testinfra/testinfra.go b/pkg/tests/testinfra/testinfra.go index e9795f945ab..6e2f0660c32 100644 --- a/pkg/tests/testinfra/testinfra.go +++ b/pkg/tests/testinfra/testinfra.go @@ -362,6 +362,13 @@ func CreateGrafDir(t *testing.T, opts GrafanaOpts) (string, string) { _, err = rbacSect.NewKey("permission_cache", "false") require.NoError(t, err) + if opts.DisableAuthZClientCache { + authzSect, err := cfg.NewSection("authorization") + require.NoError(t, err) + _, err = authzSect.NewKey("cache_ttl", "0") + require.NoError(t, err) + } + analyticsSect, err := cfg.NewSection("analytics") require.NoError(t, err) _, err = analyticsSect.NewKey("intercom_secret", "intercom_secret_at_config") @@ -547,6 +554,8 @@ func CreateGrafDir(t *testing.T, opts GrafanaOpts) (string, string) { require.NoError(t, err) _, err = section.NewKey("dualWriterMode", fmt.Sprintf("%d", v.DualWriterMode)) require.NoError(t, err) + _, err = section.NewKey("enableMigration", fmt.Sprintf("%t", v.EnableMigration)) + require.NoError(t, err) } } if opts.UnifiedStorageEnableSearch { @@ -571,6 +580,12 @@ func CreateGrafDir(t *testing.T, opts GrafanaOpts) (string, string) { _, err = pathsSect.NewKey("permitted_provisioning_paths", opts.PermittedProvisioningPaths) require.NoError(t, err) } + if len(opts.ProvisioningAllowedTargets) > 0 { + provisioningSect, err := getOrCreateSection("provisioning") + require.NoError(t, err) + _, err = provisioningSect.NewKey("allowed_targets", strings.Join(opts.ProvisioningAllowedTargets, "|")) + require.NoError(t, err) + } if opts.EnableSCIM { scimSection, err := getOrCreateSection("auth.scim") require.NoError(t, err) @@ -660,6 +675,7 @@ type GrafanaOpts struct { UnifiedStorageEnableSearch bool UnifiedStorageMaxPageSizeBytes int PermittedProvisioningPaths string + ProvisioningAllowedTargets []string GrafanaComSSOAPIToken string LicensePath string EnableRecordingRules bool @@ -670,6 +686,7 @@ type GrafanaOpts struct { DisableDataMigrations bool SecretsManagerEnableDBMigrations bool OpenFeatureAPIEnabled bool + DisableAuthZClientCache bool // Allow creating grafana dir beforehand Dir string diff --git a/project.json b/project.json index a4a3fa81c09..702efba58af 100644 --- a/project.json +++ b/project.json @@ -39,7 +39,8 @@ "inputs": [ "{workspaceRoot}/scripts/cli/generateSassVariableFiles.ts", "{workspaceRoot}/packages/grafana-data/src/themes/**", - "{workspaceRoot}/packages/grafana-ui/src/themes/**" + "{workspaceRoot}/packages/grafana-ui/src/themes/**", + "{workspaceRoot}/package.json" ], "outputs": [ "{workspaceRoot}/public/sass/_variables.generated.scss", diff --git a/public/api-enterprise-spec.json b/public/api-enterprise-spec.json index d2fdd854168..9f09c0135d7 100644 --- a/public/api-enterprise-spec.json +++ b/public/api-enterprise-spec.json @@ -2263,8 +2263,7 @@ "operationId": "getTeamGroupsApi", "parameters": [ { - "type": "integer", - "format": "int64", + "type": "string", "name": "teamId", "in": "path", "required": true @@ -2308,8 +2307,7 @@ } }, { - "type": "integer", - "format": "int64", + "type": "string", "name": "teamId", "in": "path", "required": true @@ -2350,8 +2348,7 @@ "in": "query" }, { - "type": "integer", - "format": "int64", + "type": "string", "name": "teamId", "in": "path", "required": true diff --git a/public/api-merged.json b/public/api-merged.json index 570c4c2687d..323a545e0cf 100644 --- a/public/api-merged.json +++ b/public/api-merged.json @@ -9927,8 +9927,7 @@ "operationId": "getTeamGroupsApi", "parameters": [ { - "type": "integer", - "format": "int64", + "type": "string", "name": "teamId", "in": "path", "required": true @@ -9972,8 +9971,7 @@ } }, { - "type": "integer", - "format": "int64", + "type": "string", "name": "teamId", "in": "path", "required": true @@ -10014,8 +10012,7 @@ "in": "query" }, { - "type": "integer", - "format": "int64", + "type": "string", "name": "teamId", "in": "path", "required": true diff --git a/public/app/api/clients/provisioning/utils/createOnCacheEntryAdded.ts b/public/app/api/clients/provisioning/utils/createOnCacheEntryAdded.ts index c3c44ede267..0d39d4fa402 100644 --- a/public/app/api/clients/provisioning/utils/createOnCacheEntryAdded.ts +++ b/public/app/api/clients/provisioning/utils/createOnCacheEntryAdded.ts @@ -58,6 +58,7 @@ export function createOnCacheEntryAdded(resourceName: string) { }); } catch (error) { console.error('Error in onCacheEntryAdded:', error); + return; } await cacheEntryRemoved; diff --git a/public/app/core/components/Login/LoginCtrl.tsx b/public/app/core/components/Login/LoginCtrl.tsx index 1a5f3d572e4..1bab9faf64e 100644 --- a/public/app/core/components/Login/LoginCtrl.tsx +++ b/public/app/core/components/Login/LoginCtrl.tsx @@ -119,11 +119,11 @@ export const LoginCtrl = memo(({ resetCode, children }: Props) => { }, []); const login = useCallback( - (formModel: FormModel) => { + async (formModel: FormModel) => { setLoginErrorMessage(undefined); setIsLoggingIn(true); - getBackendSrv() + return getBackendSrv() .post('/login', formModel, { showErrorAlert: false }) .then((result) => { setResult(result); diff --git a/public/app/core/reducers/root.ts b/public/app/core/reducers/root.ts index d86b93c916e..b73e12e2f22 100644 --- a/public/app/core/reducers/root.ts +++ b/public/app/core/reducers/root.ts @@ -23,7 +23,6 @@ import { reducer as pluginsReducer } from 'app/features/plugins/admin/state/redu import userReducers from 'app/features/profile/state/reducers'; import serviceAccountsReducer from 'app/features/serviceaccounts/state/reducers'; import supportBundlesReducer from 'app/features/support-bundles/state/reducers'; -import teamsReducers from 'app/features/teams/state/reducers'; import usersReducers from 'app/features/users/state/reducers'; import templatingReducers from 'app/features/variables/state/keyedVariablesReducer'; @@ -33,7 +32,6 @@ import { cleanUpAction } from '../actions/cleanUp'; const rootReducers = { ...sharedReducers, ...alertingReducers, - ...teamsReducers, ...dashboardReducers, ...exploreReducers, ...dataSourcesReducers, diff --git a/public/app/core/services/echo/init.ts b/public/app/core/services/echo/init.ts index d4ff585b700..9fce1a539ef 100644 --- a/public/app/core/services/echo/init.ts +++ b/public/app/core/services/echo/init.ts @@ -146,7 +146,17 @@ async function initRudderstackBackend() { return; } - const modulePromise = config.featureToggles.rudderstackUpgrade + // Logic: if only one of the sdk urls is provided, use respective code + // otherwise defer to the feature toggle. + + const hasOldSdkUrl = Boolean(config.rudderstackSdkUrl); + const hasNewSdkUrl = Boolean(config.rudderstackV3SdkUrl); + const onlyOneSdkUrlSet = hasOldSdkUrl !== hasNewSdkUrl; + const useNewRudderstack = onlyOneSdkUrlSet ? hasNewSdkUrl : config.featureToggles.rudderstackUpgrade; + + const sdkUrl = useNewRudderstack ? config.rudderstackV3SdkUrl : config.rudderstackSdkUrl; + + const modulePromise = useNewRudderstack ? import('./backends/analytics/RudderstackV3Backend') : import('./backends/analytics/RudderstackBackend'); @@ -156,7 +166,7 @@ async function initRudderstackBackend() { writeKey: config.rudderstackWriteKey, dataPlaneUrl: config.rudderstackDataPlaneUrl, user: contextSrv.user, - sdkUrl: config.rudderstackSdkUrl, + sdkUrl, configUrl: config.rudderstackConfigUrl, integrationsUrl: config.rudderstackIntegrationsUrl, buildInfo: config.buildInfo, diff --git a/public/app/features/admin/UserListAdminPage.tsx b/public/app/features/admin/UserListAdminPage.tsx index cd7695b1db8..feebb6b98e1 100644 --- a/public/app/features/admin/UserListAdminPage.tsx +++ b/public/app/features/admin/UserListAdminPage.tsx @@ -3,7 +3,7 @@ import { ComponentType, useEffect } from 'react'; import { connect, ConnectedProps } from 'react-redux'; import { GrafanaTheme2 } from '@grafana/data'; -import { selectors as e2eSelectors } from '@grafana/e2e-selectors/src'; +import { selectors as e2eSelectors } from '@grafana/e2e-selectors'; import { Trans, t } from '@grafana/i18n'; import { LinkButton, RadioButtonGroup, useStyles2, FilterInput, EmptyState } from '@grafana/ui'; import { Page } from 'app/core/components/Page/Page'; diff --git a/public/app/features/admin/UserListAnonymousPage.tsx b/public/app/features/admin/UserListAnonymousPage.tsx index eec26483830..bfb1f6f9125 100644 --- a/public/app/features/admin/UserListAnonymousPage.tsx +++ b/public/app/features/admin/UserListAnonymousPage.tsx @@ -3,7 +3,7 @@ import { useEffect } from 'react'; import { connect, ConnectedProps } from 'react-redux'; import { GrafanaTheme2 } from '@grafana/data'; -import { selectors as e2eSelectors } from '@grafana/e2e-selectors/src'; +import { selectors as e2eSelectors } from '@grafana/e2e-selectors'; import { t } from '@grafana/i18n'; import { RadioButtonGroup, useStyles2, FilterInput } from '@grafana/ui'; import { Page } from 'app/core/components/Page/Page'; diff --git a/public/app/features/admin/UserListPage.test.tsx b/public/app/features/admin/UserListPage.test.tsx index 6601c06827d..4df8161b70c 100644 --- a/public/app/features/admin/UserListPage.test.tsx +++ b/public/app/features/admin/UserListPage.test.tsx @@ -1,7 +1,7 @@ import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; -import { selectors as e2eSelectors } from '@grafana/e2e-selectors/src'; +import { selectors as e2eSelectors } from '@grafana/e2e-selectors'; import { GrafanaBootConfig } from '@grafana/runtime'; import config from 'app/core/config'; diff --git a/public/app/features/admin/UserListPublicDashboardPage/DashboardsListModalButton.tsx b/public/app/features/admin/UserListPublicDashboardPage/DashboardsListModalButton.tsx index af1eda1f2fd..bf384a83bbc 100644 --- a/public/app/features/admin/UserListPublicDashboardPage/DashboardsListModalButton.tsx +++ b/public/app/features/admin/UserListPublicDashboardPage/DashboardsListModalButton.tsx @@ -1,7 +1,7 @@ import { css, cx } from '@emotion/css'; import { GrafanaTheme2 } from '@grafana/data'; -import { selectors as e2eSelectors } from '@grafana/e2e-selectors/src'; +import { selectors as e2eSelectors } from '@grafana/e2e-selectors'; import { Trans, t } from '@grafana/i18n'; import { Button, LoadingPlaceholder, Modal, ModalsController, useStyles2 } from '@grafana/ui'; import { diff --git a/public/app/features/admin/UserListPublicDashboardPage/UserListPublicDashboardPage.tsx b/public/app/features/admin/UserListPublicDashboardPage/UserListPublicDashboardPage.tsx index c3618ba9b67..c18cb9c5c15 100644 --- a/public/app/features/admin/UserListPublicDashboardPage/UserListPublicDashboardPage.tsx +++ b/public/app/features/admin/UserListPublicDashboardPage/UserListPublicDashboardPage.tsx @@ -1,4 +1,4 @@ -import { selectors as e2eSelectors } from '@grafana/e2e-selectors/src'; +import { selectors as e2eSelectors } from '@grafana/e2e-selectors'; import { Trans, t } from '@grafana/i18n'; import { Icon, Stack, Tag, Tooltip } from '@grafana/ui'; import { Page } from 'app/core/components/Page/Page'; diff --git a/public/app/features/alerting/unified/CLAUDE.md b/public/app/features/alerting/unified/CLAUDE.md index 124b9da622f..35ea0486876 100644 --- a/public/app/features/alerting/unified/CLAUDE.md +++ b/public/app/features/alerting/unified/CLAUDE.md @@ -1,3 +1,10 @@ +--- +title: Alerting Squad Guidelines +description: Alerting-specific patterns and conventions for Grafana +globs: + - 'public/app/features/alerting/**' +--- + # Alerting Squad - Claude Code Configuration This file provides context for Claude Code when working on the Grafana Alerting codebase. It contains alerting-specific patterns and references to Grafana's coding standards. diff --git a/public/app/features/alerting/unified/components/receivers/NewReceiverView.test.tsx b/public/app/features/alerting/unified/components/receivers/NewReceiverView.test.tsx index e1a1aa5aeba..ad6ee94d73e 100644 --- a/public/app/features/alerting/unified/components/receivers/NewReceiverView.test.tsx +++ b/public/app/features/alerting/unified/components/receivers/NewReceiverView.test.tsx @@ -1,6 +1,6 @@ import { Route, Routes } from 'react-router-dom-v5-compat'; import { render, screen } from 'test/test-utils'; -import { byLabelText, byPlaceholderText, byRole, byTestId } from 'testing-library-selector'; +import { byPlaceholderText, byRole, byTestId } from 'testing-library-selector'; import { captureRequests } from 'app/features/alerting/unified/mocks/server/events'; import { AccessControlAction } from 'app/types/accessControl'; @@ -122,7 +122,7 @@ const ui = { inputs: { name: byPlaceholderText('Name'), email: { - addresses: byLabelText(/Addresses/), + addresses: byRole('textbox', { name: /^Addresses/ }), }, }, }; diff --git a/public/app/features/alerting/unified/components/receivers/form/ChannelOptions.tsx b/public/app/features/alerting/unified/components/receivers/form/ChannelOptions.tsx index 16042c0e654..073b88598dc 100644 --- a/public/app/features/alerting/unified/components/receivers/form/ChannelOptions.tsx +++ b/public/app/features/alerting/unified/components/receivers/form/ChannelOptions.tsx @@ -30,8 +30,8 @@ export interface Props { * This is used to access the settings and secure fields for the integration in a type-safe way. */ integrationPrefix: `items.${number}`; + canEditProtectedFields: boolean; readOnly?: boolean; - customValidators?: Record['customValidator']>; } @@ -44,6 +44,7 @@ export function ChannelOptions({ integrationPrefix, readOnly = false, customValidators = {}, + canEditProtectedFields, }: Props): JSX.Element { const { watch } = useFormContext>(); @@ -54,7 +55,7 @@ export function ChannelOptions({ const getOptionMeta = (option: NotificationChannelOption): OptionMeta => ({ required: determineRequired(option, settings, secureFields), - readOnly: determineReadOnly(option, settings, secureFields), + readOnly: determineReadOnly(option, settings, secureFields, canEditProtectedFields), }); return ( @@ -78,6 +79,7 @@ export function ChannelOptions({ label={option.label} description={option.description} htmlFor={`${settingsPath}${option.propertyName}`} + noMargin > ({ ); } - const error: FieldError | DeepMap | undefined = ( - (option.secure ? errors?.secureFields : errors?.settings) as DeepMap | undefined - )?.[option.secureFieldKey ?? option.propertyName]; + const errorSource = option.secure ? errors?.secureFields : errors?.settings; + const propertyKey = option.secureFieldKey ?? option.propertyName; + const error = // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + (errorSource as Record, FieldError>> | undefined)?.[ + propertyKey + ]; const defaultValue = defaultValues?.settings?.[option.propertyName]; @@ -140,8 +145,14 @@ const determineRequired = ( const determineReadOnly = ( option: NotificationChannelOption, settings: Record, - secureFields: NotificationChannelSecureFields + secureFields: NotificationChannelSecureFields, + canEditProtectedFields: boolean ) => { + if (option.protected && !canEditProtectedFields) { + return true; + } + + // Handle fields with dependencies (e.g., field B depends on field A being set) if (!option.dependsOn) { return false; } diff --git a/public/app/features/alerting/unified/components/receivers/form/ChannelSubForm.test.tsx b/public/app/features/alerting/unified/components/receivers/form/ChannelSubForm.test.tsx index 4fda03e9d53..00a933acec3 100644 --- a/public/app/features/alerting/unified/components/receivers/form/ChannelSubForm.test.tsx +++ b/public/app/features/alerting/unified/components/receivers/form/ChannelSubForm.test.tsx @@ -89,6 +89,7 @@ describe('ChannelSubForm', () => { commonSettingsComponent={GrafanaCommonChannelSettings} isEditable={true} isTestable={false} + canEditProtectedFields={true} /> diff --git a/public/app/features/alerting/unified/components/receivers/form/ChannelSubForm.tsx b/public/app/features/alerting/unified/components/receivers/form/ChannelSubForm.tsx index 645c6565a01..c49b5184623 100644 --- a/public/app/features/alerting/unified/components/receivers/form/ChannelSubForm.tsx +++ b/public/app/features/alerting/unified/components/receivers/form/ChannelSubForm.tsx @@ -35,6 +35,7 @@ interface Props { onDelete?: () => void; isEditable?: boolean; isTestable?: boolean; + canEditProtectedFields: boolean; customValidators?: React.ComponentProps['customValidators']; } @@ -52,6 +53,7 @@ export function ChannelSubForm({ commonSettingsComponent: CommonSettingsComponent, isEditable = true, isTestable, + canEditProtectedFields, customValidators = {}, }: Props): JSX.Element { const styles = useStyles2(getStyles); @@ -210,6 +212,7 @@ export function ChannelSubForm({ label={t('alerting.channel-sub-form.label-integration', 'Integration')} htmlFor={contactPointTypeInputId} data-testid={`${pathPrefix}type`} + noMargin > ({ onDeleteSubform={onDeleteSubform} integrationPrefix={channelFieldPath} readOnly={!isEditable} + canEditProtectedFields={canEditProtectedFields} customValidators={customValidators} /> {!!(mandatoryOptions.length && optionalOptions.length) && ( @@ -301,6 +305,7 @@ export function ChannelSubForm({ errors={errors} integrationPrefix={channelFieldPath} readOnly={!isEditable} + canEditProtectedFields={canEditProtectedFields} customValidators={customValidators} /> diff --git a/public/app/features/alerting/unified/components/receivers/form/CloudReceiverForm.tsx b/public/app/features/alerting/unified/components/receivers/form/CloudReceiverForm.tsx index 6512dcf86b3..ea490821452 100644 --- a/public/app/features/alerting/unified/components/receivers/form/CloudReceiverForm.tsx +++ b/public/app/features/alerting/unified/components/receivers/form/CloudReceiverForm.tsx @@ -91,6 +91,7 @@ export const CloudReceiverForm = ({ contactPoint, alertManagerSourceName, readOn alertManagerSourceName={alertManagerSourceName} defaultItem={defaultChannelValues} commonSettingsComponent={CloudCommonChannelSettings} + canEditProtectedFields={true} /> ); diff --git a/public/app/features/alerting/unified/components/receivers/form/GrafanaReceiverForm.tsx b/public/app/features/alerting/unified/components/receivers/form/GrafanaReceiverForm.tsx index de17ab6c7c0..df68ab185dc 100644 --- a/public/app/features/alerting/unified/components/receivers/form/GrafanaReceiverForm.tsx +++ b/public/app/features/alerting/unified/components/receivers/form/GrafanaReceiverForm.tsx @@ -9,7 +9,7 @@ import { } from 'app/features/alerting/unified/components/contact-points/useContactPoints'; import { showManageContactPointPermissions } from 'app/features/alerting/unified/components/contact-points/utils'; import { GRAFANA_RULES_SOURCE_NAME } from 'app/features/alerting/unified/utils/datasource'; -import { canEditEntity } from 'app/features/alerting/unified/utils/k8s/utils'; +import { canEditEntity, canModifyProtectedEntity } from 'app/features/alerting/unified/utils/k8s/utils'; import { GrafanaManagedContactPoint, GrafanaManagedReceiverConfig, @@ -124,8 +124,10 @@ export const GrafanaReceiverForm = ({ contactPoint, readOnly = false, editMode } // If there is no contact point it means we're creating a new one, so scoped permissions doesn't exist yet const hasScopedEditPermissions = contactPoint ? canEditEntity(contactPoint) : true; + const hasScopedEditProtectedPermissions = contactPoint ? canModifyProtectedEntity(contactPoint) : true; const isEditable = !readOnly && hasScopedEditPermissions && !contactPoint?.provisioned; const isTestable = !readOnly; + const canEditProtectedFields = editMode ? hasScopedEditProtectedPermissions : true; if (isLoadingNotifiers || isLoadingOnCallIntegration) { return ( @@ -178,6 +180,7 @@ export const GrafanaReceiverForm = ({ contactPoint, readOnly = false, editMode } canManagePermissions={ editMode && contactPoint && showManageContactPointPermissions(GRAFANA_RULES_SOURCE_NAME, contactPoint) } + canEditProtectedFields={canEditProtectedFields} /> {testReceivers && ( { showDefaultRouteWarning?: boolean; contactPointId?: string; canManagePermissions?: boolean; + canEditProtectedFields: boolean; } export function ReceiverForm({ @@ -58,6 +59,7 @@ export function ReceiverForm({ showDefaultRouteWarning, contactPointId, canManagePermissions, + canEditProtectedFields, }: Props) { const notifyApp = useAppNotification(); const styles = useStyles2(getStyles); @@ -66,15 +68,16 @@ export function ReceiverForm({ // normalize deprecated and new config values const normalizedConfig = normalizeFormValues(initialValues); - const defaultValues = normalizedConfig ?? { + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + const defaultValues = (normalizedConfig ?? { name: '', items: [ { ...defaultItem, __id: String(Math.random()), - } as any, + }, ], - }; + }) as ReceiverFormValues; const formAPI = useForm>({ // making a copy here beacuse react-hook-form will mutate these, and break if the object is frozen. for real. @@ -148,6 +151,7 @@ export function ReceiverForm({ invalid={!!errors.name} error={errors.name && errors.name.message} required + noMargin > ({ onDelete={() => remove(index)} pathPrefix={pathPrefix} notifiers={notifiers} - errors={errors?.items?.[index] as FieldErrors} + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + errors={errors?.items?.[index] as FieldErrors | undefined} commonSettingsComponent={commonSettingsComponent} isEditable={isEditable} isTestable={isTestable} + canEditProtectedFields={canEditProtectedFields} customValidators={customValidators ? customValidators[field.type] : undefined} /> ); diff --git a/public/app/features/alerting/unified/components/receivers/form/fields/OptionField.test.tsx b/public/app/features/alerting/unified/components/receivers/form/fields/OptionField.test.tsx new file mode 100644 index 00000000000..c52b4bfeca5 --- /dev/null +++ b/public/app/features/alerting/unified/components/receivers/form/fields/OptionField.test.tsx @@ -0,0 +1,448 @@ +import userEvent from '@testing-library/user-event'; +import { FormProvider, useForm } from 'react-hook-form'; +import { render, screen, waitFor } from 'test/test-utils'; + +import { + NotificationChannelOption, + NotificationChannelSecureFields, + OptionMeta, +} from 'app/features/alerting/unified/types/alerting'; + +import { OptionField } from './OptionField'; + +const TestWrapper = ({ children }: { children: React.ReactNode }) => { + const methods = useForm(); + return {children}; +}; + +const renderOptionField = ( + option: NotificationChannelOption, + props: { + getOptionMeta?: (option: NotificationChannelOption) => OptionMeta; + readOnly?: boolean; + secureFields?: NotificationChannelSecureFields; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + defaultValue?: any; + } = {} +) => { + const defaultProps = { + option, + defaultValue: '', + pathPrefix: 'test.', + secureFields: {}, + ...props, + }; + + return render( + + + + ); +}; + +describe('OptionField', () => { + describe('Protected field indicator', () => { + it('should display lock icon with tooltip when field is protected and readOnly', async () => { + const option: NotificationChannelOption = { + propertyName: 'testField', + label: 'Test Field', + description: 'A test field', + element: 'input', + inputType: 'text', + placeholder: '', + required: false, + secure: false, + showWhen: { field: '', is: '' }, + validationRule: '', + protected: true, + dependsOn: '', + }; + + const getOptionMeta = jest.fn().mockReturnValue({ readOnly: true, required: false }); + + renderOptionField(option, { getOptionMeta }); + + // Check that lock icon is displayed + const lockIcon = screen.getByTestId('lock-icon'); + expect(lockIcon).toBeInTheDocument(); + + // Hover over the icon to show tooltip + await userEvent.hover(lockIcon); + + // Check that tooltip appears with correct text + await waitFor(() => { + expect( + screen.getByText('This field is protected and can only be edited by users with elevated permissions') + ).toBeInTheDocument(); + }); + }); + + it('should NOT display lock icon when field is protected but NOT readOnly', () => { + const option: NotificationChannelOption = { + propertyName: 'testField', + label: 'Test Field', + description: 'A test field', + element: 'input', + inputType: 'text', + placeholder: '', + required: false, + secure: false, + showWhen: { field: '', is: '' }, + validationRule: '', + protected: true, + dependsOn: '', + }; + + const getOptionMeta = jest.fn().mockReturnValue({ readOnly: false, required: false }); + + renderOptionField(option, { getOptionMeta }); + + // Lock icon should not be displayed + expect(screen.queryByTestId('lock-icon')).not.toBeInTheDocument(); + }); + + it('should NOT display lock icon when field is NOT protected', () => { + const option: NotificationChannelOption = { + propertyName: 'testField', + label: 'Test Field', + description: 'A test field', + element: 'input', + inputType: 'text', + placeholder: '', + required: false, + secure: false, + showWhen: { field: '', is: '' }, + validationRule: '', + protected: false, + dependsOn: '', + }; + + const getOptionMeta = jest.fn().mockReturnValue({ readOnly: true, required: false }); + + renderOptionField(option, { getOptionMeta }); + + // Lock icon should not be displayed + expect(screen.queryByTestId('lock-icon')).not.toBeInTheDocument(); + }); + + it('should NOT display lock icon when getOptionMeta is not provided', () => { + const option: NotificationChannelOption = { + propertyName: 'testField', + label: 'Test Field', + description: 'A test field', + element: 'input', + inputType: 'text', + placeholder: '', + required: false, + secure: false, + showWhen: { field: '', is: '' }, + validationRule: '', + protected: true, + dependsOn: '', + }; + + renderOptionField(option); + + // Lock icon should not be displayed + expect(screen.queryByTestId('lock-icon')).not.toBeInTheDocument(); + }); + + it('should display lock icon for checkbox fields when protected and readOnly', () => { + const option: NotificationChannelOption = { + propertyName: 'testCheckbox', + label: 'Test Checkbox', + description: 'A test checkbox', + element: 'checkbox', + inputType: '', + placeholder: '', + required: false, + secure: false, + showWhen: { field: '', is: '' }, + validationRule: '', + protected: true, + dependsOn: '', + }; + + const getOptionMeta = jest.fn().mockReturnValue({ readOnly: true, required: false }); + + renderOptionField(option, { getOptionMeta }); + + // Lock icon should be displayed even for checkbox + const lockIcon = screen.getByTestId('lock-icon'); + expect(lockIcon).toBeInTheDocument(); + }); + + it('should display lock icon for select fields when protected and readOnly', () => { + const option: NotificationChannelOption = { + propertyName: 'testSelect', + label: 'Test Select', + description: 'A test select', + element: 'select', + inputType: '', + placeholder: '', + required: false, + secure: false, + showWhen: { field: '', is: '' }, + validationRule: '', + protected: true, + dependsOn: '', + selectOptions: [ + { label: 'Option 1', value: 'opt1' }, + { label: 'Option 2', value: 'opt2' }, + ], + }; + + const getOptionMeta = jest.fn().mockReturnValue({ readOnly: true, required: false }); + + renderOptionField(option, { getOptionMeta }); + + // Lock icon should be displayed + const lockIcon = screen.getByTestId('lock-icon'); + expect(lockIcon).toBeInTheDocument(); + }); + }); + + describe('Subform fields', () => { + it('should pass getOptionMeta to SubformField component', () => { + const getOptionMeta = jest.fn().mockReturnValue({ readOnly: true, required: false }); + + const option: NotificationChannelOption = { + propertyName: 'testSubform', + label: 'Test Subform', + description: 'A test subform', + element: 'subform', + inputType: '', + placeholder: '', + required: false, + secure: false, + showWhen: { field: '', is: '' }, + validationRule: '', + protected: false, + dependsOn: '', + subformOptions: [ + { + propertyName: 'nestedField', + label: 'Nested Field', + description: 'A nested field', + element: 'input', + inputType: 'text', + placeholder: '', + required: false, + secure: false, + showWhen: { field: '', is: '' }, + validationRule: '', + protected: true, + dependsOn: '', + }, + ], + }; + + renderOptionField(option, { getOptionMeta, defaultValue: { nestedField: 'test' } }); + + // The subform should be rendered with the nested field + expect(screen.getByText('Test Subform')).toBeInTheDocument(); + + // Verify that getOptionMeta was called for the nested field + // This ensures it was passed through to the SubformField component + expect(getOptionMeta).toHaveBeenCalled(); + }); + + it('should display lock icon for protected fields inside subform when readOnly', async () => { + const getOptionMeta = jest.fn((opt) => { + // Make the nested protected field readOnly + if (opt.protected) { + return { readOnly: true, required: false }; + } + return { readOnly: false, required: false }; + }); + + const option: NotificationChannelOption = { + propertyName: 'oauth2', + label: 'OAuth2 Configuration', + description: 'OAuth2 settings', + element: 'subform', + inputType: '', + placeholder: '', + required: false, + secure: false, + showWhen: { field: '', is: '' }, + validationRule: '', + protected: false, + dependsOn: '', + subformOptions: [ + { + propertyName: 'token_url', + label: 'Token URL', + description: 'OAuth2 token URL', + element: 'input', + inputType: 'text', + placeholder: '', + required: false, + secure: false, + showWhen: { field: '', is: '' }, + validationRule: '', + protected: true, + dependsOn: '', + }, + ], + }; + + renderOptionField(option, { getOptionMeta, defaultValue: { token_url: 'https://example.com/token' } }); + + // Check that lock icon is displayed for the nested protected field + const lockIcon = screen.getByTestId('lock-icon'); + expect(lockIcon).toBeInTheDocument(); + + // Hover over the icon to show tooltip + await userEvent.hover(lockIcon); + + // Check that tooltip appears + await waitFor(() => { + expect( + screen.getByText('This field is protected and can only be edited by users with elevated permissions') + ).toBeInTheDocument(); + }); + }); + + it('should NOT display lock icon for protected fields inside subform when user can edit', () => { + const getOptionMeta = jest.fn().mockReturnValue({ readOnly: false, required: false }); + + const option: NotificationChannelOption = { + propertyName: 'oauth2', + label: 'OAuth2 Configuration', + description: 'OAuth2 settings', + element: 'subform', + inputType: '', + placeholder: '', + required: false, + secure: false, + showWhen: { field: '', is: '' }, + validationRule: '', + protected: false, + dependsOn: '', + subformOptions: [ + { + propertyName: 'token_url', + label: 'Token URL', + description: 'OAuth2 token URL', + element: 'input', + inputType: 'text', + placeholder: '', + required: false, + secure: false, + showWhen: { field: '', is: '' }, + validationRule: '', + protected: true, + dependsOn: '', + }, + ], + }; + + renderOptionField(option, { getOptionMeta, defaultValue: { token_url: 'https://example.com/token' } }); + + // Lock icon should not be displayed when user has permission + expect(screen.queryByTestId('lock-icon')).not.toBeInTheDocument(); + }); + }); + + describe('Subform array fields', () => { + it('should pass getOptionMeta to SubformArrayField component', () => { + const getOptionMeta = jest.fn().mockReturnValue({ readOnly: true, required: false }); + + const option: NotificationChannelOption = { + propertyName: 'testSubformArray', + label: 'Test Subform Array', + description: 'A test subform array', + element: 'subform_array', + inputType: '', + placeholder: '', + required: false, + secure: false, + showWhen: { field: '', is: '' }, + validationRule: '', + protected: false, + dependsOn: '', + subformOptions: [ + { + propertyName: 'nestedField', + label: 'Nested Field', + description: 'A nested field', + element: 'input', + inputType: 'text', + placeholder: '', + required: false, + secure: false, + showWhen: { field: '', is: '' }, + validationRule: '', + protected: true, + dependsOn: '', + }, + ], + }; + + renderOptionField(option, { getOptionMeta, defaultValue: [{ nestedField: 'test' }] }); + + // The subform array should be rendered + expect(screen.getByText('Test Subform Array (1)')).toBeInTheDocument(); + + // Verify that getOptionMeta was called + expect(getOptionMeta).toHaveBeenCalled(); + }); + + it('should display lock icon for protected fields inside subform array when readOnly', async () => { + const getOptionMeta = jest.fn((opt) => { + if (opt.protected) { + return { readOnly: true, required: false }; + } + return { readOnly: false, required: false }; + }); + + const option: NotificationChannelOption = { + propertyName: 'headers', + label: 'HTTP Headers', + description: 'Custom headers', + element: 'subform_array', + inputType: '', + placeholder: '', + required: false, + secure: false, + showWhen: { field: '', is: '' }, + validationRule: '', + protected: false, + dependsOn: '', + subformOptions: [ + { + propertyName: 'authorization', + label: 'Authorization Header', + description: 'Auth header value', + element: 'input', + inputType: 'text', + placeholder: '', + required: false, + secure: false, + showWhen: { field: '', is: '' }, + validationRule: '', + protected: true, + dependsOn: '', + }, + ], + }; + + renderOptionField(option, { getOptionMeta, defaultValue: [{ authorization: 'Bearer token' }] }); + + // Check that lock icon is displayed for the nested protected field + const lockIcon = screen.getByTestId('lock-icon'); + expect(lockIcon).toBeInTheDocument(); + + // Hover over the icon to show tooltip + await userEvent.hover(lockIcon); + + // Check that tooltip appears + await waitFor(() => { + expect( + screen.getByText('This field is protected and can only be edited by users with elevated permissions') + ).toBeInTheDocument(); + }); + }); + }); +}); diff --git a/public/app/features/alerting/unified/components/receivers/form/fields/OptionField.tsx b/public/app/features/alerting/unified/components/receivers/form/fields/OptionField.tsx index d965fafb40d..f037a127b64 100644 --- a/public/app/features/alerting/unified/components/receivers/form/fields/OptionField.tsx +++ b/public/app/features/alerting/unified/components/receivers/form/fields/OptionField.tsx @@ -3,15 +3,19 @@ import { FC } from 'react'; import { Controller, DeepMap, FieldError, useFormContext } from 'react-hook-form'; import { GrafanaTheme2 } from '@grafana/data'; +import { t } from '@grafana/i18n'; import { Checkbox, Field, + Icon, Input, RadioButtonList, SecretInput, SecretTextArea, Select, + Stack, TextArea, + Tooltip, useStyles2, } from '@grafana/ui'; import { @@ -64,6 +68,7 @@ export const OptionField: FC = ({ errors={error} pathPrefix={pathPrefix} onDelete={onDeleteSubform} + getOptionMeta={getOptionMeta} /> ); } @@ -76,13 +81,34 @@ export const OptionField: FC = ({ option={option} pathPrefix={pathPrefix} errors={error as Array> | undefined} + getOptionMeta={getOptionMeta} /> ); } + const shouldShowProtectedIndicator = option.protected && getOptionMeta?.(option).readOnly; + + const labelText = option.element !== 'checkbox' && option.element !== 'radio' ? option.label : undefined; + + const label = shouldShowProtectedIndicator ? ( + + + + + {labelText} + + ) : ( + labelText + ); + return ( ({ + useAssistant: jest.fn(), + createAssistantContextItem: jest.fn((type: string, data: T) => ({ + type, + ...data, + })), +})); + +const mockUseAssistant = jest.mocked(useAssistant); + +const mockPauseExecute = jest.fn().mockResolvedValue(undefined); +jest.mock('../../hooks/ruleGroup/usePauseAlertRule', () => ({ + usePauseRuleInGroup: () => [ + { + execute: mockPauseExecute, + }, + { loading: false, error: undefined }, + ], +})); + +const server = setupMswServer(); + +setPluginLinksHook(() => ({ + links: [], + isLoading: false, +})); + +setupDataSources(); + +const user = userEvent.setup(); +const handleSilence = jest.fn(); +const handleDelete = jest.fn(); +const handleDuplicateRule = jest.fn(); + +const ui = { + moreButton: byLabelText(/More/), + menu: byRole('menu'), + menuItems: { + pause: byRole('menuitem', { name: /Pause evaluation/i }), + resume: byRole('menuitem', { name: /Resume evaluation/i }), + silence: byRole('menuitem', { name: /Silence notifications/i }), + duplicate: byRole('menuitem', { name: /Duplicate/i }), + copyLink: byRole('menuitem', { name: /Copy link/i }), + export: byRole('menuitem', { name: /Export/i }), + delete: byRole('menuitem', { name: /Delete/i }), + manageEnrichments: byRole('menuitem', { name: /Manage enrichments/i }), + declareIncident: byRole('link', { name: /Declare incident/i }), + analyzeRule: byRole('menuitem', { name: /Analyze rule/i }), + }, +}; + +const getMenuContents = async () => { + await screen.findByRole('menu'); + const allMenuItems = screen.queryAllByRole('menuitem').map((el) => el.textContent); + const allLinkItems = screen.queryAllByRole('link').map((el) => el.textContent); + + return [...allMenuItems, ...allLinkItems]; +}; + +const openMenu = async () => { + await user.click(await ui.moreButton.find()); + await waitFor(() => { + expect(ui.menu.query()).toBeInTheDocument(); + }); +}; + +// Helper function to create a default rule setup +const createDefaultRuleSetup = () => { + const mockRule = getGrafanaRule(); + const identifier = fromCombinedRule('grafana', mockRule); + const groupIdentifier = { + groupOrigin: 'grafana' as const, + namespace: { uid: 'namespace-uid' }, + groupName: 'group-name', + }; + + return { mockRule, identifier, groupIdentifier }; +}; + +describe('AlertRuleMenu', () => { + const originalBuildInfo = config.buildInfo; + + beforeEach(() => { + jest.clearAllMocks(); + mockPauseExecute.mockResolvedValue(undefined); + mockOpenAssistant.mockClear(); + // Default: assistant unavailable + mockUseAssistant.mockReturnValue({ + isAvailable: false, + openAssistant: mockOpenAssistant, + } as unknown as ReturnType); + + // Reset config to defaults + config.buildInfo = { ...originalBuildInfo }; + + // Set up default folder mock for Grafana rules (namespace-uid is the default folder UID) + mockFolderApi(server).folder('namespace-uid', mockFolder({ uid: 'namespace-uid', title: 'Test Folder' })); + + // Set up default permissions (no permissions granted by default) + grantUserPermissions([]); + setFolderAccessControl({}); + }); + + afterEach(() => { + config.buildInfo = originalBuildInfo; + }); + + describe('Basic Rendering', () => { + it('renders MoreButton correctly', async () => { + const mockRule = getGrafanaRule(); + const identifier = fromCombinedRule('grafana', mockRule); + const groupIdentifier = { + groupOrigin: 'grafana' as const, + namespace: { uid: 'namespace-uid' }, + groupName: 'group-name', + }; + + render( + + ); + + expect(await ui.moreButton.find()).toBeInTheDocument(); + }); + + it('opens menu when MoreButton is clicked', async () => { + const mockRule = getGrafanaRule(); + const identifier = fromCombinedRule('grafana', mockRule); + const groupIdentifier = { + groupOrigin: 'grafana' as const, + namespace: { uid: 'namespace-uid' }, + groupName: 'group-name', + }; + + render( + + ); + + await openMenu(); + + expect(ui.menu.query()).toBeInTheDocument(); + }); + + it('closes menu when clicking outside', async () => { + const mockRule = getGrafanaRule(); + const identifier = fromCombinedRule('grafana', mockRule); + const groupIdentifier = { + groupOrigin: 'grafana' as const, + namespace: { uid: 'namespace-uid' }, + groupName: 'group-name', + }; + + render( + + ); + + await openMenu(); + expect(ui.menu.query()).toBeInTheDocument(); + + // Click outside the menu + await user.click(document.body); + + await waitFor(() => { + expect(ui.menu.query()).not.toBeInTheDocument(); + }); + }); + + it('menu contains expected structure', async () => { + const mockRule = getGrafanaRule({ + promRule: mockPromAlertingRule({ state: PromAlertingRuleState.Inactive }), + }); + const identifier = fromCombinedRule('grafana', mockRule); + const groupIdentifier = { + groupOrigin: 'grafana' as const, + namespace: { uid: 'namespace-uid' }, + groupName: 'group-name', + }; + + render( + + ); + + await openMenu(); + + const menuContents = await getMenuContents(); + expect(menuContents).toHaveLength(1); + expect(menuContents).toContain('Copy link'); + }); + }); + + describe('Permissions', () => { + // Generalized test to reduce repetition for menu item visibility + type MenuItemTestCase = { + description: string; + action: AlertRuleAction; + menuItem: keyof typeof ui.menuItems; + granted: boolean; + shouldShow: boolean; + }; + + const testMenuItemVisibility = ({ description, action, menuItem, granted, shouldShow }: MenuItemTestCase) => { + it(description, async () => { + const { mockRule, identifier, groupIdentifier } = createDefaultRuleSetup(); + + // Grant permissions based on action + const permissions: AccessControlAction[] = []; + const folderAccessControl: Record = {}; + + if (granted) { + switch (action) { + case AlertRuleAction.Pause: + case AlertRuleAction.Update: + permissions.push(AccessControlAction.AlertingRuleUpdate); + folderAccessControl[AccessControlAction.AlertingRuleUpdate] = true; + break; + case AlertRuleAction.Delete: + permissions.push(AccessControlAction.AlertingRuleDelete); + folderAccessControl[AccessControlAction.AlertingRuleDelete] = true; + break; + case AlertRuleAction.Duplicate: + permissions.push(AccessControlAction.AlertingRuleCreate); + break; + case AlertRuleAction.Silence: + permissions.push(AccessControlAction.AlertingInstanceCreate, AccessControlAction.AlertingSilenceCreate); + break; + case AlertRuleAction.ModifyExport: + permissions.push(AccessControlAction.AlertingRuleRead); + break; + } + } + + grantUserPermissions(permissions); + setFolderAccessControl(folderAccessControl); + + // Set up folder mock for Grafana rules with matching access control + mockFolderApi(server).folder( + 'namespace-uid', + mockFolder({ + uid: 'namespace-uid', + title: 'Test Folder', + accessControl: folderAccessControl, + }) + ); + + render( + + ); + + await openMenu(); + if (shouldShow) { + expect(await ui.menuItems[menuItem].find()).toBeInTheDocument(); + } else { + expect(ui.menuItems[menuItem].query()).not.toBeInTheDocument(); + } + }); + }; + + describe('Pause/Resume visibility', () => { + testMenuItemVisibility({ + description: 'shows Pause when pause permission is granted', + action: AlertRuleAction.Pause, + menuItem: 'pause', + granted: true, + shouldShow: true, + }); + + testMenuItemVisibility({ + description: 'hides Pause when pause permission is denied', + action: AlertRuleAction.Pause, + menuItem: 'pause', + granted: false, + shouldShow: false, + }); + }); + + describe('Delete visibility', () => { + testMenuItemVisibility({ + description: 'shows Delete when delete permission is granted', + action: AlertRuleAction.Delete, + menuItem: 'delete', + granted: true, + shouldShow: true, + }); + + testMenuItemVisibility({ + description: 'hides Delete when delete permission is denied', + action: AlertRuleAction.Delete, + menuItem: 'delete', + granted: false, + shouldShow: false, + }); + }); + + describe('Duplicate visibility', () => { + testMenuItemVisibility({ + description: 'shows Duplicate when duplicate permission is granted', + action: AlertRuleAction.Duplicate, + menuItem: 'duplicate', + granted: true, + shouldShow: true, + }); + + testMenuItemVisibility({ + description: 'hides Duplicate when duplicate permission is denied', + action: AlertRuleAction.Duplicate, + menuItem: 'duplicate', + granted: false, + shouldShow: false, + }); + }); + + describe('Silence visibility', () => { + testMenuItemVisibility({ + description: 'shows Silence when silence permission is granted', + action: AlertRuleAction.Silence, + menuItem: 'silence', + granted: true, + shouldShow: true, + }); + + testMenuItemVisibility({ + description: 'hides Silence when silence permission is denied', + action: AlertRuleAction.Silence, + menuItem: 'silence', + granted: false, + shouldShow: false, + }); + }); + + describe('Export visibility', () => { + testMenuItemVisibility({ + description: 'shows Export when export permission is granted', + action: AlertRuleAction.ModifyExport, + menuItem: 'export', + granted: true, + shouldShow: true, + }); + + testMenuItemVisibility({ + description: 'hides Export when export permission is denied', + action: AlertRuleAction.ModifyExport, + menuItem: 'export', + granted: false, + shouldShow: false, + }); + }); + + describe('Copy Link visibility', () => { + it('shows Copy Link when shareUrl exists', async () => { + const { mockRule, identifier, groupIdentifier } = createDefaultRuleSetup(); + + render( + + ); + + await openMenu(); + expect(await ui.menuItems.copyLink.find()).toBeInTheDocument(); + }); + }); + }); + + describe('Rule Types', () => { + beforeEach(() => { + // Grant all permissions for testing rule type differences + grantUserPermissions([ + AccessControlAction.AlertingRuleRead, + AccessControlAction.AlertingRuleUpdate, + AccessControlAction.AlertingRuleDelete, + AccessControlAction.AlertingRuleCreate, + AccessControlAction.AlertingInstanceCreate, + AccessControlAction.AlertingSilenceCreate, + ]); + setFolderAccessControl({ + [AccessControlAction.AlertingRuleUpdate]: true, + [AccessControlAction.AlertingRuleDelete]: true, + }); + mockFolderApi(server).folder( + 'namespace-uid', + mockFolder({ + uid: 'namespace-uid', + title: 'Test Folder', + accessControl: { + [AccessControlAction.AlertingRuleUpdate]: true, + [AccessControlAction.AlertingRuleDelete]: true, + }, + }) + ); + }); + + describe('Grafana-managed rules', () => { + it('shows Pause option for Grafana-managed alerting rules', async () => { + const mockRule = getGrafanaRule(); + const identifier = fromCombinedRule('grafana', mockRule); + const groupIdentifier = { + groupOrigin: 'grafana' as const, + namespace: { uid: 'namespace-uid' }, + groupName: 'group-name', + }; + + render( + + ); + + await openMenu(); + expect(await ui.menuItems.pause.find()).toBeInTheDocument(); + }); + + it('does not show Pause option for datasource-managed rules', async () => { + const datasource = mockDataSource({ uid: 'mimir', name: 'Mimir' }); + const mockRule = getCloudRule({}, { rulesSource: datasource }); + const identifier = fromCombinedRule(datasource.name, mockRule); + const groupIdentifier = { + groupOrigin: 'datasource' as const, + rulesSource: { uid: datasource.uid, name: datasource.name, ruleSourceType: 'datasource' as const }, + namespace: { name: 'namespace-name' }, + groupName: 'group-name', + }; + + render( + + ); + + await openMenu(); + expect(ui.menuItems.pause.query()).not.toBeInTheDocument(); + }); + }); + + describe('Alerting vs Recording rules', () => { + it('shows Silence option for alerting rules', async () => { + const mockRule = getGrafanaRule({ + promRule: mockPromAlertingRule({ type: PromRuleType.Alerting }), + }); + const identifier = fromCombinedRule('grafana', mockRule); + const groupIdentifier = { + groupOrigin: 'grafana' as const, + namespace: { uid: 'namespace-uid' }, + groupName: 'group-name', + }; + + render( + + ); + + await openMenu(); + expect(await ui.menuItems.silence.find()).toBeInTheDocument(); + }); + + it('does not show Silence option for recording rules', async () => { + const mockRule = getGrafanaRule({ + promRule: mockPromRecordingRule({ type: PromRuleType.Recording }), + }); + // Override the rulerRule to be a recording rule + mockRule.rulerRule = mockRulerGrafanaRecordingRule( + {}, + { + uid: 'mock-rule-uid-123', + namespace_uid: 'namespace-uid', + } + ); + const identifier = fromCombinedRule('grafana', mockRule); + const groupIdentifier = { + groupOrigin: 'grafana' as const, + namespace: { uid: 'namespace-uid' }, + groupName: 'group-name', + }; + + mockFolderApi(server).folder( + 'namespace-uid', + mockFolder({ + uid: 'namespace-uid', + title: 'Test Folder', + }) + ); + + render( + + ); + + await openMenu(); + expect(ui.menuItems.silence.query()).not.toBeInTheDocument(); + }); + }); + + describe('Provisioned rules', () => { + it('hides Delete option for provisioned rules', async () => { + const mockRule = getGrafanaRule({ + rulerRule: mockGrafanaRulerRule({ provenance: 'file' }), + }); + const identifier = fromCombinedRule('grafana', mockRule); + const groupIdentifier = { + groupOrigin: 'grafana' as const, + namespace: { uid: 'namespace-uid' }, + groupName: 'group-name', + }; + + render( + + ); + + await openMenu(); + expect(ui.menuItems.delete.query()).not.toBeInTheDocument(); + }); + + it('hides Pause option for provisioned rules', async () => { + const mockRule = getGrafanaRule({ + rulerRule: mockGrafanaRulerRule({ provenance: 'file' }), + }); + const identifier = fromCombinedRule('grafana', mockRule); + const groupIdentifier = { + groupOrigin: 'grafana' as const, + namespace: { uid: 'namespace-uid' }, + groupName: 'group-name', + }; + + render( + + ); + + await openMenu(); + expect(ui.menuItems.pause.query()).not.toBeInTheDocument(); + }); + }); + + describe('Mixed data scenarios', () => { + it('works with only promRule available', async () => { + const mockRule = getGrafanaRule(); + const identifier = fromCombinedRule('grafana', mockRule); + const groupIdentifier = { + groupOrigin: 'grafana' as const, + namespace: { uid: 'namespace-uid' }, + groupName: 'group-name', + }; + + render( + + ); + + await openMenu(); + expect(ui.menu.query()).toBeInTheDocument(); + }); + + it('works with only rulerRule available', async () => { + const mockRule = getGrafanaRule(); + const identifier = fromCombinedRule('grafana', mockRule); + const groupIdentifier = { + groupOrigin: 'grafana' as const, + namespace: { uid: 'namespace-uid' }, + groupName: 'group-name', + }; + + render( + + ); + + await openMenu(); + expect(ui.menu.query()).toBeInTheDocument(); + }); + + it('works with both promRule and rulerRule available', async () => { + const mockRule = getGrafanaRule(); + const identifier = fromCombinedRule('grafana', mockRule); + const groupIdentifier = { + groupOrigin: 'grafana' as const, + namespace: { uid: 'namespace-uid' }, + groupName: 'group-name', + }; + + render( + + ); + + await openMenu(); + expect(ui.menu.query()).toBeInTheDocument(); + }); + }); + }); + + describe('Handler Callbacks', () => { + describe('handleSilence', () => { + it('calls handleSilence when Silence menu item is clicked', async () => { + grantUserPermissions([AccessControlAction.AlertingInstanceCreate, AccessControlAction.AlertingSilenceCreate]); + mockFolderApi(server).folder('namespace-uid', mockFolder({ uid: 'namespace-uid', title: 'Test Folder' })); + + const { mockRule, identifier, groupIdentifier } = createDefaultRuleSetup(); + + render( + + ); + + await openMenu(); + await user.click(await ui.menuItems.silence.find()); + + expect(handleSilence).toHaveBeenCalledTimes(1); + }); + }); + + describe('handleManageEnrichments', () => { + testWithFeatureToggles({ + enable: ['alertEnrichment', 'alertingEnrichmentPerRule'], + }); + + it('calls handleManageEnrichments when Manage enrichments menu item is clicked', async () => { + // Both toggles need to be enabled: alertEnrichment for the hook, alertingEnrichmentPerRule for the component + grantUserPermissions([AccessControlAction.AlertingEnrichmentsRead]); + mockFolderApi(server).folder('namespace-uid', mockFolder({ uid: 'namespace-uid', title: 'Test Folder' })); + + const handleManageEnrichments = jest.fn(); + const { mockRule, identifier, groupIdentifier } = createDefaultRuleSetup(); + + render( + + ); + + await openMenu(); + await user.click(await ui.menuItems.manageEnrichments.find()); + + expect(handleManageEnrichments).toHaveBeenCalledTimes(1); + }); + }); + + describe('handleDelete', () => { + it('calls handleDelete with correct identifier and groupIdentifier when Delete menu item is clicked', async () => { + grantUserPermissions([AccessControlAction.AlertingRuleDelete]); + setFolderAccessControl({ [AccessControlAction.AlertingRuleDelete]: true }); + mockFolderApi(server).folder( + 'namespace-uid', + mockFolder({ + uid: 'namespace-uid', + title: 'Test Folder', + accessControl: { [AccessControlAction.AlertingRuleDelete]: true }, + }) + ); + + const { mockRule, identifier, groupIdentifier } = createDefaultRuleSetup(); + + render( + + ); + + await openMenu(); + await user.click(await ui.menuItems.delete.find()); + + expect(handleDelete).toHaveBeenCalledTimes(1); + expect(handleDelete).toHaveBeenCalledWith(identifier, groupIdentifier); + }); + + it('does not call handleDelete when identifier is not editable', async () => { + grantUserPermissions([AccessControlAction.AlertingRuleDelete]); + setFolderAccessControl({ [AccessControlAction.AlertingRuleDelete]: true }); + mockFolderApi(server).folder( + 'namespace-uid', + mockFolder({ + uid: 'namespace-uid', + title: 'Test Folder', + accessControl: { [AccessControlAction.AlertingRuleDelete]: true }, + }) + ); + + const { mockRule, groupIdentifier } = createDefaultRuleSetup(); + // Create a non-editable identifier (e.g., Prometheus rule identifier without rulerRule) + // For external rules without rulerRule, the delete button should not appear + const identifier = fromCombinedRule('prometheus', { + ...mockRule, + rulerRule: undefined, + }); + + render( + + ); + + await openMenu(); + expect(ui.menuItems.delete.query()).not.toBeInTheDocument(); + expect(handleDelete).not.toHaveBeenCalled(); + }); + }); + + describe('handleDuplicateRule', () => { + it('calls handleDuplicateRule with correct identifier when Duplicate menu item is clicked', async () => { + grantUserPermissions([AccessControlAction.AlertingRuleCreate]); + mockFolderApi(server).folder('namespace-uid', mockFolder({ uid: 'namespace-uid', title: 'Test Folder' })); + + const { mockRule, identifier, groupIdentifier } = createDefaultRuleSetup(); + + render( + + ); + + await openMenu(); + await user.click(await ui.menuItems.duplicate.find()); + + expect(handleDuplicateRule).toHaveBeenCalledTimes(1); + expect(handleDuplicateRule).toHaveBeenCalledWith(identifier); + }); + }); + + describe('onPauseChange', () => { + it('calls onPauseChange after pause state change when Pause menu item is clicked', async () => { + const onPauseChange = jest.fn(); + grantUserPermissions([AccessControlAction.AlertingRuleUpdate]); + setFolderAccessControl({ [AccessControlAction.AlertingRuleUpdate]: true }); + mockFolderApi(server).folder( + 'namespace-uid', + mockFolder({ + uid: 'namespace-uid', + title: 'Test Folder', + accessControl: { [AccessControlAction.AlertingRuleUpdate]: true }, + }) + ); + + const { mockRule, identifier, groupIdentifier } = createDefaultRuleSetup(); + + render( + + ); + + await openMenu(); + await user.click(await ui.menuItems.pause.find()); + + await waitFor(() => { + expect(mockPauseExecute).toHaveBeenCalledTimes(1); + }); + + await waitFor(() => { + expect(onPauseChange).toHaveBeenCalledTimes(1); + }); + expect(onPauseChange).toHaveBeenCalledWith(); + }); + + it('calls onPauseChange after resume state change when Resume menu item is clicked', async () => { + const onPauseChange = jest.fn(); + grantUserPermissions([AccessControlAction.AlertingRuleUpdate]); + setFolderAccessControl({ [AccessControlAction.AlertingRuleUpdate]: true }); + mockFolderApi(server).folder( + 'namespace-uid', + mockFolder({ + uid: 'namespace-uid', + title: 'Test Folder', + accessControl: { [AccessControlAction.AlertingRuleUpdate]: true }, + }) + ); + + const mockRule = getGrafanaRule({ + rulerRule: mockGrafanaRulerRule({ is_paused: true }), + }); + const identifier = fromCombinedRule('grafana', mockRule); + const groupIdentifier = { + groupOrigin: 'grafana' as const, + namespace: { uid: 'namespace-uid' }, + groupName: 'group-name', + }; + + render( + + ); + + await openMenu(); + await user.click(await ui.menuItems.resume.find()); + + await waitFor(() => { + expect(mockPauseExecute).toHaveBeenCalledTimes(1); + }); + + await waitFor(() => { + expect(onPauseChange).toHaveBeenCalledTimes(1); + }); + expect(onPauseChange).toHaveBeenCalledWith(); + }); + }); + }); + + describe('Feature Flags', () => { + describe('alertingEnrichmentPerRule', () => { + describe('when feature flag is disabled', () => { + testWithFeatureToggles({ + disable: ['alertingEnrichmentPerRule'], + }); + + it('hides Manage enrichments when feature flag is disabled', async () => { + grantUserPermissions([AccessControlAction.AlertingEnrichmentsRead]); + + const handleManageEnrichments = jest.fn(); + const { mockRule, identifier, groupIdentifier } = createDefaultRuleSetup(); + + render( + + ); + + await openMenu(); + expect(ui.menuItems.manageEnrichments.query()).not.toBeInTheDocument(); + }); + }); + + describe('when feature flag is enabled', () => { + testWithFeatureToggles({ + enable: ['alertEnrichment', 'alertingEnrichmentPerRule'], + }); + + it('shows Manage enrichments when feature flag is enabled and all conditions are met', async () => { + // Both toggles need to be enabled: alertEnrichment for the hook, alertingEnrichmentPerRule for the component + grantUserPermissions([AccessControlAction.AlertingEnrichmentsRead]); + mockFolderApi(server).folder('namespace-uid', mockFolder({ uid: 'namespace-uid', title: 'Test Folder' })); + + const handleManageEnrichments = jest.fn(); + const { mockRule, identifier, groupIdentifier } = createDefaultRuleSetup(); + + render( + + ); + + await openMenu(); + expect(await ui.menuItems.manageEnrichments.find()).toBeInTheDocument(); + }); + }); + + describe('when feature flags are enabled but permission is missing', () => { + testWithFeatureToggles({ + enable: ['alertEnrichment', 'alertingEnrichmentPerRule'], + }); + + it('hides Manage enrichments when enrichment ability is not allowed', async () => { + // Enable both toggles to ensure we're testing the permission check, not the toggles + grantUserPermissions([]); + mockFolderApi(server).folder('namespace-uid', mockFolder({ uid: 'namespace-uid', title: 'Test Folder' })); + + const handleManageEnrichments = jest.fn(); + const { mockRule, identifier, groupIdentifier } = createDefaultRuleSetup(); + + render( + + ); + + await openMenu(); + expect(ui.menuItems.manageEnrichments.query()).not.toBeInTheDocument(); + }); + }); + }); + + describe('Open-source vs Enterprise', () => { + it('hides Declare Incident in open-source edition for firing alerting rules', async () => { + config.buildInfo.edition = GrafanaEdition.OpenSource; + config.buildInfo.env = 'production'; + + const mockRule = getGrafanaRule({ + promRule: mockPromAlertingRule({ state: PromAlertingRuleState.Firing }), + }); + const identifier = fromCombinedRule('grafana', mockRule); + const groupIdentifier = { + groupOrigin: 'grafana' as const, + namespace: { uid: 'namespace-uid' }, + groupName: 'group-name', + }; + + render( + + ); + + await openMenu(); + expect(ui.menuItems.declareIncident.query()).not.toBeInTheDocument(); + }); + + it('shows Declare Incident in enterprise edition for firing alerting rules', async () => { + config.buildInfo.edition = GrafanaEdition.Enterprise; + config.buildInfo.env = 'production'; + + const mockRule = getGrafanaRule({ + promRule: mockPromAlertingRule({ state: PromAlertingRuleState.Firing }), + }); + const identifier = fromCombinedRule('grafana', mockRule); + const groupIdentifier = { + groupOrigin: 'grafana' as const, + namespace: { uid: 'namespace-uid' }, + groupName: 'group-name', + }; + + render( + + ); + + await openMenu(); + expect(await ui.menuItems.declareIncident.find()).toBeInTheDocument(); + }); + + it('shows Declare Incident in dev mode even for open-source edition', async () => { + config.buildInfo.edition = GrafanaEdition.OpenSource; + config.buildInfo.env = 'development'; + + const mockRule = getGrafanaRule({ + promRule: mockPromAlertingRule({ state: PromAlertingRuleState.Firing }), + }); + const identifier = fromCombinedRule('grafana', mockRule); + const groupIdentifier = { + groupOrigin: 'grafana' as const, + namespace: { uid: 'namespace-uid' }, + groupName: 'group-name', + }; + + render( + + ); + + await openMenu(); + expect(await ui.menuItems.declareIncident.find()).toBeInTheDocument(); + }); + + it('hides Declare Incident for non-firing alerting rules in enterprise', async () => { + config.buildInfo.edition = GrafanaEdition.Enterprise; + config.buildInfo.env = 'production'; + + const mockRule = getGrafanaRule({ + promRule: mockPromAlertingRule({ state: PromAlertingRuleState.Inactive }), + }); + const identifier = fromCombinedRule('grafana', mockRule); + const groupIdentifier = { + groupOrigin: 'grafana' as const, + namespace: { uid: 'namespace-uid' }, + groupName: 'group-name', + }; + + render( + + ); + + await openMenu(); + expect(ui.menuItems.declareIncident.query()).not.toBeInTheDocument(); + }); + + it('hides Declare Incident for recording rules', async () => { + config.buildInfo.edition = GrafanaEdition.Enterprise; + config.buildInfo.env = 'production'; + + const mockRule = getGrafanaRule({ + promRule: mockPromRecordingRule({ type: PromRuleType.Recording }), + }); + const identifier = fromCombinedRule('grafana', mockRule); + const groupIdentifier = { + groupOrigin: 'grafana' as const, + namespace: { uid: 'namespace-uid' }, + groupName: 'group-name', + }; + + render( + + ); + + await openMenu(); + expect(ui.menuItems.declareIncident.query()).not.toBeInTheDocument(); + }); + }); + + describe('Assistant availability', () => { + beforeEach(() => { + // Reset config to ensure clean state for assistant tests + config.buildInfo = { ...originalBuildInfo }; + config.buildInfo.env = 'production'; + config.buildInfo.edition = GrafanaEdition.OpenSource; + // Reset assistant mock to default (unavailable) for each test + mockUseAssistant.mockReturnValue({ + isAvailable: false, + openAssistant: mockOpenAssistant, + } as unknown as ReturnType); + }); + + it('shows Analyze Rule when assistant is available for Grafana-managed rules', async () => { + // Override mock to return available + mockUseAssistant.mockReturnValue({ + isAvailable: true, + openAssistant: mockOpenAssistant, + } as unknown as ReturnType); + + // Create a Grafana rule with promRule that has uid and folderUid + const mockRule = getGrafanaRule({ + promRule: mockPromAlertingRule({ + uid: 'test-rule-uid', + folderUid: 'test-folder-uid', + }), + }); + const identifier = fromCombinedRule('grafana', mockRule); + const groupIdentifier = { + groupOrigin: 'grafana' as const, + namespace: { uid: 'namespace-uid' }, + groupName: 'group-name', + }; + + render( + + ); + + await openMenu(); + expect(await ui.menuItems.analyzeRule.find()).toBeInTheDocument(); + }); + + it('hides Analyze Rule when assistant is unavailable', async () => { + // Mock already set to unavailable in beforeEach, but be explicit + mockUseAssistant.mockReturnValue({ + isAvailable: false, + openAssistant: mockOpenAssistant, + } as unknown as ReturnType); + + const { mockRule, identifier, groupIdentifier } = createDefaultRuleSetup(); + + render( + + ); + + await openMenu(); + expect(ui.menuItems.analyzeRule.query()).not.toBeInTheDocument(); + }); + + it('hides Analyze Rule for datasource-managed rules even when assistant is available', async () => { + mockUseAssistant.mockReturnValue({ + isAvailable: true, + openAssistant: mockOpenAssistant, + } as unknown as ReturnType); + + const datasource = mockDataSource({ uid: 'mimir', name: 'Mimir' }); + const mockRule = getCloudRule({}, { rulesSource: datasource }); + const identifier = fromCombinedRule(datasource.name, mockRule); + const groupIdentifier = { + groupOrigin: 'datasource' as const, + rulesSource: { uid: datasource.uid, name: datasource.name, ruleSourceType: 'datasource' as const }, + namespace: { name: 'namespace-name' }, + groupName: 'group-name', + }; + + render( + + ); + + await openMenu(); + expect(ui.menuItems.analyzeRule.query()).not.toBeInTheDocument(); + }); + }); + }); + + describe('Edge Cases', () => { + describe('Missing Data', () => { + describe('with enrichment feature flags enabled', () => { + testWithFeatureToggles({ + enable: ['alertEnrichment', 'alertingEnrichmentPerRule'], + }); + + it('hides Manage enrichments when ruleUid is missing even if all other conditions are met', async () => { + grantUserPermissions([AccessControlAction.AlertingEnrichmentsRead]); + // Note: Cloud rules typically don't have a ruleUid, so this tests that case + mockFolderApi(server).folder('namespace-uid', mockFolder({ uid: 'namespace-uid', title: 'Test Folder' })); + + const handleManageEnrichments = jest.fn(); + const datasource = mockDataSource({ uid: 'prometheus', name: 'Prometheus' }); + const mockRule = getCloudRule({}, { rulesSource: datasource }); + const identifier = fromCombinedRule(datasource.name, mockRule); + const groupIdentifier = { + groupOrigin: 'datasource' as const, + rulesSource: { uid: datasource.uid, name: datasource.name, ruleSourceType: 'datasource' as const }, + namespace: { name: 'namespace-name' }, + groupName: 'group-name', + }; + + render( + + ); + + await openMenu(); + expect(ui.menuItems.manageEnrichments.query()).not.toBeInTheDocument(); + }); + }); + + it('hides Pause option when ruleUid is missing even if pause permission is granted', async () => { + grantUserPermissions([AccessControlAction.AlertingRuleUpdate]); + setFolderAccessControl({ [AccessControlAction.AlertingRuleUpdate]: true }); + + const datasource = mockDataSource({ uid: 'prometheus', name: 'Prometheus' }); + const mockRule = getCloudRule({}, { rulesSource: datasource }); + const identifier = fromCombinedRule(datasource.name, mockRule); + const groupIdentifier = { + groupOrigin: 'datasource' as const, + rulesSource: { uid: datasource.uid, name: datasource.name, ruleSourceType: 'datasource' as const }, + namespace: { name: 'namespace-name' }, + groupName: 'group-name', + }; + + render( + + ); + + await openMenu(); + expect(ui.menuItems.pause.query()).not.toBeInTheDocument(); + }); + + it('pause still works when onPauseChange is not provided', async () => { + grantUserPermissions([AccessControlAction.AlertingRuleUpdate]); + setFolderAccessControl({ [AccessControlAction.AlertingRuleUpdate]: true }); + mockFolderApi(server).folder( + 'namespace-uid', + mockFolder({ + uid: 'namespace-uid', + title: 'Test Folder', + accessControl: { [AccessControlAction.AlertingRuleUpdate]: true }, + }) + ); + + const { mockRule, identifier, groupIdentifier } = createDefaultRuleSetup(); + + render( + + ); + + await openMenu(); + await user.click(await ui.menuItems.pause.find()); + + // Pause should still execute even without callback + await waitFor(() => { + expect(mockPauseExecute).toHaveBeenCalledTimes(1); + }); + }); + }); + + describe('Empty States', () => { + it('shows minimal menu with only Copy Link when no permissions are granted', async () => { + // Use a non-firing rule to avoid Declare Incident showing + const mockRule = getGrafanaRule({ + promRule: mockPromAlertingRule({ state: PromAlertingRuleState.Inactive }), + }); + const identifier = fromCombinedRule('grafana', mockRule); + const groupIdentifier = { + groupOrigin: 'grafana' as const, + namespace: { uid: 'namespace-uid' }, + groupName: 'group-name', + }; + + config.buildInfo.edition = GrafanaEdition.OpenSource; + config.buildInfo.env = 'production'; + + render( + + ); + + await openMenu(); + + expect(await ui.menuItems.copyLink.find()).toBeInTheDocument(); + expect(ui.menuItems.pause.query()).not.toBeInTheDocument(); + expect(ui.menuItems.silence.query()).not.toBeInTheDocument(); + expect(ui.menuItems.duplicate.query()).not.toBeInTheDocument(); + expect(ui.menuItems.export.query()).not.toBeInTheDocument(); + expect(ui.menuItems.delete.query()).not.toBeInTheDocument(); + expect(ui.menuItems.manageEnrichments.query()).not.toBeInTheDocument(); + expect(ui.menuItems.declareIncident.query()).not.toBeInTheDocument(); + expect(ui.menuItems.analyzeRule.query()).not.toBeInTheDocument(); + }); + + it('menu still opens even when no applicable items are available', async () => { + // All abilities denied and no shareUrl + const mockRule = getGrafanaRule({ + promRule: mockPromAlertingRule({ state: PromAlertingRuleState.Inactive }), + }); + const identifier = fromCombinedRule('grafana', mockRule); + const groupIdentifier = { + groupOrigin: 'grafana' as const, + namespace: { uid: 'namespace-uid' }, + groupName: 'group-name', + }; + + config.buildInfo.edition = GrafanaEdition.OpenSource; + config.buildInfo.env = 'production'; + + // Mock createShareLink to return undefined + const createShareLinkSpy = jest.spyOn(miscUtils, 'createShareLink'); + createShareLinkSpy.mockReturnValue(undefined); + + render( + + ); + + await openMenu(); + + expect(ui.menu.query()).toBeInTheDocument(); + const menuItems = screen.queryAllByRole('menuitem'); + const linkItems = screen.queryAllByRole('link'); + expect(menuItems.length).toBe(0); + expect(linkItems.length).toBe(0); + + createShareLinkSpy.mockRestore(); + }); + }); + + describe('Error Handling', () => { + it('handles gracefully when clipboard API is unavailable', async () => { + const originalClipboard = navigator.clipboard; + // Mock clipboard as undefined to simulate unavailable API + Object.defineProperty(navigator, 'clipboard', { + value: undefined, + writable: true, + configurable: true, + }); + + const mockRule = getGrafanaRule({ + promRule: mockPromAlertingRule({ state: PromAlertingRuleState.Inactive }), + }); + const identifier = fromCombinedRule('grafana', mockRule); + const groupIdentifier = { + groupOrigin: 'grafana' as const, + namespace: { uid: 'namespace-uid' }, + groupName: 'group-name', + }; + + config.buildInfo.edition = GrafanaEdition.OpenSource; + config.buildInfo.env = 'production'; + + render( + + ); + + await openMenu(); + const copyLinkItem = await ui.menuItems.copyLink.find(); + + await expect(user.click(copyLinkItem)).resolves.not.toThrow(); + + // Restore clipboard + Object.defineProperty(navigator, 'clipboard', { + value: originalClipboard, + writable: true, + configurable: true, + }); + }); + + it('handles gracefully when shareUrl is undefined', async () => { + // Use a non-firing rule to avoid Declare Incident showing + const mockRule = getGrafanaRule({ + promRule: mockPromAlertingRule({ state: PromAlertingRuleState.Inactive }), + }); + const identifier = fromCombinedRule('grafana', mockRule); + const groupIdentifier = { + groupOrigin: 'grafana' as const, + namespace: { uid: 'namespace-uid' }, + groupName: 'group-name', + }; + + config.buildInfo.edition = GrafanaEdition.OpenSource; + config.buildInfo.env = 'production'; + + // Mock createShareLink to return undefined + const createShareLinkSpy = jest.spyOn(require('app/features/alerting/unified/utils/misc'), 'createShareLink'); + createShareLinkSpy.mockReturnValue(undefined); + + render( + + ); + + await openMenu(); + + expect(ui.menuItems.copyLink.query()).not.toBeInTheDocument(); + expect(ui.menu.query()).toBeInTheDocument(); + + createShareLinkSpy.mockRestore(); + }); + }); + }); +}); diff --git a/public/app/features/alerting/unified/featureToggles.ts b/public/app/features/alerting/unified/featureToggles.ts index 7ca1747a8c5..15fa8e11fd8 100644 --- a/public/app/features/alerting/unified/featureToggles.ts +++ b/public/app/features/alerting/unified/featureToggles.ts @@ -26,3 +26,8 @@ export const shouldUseBackendFilters = () => config.featureToggles.alertingUIUse export const shouldUseFullyCompatibleBackendFilters = () => config.featureToggles.alertingUIUseFullyCompatBackendFilters ?? false; + +/** + * Saved searches feature - allows users to save and apply search queries on the Alert Rules page. + */ +export const shouldUseSavedSearches = () => config.featureToggles.alertingSavedSearches ?? false; diff --git a/public/app/features/alerting/unified/mockApi.ts b/public/app/features/alerting/unified/mockApi.ts index 614c8235dd0..67053ade5f6 100644 --- a/public/app/features/alerting/unified/mockApi.ts +++ b/public/app/features/alerting/unified/mockApi.ts @@ -9,6 +9,7 @@ import { setupAlertmanagerStatusMapDefaultState, } from 'app/features/alerting/unified/mocks/server/entities/alertmanagers'; import { resetRoutingTreeMap } from 'app/features/alerting/unified/mocks/server/entities/k8s/routingtrees'; +import { resetUserStorage } from 'app/features/alerting/unified/mocks/server/handlers/userStorage'; import { DashboardDTO } from 'app/types/dashboard'; import { FolderDTO } from 'app/types/folders'; import { @@ -256,6 +257,7 @@ export function setupMswServer() { setupAlertmanagerConfigMapDefaultState(); setupAlertmanagerStatusMapDefaultState(); resetRoutingTreeMap(); + resetUserStorage(); }); return server; diff --git a/public/app/features/alerting/unified/mocks/server/all-handlers.ts b/public/app/features/alerting/unified/mocks/server/all-handlers.ts index 4b0b0ac7249..c3a9db4ac5c 100644 --- a/public/app/features/alerting/unified/mocks/server/all-handlers.ts +++ b/public/app/features/alerting/unified/mocks/server/all-handlers.ts @@ -19,6 +19,7 @@ import allPluginHandlers from 'app/features/alerting/unified/mocks/server/handle import provisioningHandlers from 'app/features/alerting/unified/mocks/server/handlers/provisioning'; import searchHandlers from 'app/features/alerting/unified/mocks/server/handlers/search'; import silenceHandlers from 'app/features/alerting/unified/mocks/server/handlers/silences'; +import userStorageHandlers from 'app/features/alerting/unified/mocks/server/handlers/userStorage'; /** * All alerting-specific handlers that are required across tests @@ -55,6 +56,7 @@ const allHandlers = [ ...datasourcesHandlers, ...evalHandlers, ...pluginsHandlers, + ...userStorageHandlers, ]; export default allHandlers; diff --git a/public/app/features/alerting/unified/mocks/server/handlers/userStorage.ts b/public/app/features/alerting/unified/mocks/server/handlers/userStorage.ts new file mode 100644 index 00000000000..b2a162ea898 --- /dev/null +++ b/public/app/features/alerting/unified/mocks/server/handlers/userStorage.ts @@ -0,0 +1,171 @@ +import { HttpResponse, http } from 'msw'; + +import { config } from '@grafana/runtime'; + +/** + * UserStorage spec type matching the backend API response. + */ +interface UserStorageSpec { + data: { [key: string]: string }; +} + +/** + * In-memory storage for UserStorage mock data. + * This allows tests to set up and verify storage state. + */ +let userStorageData: Record = {}; + +/** + * Get the base URL for UserStorage API. + * Uses config.namespace which defaults to 'default' in tests. + */ +const getBaseUrl = () => `/apis/userstorage.grafana.app/v0alpha1/namespaces/${config.namespace}/user-storage`; + +/** + * Reset the in-memory storage. Call this in beforeEach to ensure clean test state. + */ +export function resetUserStorage(): void { + userStorageData = {}; +} + +/** + * Get the resource name for a given service, matching how UserStorage constructs it. + * This uses config.bootData.user to determine the user identifier. + * + * @param service - The service name (e.g., 'alerting') + * @returns The resource name in format `{service}:{userUID}` + * + * @example + * // In a test with config.bootData.user = { uid: '', id: 123 } + * const resourceName = getResourceName('alerting'); // 'alerting:123' + * + * // In a test with config.bootData.user = { uid: 'abc-123', id: 456 } + * const resourceName = getResourceName('alerting'); // 'alerting:abc-123' + */ +export function getResourceName(service: string): string { + const user = config.bootData?.user; + const userUID = user?.uid === '' || !user?.uid ? String(user?.id ?? 'anonymous') : user.uid; + return `${service}:${userUID}`; +} + +/** + * Convenience constant for the alerting service name. + * Use with getResourceName('alerting') or ALERTING_SERVICE directly. + */ +export const ALERTING_SERVICE = 'alerting'; + +/** + * Set up initial data in the UserStorage mock. + * @param resourceName - The resource name (e.g., 'alerting:123'). Use getResourceName() to construct this. + * @param key - The storage key + * @param value - The value to store + */ +export function setUserStorageItem(resourceName: string, key: string, value: string): void { + if (!userStorageData[resourceName]) { + userStorageData[resourceName] = { data: {} }; + } + userStorageData[resourceName].data[key] = value; +} + +/** + * Convenience function to set alerting storage items using the current config's user. + * This automatically constructs the resource name from config.bootData.user. + * + * @param key - The storage key (e.g., 'savedSearches') + * @param value - The value to store (will be stored as-is, caller should JSON.stringify if needed) + * + * @example + * // Set up saved searches for testing + * setAlertingStorageItem('savedSearches', JSON.stringify([{ id: '1', name: 'Test', query: 'state:firing', isDefault: false, createdAt: Date.now() }])); + */ +export function setAlertingStorageItem(key: string, value: string): void { + const resourceName = getResourceName(ALERTING_SERVICE); + setUserStorageItem(resourceName, key, value); +} + +/** + * Convenience function to get alerting storage items using the current config's user. + * + * @param key - The storage key (e.g., 'savedSearches') + * @returns The stored value or null if not found + */ +export function getAlertingStorageItem(key: string): string | null { + const resourceName = getResourceName(ALERTING_SERVICE); + return getUserStorageItem(resourceName, key); +} + +/** + * Get data from the UserStorage mock. + * @param resourceName - The resource name (e.g., 'alerting:123') + * @param key - The storage key + * @returns The stored value or null if not found + */ +export function getUserStorageItem(resourceName: string, key: string): string | null { + return userStorageData[resourceName]?.data[key] ?? null; +} + +/** + * Get the full storage spec for a resource. + * @param resourceName - The resource name + */ +export function getUserStorageSpec(resourceName: string): UserStorageSpec | null { + return userStorageData[resourceName] ?? null; +} + +/** + * MSW handler for GET UserStorage (retrieve stored data) + */ +const getUserStorageHandler = () => + http.get<{ resourceName: string }>(`${getBaseUrl()}/:resourceName`, ({ params }) => { + const spec = userStorageData[params.resourceName]; + + if (!spec) { + return HttpResponse.json({ message: 'Not found' }, { status: 404 }); + } + + return HttpResponse.json({ spec }); + }); + +/** + * MSW handler for POST UserStorage (create new storage) + */ +const createUserStorageHandler = () => + http.post(getBaseUrl(), async ({ request }) => { + const body = (await request.json()) as { + metadata: { name: string; labels: { user: string; service: string } }; + spec: UserStorageSpec; + }; + + const resourceName = body.metadata.name; + userStorageData[resourceName] = body.spec; + + return HttpResponse.json({ spec: body.spec }, { status: 201 }); + }); + +/** + * MSW handler for PATCH UserStorage (update existing storage) + */ +const patchUserStorageHandler = () => + http.patch<{ resourceName: string }>(`${getBaseUrl()}/:resourceName`, async ({ params, request }) => { + const body = (await request.json()) as { spec: UserStorageSpec }; + const resourceName = params.resourceName; + + if (!userStorageData[resourceName]) { + userStorageData[resourceName] = { data: {} }; + } + + // Merge the new data with existing data + userStorageData[resourceName].data = { + ...userStorageData[resourceName].data, + ...body.spec.data, + }; + + return HttpResponse.json({ spec: userStorageData[resourceName] }); + }); + +/** + * All UserStorage MSW handlers + */ +const handlers = [getUserStorageHandler(), createUserStorageHandler(), patchUserStorageHandler()]; + +export default handlers; diff --git a/public/app/features/alerting/unified/rule-editor/CloneRuleEditor.test.tsx b/public/app/features/alerting/unified/rule-editor/CloneRuleEditor.test.tsx index 2572d9ddfc5..bc2153c38fe 100644 --- a/public/app/features/alerting/unified/rule-editor/CloneRuleEditor.test.tsx +++ b/public/app/features/alerting/unified/rule-editor/CloneRuleEditor.test.tsx @@ -165,10 +165,10 @@ describe('CloneRuleEditor', function () { ); await waitFor(() => { - expect(ui.inputs.name.get()).toHaveValue('First Ruler Rule (copy)'); + expect(ui.inputs.namespace.get()).toHaveTextContent('namespace-one'); }); + expect(ui.inputs.name.get()).toHaveValue('First Ruler Rule (copy)'); expect(ui.inputs.expr.get()).toHaveValue('vector(1) > 0'); - expect(ui.inputs.namespace.get()).toHaveTextContent('namespace-one'); expect(ui.inputs.group.get()).toHaveTextContent('group1'); expect( byRole('listitem', { diff --git a/public/app/features/alerting/unified/rule-list/RuleList.v2.test.tsx b/public/app/features/alerting/unified/rule-list/RuleList.v2.test.tsx index d4c445a2772..7985791cfa2 100644 --- a/public/app/features/alerting/unified/rule-list/RuleList.v2.test.tsx +++ b/public/app/features/alerting/unified/rule-list/RuleList.v2.test.tsx @@ -1,5 +1,5 @@ import { HttpResponse } from 'msw'; -import { render, testWithFeatureToggles } from 'test/test-utils'; +import { render, testWithFeatureToggles, waitFor } from 'test/test-utils'; import { byRole, byTestId } from 'testing-library-selector'; import { OrgRole } from '@grafana/data'; @@ -12,7 +12,8 @@ import { setGrafanaRuleGroupExportResolver } from '../mocks/server/configure'; import { alertingFactory } from '../mocks/server/db'; import { RulesFilter } from '../search/rulesSearchParser'; -import RuleList, { RuleListActions } from './RuleList.v2'; +import RuleListPage, { RuleListActions } from './RuleList.v2'; +import { loadDefaultSavedSearch } from './filter/useSavedSearches'; // This tests only checks if proper components are rendered, so we mock them // Both FilterView and GroupedView are tested in their own tests @@ -24,6 +25,30 @@ jest.mock('./GroupedView', () => ({ GroupedView: () =>
Grouped View
, })); +jest.mock('./filter/useSavedSearches', () => ({ + ...jest.requireActual('./filter/useSavedSearches'), + loadDefaultSavedSearch: jest.fn(), + useSavedSearches: jest.fn(() => ({ + savedSearches: [], + isLoading: false, + saveSearch: jest.fn(), + renameSearch: jest.fn(), + deleteSearch: jest.fn(), + setDefaultSearch: jest.fn(), + })), +})); + +const loadDefaultSavedSearchMock = loadDefaultSavedSearch as jest.MockedFunction; + +beforeEach(() => { + loadDefaultSavedSearchMock.mockResolvedValue(null); + // Clear session storage to ensure clean state for each test + // This prevents the "visited" flag from affecting subsequent tests + sessionStorage.clear(); + // Set the visited flag for non-default-search tests to prevent the hook from trying to load + sessionStorage.setItem('grafana.alerting.ruleList.visited', 'true'); +}); + const ui = { filterView: byTestId('filter-view'), groupedView: byTestId('grouped-view'), @@ -45,16 +70,16 @@ setupMswServer(); alertingFactory.dataSource.build({ name: 'Mimir', uid: 'mimir' }); alertingFactory.dataSource.build({ name: 'Prometheus', uid: 'prometheus' }); -describe('RuleList v2', () => { +describe('RuleListPage v2', () => { it('should show grouped view by default', () => { - render(); + render(); expect(ui.groupedView.get()).toBeInTheDocument(); expect(ui.filterView.query()).not.toBeInTheDocument(); }); it('should show grouped view when invalid view parameter is provided', () => { - render(, { + render(, { historyOptions: { initialEntries: ['/?view=invalid'], }, @@ -65,35 +90,35 @@ describe('RuleList v2', () => { }); it('should show list view when "view=list" URL parameter is present', () => { - render(, { historyOptions: { initialEntries: ['/?view=list'] } }); + render(, { historyOptions: { initialEntries: ['/?view=list'] } }); expect(ui.filterView.get()).toBeInTheDocument(); expect(ui.groupedView.query()).not.toBeInTheDocument(); }); it('should show grouped view when only group filter is applied', () => { - render(, { historyOptions: { initialEntries: ['/?search=group:cpu-usage'] } }); + render(, { historyOptions: { initialEntries: ['/?search=group:cpu-usage'] } }); expect(ui.groupedView.get()).toBeInTheDocument(); expect(ui.filterView.query()).not.toBeInTheDocument(); }); it('should show grouped view when only namespace filter is applied', () => { - render(, { historyOptions: { initialEntries: ['/?search=namespace:global'] } }); + render(, { historyOptions: { initialEntries: ['/?search=namespace:global'] } }); expect(ui.groupedView.get()).toBeInTheDocument(); expect(ui.filterView.query()).not.toBeInTheDocument(); }); it('should show grouped view when both group and namespace filters are applied', () => { - render(, { historyOptions: { initialEntries: ['/?search=group:cpu-usage namespace:global'] } }); + render(, { historyOptions: { initialEntries: ['/?search=group:cpu-usage namespace:global'] } }); expect(ui.groupedView.get()).toBeInTheDocument(); expect(ui.filterView.query()).not.toBeInTheDocument(); }); it('should show list view when group and namespace filters are combined with other filter types', () => { - render(, { + render(, { historyOptions: { initialEntries: ['/?search=group:cpu-usage namespace:global state:firing'] }, }); @@ -102,14 +127,14 @@ describe('RuleList v2', () => { }); it('should show grouped view when view parameter is empty', () => { - render(, { historyOptions: { initialEntries: ['/?view='] } }); + render(, { historyOptions: { initialEntries: ['/?view='] } }); expect(ui.groupedView.get()).toBeInTheDocument(); expect(ui.filterView.query()).not.toBeInTheDocument(); }); it('should show grouped view when search parameter is empty', () => { - render(, { historyOptions: { initialEntries: ['/?search='] } }); + render(, { historyOptions: { initialEntries: ['/?search='] } }); expect(ui.groupedView.get()).toBeInTheDocument(); expect(ui.filterView.query()).not.toBeInTheDocument(); @@ -125,28 +150,28 @@ describe('RuleList v2', () => { { filterType: 'ruleHealth', searchQuery: 'health:error' }, { filterType: 'contactPoint', searchQuery: 'contactPoint:slack' }, ])('should show list view when %s filter is applied', ({ filterType, searchQuery }) => { - render(, { historyOptions: { initialEntries: [`/?search=${encodeURIComponent(searchQuery)}`] } }); + render(, { historyOptions: { initialEntries: [`/?search=${encodeURIComponent(searchQuery)}`] } }); expect(ui.filterView.get()).toBeInTheDocument(); expect(ui.groupedView.query()).not.toBeInTheDocument(); }); it('should show list view when "view=list" URL parameter is present with group filter', () => { - render(, { historyOptions: { initialEntries: ['/?view=list&search=group:cpu-usage'] } }); + render(, { historyOptions: { initialEntries: ['/?view=list&search=group:cpu-usage'] } }); expect(ui.filterView.get()).toBeInTheDocument(); expect(ui.groupedView.query()).not.toBeInTheDocument(); }); it('should show list view when "view=list" URL parameter is present with namespace filter', () => { - render(, { historyOptions: { initialEntries: ['/?view=list&search=namespace:global'] } }); + render(, { historyOptions: { initialEntries: ['/?view=list&search=namespace:global'] } }); expect(ui.filterView.get()).toBeInTheDocument(); expect(ui.groupedView.query()).not.toBeInTheDocument(); }); it('should show list view when "view=list" URL parameter is present with both group and namespace filters', () => { - render(, { + render(, { historyOptions: { initialEntries: ['/?view=list&search=group:cpu-usage namespace:global'] }, }); @@ -342,10 +367,10 @@ describe('RuleListActions', () => { }); }); -describe('RuleList v2 - View switching', () => { +describe('RuleListPage v2 - View switching', () => { it('should preserve both group and namespace filters when switching from list view to grouped view', async () => { // Start with list view and both group and namespace filters - const { user } = render(, { + const { user } = render(, { historyOptions: { initialEntries: ['/?view=list&search=group:cpu-usage namespace:global'] }, }); expect(ui.filterView.get()).toBeInTheDocument(); @@ -365,7 +390,7 @@ describe('RuleList v2 - View switching', () => { it('should clear all filters when switching from list view to grouped view with group, namespace and other filters', async () => { // Start with list view with all types of filters - const { user } = render(, { + const { user } = render(, { historyOptions: { initialEntries: ['/?view=list&search=group:cpu-usage namespace:global state:firing rule:"test"'], }, @@ -385,3 +410,86 @@ describe('RuleList v2 - View switching', () => { expect(ui.modeSelector.list.query()).not.toBeChecked(); }); }); +describe('RuleListPage v2 - Default search auto-apply', () => { + // These tests verify that the default search is applied at the page level, + // BEFORE child components mount, preventing double API requests. + + testWithFeatureToggles({ enable: ['alertingListViewV2', 'alertingSavedSearches'] }); + + beforeEach(() => { + // Clear the visited flag so the hook detects this as a first visit + sessionStorage.removeItem('grafana.alerting.ruleList.visited'); + // Clear mock call history between tests + loadDefaultSavedSearchMock.mockClear(); + }); + + it('should apply default search before rendering child components', async () => { + const mockDefaultSearch = { + id: '1', + name: 'My Default', + query: 'state:firing', + isDefault: true, + createdAt: Date.now(), + }; + + // Mock loadDefaultSavedSearch to return a default search + loadDefaultSavedSearchMock.mockResolvedValue(mockDefaultSearch); + + render(); + + // Wait for loadDefaultSavedSearch to be called + await waitFor(() => { + expect(loadDefaultSavedSearchMock).toHaveBeenCalled(); + }); + + // Wait for the filter view to render with the applied search + await waitFor(() => { + expect(ui.filterView.get()).toBeInTheDocument(); + }); + + // Verify the search input shows the applied search query + expect(ui.searchInput.get()).toHaveValue('state:firing'); + }); + + it('should not apply default search when URL already has search parameter', async () => { + const mockDefaultSearch = { + id: '1', + name: 'My Default', + query: 'state:firing', + isDefault: true, + createdAt: Date.now(), + }; + + // loadDefaultSavedSearch should not be called when URL has search param + loadDefaultSavedSearchMock.mockResolvedValue(mockDefaultSearch); + + render(, { + historyOptions: { initialEntries: ['/?search=label:team=backend'] }, + }); + + // Wait for the component to render + await waitFor(() => { + expect(ui.searchInput.get()).toBeInTheDocument(); + }); + + // Should show the URL's search, not the default + expect(ui.searchInput.get()).toHaveValue('label:team=backend'); + + // Verify loadDefaultSavedSearch was not called because filters are already active + // The hook should not execute at all when hasActiveFilters is true + expect(loadDefaultSavedSearchMock).not.toHaveBeenCalled(); + }); + + it('should render normally when no default search exists', async () => { + loadDefaultSavedSearchMock.mockResolvedValue(null); + + render(); + + // Wait for the component to render after checking for default search + await waitFor(() => { + expect(ui.groupedView.get()).toBeInTheDocument(); + }); + + expect(ui.searchInput.get()).toHaveValue(''); + }); +}); diff --git a/public/app/features/alerting/unified/rule-list/RuleList.v2.tsx b/public/app/features/alerting/unified/rule-list/RuleList.v2.tsx index e828b00fa16..284bd6ad757 100644 --- a/public/app/features/alerting/unified/rule-list/RuleList.v2.tsx +++ b/public/app/features/alerting/unified/rule-list/RuleList.v2.tsx @@ -18,6 +18,7 @@ import { FilterView } from './FilterView'; import { GroupedView } from './GroupedView'; import { RuleListPageTitle } from './RuleListPageTitle'; import RulesFilter from './filter/RulesFilter'; +import { useApplyDefaultSearch } from './filter/useApplyDefaultSearch'; function RuleList() { const { filterState } = useRulesFilter(); @@ -117,14 +118,16 @@ export function RuleListActions() { } export default function RuleListPage() { + const { isApplying } = useApplyDefaultSearch(); + return ( } - isLoading={false} + isLoading={isApplying} actions={} > - + {!isApplying && } ); } diff --git a/public/app/features/alerting/unified/rule-list/filter/InlineRenameInput.tsx b/public/app/features/alerting/unified/rule-list/filter/InlineRenameInput.tsx new file mode 100644 index 00000000000..ae2db9e7264 --- /dev/null +++ b/public/app/features/alerting/unified/rule-list/filter/InlineRenameInput.tsx @@ -0,0 +1,146 @@ +import { css } from '@emotion/css'; +import { useEffect } from 'react'; +import { useForm } from 'react-hook-form'; + +import { GrafanaTheme2 } from '@grafana/data'; +import { t } from '@grafana/i18n'; +import { Box, IconButton, Input, Stack, Text, useStyles2 } from '@grafana/ui'; + +import { useAppNotification } from '../../../../../core/copy/appNotification'; + +import { SavedSearch, isValidationError, validateSearchName } from './savedSearchesSchema'; + +// ============================================================================ +// Inline Rename Input (compact input with icon buttons for renaming) +// ============================================================================ + +export interface InlineRenameInputProps { + initialValue: string; + /** Callback to save the renamed search. Throws ValidationError on validation failure. */ + onSave: (name: string) => Promise; + onCancel: () => void; + savedSearches: SavedSearch[]; + excludeId: string; +} + +interface FormValues { + name: string; +} + +export function InlineRenameInput({ + initialValue, + onSave, + onCancel, + savedSearches, + excludeId, +}: InlineRenameInputProps) { + const styles = useStyles2(getStyles); + const notifyApp = useAppNotification(); + + const { + register, + handleSubmit, + setFocus, + formState: { errors, isSubmitting }, + } = useForm({ + defaultValues: { name: initialValue }, + }); + + // Focus and select input on mount using react-hook-form's setFocus + useEffect(() => { + setFocus('name', { shouldSelect: true }); + }, [setFocus]); + + const onSubmit = async (data: FormValues) => { + try { + await onSave(data.name.trim()); + } catch (error) { + // Check if it's a validation error (has field and message) + if (isValidationError(error)) { + // Validation errors are shown inline in the form + // This is handled by react-hook-form validation, but we keep this + // as a fallback for server-side validation errors + return; + } + // For generic save operation errors, show a notification + notifyApp.error( + t('alerting.saved-searches.error-rename-title', 'Failed to rename'), + t('alerting.saved-searches.error-rename-description', 'Your changes could not be saved. Please try again.') + ); + } + }; + + const handleKeyDown = (e: React.KeyboardEvent) => { + if (e.key === 'Escape') { + e.preventDefault(); + onCancel(); + } + }; + + return ( + +
+ + {/* Input area - flex=1 like the name area in list items */} + + { + const error = validateSearchName(value, savedSearches, excludeId); + return error ?? true; + }, + })} + onKeyDown={handleKeyDown} + placeholder={t('alerting.saved-searches.name-placeholder', 'Enter a name...')} + invalid={!!errors.name} + disabled={isSubmitting} + /> + + + {/* X icon - cancel */} + + + {/* Check icon - confirm rename */} + {/* Note: IconButton doesn't forward type="submit", so we use onClick with handleSubmit */} + + +
+ {errors.name?.message && ( + + {errors.name.message} + + )} +
+ ); +} + +// ============================================================================ +// Styles +// ============================================================================ + +function getStyles(theme: GrafanaTheme2) { + return { + successIcon: css({ + color: theme.colors.success.main, + }), + }; +} diff --git a/public/app/features/alerting/unified/rule-list/filter/InlineSaveInput.tsx b/public/app/features/alerting/unified/rule-list/filter/InlineSaveInput.tsx new file mode 100644 index 00000000000..9fd11151cd0 --- /dev/null +++ b/public/app/features/alerting/unified/rule-list/filter/InlineSaveInput.tsx @@ -0,0 +1,139 @@ +import { css } from '@emotion/css'; +import { useEffect } from 'react'; +import { useForm } from 'react-hook-form'; + +import { GrafanaTheme2 } from '@grafana/data'; +import { t } from '@grafana/i18n'; +import { Box, IconButton, Input, Stack, Text, useStyles2 } from '@grafana/ui'; + +import { useAppNotification } from '../../../../../core/copy/appNotification'; + +import { SavedSearch, isValidationError, validateSearchName } from './savedSearchesSchema'; + +// ============================================================================ +// Inline Save Input (compact input with icon buttons) +// ============================================================================ + +export interface InlineSaveInputProps { + /** Callback to save the search. Throws ValidationError on validation failure. */ + onSave: (name: string) => Promise; + onCancel: () => void; + savedSearches: SavedSearch[]; +} + +interface FormValues { + name: string; +} + +export function InlineSaveInput({ onSave, onCancel, savedSearches }: InlineSaveInputProps) { + const styles = useStyles2(getStyles); + const notifyApp = useAppNotification(); + + const { + register, + handleSubmit, + setFocus, + formState: { errors, isSubmitting }, + } = useForm({ + defaultValues: { name: '' }, + }); + + // Focus input on mount using react-hook-form's setFocus + useEffect(() => { + setFocus('name'); + }, [setFocus]); + + const onSubmit = async (data: FormValues) => { + try { + await onSave(data.name.trim()); + } catch (error) { + // Check if it's a validation error (has field and message) + if (isValidationError(error)) { + // Validation errors are shown inline in the form + // This is handled by react-hook-form validation, but we keep this + // as a fallback for server-side validation errors + return; + } + // For generic save operation errors, show a notification + notifyApp.error( + t('alerting.saved-searches.error-save-title', 'Failed to save'), + t('alerting.saved-searches.error-save-description', 'Your changes could not be saved. Please try again.') + ); + } + }; + + const handleKeyDown = (e: React.KeyboardEvent) => { + if (e.key === 'Escape') { + e.preventDefault(); + onCancel(); + } + }; + + return ( + + {/* Match exact structure of SavedSearchItem: [flex-1 content] [icon] [icon] with gap={1} */} +
+ + {/* Input area - flex=1 like the name area in list items */} + + { + const error = validateSearchName(value, savedSearches); + return error ?? true; + }, + })} + onKeyDown={handleKeyDown} + placeholder={t('alerting.saved-searches.name-placeholder', 'Enter a name...')} + invalid={!!errors.name} + disabled={isSubmitting} + /> + + + {/* X icon - aligned with magnifying glass */} + + + {/* Check icon - aligned with action menu */} + {/* Note: IconButton doesn't forward type="submit", so we use onClick with handleSubmit */} + + +
+ {errors.name?.message && ( + + {errors.name.message} + + )} +
+ ); +} + +// ============================================================================ +// Styles +// ============================================================================ + +function getStyles(theme: GrafanaTheme2) { + return { + successIcon: css({ + color: theme.colors.success.main, + }), + }; +} diff --git a/public/app/features/alerting/unified/rule-list/filter/RulesFilter.v2.test.tsx b/public/app/features/alerting/unified/rule-list/filter/RulesFilter.v2.test.tsx index a8f6c91cbc3..8da5901a4b8 100644 --- a/public/app/features/alerting/unified/rule-list/filter/RulesFilter.v2.test.tsx +++ b/public/app/features/alerting/unified/rule-list/filter/RulesFilter.v2.test.tsx @@ -1,8 +1,8 @@ -import { render, screen } from 'test/test-utils'; +import { render, screen, testWithFeatureToggles, waitFor } from 'test/test-utils'; import { byRole, byTestId } from 'testing-library-selector'; import { ComponentTypeWithExtensionMeta, PluginExtensionComponentMeta, PluginExtensionTypes } from '@grafana/data'; -import { config, locationService, setPluginComponentsHook } from '@grafana/runtime'; +import { locationService, setPluginComponentsHook } from '@grafana/runtime'; import { setupMswServer } from 'app/features/alerting/unified/mockApi'; import { grantUserPermissions } from 'app/features/alerting/unified/mocks'; import { AccessControlAction } from 'app/types/accessControl'; @@ -15,6 +15,51 @@ import { setupPluginsExtensionsHook } from '../../testSetup/plugins'; import RulesFilter from './RulesFilter'; +// Mock config for UserStorage (namespace and user must be set before UserStorage module loads) +// This allows the real UserStorage class to work with MSW handlers +jest.mock('@grafana/runtime', () => ({ + ...jest.requireActual('@grafana/runtime'), + reportInteraction: jest.fn(), // Silence analytics calls from useSavedSearches + getDataSourceSrv: () => ({ + getList: jest.fn().mockReturnValue([ + { name: 'Prometheus', uid: 'prometheus-uid' }, + { name: 'Loki', uid: 'loki-uid' }, + ]), + }), + config: { + ...jest.requireActual('@grafana/runtime').config, + namespace: 'default', + bootData: { + ...jest.requireActual('@grafana/runtime').config.bootData, + navTree: [], + user: { + uid: 'test-user-123', + id: 123, + isSignedIn: true, + }, + }, + }, +})); + +// Set up contextSrv.user.id for useSavedSearches session storage key. +// The hook uses this ID to create a per-user session storage key. +// Note: hasPermission must be mocked here because RulesFilter.v1.tsx calls it at module load time, +// before grantUserPermissions can set up the spy. grantUserPermissions still works for runtime checks. +jest.mock('app/core/services/context_srv', () => { + const actual = jest.requireActual('app/core/services/context_srv'); + return { + ...actual, + contextSrv: { + ...actual.contextSrv, + user: { + ...actual.contextSrv.user, + id: 123, + }, + hasPermission: jest.fn().mockReturnValue(true), + }, + }; +}); + // Grant permission before importing the component since permission check happens at module level grantUserPermissions([AccessControlAction.AlertingReceiversRead]); // eslint-disable-next-line @typescript-eslint/no-var-requires @@ -46,6 +91,7 @@ jest.mock('../../hooks/useFilteredRules', () => ({ const useRulesFilterMock = useRulesFilter as jest.MockedFunction; +// Set up MSW server with UserStorage handlers setupMswServer(); jest.spyOn(analytics, 'trackFilterButtonClick'); @@ -54,16 +100,6 @@ jest.spyOn(analytics, 'trackFilterButtonClearClick'); jest.spyOn(analytics, 'trackAlertRuleFilterEvent'); jest.spyOn(analytics, 'trackRulesSearchInputCleared'); -jest.mock('@grafana/runtime', () => ({ - ...jest.requireActual('@grafana/runtime'), - getDataSourceSrv: () => ({ - getList: jest.fn().mockReturnValue([ - { name: 'Prometheus', uid: 'prometheus-uid' }, - { name: 'Loki', uid: 'loki-uid' }, - ]), - }), -})); - jest.mock('../../components/rules/MultipleDataSourcePicker', () => { const original = jest.requireActual('../../components/rules/MultipleDataSourcePicker'); return { @@ -113,6 +149,8 @@ const ui = { beforeEach(() => { locationService.replace({ search: '' }); jest.clearAllMocks(); + sessionStorage.clear(); + localStorage.clear(); mockFilterState = { ruleName: '', @@ -150,45 +188,46 @@ beforeEach(() => { }); describe('RulesFilter Feature Flag', () => { - const originalFeatureToggle = config.featureToggles.alertingFilterV2; + describe('with alertingFilterV2 enabled', () => { + testWithFeatureToggles({ enable: ['alertingFilterV2'] }); - afterEach(() => { - config.featureToggles.alertingFilterV2 = originalFeatureToggle; + it('Should render RulesFilterV2 when alertingFilterV2 feature flag is enabled', async () => { + render(); + + // Wait for suspense to resolve and check that the V2 filter button is present + await screen.findByRole('button', { name: 'Filter' }); + expect(ui.filterButton.get()).toBeInTheDocument(); + expect(ui.searchInput.get()).toBeInTheDocument(); + }); }); - it('Should render RulesFilterV2 when alertingFilterV2 feature flag is enabled', async () => { - config.featureToggles.alertingFilterV2 = true; + describe('with alertingFilterV2 disabled', () => { + testWithFeatureToggles({ disable: ['alertingFilterV2'] }); - render(); + it('Should render RulesFilterV1 when alertingFilterV2 feature flag is disabled', async () => { + render(); - // Wait for suspense to resolve and check that the V2 filter button is present - await screen.findByRole('button', { name: 'Filter' }); - expect(ui.filterButton.get()).toBeInTheDocument(); - expect(ui.searchInput.get()).toBeInTheDocument(); - }); + // Wait for suspense to resolve and check V1 structure + await screen.findByText('Search'); - it('Should render RulesFilterV1 when alertingFilterV2 feature flag is disabled', async () => { - config.featureToggles.alertingFilterV2 = false; + // V1 has search input but no V2-style filter button + expect(ui.searchInput.get()).toBeInTheDocument(); + expect(ui.filterButton.query()).not.toBeInTheDocument(); - render(); - - // Wait for suspense to resolve and check V1 structure - await screen.findByText('Search'); - - // V1 has search input but no V2-style filter button - expect(ui.searchInput.get()).toBeInTheDocument(); - expect(ui.filterButton.query()).not.toBeInTheDocument(); - - // V1 has a help icon next to the search input - expect(screen.getByText('Search')).toBeInTheDocument(); + // V1 has a help icon next to the search input + expect(screen.getByText('Search')).toBeInTheDocument(); + }); }); }); describe('RulesFilterV2', () => { - it('Should render component without crashing', () => { + it('Should render component without crashing', async () => { render(); - expect(ui.searchInput.get()).toBeInTheDocument(); + // Wait for async hook operations (useSavedSearches) to complete + await waitFor(() => { + expect(ui.searchInput.get()).toBeInTheDocument(); + }); expect(ui.filterButton.get()).toBeInTheDocument(); }); @@ -429,4 +468,6 @@ describe('RulesFilterV2', () => { expect(analytics.trackFilterButtonClick).toHaveBeenCalledTimes(1); }); }); + + // Auto-apply of default search is tested in RuleList.v2.test.tsx (behavior is in RuleListPage) }); diff --git a/public/app/features/alerting/unified/rule-list/filter/RulesFilter.v2.tsx b/public/app/features/alerting/unified/rule-list/filter/RulesFilter.v2.tsx index 0091cdddec9..eb2e368ad80 100644 --- a/public/app/features/alerting/unified/rule-list/filter/RulesFilter.v2.tsx +++ b/public/app/features/alerting/unified/rule-list/filter/RulesFilter.v2.tsx @@ -39,10 +39,14 @@ import { useLabelOptions, useNamespaceAndGroupOptions, } from '../../components/rules/Filter/useRuleFilterAutocomplete'; +import { shouldUseSavedSearches } from '../../featureToggles'; import { useRulesFilter } from '../../hooks/useFilteredRules'; import { RuleHealth, RuleSource, getSearchFilterFromQuery } from '../../search/rulesSearchParser'; import { RulesFilterProps } from './RulesFilter'; +import { SavedSearches } from './SavedSearches'; +import { SavedSearch } from './savedSearchesSchema'; +import { trackSavedSearchApplied, useSavedSearches } from './useSavedSearches'; import { emptyAdvancedFilters, formAdvancedFiltersToRuleFilter, @@ -86,6 +90,19 @@ export default function RulesFilter({ viewMode, onViewModeChange }: RulesFilterP const popupRef = useRef(null); const { pluginsFilterEnabled } = usePluginsFilterStatus(); + // Feature toggle for saved searches + const savedSearchesEnabled = shouldUseSavedSearches(); + + // Saved searches hook with UserStorage persistence + const { + savedSearches, + isLoading: savedSearchesLoading, + saveSearch, + renameSearch, + deleteSearch, + setDefaultSearch, + } = useSavedSearches(); + // this form will managed the search query string, which is updated either by the user typing in the input or by the advanced filters const { control, setValue, handleSubmit } = useForm({ defaultValues: { @@ -97,6 +114,20 @@ export default function RulesFilter({ viewMode, onViewModeChange }: RulesFilterP setValue('query', searchQuery); }, [searchQuery, setValue]); + // Apply saved search - triggers filtering (which updates search input and URL) + const handleApplySearch = useCallback( + (search: SavedSearch) => { + const parsedFilter = getSearchFilterFromQuery(search.query); + updateFilters(parsedFilter); + + // Track analytics + trackSavedSearchApplied(search); + }, + [updateFilters] + ); + + // Auto-apply of default search is handled in RuleListPage (before FilterView mounts) + const submitHandler: SubmitHandler = (values: SearchQueryForm) => { const parsedFilter = getSearchFilterFromQuery(values.query); trackAlertRuleFilterEvent({ filterMethod: 'search-input', filter: parsedFilter, filterVariant: 'v2' }); @@ -240,7 +271,21 @@ export default function RulesFilter({ viewMode, onViewModeChange }: RulesFilterP {filterButtonLabel} - + {savedSearchesEnabled && ( + + )} + + + diff --git a/public/app/features/alerting/unified/rule-list/filter/SavedSearchItem.tsx b/public/app/features/alerting/unified/rule-list/filter/SavedSearchItem.tsx new file mode 100644 index 00000000000..0fb92622b2d --- /dev/null +++ b/public/app/features/alerting/unified/rule-list/filter/SavedSearchItem.tsx @@ -0,0 +1,226 @@ +import { css } from '@emotion/css'; + +import { GrafanaTheme2 } from '@grafana/data'; +import { t } from '@grafana/i18n'; +import { Dropdown, Icon, IconButton, Menu, Stack, Text, useStyles2 } from '@grafana/ui'; + +import { InlineRenameInput } from './InlineRenameInput'; +import { SavedSearch } from './savedSearchesSchema'; + +// ============================================================================ +// Saved Search Item +// ============================================================================ + +export interface SavedSearchItemProps { + search: SavedSearch; + isRenaming: boolean; + isDeleting: boolean; + isDisabled: boolean; + onApply: () => void; + onStartRename: () => void; + onCancelRename: () => void; + onRenameComplete: (newName: string) => Promise; + onStartDelete: () => void; + onCancelDelete: () => void; + onDeleteConfirm: () => Promise; + onSetDefault: () => void; + savedSearches: SavedSearch[]; + /** Portal root for the action menu - should be the outer dropdown container */ + menuPortalRoot?: HTMLElement | null; +} + +export function SavedSearchItem({ + search, + isRenaming, + isDeleting, + isDisabled, + onApply, + onStartRename, + onCancelRename, + onRenameComplete, + onStartDelete, + onCancelDelete, + onDeleteConfirm, + onSetDefault, + savedSearches, + menuPortalRoot, +}: SavedSearchItemProps) { + const styles = useStyles2(getStyles); + + // Rename mode - inline form matching the save form + // Stop propagation to prevent parent Dropdown from closing when interacting with form + if (isRenaming) { + return ( + // eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-noninteractive-element-interactions +
e.stopPropagation()}> + +
+ ); + } + + // Delete confirm mode - inline with name visible + // Stop propagation to prevent parent Dropdown from closing when interacting with delete confirmation + if (isDeleting) { + return ( + // eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-noninteractive-element-interactions +
e.stopPropagation()}> + + {/* Name remains visible */} + + {search.name} + + + {/* X icon - cancel delete */} + + + {/* Trash icon - confirm delete */} + + +
+ ); + } + + // Default display mode + return ( +
+ + {/* Name and default indicator */} + + {search.name} + {search.isDefault && ( + + )} + + + {/* Apply button (magnifying glass) */} + + + {/* Action menu - stop propagation to prevent parent Dropdown from closing */} + {/* eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions */} +
e.stopPropagation()}> + +
+
+
+ ); +} + +// ============================================================================ +// Action Menu (three-dot menu) +// ============================================================================ + +interface ActionMenuProps { + isDefault: boolean; + isDisabled: boolean; + onSetDefault: () => void; + onRename: () => void; + onDelete: () => void; + /** Portal root for the menu - renders inside the outer dropdown to prevent useDismiss issues */ + portalRoot?: HTMLElement | null; +} + +function ActionMenu({ isDefault, isDisabled, onSetDefault, onRename, onDelete, portalRoot }: ActionMenuProps) { + const menu = ( + + + + + + + ); + + return ( + + + + ); +} + +// ============================================================================ +// Styles +// ============================================================================ + +function getStyles(theme: GrafanaTheme2) { + return { + item: css({ + padding: theme.spacing(0.5), + borderRadius: theme.shape.radius.default, + '&:hover': { + backgroundColor: theme.colors.action.hover, + }, + }), + defaultIcon: css({ + color: theme.colors.warning.main, + flexShrink: 0, + }), + deleteIcon: css({ + color: theme.colors.error.main, + }), + actionMenuWrapper: css({ + display: 'flex', + alignItems: 'center', + }), + }; +} diff --git a/public/app/features/alerting/unified/rule-list/filter/SavedSearches.README.md b/public/app/features/alerting/unified/rule-list/filter/SavedSearches.README.md new file mode 100644 index 00000000000..8935cecaaa1 --- /dev/null +++ b/public/app/features/alerting/unified/rule-list/filter/SavedSearches.README.md @@ -0,0 +1,404 @@ +# Saved Searches Feature + +The Saved Searches feature allows users to save, manage, and quickly apply search queries on the Alert Rules page. + +## Overview + +Users can: + +- **Save** the current search query with a custom name +- **Apply** a saved search to instantly filter rules +- **Rename** existing saved searches +- **Delete** saved searches they no longer need +- **Set a default** search that auto-applies when navigating to the page + +## Components + +### `` + +The main component that renders a button and dropdown for managing saved searches. + +```tsx +import { SavedSearches } from './SavedSearches'; + +; +``` + +#### Props + +| Prop | Type | Required | Description | +| -------------------- | ------------------------------------------------------------------- | -------- | ------------------------------------------- | +| `savedSearches` | `SavedSearch[]` | Yes | Array of saved search objects | +| `currentSearchQuery` | `string` | Yes | The current search query in the input field | +| `onSave` | `(name: string, query: string) => Promise` | Yes | Called when user saves a new search | +| `onRename` | `(id: string, newName: string) => Promise` | Yes | Called when user renames a search | +| `onDelete` | `(id: string) => Promise` | Yes | Called when user deletes a search | +| `onApply` | `(search: SavedSearch) => void` | Yes | Called when user applies a search | +| `onSetDefault` | `(id: string \| null) => Promise` | Yes | Called when user sets/clears default | + +#### Types + +```typescript +interface SavedSearch { + /** Unique identifier */ + id: string; + /** User-provided name */ + name: string; + /** The search query string */ + query: string; + /** Whether this is the default search */ + isDefault: boolean; + /** Unix timestamp of creation */ + createdAt: number; +} + +interface ValidationError { + /** The field with the error */ + field: string; + /** Error message to display */ + message: string; +} +``` + +### `useSavedSearches()` Hook + +A custom hook that manages saved searches with UserStorage persistence. + +```tsx +import { useSavedSearches, trackSavedSearchApplied } from './useSavedSearches'; + +const { savedSearches, isLoading, saveSearch, renameSearch, deleteSearch, setDefaultSearch, getAutoApplySearch } = + useSavedSearches(); + +// Track when a search is applied +const handleApply = (search: SavedSearch) => { + applySearchToFilter(search.query); + trackSavedSearchApplied(search); +}; +``` + +#### Return Value + +| Property | Type | Description | +| -------------------- | --------------------------------------------------- | ------------------------------------- | +| `savedSearches` | `SavedSearch[]` | Current list of saved searches | +| `isLoading` | `boolean` | Whether initial load is in progress | +| `saveSearch` | `(name, query) => Promise` | Save a new search | +| `renameSearch` | `(id, newName) => Promise` | Rename an existing search | +| `deleteSearch` | `(id) => Promise` | Delete a search | +| `setDefaultSearch` | `(id \| null) => Promise` | Set or clear the default search | +| `getAutoApplySearch` | `() => SavedSearch \| null` | Get the default search for auto-apply | + +## Integration + +### Basic Integration + +```tsx +import { SavedSearches, SavedSearch } from './SavedSearches'; +import { useSavedSearches, trackSavedSearchApplied } from './useSavedSearches'; + +function MyFilterComponent() { + const { filterState, updateFilters } = useMyFilter(); + + const { savedSearches, saveSearch, renameSearch, deleteSearch, setDefaultSearch, getAutoApplySearch } = + useSavedSearches(); + + // Handle applying a saved search + const handleApply = useCallback( + (search: SavedSearch) => { + // Update your filter state with the saved query + updateFilters(parseQuery(search.query)); + + // Track analytics + trackSavedSearchApplied(search); + }, + [updateFilters] + ); + + // Auto-apply default search on navigation + useEffect(() => { + const defaultSearch = getAutoApplySearch(); + if (defaultSearch) { + handleApply(defaultSearch); + } + }, [getAutoApplySearch, handleApply]); + + return ( + + ); +} +``` + +### Feature Toggle + +The feature is gated behind the `alertingSavedSearches` feature toggle: + +```tsx +import { shouldUseSavedSearches } from '../../featureToggles'; + +function MyComponent() { + const savedSearchesEnabled = shouldUseSavedSearches(); + + return ( + <> + {savedSearchesEnabled && } + + ); +} +``` + +To enable during development, set in Grafana config: + +```ini +[feature_toggles] +alertingSavedSearches = true +``` + +## Behavior + +### Dropdown States + +1. **List Mode** (default) + - Shows saved searches sorted: default first, then alphabetical + - Shows "Save current search" button when `currentSearchQuery` is non-empty + - Empty state when no saved searches exist + +2. **Save Mode** + - Name input with validation + - Save/Cancel buttons + - Triggered by clicking "Save current search" + +3. **Rename Mode** (per-item) + - Inline editing of search name + - Confirm with Enter, cancel with Escape + +4. **Delete Confirmation** (per-item) + - Inline confirmation prompt + - Delete/Cancel buttons + +### Validation Rules + +| Rule | Message | +| ------------------------------ | ---------------------------------------------- | +| Name required | "Name is required" | +| Max length 64 | "Name must be 64 characters or less" | +| Unique name (case-insensitive) | "A saved search with this name already exists" | + +### Auto-Apply Default Search + +The default search auto-applies when: + +1. User **navigates** to the Alert Rules page (not on refresh) +2. No search query is present in the URL +3. A default search is configured + +This is tracked via `sessionStorage` to distinguish navigation from refresh. + +### Persistence + +Saved searches are stored using `UserStorage`: + +- **Backend API**: `/apis/userstorage.grafana.app/v0alpha1/namespaces/{namespace}/user-storage` +- **Fallback**: `localStorage` (when user not signed in or API fails) +- **Storage key**: `alerting.savedSearches` + +## Analytics + +The feature tracks the following events via `reportInteraction`: + +| Event | Properties | When | +| ------------------------------------------- | -------------------------- | -------------------- | +| `grafana_alerting_saved_search_save` | `hasDefault`, `totalCount` | Search saved | +| `grafana_alerting_saved_search_apply` | `isDefault` | Search applied | +| `grafana_alerting_saved_search_delete` | - | Search deleted | +| `grafana_alerting_saved_search_rename` | - | Search renamed | +| `grafana_alerting_saved_search_set_default` | `action: 'set' \| 'clear'` | Default changed | +| `grafana_alerting_saved_search_auto_apply` | - | Default auto-applied | + +## Testing + +### Component Tests + +Location: `SavedSearches.test.tsx` + +```bash +yarn test SavedSearches.test.tsx +``` + +Test categories: + +- **Rendering**: Button, dropdown, list sorting, empty state +- **Save functionality**: Validation, errors, success flow +- **Apply functionality**: Click handling, dropdown close +- **Action menu**: Set default, rename, delete options +- **Delete confirmation**: Confirm/cancel flows +- **Keyboard navigation**: Escape key handling +- **Edge cases**: Empty queries, whitespace trimming + +### Hook Tests + +Location: `useSavedSearches.test.tsx` + +```bash +yarn test useSavedSearches.test.tsx +``` + +Test categories: + +- **Initial loading**: Loading state, storage load, empty storage +- **saveSearch**: New search, duplicate detection, analytics +- **renameSearch**: Rename flow, duplicate detection +- **deleteSearch**: Delete flow, analytics +- **setDefaultSearch**: Set/clear default, analytics +- **getAutoApplySearch**: Navigation detection, URL check +- **Error handling**: Storage errors, notifications + +### Mocking UserStorage API with MSW + +The hook and component tests use MSW to mock the UserStorage API endpoints. +The handlers are defined in `mocks/server/handlers/userStorage.ts` and included via `setupMswServer()`: + +```typescript +import { setupMswServer, setAlertingStorageItem, getAlertingStorageItem } from 'app/features/alerting/unified/mockApi'; + +// Set up MSW server with UserStorage handlers (call at module level) +setupMswServer(); + +// In tests, use helper functions to set up storage data: +it('should load saved searches', async () => { + setAlertingStorageItem('savedSearches', JSON.stringify(mockSavedSearches)); + + const { result } = renderHook(() => useSavedSearches(), { wrapper: createWrapper() }); + + await waitFor(() => { + expect(result.current.isLoading).toBe(false); + }); + + expect(result.current.savedSearches).toEqual(mockSavedSearches); +}); + +// Verify persisted data: +it('should save a new search', async () => { + // ... perform save action ... + + const storedData = getAlertingStorageItem('savedSearches'); + expect(storedData).toContain('"name":"New Search"'); +}); +``` + +**Important**: Tests must mock `config.namespace` and `config.bootData.user` before imports, +so that `UserStorage` constructs the correct API URLs: + +```typescript +jest.mock('@grafana/runtime', () => ({ + ...jest.requireActual('@grafana/runtime'), + config: { + ...jest.requireActual('@grafana/runtime').config, + namespace: 'default', + bootData: { + ...jest.requireActual('@grafana/runtime').config.bootData, + user: { uid: 'test-user-123', id: 123, isSignedIn: true }, + }, + }, +})); +``` + +### Verifying Notifications in UI + +Tests verify error notifications by rendering the `AppNotificationList` component: + +```typescript +import { AppNotificationList } from 'app/core/components/AppNotifications/AppNotificationList'; +import { getWrapper, screen } from 'test/test-utils'; + +function createWrapper() { + const Wrapper = getWrapper({ renderWithRouter: true }); + return function WrapperWithNotifications({ children }) { + return ( + + + {children} + + ); + }; +} + +// In tests (e.g., malformed JSON triggers error notification): +it('should handle malformed JSON gracefully', async () => { + setAlertingStorageItem('savedSearches', 'not valid json'); + + const { result } = renderHook(() => useSavedSearches(), { wrapper: createWrapper() }); + + await waitFor(() => { + expect(result.current.isLoading).toBe(false); + }); + + expect(await screen.findByText(/failed to load saved searches/i)).toBeInTheDocument(); +}); +``` + +## Accessibility + +- Dropdown has `role="dialog"` for screen readers +- Action menu uses `@grafana/ui` `Dropdown` and `Menu` components +- Keyboard support: + - `Escape`: Close dropdown or cancel current operation + - `Tab`: Navigate through interactive elements + - `Enter`: Confirm inputs + +## File Structure + +``` +public/app/features/alerting/unified/rule-list/filter/ +├── SavedSearches.tsx # Main component +├── SavedSearches.test.tsx # Component tests +├── SavedSearches.README.md # This documentation +├── useSavedSearches.ts # Custom hook with persistence +└── useSavedSearches.test.tsx # Hook tests +``` + +## Dependencies + +- `@grafana/ui`: Button, Dropdown, Menu, Icon, Input, Stack, Box, Spinner, PopupCard +- `@grafana/i18n`: Trans, t (internationalization) +- `@grafana/runtime`: reportInteraction +- `@grafana/runtime/internal`: UserStorage +- `@emotion/css`: Styling via useStyles2 + +## E2E Tests + +Location: `e2e-playwright/alerting-suite/saved-searches.spec.ts` + +```bash +yarn e2e:playwright --grep "saved-searches" +``` + +Test scenarios: + +- Display Saved searches button +- Open/close dropdown +- Empty state +- Save current search (enabled/disabled) +- Create new saved search +- Validation errors (duplicate name) +- Apply saved search +- Rename saved search +- Delete saved search +- Set as default +- Keyboard navigation (Escape to close/cancel) diff --git a/public/app/features/alerting/unified/rule-list/filter/SavedSearches.test.tsx b/public/app/features/alerting/unified/rule-list/filter/SavedSearches.test.tsx new file mode 100644 index 00000000000..7e3604c5eec --- /dev/null +++ b/public/app/features/alerting/unified/rule-list/filter/SavedSearches.test.tsx @@ -0,0 +1,348 @@ +import { render, screen, waitFor } from 'test/test-utils'; +import { byPlaceholderText, byRole, byText } from 'testing-library-selector'; + +import { SavedSearches } from './SavedSearches'; +import { SavedSearch } from './savedSearchesSchema'; + +/** + * UI selectors for SavedSearches component tests. + * Using testing-library-selector for reusable, consistent selectors. + */ +const ui = { + // Main trigger button + savedSearchesButton: byRole('button', { name: /saved searches/i }), + // Dropdown dialog + dropdown: byRole('dialog'), + // Save functionality + saveButton: byRole('button', { name: /save current search/i }), + saveConfirmButton: byRole('button', { name: /save$/i }), + saveInput: byPlaceholderText(/enter a name/i), + // Action buttons + cancelButton: byRole('button', { name: /cancel/i }), + applyButtons: byRole('button', { name: /apply this search/i }), + actionMenuButtons: byRole('button', { name: /actions/i }), + deleteButton: byRole('button', { name: /delete/i }), + // Menu items (using byRole for proper accessibility testing) + setAsDefaultMenuItem: byRole('menuitem', { name: /set as default/i }), + removeDefaultMenuItem: byRole('menuitem', { name: /remove default/i }), + renameMenuItem: byRole('menuitem', { name: /rename/i }), + deleteMenuItem: byRole('menuitem', { name: /^delete$/i }), + // Messages + emptyStateMessage: byText(/no saved searches/i), + nameRequiredError: byText(/name is required/i), + duplicateNameError: byText(/a saved search with this name already exists/i), +}; + +// Mock data is ordered as it will appear after sorting by useSavedSearches: +// default search first, then alphabetically by name +const mockSavedSearches: SavedSearch[] = [ + { + id: '2', + name: 'Default Search', + query: 'label:team=A', + isDefault: true, + createdAt: Date.now() - 2000, + }, + { + id: '3', + name: 'Critical Alerts', + query: 'label:severity=critical state:firing', + isDefault: false, + createdAt: Date.now() - 3000, + }, + { + id: '1', + name: 'My Firing Rules', + query: 'state:firing', + isDefault: false, + createdAt: Date.now() - 1000, + }, +]; + +const defaultProps = { + savedSearches: mockSavedSearches, + currentSearchQuery: '', + onSave: jest.fn(), + onRename: jest.fn(), + onDelete: jest.fn(), + onApply: jest.fn(), + onSetDefault: jest.fn(), +}; + +describe('SavedSearches', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + describe('Displaying saved searches', () => { + it('shows empty state when no saved searches exist', async () => { + const { user } = render(); + + await user.click(ui.savedSearchesButton.get()); + + expect(ui.emptyStateMessage.get()).toBeInTheDocument(); + }); + + it('displays saved searches with default search marked with star icon', async () => { + const { user } = render(); + + await user.click(ui.savedSearchesButton.get()); + + // Verify searches are displayed + const applyButtons = await ui.applyButtons.findAll(); + expect(applyButtons).toHaveLength(3); + + // Verify the default search has a star icon + expect(screen.getByText('Default Search')).toBeInTheDocument(); + expect(screen.getByTitle('Default search')).toBeInTheDocument(); + }); + }); + + describe('Saving a search', () => { + it('saves current search with the provided name', async () => { + defaultProps.onSave.mockResolvedValue(undefined); + const { user } = render(); + + await user.click(ui.savedSearchesButton.get()); + await user.click(await ui.saveButton.find()); + await user.type(await ui.saveInput.find(), 'My New Search'); + await user.click(ui.saveConfirmButton.get()); + + expect(defaultProps.onSave).toHaveBeenCalledWith('My New Search', 'state:pending'); + }); + + it('disables save button when currentSearchQuery is empty', async () => { + const { user } = render(); + + await user.click(ui.savedSearchesButton.get()); + + // Use findByText + closest because findByRole fails to find disabled Grafana Button + // (due to aria-disabled="false" + disabled="" attribute mismatch in Grafana UI) + const saveButtonText = await screen.findByText(/save current search/i); + // eslint-disable-next-line testing-library/no-node-access + const saveButton = saveButtonText.closest('button'); + expect(saveButton).toBeDisabled(); + }); + + it('shows validation error when name is empty', async () => { + const { user } = render(); + + await user.click(ui.savedSearchesButton.get()); + await user.click(await ui.saveButton.find()); + await user.click(await ui.saveConfirmButton.find()); + + expect(await ui.nameRequiredError.find()).toBeInTheDocument(); + }); + + it('shows validation error for duplicate name', async () => { + defaultProps.onSave.mockResolvedValue({ + field: 'name', + message: 'A saved search with this name already exists', + }); + const { user } = render(); + + await user.click(ui.savedSearchesButton.get()); + await user.click(await ui.saveButton.find()); + await user.type(await ui.saveInput.find(), 'My Firing Rules'); + await user.click(ui.saveConfirmButton.get()); + + expect(await ui.duplicateNameError.find()).toBeInTheDocument(); + }); + + it('trims whitespace from search name before saving', async () => { + defaultProps.onSave.mockResolvedValue(undefined); + const { user } = render(); + + await user.click(ui.savedSearchesButton.get()); + await user.click(await ui.saveButton.find()); + await user.type(await ui.saveInput.find(), ' My Search '); + await user.click(ui.saveConfirmButton.get()); + + expect(defaultProps.onSave).toHaveBeenCalledWith('My Search', 'state:pending'); + }); + + it('cancels save when cancel button is clicked', async () => { + const { user } = render(); + + await user.click(ui.savedSearchesButton.get()); + await user.click(await ui.saveButton.find()); + await user.click(await ui.cancelButton.find()); + + expect(defaultProps.onSave).not.toHaveBeenCalled(); + expect(ui.saveInput.query()).not.toBeInTheDocument(); + }); + }); + + describe('Applying a search', () => { + it('applies the selected search and closes dropdown', async () => { + const { user } = render(); + + await user.click(ui.savedSearchesButton.get()); + const applyButtons = await ui.applyButtons.findAll(); + // Click the apply button for "My Firing Rules" (third in list: Default, Critical, My Firing) + await user.click(applyButtons[2]); + + expect(defaultProps.onApply).toHaveBeenCalledWith( + expect.objectContaining({ + id: '1', + name: 'My Firing Rules', + query: 'state:firing', + }) + ); + + await waitFor(() => { + expect(ui.dropdown.query()).not.toBeInTheDocument(); + }); + }); + }); + + describe('Setting default search', () => { + it('sets a search as default', async () => { + const { user } = render(); + + await user.click(ui.savedSearchesButton.get()); + // Use a non-default search's menu (second item: "Critical Alerts") + const menuButtons = await ui.actionMenuButtons.findAll(); + await user.click(menuButtons[1]); + await user.click(await ui.setAsDefaultMenuItem.find()); + + expect(defaultProps.onSetDefault).toHaveBeenCalledWith('3'); + }); + + it('removes default from a search', async () => { + const { user } = render(); + + await user.click(ui.savedSearchesButton.get()); + // Default Search is first item (index 0) + const menuButtons = await ui.actionMenuButtons.findAll(); + await user.click(menuButtons[0]); + await user.click(await ui.removeDefaultMenuItem.find()); + + expect(defaultProps.onSetDefault).toHaveBeenCalledWith(null); + }); + }); + + describe('Renaming a search', () => { + it('renames a search successfully', async () => { + defaultProps.onRename.mockResolvedValue(undefined); + const { user } = render(); + + await user.click(ui.savedSearchesButton.get()); + const menuButtons = await ui.actionMenuButtons.findAll(); + await user.click(menuButtons[0]); + await user.click(await ui.renameMenuItem.find()); + + const input = await screen.findByDisplayValue('Default Search'); + await user.clear(input); + await user.type(input, 'Renamed Search'); + await user.keyboard('{Enter}'); + + expect(defaultProps.onRename).toHaveBeenCalledWith('2', 'Renamed Search'); + }); + + it('shows validation error for duplicate name when renaming', async () => { + defaultProps.onRename.mockResolvedValue({ + field: 'name', + message: 'A saved search with this name already exists', + }); + const { user } = render(); + + await user.click(ui.savedSearchesButton.get()); + const menuButtons = await ui.actionMenuButtons.findAll(); + await user.click(menuButtons[0]); + await user.click(await ui.renameMenuItem.find()); + + const input = await screen.findByDisplayValue('Default Search'); + await user.clear(input); + await user.type(input, 'My Firing Rules'); + await user.keyboard('{Enter}'); + + await waitFor(() => { + expect(ui.duplicateNameError.get()).toBeInTheDocument(); + }); + }); + }); + + describe('Deleting a search', () => { + it('deletes a search after confirmation', async () => { + const { user } = render(); + + await user.click(ui.savedSearchesButton.get()); + const menuButtons = await ui.actionMenuButtons.findAll(); + // Delete the first item (Default Search, id: '2') + await user.click(menuButtons[0]); + await user.click(await ui.deleteMenuItem.find()); + + // Confirm delete + const deleteButtons = await ui.deleteButton.findAll(); + await user.click(deleteButtons[deleteButtons.length - 1]); + + expect(defaultProps.onDelete).toHaveBeenCalledWith('2'); + }); + + it('cancels delete when cancel is clicked', async () => { + const { user } = render(); + + await user.click(ui.savedSearchesButton.get()); + const menuButtons = await ui.actionMenuButtons.findAll(); + await user.click(menuButtons[0]); + await user.click(await ui.deleteMenuItem.find()); + + await user.click(await ui.cancelButton.find()); + + expect(defaultProps.onDelete).not.toHaveBeenCalled(); + expect(screen.getByText('Default Search')).toBeInTheDocument(); + }); + }); + + describe('Keyboard navigation', () => { + it('closes dropdown when Escape is pressed', async () => { + const { user } = render(); + + await user.click(ui.savedSearchesButton.get()); + expect(await ui.dropdown.find()).toBeInTheDocument(); + + await user.keyboard('{Escape}'); + + await waitFor(() => { + expect(ui.dropdown.query()).not.toBeInTheDocument(); + }); + }); + + it('cancels save mode when Escape is pressed without closing dropdown', async () => { + const { user } = render(); + + await user.click(ui.savedSearchesButton.get()); + await user.click(await ui.saveButton.find()); + expect(await ui.saveInput.find()).toBeInTheDocument(); + + await user.keyboard('{Escape}'); + + await waitFor(() => { + expect(ui.saveInput.query()).not.toBeInTheDocument(); + }); + // Dropdown should still be open + expect(ui.dropdown.get()).toBeInTheDocument(); + }); + }); + + describe('Edge cases', () => { + it('handles empty search query display gracefully', async () => { + const searchesWithEmptyQuery: SavedSearch[] = [ + { + id: '1', + name: 'Empty Search', + query: '', + isDefault: false, + createdAt: Date.now(), + }, + ]; + + const { user } = render(); + + await user.click(ui.savedSearchesButton.get()); + + expect(await screen.findByText('Empty Search')).toBeInTheDocument(); + }); + }); +}); diff --git a/public/app/features/alerting/unified/rule-list/filter/SavedSearches.tsx b/public/app/features/alerting/unified/rule-list/filter/SavedSearches.tsx new file mode 100644 index 00000000000..0d4391642f0 --- /dev/null +++ b/public/app/features/alerting/unified/rule-list/filter/SavedSearches.tsx @@ -0,0 +1,556 @@ +/** + * SavedSearches Component + * + * Allows users to save, manage, and quickly apply search queries on the Alert Rules page. + * + * ## Features + * - Save current search query with a custom name + * - Mark one search as "default" (auto-applied on navigation) + * - Rename, delete, and apply saved searches + * - Alphabetical sorting with default search pinned first + * + * ## Props + * @param savedSearches - Array of saved search objects + * @param currentSearchQuery - The current search query string from the filter state + * @param onSave - Callback to save a new search. Throws ValidationError on failure. + * @param onRename - Callback to rename an existing search. Throws ValidationError on failure. + * @param onDelete - Callback to delete a search + * @param onApply - Callback when a saved search is applied + * @param onSetDefault - Callback to set/unset default search (pass null to unset) + * @param disabled - Disables all interactions + * @param className - Additional CSS class name + * + * ## Internal States + * - Dropdown open/closed + * - Save mode (inputting new search name) + * - Rename mode (editing existing search name, by item ID) + * - Delete confirm mode (confirming deletion, by item ID) + * + * ## Accessibility + * - Uses role="dialog" for the dropdown panel + * - Basic keyboard navigation (Escape to close, Tab to navigate) + * - Focus moves to "Save current search" button when dropdown opens + * + * @example + * ```tsx + * + * ``` + */ + +import { css } from '@emotion/css'; +import { useCallback, useEffect, useReducer, useRef } from 'react'; + +import { GrafanaTheme2 } from '@grafana/data'; +import { Trans, t } from '@grafana/i18n'; +import { Box, Button, Spinner, Stack, Text, useStyles2 } from '@grafana/ui'; + +import { PopupCard } from '../../components/HoverCard'; + +import { InlineSaveInput } from './InlineSaveInput'; +import { SavedSearchItem } from './SavedSearchItem'; +import { SavedSearch } from './savedSearchesSchema'; + +// ============================================================================ +// Types +// ============================================================================ + +export interface SavedSearchesProps { + /** Array of saved search objects */ + savedSearches: SavedSearch[]; + /** The current search query string from the filter state */ + currentSearchQuery: string; + /** Callback to save a new search. Throws ValidationError on failure. */ + onSave: (name: string, query: string) => Promise; + /** Callback to rename an existing search. Throws ValidationError on failure. */ + onRename: (id: string, newName: string) => Promise; + /** Callback to delete a search */ + onDelete: (id: string) => Promise; + /** Callback when a saved search is applied */ + onApply: (search: SavedSearch) => void; + /** Callback to set/unset default search. Pass null to remove default. */ + onSetDefault: (id: string | null) => Promise; + /** Whether saved searches are still loading from storage */ + isLoading?: boolean; + /** Additional CSS class name */ + className?: string; +} + +// ============================================================================ +// State Management (Reducer) +// ============================================================================ + +// Active action type - represents the current action in progress +type ActiveAction = 'idle' | { type: 'saving' } | { type: 'renaming'; id: string } | { type: 'deleting'; id: string }; + +// Component state +interface DropdownState { + isOpen: boolean; + activeAction: ActiveAction; +} + +// Action types for the reducer +type DropdownAction = + | { type: 'OPEN' } + | { type: 'CLOSE' } + | { type: 'SET_VISIBLE'; visible: boolean } + | { type: 'START_SAVE' } + | { type: 'START_RENAME'; id: string } + | { type: 'START_DELETE'; id: string } + | { type: 'CANCEL_ACTION' } + | { type: 'COMPLETE_ACTION' } + | { type: 'APPLY_AND_CLOSE' }; + +const initialState: DropdownState = { + isOpen: false, + activeAction: 'idle', +}; + +/** + * Reducer for managing dropdown state and active actions. + * Centralizes all state transitions for easier reasoning and testing. + */ +function dropdownReducer(state: DropdownState, action: DropdownAction): DropdownState { + switch (action.type) { + case 'OPEN': + return { ...state, isOpen: true }; + + case 'CLOSE': + // Reset action when closing + return { isOpen: false, activeAction: 'idle' }; + + case 'SET_VISIBLE': + // When visibility changes, reset action if closing + return action.visible ? { ...state, isOpen: true } : { isOpen: false, activeAction: 'idle' }; + + case 'START_SAVE': + // Only start save if no action is active + return state.activeAction === 'idle' ? { ...state, activeAction: { type: 'saving' } } : state; + + case 'START_RENAME': + // Only start rename if no action is active + return state.activeAction === 'idle' ? { ...state, activeAction: { type: 'renaming', id: action.id } } : state; + + case 'START_DELETE': + // Only start delete if no action is active + return state.activeAction === 'idle' ? { ...state, activeAction: { type: 'deleting', id: action.id } } : state; + + case 'CANCEL_ACTION': + case 'COMPLETE_ACTION': + // Return to idle state + return { ...state, activeAction: 'idle' }; + + case 'APPLY_AND_CLOSE': + // Only apply if no action is active, then close + return state.activeAction === 'idle' ? { isOpen: false, activeAction: 'idle' } : state; + + default: + return state; + } +} + +// ============================================================================ +// Main Component +// ============================================================================ + +export function SavedSearches({ + savedSearches, + currentSearchQuery, + onSave, + onRename, + onDelete, + onApply, + onSetDefault, + isLoading = false, + className, +}: SavedSearchesProps) { + const styles = useStyles2(getStyles); + + // Centralized state management via reducer + const [state, dispatch] = useReducer(dropdownReducer, initialState); + const { isOpen, activeAction } = state; + + // Refs + const saveButtonRef = useRef(null); + const dialogRef = useRef(null); + + // Focus dialog when dropdown opens to enable keyboard navigation + useEffect(() => { + if (isOpen && activeAction === 'idle') { + // Small delay to ensure the dropdown is rendered + const timer = setTimeout(() => { + // Focus the dialog to capture keyboard events (like Escape) + // We focus the dialog instead of the save button because the button may be disabled + dialogRef.current?.focus(); + }, 50); + return () => clearTimeout(timer); + } + return undefined; + }, [isOpen, activeAction]); + + // Handle click outside to close dropdown - excludes portal elements (like action menu) + useEffect(() => { + const handleClickOutside = (event: MouseEvent) => { + if (isOpen && dialogRef.current && event.target instanceof Node && !dialogRef.current.contains(event.target)) { + // Check if click is on a portal element (action menu dropdown) + if (event.target instanceof Element) { + const isPortalClick = + event.target.closest('[data-popper-placement]') || event.target.closest('[role="menu"]'); + + if (!isPortalClick) { + dispatch({ type: 'CLOSE' }); + } + } else { + dispatch({ type: 'CLOSE' }); + } + } + }; + + if (isOpen) { + document.addEventListener('mousedown', handleClickOutside); + } + + return () => { + document.removeEventListener('mousedown', handleClickOutside); + }; + }, [isOpen]); + + // Handle Escape key: cancel active action first, or close dropdown if no action is active + useEffect(() => { + const handleEscapeKey = (event: KeyboardEvent) => { + if (event.key === 'Escape' && isOpen) { + if (activeAction !== 'idle') { + dispatch({ type: 'CANCEL_ACTION' }); + } else { + dispatch({ type: 'CLOSE' }); + } + } + }; + + document.addEventListener('keydown', handleEscapeKey); + return () => document.removeEventListener('keydown', handleEscapeKey); + }, [isOpen, activeAction]); + + // Handlers + const handleToggle = useCallback(() => { + dispatch({ type: isOpen ? 'CLOSE' : 'OPEN' }); + }, [isOpen]); + + const handleClose = useCallback(() => { + dispatch({ type: 'CLOSE' }); + }, []); + + const handleStartSave = useCallback(() => { + dispatch({ type: 'START_SAVE' }); + }, []); + + const handleCancelSave = useCallback(() => { + dispatch({ type: 'CANCEL_ACTION' }); + }, []); + + const handleSaveComplete = useCallback( + async (name: string): Promise => { + await onSave(name, currentSearchQuery); + dispatch({ type: 'COMPLETE_ACTION' }); + }, + [onSave, currentSearchQuery] + ); + + const handleStartRename = useCallback((id: string) => { + dispatch({ type: 'START_RENAME', id }); + }, []); + + const handleCancelRename = useCallback(() => { + dispatch({ type: 'CANCEL_ACTION' }); + }, []); + + const handleRenameComplete = useCallback( + async (id: string, newName: string): Promise => { + await onRename(id, newName); + dispatch({ type: 'COMPLETE_ACTION' }); + }, + [onRename] + ); + + const handleStartDelete = useCallback((id: string) => { + dispatch({ type: 'START_DELETE', id }); + }, []); + + const handleCancelDelete = useCallback(() => { + dispatch({ type: 'CANCEL_ACTION' }); + }, []); + + const handleDeleteConfirm = useCallback( + async (id: string) => { + await onDelete(id); + dispatch({ type: 'COMPLETE_ACTION' }); + }, + [onDelete] + ); + + const handleApply = useCallback( + (search: SavedSearch) => { + // Only allow apply when no action is active (handled by reducer) + if (activeAction !== 'idle') { + return; + } + onApply(search); + dispatch({ type: 'APPLY_AND_CLOSE' }); + }, + [onApply, activeAction] + ); + + const handleSetDefault = useCallback( + async (id: string | null) => { + // Only allow set default when no action is active + if (activeAction !== 'idle') { + return; + } + await onSetDefault(id); + }, + [onSetDefault, activeAction] + ); + + const buttonLabel = t('alerting.saved-searches.button-label', 'Saved searches'); + const hasSearches = savedSearches.length > 0; + const canSave = currentSearchQuery.trim().length > 0; + + const content = ( +
+ +
+ ); + + return ( + + + + ); +} + +// ============================================================================ +// List Mode (shows saved searches or empty state) +// ============================================================================ + +interface ListModeProps { + searches: SavedSearch[]; + hasSearches: boolean; + canSave: boolean; + activeAction: ActiveAction; + saveButtonRef: React.RefObject; + isLoading: boolean; + onStartSave: () => void; + /** Callback to complete save. Throws ValidationError on validation failure. */ + onSaveComplete: (name: string) => Promise; + onCancelSave: () => void; + onApply: (search: SavedSearch) => void; + onStartRename: (id: string) => void; + onCancelRename: () => void; + /** Callback to complete rename. Throws ValidationError on validation failure. */ + onRenameComplete: (id: string, newName: string) => Promise; + onStartDelete: (id: string) => void; + onCancelDelete: () => void; + onDeleteConfirm: (id: string) => Promise; + onSetDefault: (id: string | null) => Promise; + savedSearches: SavedSearch[]; + /** Portal root for action menus - renders inside the dropdown to prevent useDismiss issues */ + menuPortalRoot: HTMLElement | null; +} + +function ListMode({ + searches, + hasSearches, + canSave, + activeAction, + saveButtonRef, + isLoading, + onStartSave, + onSaveComplete, + onCancelSave, + onApply, + onStartRename, + onCancelRename, + onRenameComplete, + onStartDelete, + onCancelDelete, + onDeleteConfirm, + onSetDefault, + savedSearches, + menuPortalRoot, +}: ListModeProps) { + const styles = useStyles2(getStyles); + + // Derived states from activeAction + const isSaveMode = typeof activeAction === 'object' && activeAction.type === 'saving'; + const isActionActive = activeAction !== 'idle'; + + // Show loading state + if (isLoading) { + return ( + + + + ); + } + + return ( + + {/* Save current search - button or inline input */} + {/* Stop propagation to prevent Dropdown from closing when interacting with save form */} + {isSaveMode ? ( + // eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions +
e.stopPropagation()}> + +
+ ) : ( + + + + )} + + {/* Empty state or list */} + {!hasSearches ? ( + + ) : ( + +
+ {searches.map((search) => { + const isRenaming = + typeof activeAction === 'object' && activeAction.type === 'renaming' && activeAction.id === search.id; + const isDeleting = + typeof activeAction === 'object' && activeAction.type === 'deleting' && activeAction.id === search.id; + // Item is disabled if any action is active and this item is not the one being acted upon + const isItemDisabled = isActionActive && !isRenaming && !isDeleting; + + return ( + onApply(search)} + onStartRename={() => onStartRename(search.id)} + onCancelRename={onCancelRename} + onRenameComplete={(newName) => onRenameComplete(search.id, newName)} + onStartDelete={() => onStartDelete(search.id)} + onCancelDelete={onCancelDelete} + onDeleteConfirm={() => onDeleteConfirm(search.id)} + onSetDefault={() => onSetDefault(search.isDefault ? null : search.id)} + savedSearches={savedSearches} + menuPortalRoot={menuPortalRoot} + /> + ); + })} +
+
+ )} +
+ ); +} + +// ============================================================================ +// Empty State +// ============================================================================ + +function EmptyState() { + return ( + + + No saved searches yet + + + ); +} + +// ============================================================================ +// Styles +// ============================================================================ + +function getStyles(theme: GrafanaTheme2) { + return { + dropdown: css({ + width: '320px', + padding: theme.spacing(0.5), + }), + list: css({ + maxHeight: '300px', + overflowY: 'auto', + }), + item: css({ + padding: theme.spacing(0.5), + borderRadius: theme.shape.radius.default, + '&:hover': { + backgroundColor: theme.colors.action.hover, + }, + }), + }; +} diff --git a/public/app/features/alerting/unified/rule-list/filter/savedSearchesSchema.ts b/public/app/features/alerting/unified/rule-list/filter/savedSearchesSchema.ts new file mode 100644 index 00000000000..807ce421957 --- /dev/null +++ b/public/app/features/alerting/unified/rule-list/filter/savedSearchesSchema.ts @@ -0,0 +1,87 @@ +/** + * Shared types and utilities for SavedSearches feature. + * + * This module is extracted to avoid circular dependencies between: + * - SavedSearches.tsx (main component) + * - InlineSaveInput.tsx, InlineRenameInput.tsx, SavedSearchItem.tsx (sub-components) + * - useSavedSearches.ts (hook) + */ + +import z from 'zod'; + +import { t } from '@grafana/i18n'; + +// ============================================================================ +// Schemas +// ============================================================================ + +/** + * Zod schema for validating a saved search object. + * Used to validate data loaded from storage. + */ +export const savedSearchSchema = z.object({ + id: z.string(), + name: z.string(), + isDefault: z.boolean(), + query: z.string(), + createdAt: z.number().optional(), +}); + +/** + * Zod schema for validating an array of saved searches. + */ +export const savedSearchesArraySchema = z.array(savedSearchSchema); + +// ============================================================================ +// Types +// ============================================================================ + +export type SavedSearch = z.infer; + +export interface ValidationError { + field: 'name'; + message: string; +} + +/** + * Type guard to check if an error is a ValidationError. + */ +export function isValidationError(error: unknown): error is ValidationError { + return Boolean( + error && + typeof error === 'object' && + 'field' in error && + 'message' in error && + error.field === 'name' && + typeof error.message === 'string' + ); +} + +// ============================================================================ +// Validation Utilities +// ============================================================================ + +/** + * Validates a saved search name. + * @param name - The name to validate + * @param savedSearches - Existing saved searches for uniqueness check + * @param excludeId - Optional ID to exclude from uniqueness check (for rename) + * @returns Error message string or null if valid + */ +export function validateSearchName(name: string, savedSearches: SavedSearch[], excludeId?: string): string | null { + const trimmed = name.trim(); + + if (!trimmed) { + return t('alerting.saved-searches.error-name-required', 'Name is required'); + } + + const isDuplicate = savedSearches.some( + (s) => (excludeId ? s.id !== excludeId : true) && s.name.toLowerCase() === trimmed.toLowerCase() + ); + + if (isDuplicate) { + return t('alerting.saved-searches.error-name-duplicate', 'A saved search with this name already exists'); + } + + return null; +} diff --git a/public/app/features/alerting/unified/rule-list/filter/useApplyDefaultSearch.ts b/public/app/features/alerting/unified/rule-list/filter/useApplyDefaultSearch.ts new file mode 100644 index 00000000000..380702fed16 --- /dev/null +++ b/public/app/features/alerting/unified/rule-list/filter/useApplyDefaultSearch.ts @@ -0,0 +1,86 @@ +import { useEffect } from 'react'; + +import { shouldUseSavedSearches } from '../../featureToggles'; +import { useAsync } from '../../hooks/useAsync'; +import { useRulesFilter } from '../../hooks/useFilteredRules'; +import { getSearchFilterFromQuery } from '../../search/rulesSearchParser'; + +import { loadDefaultSavedSearch, trackSavedSearchAutoApply } from './useSavedSearches'; + +/** + * Session storage key to track if user has visited this page in current session. + * Used to determine if we should auto-apply the default saved search. + */ +const SESSION_VISITED_KEY = 'grafana.alerting.ruleList.visited'; + +/** + * Hook that automatically applies the default saved search on first visit to the page. + * + * This hook: + * - Checks if saved searches feature is enabled + * - Detects if this is the first visit in the current session + * - Loads and applies the default saved search if one exists + * - Cleans up session storage on unmount + * + * @returns Object with isApplying boolean indicating if the default search is being loaded/applied + */ +export function useApplyDefaultSearch(): { isApplying: boolean } { + const savedSearchesEnabled = shouldUseSavedSearches(); + const { updateFilters, hasActiveFilters } = useRulesFilter(); + + // Use the internal useAsync hook which doesn't auto-execute + const [{ execute }, state] = useAsync(async () => { + const defaultSearch = await loadDefaultSavedSearch(); + if (defaultSearch) { + updateFilters(getSearchFilterFromQuery(defaultSearch.query)); + trackSavedSearchAutoApply(); + } + }); + + // Clear session storage on unmount + useEffect(() => { + return () => { + clearSessionVisitedFlag(); + }; + }, []); + + const isFirstVisit = isFirstVisitInSession(); + const shouldLoadDefault = savedSearchesEnabled && !hasActiveFilters && isFirstVisit; + + // Mark as visited on first visit, regardless of whether we load defaults + if (isFirstVisit && state.status === 'not-executed') { + markAsVisited(); + + // Execute only if we should load default + if (shouldLoadDefault) { + execute(); + } + } + + return { isApplying: state.status === 'loading' }; +} + +/** + * Check if this is a fresh navigation to the page (not a refresh or in-page URL change). + * Uses session storage which persists across refreshes but clears when tab is closed. + * + * @returns true if this is the first visit to the page in this session + */ +function isFirstVisitInSession(): boolean { + return !sessionStorage.getItem(SESSION_VISITED_KEY); +} + +/** + * Mark the page as visited in the current session. + */ +function markAsVisited(): void { + sessionStorage.setItem(SESSION_VISITED_KEY, 'true'); +} + +/** + * Clear the session visited flag. Call this when component unmounts + * so the next navigation to this page is detected as a fresh visit. + */ +function clearSessionVisitedFlag(): void { + sessionStorage.removeItem(SESSION_VISITED_KEY); +} diff --git a/public/app/features/alerting/unified/rule-list/filter/useSavedSearches.test.tsx b/public/app/features/alerting/unified/rule-list/filter/useSavedSearches.test.tsx new file mode 100644 index 00000000000..4ea83f1e38a --- /dev/null +++ b/public/app/features/alerting/unified/rule-list/filter/useSavedSearches.test.tsx @@ -0,0 +1,400 @@ +import { PropsWithChildren } from 'react'; +import { act, getWrapper, renderHook, screen, waitFor } from 'test/test-utils'; + +import * as runtime from '@grafana/runtime'; +import { AppNotificationList } from 'app/core/components/AppNotifications/AppNotificationList'; +import { setupMswServer } from 'app/features/alerting/unified/mockApi'; + +// Create mock UserStorage instance that can be configured per test +const mockUserStorage = { + getItem: jest.fn(), + setItem: jest.fn(), +}; + +// Mock UserStorage class from @grafana/runtime/internal +// This prevents the module-level instance from caching state across tests +jest.mock('@grafana/runtime/internal', () => ({ + ...jest.requireActual('@grafana/runtime/internal'), + UserStorage: jest.fn().mockImplementation(() => mockUserStorage), +})); + +// Mock config BEFORE any imports that use it (jest.mock is hoisted) +// This ensures config.namespace and config.bootData.user are set when UserStorage module loads +jest.mock('@grafana/runtime', () => ({ + ...jest.requireActual('@grafana/runtime'), + reportInteraction: jest.fn(), + config: { + ...jest.requireActual('@grafana/runtime').config, + namespace: 'default', + bootData: { + ...jest.requireActual('@grafana/runtime').config.bootData, + navTree: [], + user: { + uid: 'test-user-123', + id: 123, + isSignedIn: true, + }, + }, + }, +})); + +import { trackSavedSearchApplied, useSavedSearches } from './useSavedSearches'; + +// Set up MSW server for other handlers (not UserStorage - that's mocked directly) +setupMswServer(); + +// Mock data is ordered as it will appear after sorting by useSavedSearches: +// default search first, then alphabetically by name +const mockSavedSearches = [ + { + id: '2', + name: 'Default Search', + query: 'label:team=A', + isDefault: true, + createdAt: Date.now() - 2000, + }, + { + id: '1', + name: 'Test Search 1', + query: 'state:firing', + isDefault: false, + createdAt: Date.now() - 1000, + }, +]; + +// Wrapper that includes AppNotificationList to verify UI notifications +function createWrapper() { + const Wrapper = getWrapper({ renderWithRouter: true }); + return function WrapperWithNotifications({ children }: PropsWithChildren) { + return ( + + + {children} + + ); + }; +} + +describe('useSavedSearches', () => { + beforeEach(() => { + jest.clearAllMocks(); + sessionStorage.clear(); + localStorage.clear(); + // Reset mock UserStorage to default behavior (empty storage) + mockUserStorage.getItem.mockResolvedValue(null); + mockUserStorage.setItem.mockResolvedValue(undefined); + }); + + describe('Initial loading', () => { + it('should load saved searches from UserStorage', async () => { + mockUserStorage.getItem.mockResolvedValue(JSON.stringify(mockSavedSearches)); + + const { result } = renderHook(() => useSavedSearches(), { wrapper: createWrapper() }); + + await waitFor(() => { + expect(result.current.isLoading).toBe(false); + }); + + expect(result.current.savedSearches).toEqual(mockSavedSearches); + }); + + it('should handle empty storage gracefully', async () => { + // Storage is empty by default after resetUserStorage() in afterEach + + const { result } = renderHook(() => useSavedSearches(), { wrapper: createWrapper() }); + + await waitFor(() => { + expect(result.current.isLoading).toBe(false); + }); + + expect(result.current.savedSearches).toEqual([]); + }); + + it('should handle 404 (no stored data) gracefully', async () => { + // When no data exists, UserStorage returns 404, which is handled as "not found" + // The hook should return an empty array without error + + const { result } = renderHook(() => useSavedSearches(), { wrapper: createWrapper() }); + + await waitFor(() => { + expect(result.current.isLoading).toBe(false); + }); + + // UserStorage handles 404 gracefully - returns empty storage + expect(result.current.savedSearches).toEqual([]); + }); + + it('should filter out invalid saved search entries', async () => { + jest.spyOn(console, 'warn').mockImplementation(); + const mixedData = [ + mockSavedSearches[0], // Valid + { id: '3', name: 'Invalid', query: 123, isDefault: false }, // Invalid query type + { id: '4', name: null, query: 'valid', isDefault: false }, // Invalid name type + mockSavedSearches[1], // Valid + ]; + mockUserStorage.getItem.mockResolvedValue(JSON.stringify(mixedData)); + + const { result } = renderHook(() => useSavedSearches(), { wrapper: createWrapper() }); + + await waitFor(() => { + expect(result.current.isLoading).toBe(false); + }); + + // Invalid entries are filtered out, valid ones are preserved + expect(result.current.savedSearches).toHaveLength(2); + expect(result.current.savedSearches[0].name).toBe('Default Search'); + expect(result.current.savedSearches[1].name).toBe('Test Search 1'); + }); + + it('should handle malformed JSON gracefully', async () => { + jest.spyOn(console, 'error').mockImplementation(); + mockUserStorage.getItem.mockResolvedValue('not valid json'); + + const { result } = renderHook(() => useSavedSearches(), { wrapper: createWrapper() }); + + await waitFor(() => { + expect(result.current.isLoading).toBe(false); + }); + + // Verify error notification appears in the UI + expect(await screen.findByText(/failed to load saved searches/i)).toBeInTheDocument(); + expect(result.current.savedSearches).toEqual([]); + }); + }); + + describe('saveSearch', () => { + it('should save a new search', async () => { + // Start with empty storage (default mock behavior) + + const { result } = renderHook(() => useSavedSearches(), { wrapper: createWrapper() }); + + await waitFor(() => { + expect(result.current.isLoading).toBe(false); + }); + + await act(async () => { + await result.current.saveSearch('New Search', 'state:pending'); + }); + + expect(result.current.savedSearches).toHaveLength(1); + expect(result.current.savedSearches[0].name).toBe('New Search'); + expect(result.current.savedSearches[0].query).toBe('state:pending'); + + // Verify data was persisted via UserStorage.setItem + expect(mockUserStorage.setItem).toHaveBeenCalledWith( + 'savedSearches', + expect.stringContaining('"name":"New Search"') + ); + }); + + it('should throw validation error for duplicate name (case-insensitive)', async () => { + mockUserStorage.getItem.mockResolvedValue(JSON.stringify(mockSavedSearches)); + + const { result } = renderHook(() => useSavedSearches(), { wrapper: createWrapper() }); + + await waitFor(() => { + expect(result.current.isLoading).toBe(false); + }); + + await act(async () => { + await expect(result.current.saveSearch('TEST SEARCH 1', 'state:pending')).rejects.toEqual({ + field: 'name', + message: expect.stringContaining('already exists'), + }); + }); + }); + + it('should track analytics on save', async () => { + // Start with empty storage + + const { result } = renderHook(() => useSavedSearches(), { wrapper: createWrapper() }); + + await waitFor(() => { + expect(result.current.isLoading).toBe(false); + }); + + await act(async () => { + await result.current.saveSearch('New Search', 'state:pending'); + }); + + expect(runtime.reportInteraction).toHaveBeenCalledWith( + 'grafana_alerting_saved_search_save', + expect.objectContaining({ + hasDefault: false, + totalCount: 1, + }) + ); + }); + }); + + describe('renameSearch', () => { + it('should rename an existing search', async () => { + mockUserStorage.getItem.mockResolvedValue(JSON.stringify(mockSavedSearches)); + + const { result } = renderHook(() => useSavedSearches(), { wrapper: createWrapper() }); + + await waitFor(() => { + expect(result.current.isLoading).toBe(false); + }); + + await act(async () => { + await result.current.renameSearch('1', 'Renamed Search'); + }); + + expect(result.current.savedSearches.find((s) => s.id === '1')?.name).toBe('Renamed Search'); + + // Verify data was persisted via UserStorage.setItem + expect(mockUserStorage.setItem).toHaveBeenCalledWith( + 'savedSearches', + expect.stringContaining('"name":"Renamed Search"') + ); + }); + + it('should throw validation error for duplicate name on rename', async () => { + mockUserStorage.getItem.mockResolvedValue(JSON.stringify(mockSavedSearches)); + + const { result } = renderHook(() => useSavedSearches(), { wrapper: createWrapper() }); + + await waitFor(() => { + expect(result.current.isLoading).toBe(false); + }); + + await act(async () => { + await expect(result.current.renameSearch('1', 'Default Search')).rejects.toEqual({ + field: 'name', + message: expect.stringContaining('already exists'), + }); + }); + }); + }); + + describe('deleteSearch', () => { + it('should delete a search', async () => { + mockUserStorage.getItem.mockResolvedValue(JSON.stringify(mockSavedSearches)); + + const { result } = renderHook(() => useSavedSearches(), { wrapper: createWrapper() }); + + await waitFor(() => { + expect(result.current.isLoading).toBe(false); + }); + + expect(result.current.savedSearches).toHaveLength(2); + + await act(async () => { + await result.current.deleteSearch('1'); + }); + + expect(result.current.savedSearches).toHaveLength(1); + expect(result.current.savedSearches.find((s) => s.id === '1')).toBeUndefined(); + }); + + it('should track analytics on delete', async () => { + mockUserStorage.getItem.mockResolvedValue(JSON.stringify(mockSavedSearches)); + + const { result } = renderHook(() => useSavedSearches(), { wrapper: createWrapper() }); + + await waitFor(() => { + expect(result.current.isLoading).toBe(false); + }); + + await act(async () => { + await result.current.deleteSearch('1'); + }); + + expect(runtime.reportInteraction).toHaveBeenCalledWith('grafana_alerting_saved_search_delete'); + }); + }); + + describe('setDefaultSearch', () => { + it('should set a search as default', async () => { + mockUserStorage.getItem.mockResolvedValue(JSON.stringify(mockSavedSearches)); + + const { result } = renderHook(() => useSavedSearches(), { wrapper: createWrapper() }); + + await waitFor(() => { + expect(result.current.isLoading).toBe(false); + }); + + await act(async () => { + await result.current.setDefaultSearch('1'); + }); + + expect(result.current.savedSearches.find((s) => s.id === '1')?.isDefault).toBe(true); + expect(result.current.savedSearches.find((s) => s.id === '2')?.isDefault).toBe(false); + }); + + it('should clear default when null is passed', async () => { + mockUserStorage.getItem.mockResolvedValue(JSON.stringify(mockSavedSearches)); + + const { result } = renderHook(() => useSavedSearches(), { wrapper: createWrapper() }); + + await waitFor(() => { + expect(result.current.isLoading).toBe(false); + }); + + await act(async () => { + await result.current.setDefaultSearch(null); + }); + + expect(result.current.savedSearches.every((s) => !s.isDefault)).toBe(true); + }); + + it('should track analytics with correct action', async () => { + mockUserStorage.getItem.mockResolvedValue(JSON.stringify(mockSavedSearches)); + + const { result } = renderHook(() => useSavedSearches(), { wrapper: createWrapper() }); + + await waitFor(() => { + expect(result.current.isLoading).toBe(false); + }); + + await act(async () => { + await result.current.setDefaultSearch('1'); + }); + + expect(runtime.reportInteraction).toHaveBeenCalledWith('grafana_alerting_saved_search_set_default', { + action: 'set', + }); + + jest.clearAllMocks(); + + await act(async () => { + await result.current.setDefaultSearch(null); + }); + + expect(runtime.reportInteraction).toHaveBeenCalledWith('grafana_alerting_saved_search_set_default', { + action: 'clear', + }); + }); + }); +}); + +describe('trackSavedSearchApplied', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('should track with isDefault true for default searches', () => { + trackSavedSearchApplied({ + id: '1', + name: 'Default', + query: 'state:firing', + isDefault: true, + createdAt: Date.now(), + }); + + expect(runtime.reportInteraction).toHaveBeenCalledWith('grafana_alerting_saved_search_apply', { isDefault: true }); + }); + + it('should track with isDefault false for non-default searches', () => { + trackSavedSearchApplied({ + id: '1', + name: 'Regular', + query: 'state:firing', + isDefault: false, + createdAt: Date.now(), + }); + + expect(runtime.reportInteraction).toHaveBeenCalledWith('grafana_alerting_saved_search_apply', { isDefault: false }); + }); +}); diff --git a/public/app/features/alerting/unified/rule-list/filter/useSavedSearches.ts b/public/app/features/alerting/unified/rule-list/filter/useSavedSearches.ts new file mode 100644 index 00000000000..5c81ce990b3 --- /dev/null +++ b/public/app/features/alerting/unified/rule-list/filter/useSavedSearches.ts @@ -0,0 +1,353 @@ +import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; +import { v4 as uuidv4 } from 'uuid'; + +import { t } from '@grafana/i18n'; +import { reportInteraction } from '@grafana/runtime'; +import { UserStorage } from '@grafana/runtime/internal'; + +import { useAppNotification } from '../../../../../core/copy/appNotification'; +import { logError, logWarning } from '../../Analytics'; +import { isLoading as isLoadingState, isUninitialized, useAsync } from '../../hooks/useAsync'; + +import { SavedSearch, savedSearchSchema, savedSearchesArraySchema, validateSearchName } from './savedSearchesSchema'; + +/** + * Storage key for saved searches in UserStorage. + */ +const SAVED_SEARCHES_STORAGE_KEY = 'savedSearches'; + +/** + * UserStorage instance for saved searches. + * Uses 'alerting' as the service namespace. + */ +const userStorage = new UserStorage('alerting'); + +/** + * Analytics tracking functions for saved search actions. + */ +function trackSavedSearchSave(props: { hasDefault: boolean; totalCount: number }) { + reportInteraction('grafana_alerting_saved_search_save', props); +} + +function trackSavedSearchApply(props: { isDefault: boolean }) { + reportInteraction('grafana_alerting_saved_search_apply', props); +} + +function trackSavedSearchDelete() { + reportInteraction('grafana_alerting_saved_search_delete'); +} + +function trackSavedSearchRename() { + reportInteraction('grafana_alerting_saved_search_rename'); +} + +function trackSavedSearchSetDefault(props: { action: 'set' | 'clear' }) { + reportInteraction('grafana_alerting_saved_search_set_default', props); +} + +export function trackSavedSearchAutoApply() { + reportInteraction('grafana_alerting_saved_search_auto_apply'); +} + +/** + * Validates and parses an array of saved searches using zod schema. + * Returns valid entries and logs warnings for invalid data. + */ +function validateSavedSearches(data: unknown): SavedSearch[] { + const result = savedSearchesArraySchema.safeParse(data); + + if (result.success) { + return result.data; + } + + // If the whole array failed, try to salvage individual valid entries + if (!Array.isArray(data)) { + logWarning('Saved searches data is not an array, returning empty array'); + return []; + } + + logWarning('Saved searches validation failed, filtering invalid entries', { + issues: JSON.stringify(result.error.issues), + }); + + const validEntries: SavedSearch[] = []; + for (const item of data) { + const itemResult = savedSearchSchema.safeParse(item); + if (itemResult.success) { + validEntries.push(itemResult.data); + } + } + return validEntries; +} + +/** + * Sorts saved searches: default search first, then others alphabetically. + * @param searches - Array of saved searches to sort + * @returns Sorted array with default first, then alphabetically by name + */ +function sortSavedSearches(searches: SavedSearch[]): SavedSearch[] { + const defaultSearch = searches.find((s) => s.isDefault); + const collator = new Intl.Collator(undefined, { sensitivity: 'base' }); + const others = searches.filter((s) => !s.isDefault).sort((a, b) => collator.compare(a.name, b.name)); + + return defaultSearch ? [defaultSearch, ...others] : others; +} + +/** + * Loads saved searches from UserStorage and validates the data. + * @returns Promise resolving to an array of valid saved searches + */ +async function loadSavedSearchesFromStorage(): Promise { + const stored = await userStorage.getItem(SAVED_SEARCHES_STORAGE_KEY); + if (!stored) { + return []; + } + + const parsed = JSON.parse(stored); + return validateSavedSearches(parsed); +} + +export async function loadDefaultSavedSearch(): Promise { + const savedSearches = await loadSavedSearchesFromStorage(); + return savedSearches.find((s) => s.isDefault) ?? null; +} + +/** + * Result of the useSavedSearches hook. + */ +export interface UseSavedSearchesResult { + /** List of saved searches */ + savedSearches: SavedSearch[]; + /** Whether the initial load from storage is complete */ + isLoading: boolean; + /** + * Save a new search with the given name and query. + * @param name - The display name for the saved search + * @param query - The search query string + * @throws ValidationError if name is not unique + */ + saveSearch: (name: string, query: string) => Promise; + /** + * Rename an existing saved search. + * @param id - The ID of the search to rename + * @param newName - The new display name + * @throws ValidationError if name is not unique + */ + renameSearch: (id: string, newName: string) => Promise; + /** + * Delete a saved search by ID. + * @param id - The ID of the search to delete + */ + deleteSearch: (id: string) => Promise; + /** + * Set or clear the default search. + * @param id - The ID to set as default, or null to clear + */ + setDefaultSearch: (id: string | null) => Promise; +} + +/** + * Hook for managing saved searches with UserStorage persistence. + * + * Features: + * - Persists saved searches to UserStorage (syncs across devices) + * - Validates data schema on load (filters invalid entries) + * - Validates name uniqueness (case-insensitive) + * - Tracks analytics for all actions + * - Shows error notifications on storage failures + * - Provides auto-apply logic for default search on navigation + * - Per-user session tracking to handle logout/login scenarios + * + * @example + * ```tsx + * const { savedSearches, saveSearch, isLoading } = useSavedSearches(); + * + * // Save current search + * const error = await saveSearch('My Search', currentQuery); + * if (error) { + * // Handle validation error + * } + * + * // Auto-apply default search on mount + * useEffect(() => { + * const defaultSearch = getAutoApplySearch(); + * if (defaultSearch) { + * applySearch(defaultSearch); + * } + * }, []); + * ``` + */ +export function useSavedSearches(): UseSavedSearchesResult { + const [savedSearches, setSavedSearches] = useState([]); + const notifyApp = useAppNotification(); + + // Track whether we've already loaded to prevent double-loading + const hasLoadedRef = useRef(false); + + // Use useAsync for loading state management + const [{ execute: executeLoad }, loadState] = useAsync(loadSavedSearchesFromStorage, []); + const isLoading = isLoadingState(loadState) || isUninitialized(loadState); + + // Load saved searches from storage on mount + useEffect(() => { + if (hasLoadedRef.current) { + return; + } + hasLoadedRef.current = true; + + // Load from UserStorage using async/await pattern + const loadSearches = async () => { + try { + const validated = await executeLoad(); + setSavedSearches(validated); + } catch (error) { + logError(error instanceof Error ? error : new Error('Failed to load saved searches from storage'), { + context: 'useSavedSearches.loadSearches', + }); + notifyApp.error( + t('alerting.saved-searches.error-load-title', 'Failed to load saved searches'), + t( + 'alerting.saved-searches.error-load-description', + 'Your saved searches could not be loaded. Please try refreshing the page.' + ) + ); + } + }; + + loadSearches(); + }, [executeLoad, notifyApp]); + + /** + * Persist saved searches to UserStorage. + */ + const persistSearches = useCallback( + async (searches: SavedSearch[]): Promise => { + try { + await userStorage.setItem(SAVED_SEARCHES_STORAGE_KEY, JSON.stringify(searches)); + } catch (error) { + logError(error instanceof Error ? error : new Error('Failed to save searches'), { + context: 'useSavedSearches.persistSearches', + }); + notifyApp.error( + t('alerting.saved-searches.error-save-title', 'Failed to save'), + t('alerting.saved-searches.error-save-description', 'Your changes could not be saved. Please try again.') + ); + throw error; + } + }, + [notifyApp] + ); + + /** + * Save a new search with the given name and query. + * @throws ValidationError if the name is not unique + */ + const saveSearch = useCallback( + async (name: string, query: string): Promise => { + // Validate name using shared validation function + const validationError = validateSearchName(name, savedSearches); + if (validationError) { + throw { field: 'name' as const, message: validationError }; + } + + const newSearch: SavedSearch = { + id: uuidv4(), + name, + query, + isDefault: false, + createdAt: Date.now(), + }; + + const newSearches = [...savedSearches, newSearch]; + + await persistSearches(newSearches); + setSavedSearches(newSearches); + + // Track analytics + trackSavedSearchSave({ + hasDefault: newSearches.some((s) => s.isDefault), + totalCount: newSearches.length, + }); + }, + [savedSearches, persistSearches] + ); + + /** + * Rename an existing saved search. + * @throws ValidationError if the new name is not unique + */ + const renameSearch = useCallback( + async (id: string, newName: string): Promise => { + // Validate name using shared validation function (excluding current item) + const validationError = validateSearchName(newName, savedSearches, id); + if (validationError) { + throw { field: 'name' as const, message: validationError }; + } + + const newSearches = savedSearches.map((s) => (s.id === id ? { ...s, name: newName } : s)); + + await persistSearches(newSearches); + setSavedSearches(newSearches); + + // Track analytics + trackSavedSearchRename(); + }, + [savedSearches, persistSearches] + ); + + /** + * Delete a saved search by ID. + */ + const deleteSearch = useCallback( + async (id: string): Promise => { + const newSearches = savedSearches.filter((s) => s.id !== id); + + await persistSearches(newSearches); + setSavedSearches(newSearches); + + // Track analytics + trackSavedSearchDelete(); + }, + [savedSearches, persistSearches] + ); + + /** + * Set or clear the default search. + * Pass null to clear the current default. + */ + const setDefaultSearch = useCallback( + async (id: string | null): Promise => { + const newSearches = savedSearches.map((s) => ({ + ...s, + isDefault: id === null ? false : s.id === id, + })); + + await persistSearches(newSearches); + setSavedSearches(newSearches); + + // Track analytics + trackSavedSearchSetDefault({ action: id === null ? 'clear' : 'set' }); + }, + [savedSearches, persistSearches] + ); + + // Sort saved searches: default first, then alphabetically by name + const sortedSavedSearches = useMemo(() => sortSavedSearches(savedSearches), [savedSearches]); + + return { + savedSearches: sortedSavedSearches, + isLoading, + saveSearch, + renameSearch, + deleteSearch, + setDefaultSearch, + }; +} + +/** + * Track when a saved search is applied (called from parent component). + * @param search - The search that was applied + */ +export function trackSavedSearchApplied(search: SavedSearch) { + trackSavedSearchApply({ isDefault: search.isDefault }); +} diff --git a/public/app/features/alerting/unified/types/alerting.ts b/public/app/features/alerting/unified/types/alerting.ts index f8dcdd8c111..c6fe667982a 100644 --- a/public/app/features/alerting/unified/types/alerting.ts +++ b/public/app/features/alerting/unified/types/alerting.ts @@ -149,6 +149,12 @@ export interface NotificationChannelOption { required: boolean; secure: boolean; secureFieldKey?: string; + /** + * protected indicates that only administrators or users with + * "alert.notifications.receivers.protected:write" permission + * are allowed to update this field + * */ + protected?: boolean; selectOptions?: Array> | null; defaultValue?: SelectableValue; showWhen: { field: string; is: string | boolean }; diff --git a/public/app/features/alerting/unified/utils/k8s/constants.ts b/public/app/features/alerting/unified/utils/k8s/constants.ts index 1eb3c371d59..cf297261733 100644 --- a/public/app/features/alerting/unified/utils/k8s/constants.ts +++ b/public/app/features/alerting/unified/utils/k8s/constants.ts @@ -21,6 +21,8 @@ export enum K8sAnnotations { AccessAdmin = 'grafana.com/access/canAdmin', /** Annotation key that indicates that the calling user is able to delete this entity */ AccessDelete = 'grafana.com/access/canDelete', + /** Annotation key that indicates that the calling user is able to modify protected fields of this entity */ + AccessModifyProtected = 'grafana.com/access/canModifyProtected', } /** diff --git a/public/app/features/alerting/unified/utils/k8s/utils.ts b/public/app/features/alerting/unified/utils/k8s/utils.ts index 8aecb9dd46b..48ec5685a69 100644 --- a/public/app/features/alerting/unified/utils/k8s/utils.ts +++ b/public/app/features/alerting/unified/utils/k8s/utils.ts @@ -42,6 +42,9 @@ export const canAdminEntity = (k8sEntity: EntityToCheck) => export const canDeleteEntity = (k8sEntity: EntityToCheck) => getAnnotation(k8sEntity, K8sAnnotations.AccessDelete) === 'true'; +export const canModifyProtectedEntity = (k8sEntity: EntityToCheck) => + getAnnotation(k8sEntity, K8sAnnotations.AccessModifyProtected) === 'true'; + /** * Escape \ and = characters for field selectors. * The Kubernetes API Machinery will decode those automatically. diff --git a/public/app/features/auth-config/FieldRenderer.tsx b/public/app/features/auth-config/FieldRenderer.tsx index 1d80f835fb0..687079f1281 100644 --- a/public/app/features/auth-config/FieldRenderer.tsx +++ b/public/app/features/auth-config/FieldRenderer.tsx @@ -35,17 +35,23 @@ export const FieldRenderer = ({ const [isSecretConfigured, setIsSecretConfigured] = useState(secretConfigured); const isDependantField = typeof field !== 'string'; const name = isDependantField ? field.name : field; - const parentValue = isDependantField ? watch(field.dependsOn) : null; + const parentValue = isDependantField && field.dependsOn ? watch(field.dependsOn) : null; const fieldData = fieldMap(provider)[name]; const theme = useTheme2(); + + // Handle disabledWhen configuration + const disabledWhen = isDependantField ? field.disabledWhen : undefined; + const disabledWhenValue = disabledWhen ? watch(disabledWhen.field) : undefined; + const isDisabled = disabledWhen ? disabledWhenValue === disabledWhen.is : false; + // Unregister a field that depends on a toggle to clear its data useEffect(() => { - if (isDependantField) { + if (isDependantField && field.dependsOn) { if (!parentValue) { unregister(name); } } - }, [unregister, name, parentValue, isDependantField]); + }, [unregister, name, parentValue, isDependantField, field]); const isNotEmptySelectableValueArray = ( current: string | boolean | Record | Array> | undefined @@ -64,6 +70,13 @@ export const FieldRenderer = ({ // eslint-disable-next-line react-hooks/exhaustive-deps }, []); + // Set the value when the field is disabled + useEffect(() => { + if (isDisabled && disabledWhen?.disabledValue) { + setValue(name, disabledWhen.disabledValue.value); + } + }, [isDisabled, disabledWhen?.disabledValue, name, setValue]); + if (!field) { console.log('missing field:', name); return null; @@ -74,12 +87,12 @@ export const FieldRenderer = ({ } // Dependant field means the field depends on another field's value and shouldn't be rendered if the parent field is false - if (isDependantField) { - const parentValue = watch(field.dependsOn); + if (isDependantField && field.dependsOn) { if (!parentValue) { return null; } } + const fieldProps = { label: fieldData.label, required: !!fieldData.validation?.required, @@ -131,10 +144,10 @@ export const FieldRenderer = ({ rules={fieldData.validation} name={name} control={control} - render={({ field: { ref, onChange, ...fieldProps }, fieldState: { invalid } }) => { + render={({ field: { ref, onChange, ...controllerFieldProps }, fieldState: { invalid } }) => { return ( setSpanFiltersSearch({ ...search, serviceNameOperator: v.value! })} - options={[toOption('='), toOption('!=')]} - value={search.serviceNameOperator} - /> - setSpanFiltersSearch({ ...search, spanNameOperator: v.value! })} - options={[toOption('='), toOption('!=')]} - value={search.spanNameOperator} - /> - setSpanFiltersSearch({ ...search, fromOperator: v.value! })} - options={[toOption('>'), toOption('>=')]} - value={search.fromOperator} - /> -
- setSpanFiltersSearch({ ...search, from: val })} - isInvalidError="Invalid duration" - // eslint-disable-next-line @grafana/i18n/no-untranslated-strings - placeholder="e.g. 100ms, 1.2s" - width={18} - value={search.from || ''} - validationRegex={durationRegex} - /> -
- onTagChange(tag, v)} - onOpenMenu={getTagKeys} - options={tagKeys || (tag.key ? [tag.key].map(toOption) : [])} - placeholder={t('explore.span-filters-tags.placeholder-select-tag', 'Select tag')} - value={tag.key || null} - /> - -
- { - setSearch({ - ...search, - tags: search.tags?.map((x) => { - return x.id === tag.id ? { ...x, value: v?.value || '' } : x; - }), - }); - }} - options={tagValues[tag.id] ? tagValues[tag.id] : tag.value ? [tag.value].map(toOption) : []} - placeholder={t('explore.span-filters-tags.placeholder-select-value', 'Select value')} - value={tag.value} - /> - )} - {(tag.operator === '=~' || tag.operator === '!~') && ( - { - setSearch({ - ...search, - tags: search.tags?.map((x) => { - return x.id === tag.id ? { ...x, value: v?.currentTarget?.value || '' } : x; - }), - }); - }} - placeholder={t('explore.span-filters-tags.placeholder-tag-value', 'Tag value')} - width={18} - value={tag.value || ''} - /> - )} - - {(tag.key || tag.value || search.tags.length > 1) && ( - removeTag(tag.id)} - tooltip={t('explore.span-filters-tags.tooltip-remove-tag', 'Remove tag')} - /> - )} - {(tag.key || tag.value) && i === search.tags.length - 1 && ( - - - - )} - -
- ))} - - ); -}; - -const getStyles = (theme: GrafanaTheme2) => ({ - addTag: css({ - marginLeft: theme.spacing(1), - }), - tagValues: css({ - maxWidth: '200px', - }), -}); diff --git a/public/app/features/explore/TraceView/components/TracePageHeader/useTraceAdHocFiltersController.ts b/public/app/features/explore/TraceView/components/TracePageHeader/useTraceAdHocFiltersController.ts index 8615c446294..c5286297087 100644 --- a/public/app/features/explore/TraceView/components/TracePageHeader/useTraceAdHocFiltersController.ts +++ b/public/app/features/explore/TraceView/components/TracePageHeader/useTraceAdHocFiltersController.ts @@ -1,18 +1,3 @@ -// Copyright (c) 2025 Grafana Labs -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - import { useMemo, useState } from 'react'; import { TraceSearchProps } from '@grafana/data'; diff --git a/public/app/features/explore/TraceView/components/constants/span.ts b/public/app/features/explore/TraceView/components/constants/span.ts index 8d2fb1e5052..2e4d04be71b 100644 --- a/public/app/features/explore/TraceView/components/constants/span.ts +++ b/public/app/features/explore/TraceView/components/constants/span.ts @@ -5,3 +5,5 @@ export const LIBRARY_NAME = 'library.name'; export const LIBRARY_VERSION = 'library.version'; export const TRACE_STATE = 'trace.state'; export const ID = 'id'; +export const SPAN_NAME = 'span.name'; +export const SERVICE_NAME = 'service.name'; diff --git a/public/app/features/explore/TraceView/components/utils/filter-spans.tsx b/public/app/features/explore/TraceView/components/utils/filter-spans.tsx index d03016dab78..69c42ee2e8f 100644 --- a/public/app/features/explore/TraceView/components/utils/filter-spans.tsx +++ b/public/app/features/explore/TraceView/components/utils/filter-spans.tsx @@ -16,7 +16,17 @@ import { SpanStatusCode } from '@opentelemetry/api'; import { SelectableValue, TraceKeyValuePair, TraceSearchProps, TraceSearchTag } from '@grafana/data'; -import { KIND, LIBRARY_NAME, LIBRARY_VERSION, STATUS, STATUS_MESSAGE, TRACE_STATE, ID } from '../constants/span'; +import { + KIND, + LIBRARY_NAME, + LIBRARY_VERSION, + STATUS, + STATUS_MESSAGE, + TRACE_STATE, + ID, + SPAN_NAME, + SERVICE_NAME, +} from '../constants/span'; import TNil from '../types/TNil'; import { TraceSpan, CriticalPathSection } from '../types/trace'; @@ -46,13 +56,13 @@ const getAdhocFilterMatches = (spans: TraceSpan[], adhocFilters: Array { // Check that adhoc filter was created expect(result.current.search.adhocFilters).toHaveLength(1); expect(result.current.search.adhocFilters?.[0]).toMatchObject({ - key: 'serviceName', + key: 'service.name', operator: '=', value: 'my-service', }); @@ -120,7 +120,7 @@ describe('useSearch', () => { // Check that adhoc filter was created expect(result.current.search.adhocFilters).toHaveLength(1); expect(result.current.search.adhocFilters?.[0]).toMatchObject({ - key: 'spanName', + key: 'span.name', operator: '!=', value: 'my-operation', }); @@ -195,13 +195,13 @@ describe('useSearch', () => { // Verify each filter const filters = result.current.search.adhocFilters || []; - expect(filters.find((f) => f.key === 'serviceName')).toMatchObject({ - key: 'serviceName', + expect(filters.find((f) => f.key === 'service.name')).toMatchObject({ + key: 'service.name', operator: '=', value: 'my-service', }); - expect(filters.find((f) => f.key === 'spanName')).toMatchObject({ - key: 'spanName', + expect(filters.find((f) => f.key === 'span.name')).toMatchObject({ + key: 'span.name', operator: '!=', value: 'my-operation', }); @@ -306,7 +306,7 @@ describe('useSearch', () => { expect(result.current.search.adhocFilters).toHaveLength(5); const filters = result.current.search.adhocFilters || []; - expect(filters.find((f) => f.key === 'serviceName')?.operator).toBe('!='); + expect(filters.find((f) => f.key === 'service.name')?.operator).toBe('!='); expect(filters.find((f) => f.key === 'tag1')?.operator).toBe('='); expect(filters.find((f) => f.key === 'tag2')?.operator).toBe('!='); expect(filters.find((f) => f.key === 'tag3')?.operator).toBe('=~'); diff --git a/public/app/features/explore/TraceView/useSearch.ts b/public/app/features/explore/TraceView/useSearch.ts index 9deb191a8d3..086866b87fb 100644 --- a/public/app/features/explore/TraceView/useSearch.ts +++ b/public/app/features/explore/TraceView/useSearch.ts @@ -7,6 +7,7 @@ import { useDispatch, useSelector } from 'app/types/store'; import { DEFAULT_SPAN_FILTERS, randomId } from '../state/constants'; import { changePanelState } from '../state/explorePane'; +import { SPAN_NAME, SERVICE_NAME } from './components/constants/span'; import { TraceSpan, CriticalPathSection } from './components/types/trace'; import { filterSpans } from './components/utils/filter-spans'; @@ -25,7 +26,7 @@ export function migrateToAdhocFilters(search: TraceSearchProps): TraceSearchProp // Migrate serviceName if (search.serviceName && search.serviceName.trim() !== '') { adhocFilters.push({ - key: 'serviceName', + key: SERVICE_NAME, operator: search.serviceNameOperator || '=', value: search.serviceName, }); @@ -34,7 +35,7 @@ export function migrateToAdhocFilters(search: TraceSearchProps): TraceSearchProp // Migrate spanName if (search.spanName && search.spanName.trim() !== '') { adhocFilters.push({ - key: 'spanName', + key: SPAN_NAME, operator: search.spanNameOperator || '=', value: search.spanName, }); diff --git a/public/app/features/explore/TraceView/utils/tags.ts b/public/app/features/explore/TraceView/utils/tags.ts index 293326e359e..38ae3c92148 100644 --- a/public/app/features/explore/TraceView/utils/tags.ts +++ b/public/app/features/explore/TraceView/utils/tags.ts @@ -9,6 +9,8 @@ import { STATUS, STATUS_MESSAGE, TRACE_STATE, + SPAN_NAME, + SERVICE_NAME, } from '../components/constants/span'; import { Trace } from '../components/types/trace'; @@ -37,6 +39,11 @@ export const getTraceTagKeys = (trace: Trace) => { span.process.tags.forEach((tag) => { keys.push(tag.key); }); + + if (span.process.serviceName) { + keys.push(SERVICE_NAME); + } + if (span.logs !== null) { span.logs.forEach((log) => { log.fields.forEach((field) => { @@ -63,6 +70,9 @@ export const getTraceTagKeys = (trace: Trace) => { if (span.traceState) { keys.push(TRACE_STATE); } + if (span.operationName) { + keys.push(SPAN_NAME); + } keys.push(ID); }); keys = uniq(keys).sort(); @@ -93,6 +103,11 @@ export const getTraceTagValues = (trace: Trace, key: string) => { } switch (key) { + case SPAN_NAME: + if (span.operationName) { + values.push(span.operationName); + } + break; case KIND: if (span.kind) { values.push(span.kind); diff --git a/public/app/features/explore/spec/query.test.tsx b/public/app/features/explore/spec/query.test.tsx index 2d2ca951ec0..1b185378ab0 100644 --- a/public/app/features/explore/spec/query.test.tsx +++ b/public/app/features/explore/spec/query.test.tsx @@ -50,7 +50,7 @@ describe('Explore: handle running/not running query', () => { jest.mocked(datasources.loki.query).mockReturnValueOnce(makeLogsQueryResponse()); // Make sure we render the logs panel - await screen.findByText(/^Logs$/); + await screen.findByRole('heading', { name: /^Logs$/ }); // Make sure we render the log line await screen.findByText(/custom log line/i); diff --git a/public/app/features/explore/spec/split.test.tsx b/public/app/features/explore/spec/split.test.tsx index e114201108a..0675a382d34 100644 --- a/public/app/features/explore/spec/split.test.tsx +++ b/public/app/features/explore/spec/split.test.tsx @@ -122,7 +122,7 @@ describe('Handles open/close splits and related events in UI and URL', () => { // Make sure we render the logs panel await waitFor(() => { - const logsPanels = screen.getAllByText(/^Logs$/); + const logsPanels = screen.getAllByRole('heading', { name: /^Logs$/ }); expect(logsPanels.length).toBe(2); }); diff --git a/public/app/features/live/dashboard/dashboardWatcher.ts b/public/app/features/live/dashboard/dashboardWatcher.ts index 086147e67e7..2bd13ee00d7 100644 --- a/public/app/features/live/dashboard/dashboardWatcher.ts +++ b/public/app/features/live/dashboard/dashboardWatcher.ts @@ -25,9 +25,11 @@ import { DashboardEvent, DashboardEventAction } from './types'; const sessionId = uuidv4(); class DashboardWatcher { + private static readonly IGNORE_SAVE_WINDOW_MS = 5000; + channel?: LiveChannelAddress; // path to the channel uid?: string; - ignoreSave?: boolean; + ignoreSave = 0; // save any events until this time passes editing = false; lastEditing?: DashboardEvent; subscription?: Unsubscribable; @@ -84,8 +86,9 @@ class DashboardWatcher { this.uid = undefined; } + // ignore the next 5 seconds of save events ignoreNextSave() { - this.ignoreSave = true; + this.ignoreSave = Date.now() + DashboardWatcher.IGNORE_SAVE_WINDOW_MS; } getRecentEditingEvent() { @@ -115,8 +118,11 @@ class DashboardWatcher { case DashboardEventAction.EditingStarted: case DashboardEventAction.Saved: { if (this.ignoreSave) { - this.ignoreSave = false; - return; + if (this.ignoreSave < Date.now()) { + this.ignoreSave = 0; // process the event + } else { + return; + } } const dash = getDashboardSrv().getCurrent(); diff --git a/public/app/features/live/dashboard/types.ts b/public/app/features/live/dashboard/types.ts index cffe686fc27..a5954211dfa 100644 --- a/public/app/features/live/dashboard/types.ts +++ b/public/app/features/live/dashboard/types.ts @@ -11,4 +11,5 @@ export interface DashboardEvent { message?: string; sessionId?: string; timestamp?: number; + rv?: string; } diff --git a/public/app/features/logs/components/LogRowMenuCell.tsx b/public/app/features/logs/components/LogRowMenuCell.tsx index 892a5eea68b..e205c1608e1 100644 --- a/public/app/features/logs/components/LogRowMenuCell.tsx +++ b/public/app/features/logs/components/LogRowMenuCell.tsx @@ -185,11 +185,12 @@ export const LogRowMenuCell = memo( } ); -type AddonOnClickListener = (event: MouseEvent, row: LogRowModel) => void | undefined; +type AddonOnClickListener = (event: MouseEvent, row: LogRowModel) => void | undefined; +type ChildElementProps = Record & { onClick: AddonOnClickListener }; function addClickListenersToNode(nodes: ReactNode[], row: LogRowModel) { return nodes.map((node, index) => { - if (isValidElement(node)) { - const onClick: AddonOnClickListener = node.props.onClick; + if (isValidElement(node)) { + const onClick = node.props.onClick; if (!onClick) { return node; } diff --git a/public/app/features/logs/components/otel/formats.ts b/public/app/features/logs/components/otel/formats.ts index c767a69a89e..23e6ec3559f 100644 --- a/public/app/features/logs/components/otel/formats.ts +++ b/public/app/features/logs/components/otel/formats.ts @@ -9,7 +9,7 @@ import { LogListModel, NEWLINES_REGEX } from '../panel/processing'; export const OTEL_PROBE_FIELD = 'severity_number'; const OTEL_LANGUAGE_UNKNOWN = 'unknown'; -function identifyOTelLanguages(logs: LogListModel[] | LogRowModel[]): string[] { +export function identifyOTelLanguages(logs: LogListModel[] | LogRowModel[]): string[] { const languagesSet = new Set(); logs.forEach((log) => { const lang = identifyOTelLanguage(log); diff --git a/public/app/features/logs/components/panel/LogLineDetailsComponent.tsx b/public/app/features/logs/components/panel/LogLineDetailsComponent.tsx index 36bdbf2bdde..0afd2e21369 100644 --- a/public/app/features/logs/components/panel/LogLineDetailsComponent.tsx +++ b/public/app/features/logs/components/panel/LogLineDetailsComponent.tsx @@ -1,6 +1,6 @@ import { css } from '@emotion/css'; import { camelCase, groupBy } from 'lodash'; -import { memo, startTransition, useCallback, useMemo, useRef, useState } from 'react'; +import { memo, startTransition, useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { DataFrameType, GrafanaTheme2, store, TimeRange } from '@grafana/data'; import { t, Trans } from '@grafana/i18n'; @@ -18,6 +18,7 @@ import { LogLineDetailsLinks } from './LogLineDetailsLinks'; import { LogLineDetailsLog } from './LogLineDetailsLog'; import { LogLineDetailsTrace } from './LogLineDetailsTrace'; import { useLogListContext } from './LogListContext'; +import { reportInteractionOnce } from './analytics'; import { getTempoTraceFromLinks } from './links'; import { LogListModel } from './processing'; @@ -124,6 +125,21 @@ export const LogLineDetailsComponent = memo( [fieldsWithLinks.links, fieldsWithLinks.linksFromVariableMap] ); + useEffect(() => { + if (noInteractions) { + return; + } + reportInteractionOnce('logs_log_line_details_fields_displayed', { + links: allLinks.length, + trace: trace !== undefined, + fields: fieldsWithoutLinks.length, + labels: labelsWithLinks.length, + labelGroups: labelGroups.join(', '), + }); + // Once + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + return ( <> diff --git a/public/app/features/logs/components/panel/LogLineDetailsHeader.tsx b/public/app/features/logs/components/panel/LogLineDetailsHeader.tsx index 34dd3b3b151..6968c4c138c 100644 --- a/public/app/features/logs/components/panel/LogLineDetailsHeader.tsx +++ b/public/app/features/logs/components/panel/LogLineDetailsHeader.tsx @@ -102,7 +102,11 @@ export const LogLineDetailsHeader = ({ focusLogLine, log, search, onSearch }: Pr } setDetailsMode(newMode); - }, [detailsMode, logOptionsStorageKey, setDetailsMode]); + + reportInteractionWrapper('logs_log_line_details_header_toggle_details_mode', { + newMode, + }); + }, [detailsMode, logOptionsStorageKey, reportInteractionWrapper, setDetailsMode]); const toggleLogLine = useCallback(() => { if (logLineDisplayed) { diff --git a/public/app/features/logs/components/panel/LogList.tsx b/public/app/features/logs/components/panel/LogList.tsx index 3c51af0342b..8cfbaee1665 100644 --- a/public/app/features/logs/components/panel/LogList.tsx +++ b/public/app/features/logs/components/panel/LogList.tsx @@ -280,6 +280,7 @@ const LogListComponent = ({ wrapLogMessage, } = useLogListContext(); const { detailsMode, showDetails, toggleDetails } = useLogDetailsContext(); + const { setSearch, showSearch } = useLogListSearchContext(); const [processedLogs, setProcessedLogs] = useState([]); const [listHeight, setListHeight] = useState(getListHeight(containerElement, app)); const theme = useTheme2(); @@ -441,6 +442,14 @@ const LogListComponent = ({ [debouncedScrollToItem, filteredLogs] ); + const onClickSearchString = useCallback( + (search: string) => { + showSearch(); + setSearch(search); + }, + [setSearch, showSearch] + ); + const logLevels = useMemo(() => getLevelsFromLogs(processedLogs), [processedLogs]); if (!containerElement || listHeight == null) { @@ -471,6 +480,7 @@ const LogListComponent = ({ {...popoverState.popoverMenuCoordinates} onClickFilterString={onClickFilterString} onClickFilterOutString={onClickFilterOutString} + onClickSearchString={onClickSearchString} onDisable={onDisablePopoverMenu} /> )} diff --git a/public/app/features/logs/components/panel/LogListContext.tsx b/public/app/features/logs/components/panel/LogListContext.tsx index 139f40ea98e..e7108af0881 100644 --- a/public/app/features/logs/components/panel/LogListContext.tsx +++ b/public/app/features/logs/components/panel/LogListContext.tsx @@ -34,7 +34,7 @@ import { getDefaultDetailsMode, getDetailsWidth } from './LogDetailsContext'; import { LogLineTimestampResolution } from './LogLine'; import { GetRowContextQueryFn, LogLineMenuCustomItem } from './LogLineMenu'; import { LogListOptions, LogListFontSize } from './LogList'; -import { reportInteractionOnce } from './analytics'; +import { collectInsights } from './analytics'; import { LogListModel } from './processing'; export interface LogListContextData extends Omit { @@ -241,7 +241,7 @@ export const LogListContextProvider = ({ if (noInteractions) { return; } - reportInteractionOnce(`logs_log_list_${app}_logs_displayed`, { + collectInsights(logs, app, { dedupStrategy, fontSize, forceEscape: logListState.forceEscape, diff --git a/public/app/features/logs/components/panel/LogListControls.tsx b/public/app/features/logs/components/panel/LogListControls.tsx index 5b482af2aad..a5deb524d66 100644 --- a/public/app/features/logs/components/panel/LogListControls.tsx +++ b/public/app/features/logs/components/panel/LogListControls.tsx @@ -5,13 +5,13 @@ import { MouseEvent, useCallback, useMemo } from 'react'; import { CoreApp, EventBus, + GrafanaTheme2, LogLevel, LogsDedupDescription, LogsDedupStrategy, LogsSortOrder, store, } from '@grafana/data'; -import { GrafanaTheme2 } from '@grafana/data/'; import { t } from '@grafana/i18n'; import { config, reportInteraction } from '@grafana/runtime'; import { Dropdown, Menu, useStyles2 } from '@grafana/ui'; diff --git a/public/app/features/logs/components/panel/LogListSearch.tsx b/public/app/features/logs/components/panel/LogListSearch.tsx index 3cdd1cbbe3d..7cae9f36d5e 100644 --- a/public/app/features/logs/components/panel/LogListSearch.tsx +++ b/public/app/features/logs/components/panel/LogListSearch.tsx @@ -18,19 +18,11 @@ interface Props { export const LOG_LIST_SEARCH_HEIGHT = 48; export const LogListSearch = ({ listRef, logs }: Props) => { - const { - hideSearch, - filterLogs, - matchingUids, - setMatchingUids, - setSearch: setContextSearch, - searchVisible, - toggleFilterLogs, - } = useLogListSearchContext(); + const { hideSearch, filterLogs, matchingUids, search, setMatchingUids, setSearch, searchVisible, toggleFilterLogs } = + useLogListSearchContext(); const { displayedFields, noInteractions } = useLogListContext(); - const [search, setSearch] = useState(''); const [currentResult, setCurrentResult] = useState(null); - const inputRef = useRef(''); + const inputRef = useRef(null); const searchUsedRef = useRef(false); const styles = useStyles2(getStyles); @@ -43,16 +35,15 @@ export const LogListSearch = ({ listRef, logs }: Props) => { const handleChange = useCallback( (e: ChangeEvent) => { - inputRef.current = e.target.value; startTransition(() => { - setSearch(inputRef.current); + setSearch(inputRef.current?.value ?? ''); }); if (!searchUsedRef.current && !noInteractions) { reportInteraction('logs_log_list_search_used'); searchUsedRef.current = true; } }, - [noInteractions] + [noInteractions, setSearch] ); const prevResult = useCallback(() => { @@ -78,19 +69,27 @@ export const LogListSearch = ({ listRef, logs }: Props) => { setCurrentResult(null); return; } - if (!currentResult) { + if (currentResult === null) { setCurrentResult(0); - listRef?.scrollToItem(logs.indexOf(matches[0]), 'center'); + // No need to filter if we're only showing matching logs, otherwise scroll to the first result. + if (!filterLogs) { + listRef?.scrollToItem(logs.indexOf(matches[0]), 'center'); + } } - }, [currentResult, listRef, logs, matches]); + }, [currentResult, filterLogs, listRef, logs, matches]); useEffect(() => { if (!searchVisible) { - setSearch(''); - setContextSearch(undefined); setMatchingUids(null); } - }, [searchVisible, setContextSearch, setMatchingUids]); + }, [searchVisible, setMatchingUids]); + + useEffect(() => { + if (!inputRef.current || !search) { + return; + } + inputRef.current.value = search; + }, [search]); useEffect(() => { const newMatchingUids = matches.map((log) => log.uid); @@ -104,13 +103,12 @@ export const LogListSearch = ({ listRef, logs }: Props) => { .forEach((log) => log.setCurrentSearch(undefined)); } - setContextSearch(search ? search : undefined); if (!sameLogs) { setMatchingUids(newMatchingUids.length ? newMatchingUids : null); } else if (!matches.length) { setMatchingUids(null); } - }, [logs, matches, matchingUids, search, setContextSearch, setMatchingUids]); + }, [logs, matches, matchingUids, search, setMatchingUids]); if (!searchVisible) { return null; @@ -126,6 +124,7 @@ export const LogListSearch = ({ listRef, logs }: Props) => { onChange={handleChange} autoFocus placeholder={t('logs.log-list-search.input-placeholder', 'Search in logs')} + ref={inputRef} suffix={suffix} /> @@ -141,22 +140,22 @@ export const LogListSearch = ({ listRef, logs }: Props) => { onClick={prevResult} disabled={!matches || !matches.length} name="angle-up" - aria-label={t('logs.log-list-search.prev', 'Previous result')} + tooltip={t('logs.log-list-search.prev', 'Previous result')} /> - + ); }; diff --git a/public/app/features/logs/components/panel/LogListSearchContext.tsx b/public/app/features/logs/components/panel/LogListSearchContext.tsx index ff1548a56cf..22be0c251a6 100644 --- a/public/app/features/logs/components/panel/LogListSearchContext.tsx +++ b/public/app/features/logs/components/panel/LogListSearchContext.tsx @@ -7,7 +7,7 @@ export interface LogListSearchContextData { search?: string; searchVisible?: boolean; setMatchingUids: (matches: string[] | null) => void; - setSearch: (search: string | undefined) => void; + setSearch: (search: string) => void; showSearch: () => void; toggleFilterLogs: () => void; } @@ -33,13 +33,14 @@ export const useLogListSearchContext = (): LogListSearchContextData => { }; export const LogListSearchContextProvider = ({ children }: { children: ReactNode }) => { - const [search, setSearch] = useState(undefined); + const [search, setSearch] = useState(''); const [searchVisible, setSearchVisible] = useState(false); const [matchingUids, setMatchingUids] = useState(null); const [filterLogs, setFilterLogs] = useState(false); const hideSearch = useCallback(() => { setSearchVisible(false); + setSearch(''); }, []); const showSearch = useCallback(() => { diff --git a/public/app/features/logs/components/panel/analytics.ts b/public/app/features/logs/components/panel/analytics.ts index 39ec415b939..54d819debb3 100644 --- a/public/app/features/logs/components/panel/analytics.ts +++ b/public/app/features/logs/components/panel/analytics.ts @@ -1,5 +1,8 @@ +import { CoreApp, LogRowModel } from '@grafana/data'; import { reportInteraction } from '@grafana/runtime'; +import { identifyOTelLanguages } from '../otel/formats'; + export const reportInteractionOnce = (interactionName: string, properties?: Record) => { const key = `logs.interactions.${interactionName}`; if (sessionStorage.getItem(key)) { @@ -8,3 +11,56 @@ export const reportInteractionOnce = (interactionName: string, properties?: Reco sessionStorage.setItem(key, '1'); reportInteraction(interactionName, properties); }; + +export function collectInsights(logs: LogRowModel[], app: CoreApp, properties?: Record) { + if (!logs.length) { + return; + } + + const { longest, shortest, average, median } = getLogsStats(logs); + + reportInteractionOnce(`logs_log_list_${app}_logs_displayed`, { + ...properties, + otelLanguage: identifyOTelLanguages(logs).join(', '), + ansi: logs.some((logs) => logs.hasAnsi), + unescaped: logs.some((logs) => logs.hasUnescapedContent), + dsType: logs[0]?.datasourceType ?? '', + count: logs.length, + longestLog: longest, + shortestLog: shortest, + averageLog: average, + medianLog: median, + }); +} + +function getLogsStats(logs: LogRowModel[]) { + let longest = 0, + shortest = logs[0].raw.length, + median = 0; + + const lengths: number[] = []; + let sum = 0; + + for (let i = 0; i < logs.length; i++) { + let length = logs[i].raw.length; + if (length > longest) { + longest = length; + } else if (length < shortest) { + shortest = length; + } + sum += length; + lengths.push(length); + } + + lengths.sort((a, b) => a - b); + + const mid = Math.floor(lengths.length / 2); + + if (lengths.length % 2 === 0) { + median = (lengths[mid - 1] + lengths[mid]) / 2; + } else { + median = lengths[mid]; + } + + return { longest, shortest, average: Math.round(sum / logs.length), median }; +} diff --git a/public/app/features/logs/components/panel/processing.ts b/public/app/features/logs/components/panel/processing.ts index dcb391c8e07..9132c2b7e6e 100644 --- a/public/app/features/logs/components/panel/processing.ts +++ b/public/app/features/logs/components/panel/processing.ts @@ -336,7 +336,7 @@ function countNewLines(log: string, limit = Infinity) { let count = 0; for (let i = 0; i < log.length; ++i) { // No need to iterate further - if (count > Infinity) { + if (count > limit) { return count; } if (log[i] === '\n') { diff --git a/public/app/features/logs/components/panel/useKeyBindings.ts b/public/app/features/logs/components/panel/useKeyBindings.ts index 6a75dcfcf2b..21776b15bb7 100644 --- a/public/app/features/logs/components/panel/useKeyBindings.ts +++ b/public/app/features/logs/components/panel/useKeyBindings.ts @@ -15,7 +15,7 @@ export const useKeyBindings = () => { const { showDetails, detailsMode, closeDetails } = useLogDetailsContext(); useEffect(() => { - function handleToggleSearch(event: KeyboardEvent) { + function handleOpenSearch(event: KeyboardEvent) { const isMac = navigator.userAgent.includes('Mac'); const isFKey = event.key === 'f' || event.key === 'F'; @@ -23,6 +23,8 @@ export const useKeyBindings = () => { showSearch(); return; } + } + function handleClose(event: KeyboardEvent) { if (event.key === 'Escape' && searchVisible) { hideSearch(); } @@ -30,9 +32,11 @@ export const useKeyBindings = () => { closeDetails(); } } - document.addEventListener('keydown', handleToggleSearch); + document.addEventListener('keydown', handleOpenSearch); + document.addEventListener('keyup', handleClose); return () => { - document.removeEventListener('keydown', handleToggleSearch); + document.removeEventListener('keydown', handleOpenSearch); + document.removeEventListener('keyup', handleClose); }; }, [closeDetails, detailsMode, hideSearch, searchVisible, showDetails.length, showSearch]); }; diff --git a/public/app/features/manage-dashboards/components/PublicDashboardListTable/PublicDashboardListTable.test.tsx b/public/app/features/manage-dashboards/components/PublicDashboardListTable/PublicDashboardListTable.test.tsx index f5d3ad028b0..0014f107004 100644 --- a/public/app/features/manage-dashboards/components/PublicDashboardListTable/PublicDashboardListTable.test.tsx +++ b/public/app/features/manage-dashboards/components/PublicDashboardListTable/PublicDashboardListTable.test.tsx @@ -3,7 +3,7 @@ import { http, HttpResponse } from 'msw'; import { setupServer } from 'msw/node'; import { render } from 'test/test-utils'; -import { selectors as e2eSelectors } from '@grafana/e2e-selectors/src'; +import { selectors as e2eSelectors } from '@grafana/e2e-selectors'; import { backendSrv } from 'app/core/services/backend_srv'; import { contextSrv } from 'app/core/services/context_srv'; diff --git a/public/app/features/manage-dashboards/components/PublicDashboardListTable/PublicDashboardListTable.tsx b/public/app/features/manage-dashboards/components/PublicDashboardListTable/PublicDashboardListTable.tsx index d14fd970d1d..a1bcedb5e70 100644 --- a/public/app/features/manage-dashboards/components/PublicDashboardListTable/PublicDashboardListTable.tsx +++ b/public/app/features/manage-dashboards/components/PublicDashboardListTable/PublicDashboardListTable.tsx @@ -3,7 +3,7 @@ import { useMemo, useState } from 'react'; import { useMedia } from 'react-use'; import { GrafanaTheme2 } from '@grafana/data'; -import { selectors as e2eSelectors } from '@grafana/e2e-selectors/src'; +import { selectors as e2eSelectors } from '@grafana/e2e-selectors'; import { Trans, t } from '@grafana/i18n'; import { reportInteraction } from '@grafana/runtime'; import { diff --git a/public/app/features/panel/components/VizTypePicker/VisualizationSuggestionCard.tsx b/public/app/features/panel/components/VizTypePicker/VisualizationSuggestionCard.tsx index 7248dbcc1e5..632c143fe3a 100644 --- a/public/app/features/panel/components/VizTypePicker/VisualizationSuggestionCard.tsx +++ b/public/app/features/panel/components/VizTypePicker/VisualizationSuggestionCard.tsx @@ -2,7 +2,7 @@ import { css, cx } from '@emotion/css'; import { cloneDeep } from 'lodash'; import { CSSProperties, HTMLAttributes, ReactNode } from 'react'; -import { colorManipulator, GrafanaTheme2, PanelData, PanelPluginVisualizationSuggestion } from '@grafana/data'; +import { GrafanaTheme2, PanelData, PanelPluginVisualizationSuggestion } from '@grafana/data'; import { selectors } from '@grafana/e2e-selectors'; import { config } from '@grafana/runtime'; import { Tooltip, useStyles2 } from '@grafana/ui'; @@ -31,7 +31,11 @@ export function VisualizationSuggestionCard({ const commonButtonProps = { 'aria-label': suggestion.name, - className: cx(className, styles.vizBox), + className: cx( + className, + styles.vizBox, + config.featureToggles.newVizSuggestions && isSelected && styles.selectedBox + ), 'data-testid': selectors.components.VisualizationPreview.card(suggestion.name), style: outerStyles, tabIndex: -1, // selection is handled by parent container @@ -56,7 +60,12 @@ export function VisualizationSuggestionCard({ content = ( ); @@ -82,22 +89,8 @@ export function VisualizationSuggestionCard({ const getStyles = (theme: GrafanaTheme2) => { return { - hoverPane: css({ - position: 'absolute', - top: -4, - left: -4, - right: -2, - bottom: -2, - borderRadius: theme.spacing(0.5), - background: 'transparent', - [theme.transitions.handleMotion('no-preference', 'reduce')]: { - transition: theme.transitions.create(['background'], { - duration: theme.transitions.duration.short, - }), - }, - }), - hoverPaneSelected: css({ - background: colorManipulator.alpha(theme.colors.text.primary, 0.1), + selectedSuggestion: css({ + filter: `blur(1px) ${theme.isDark ? 'brightness(0.5)' : 'opacity(0.3)'}`, }), vizBox: css({ position: 'relative', @@ -149,6 +142,10 @@ const getStyles = (theme: GrafanaTheme2) => { top: '6px', left: '6px', }), + selectedBox: css({ + border: `1px solid ${theme.colors.primary.border}`, + background: theme.colors.action.selected, + }), }; }; diff --git a/public/app/features/panel/components/VizTypePicker/VisualizationSuggestions.tsx b/public/app/features/panel/components/VizTypePicker/VisualizationSuggestions.tsx index e93e74f358d..d1763ad835f 100644 --- a/public/app/features/panel/components/VizTypePicker/VisualizationSuggestions.tsx +++ b/public/app/features/panel/components/VizTypePicker/VisualizationSuggestions.tsx @@ -1,6 +1,6 @@ import { css } from '@emotion/css'; import { Fragment, useState, useEffect, useCallback, useMemo } from 'react'; -import { useAsync, useMeasure } from 'react-use'; +import { useAsyncRetry, useMeasure } from 'react-use'; import { GrafanaTheme2, @@ -28,19 +28,23 @@ export interface Props { panel?: PanelModel; } +const useSuggestions = (data: PanelData | undefined) => { + const [hasFetched, setHasFetched] = useState(false); + const { value, loading, error, retry } = useAsyncRetry(async () => { + await new Promise((resolve) => setTimeout(resolve, hasFetched ? 75 : 0)); + setHasFetched(true); + return await getAllSuggestions(data); + }, [hasFetched, data]); + return { value, loading, error, retry }; +}; + export function VisualizationSuggestions({ onChange, data, panel }: Props) { const styles = useStyles2(getStyles); - const { - value: suggestions, - loading, - error, - } = useAsync(async () => { - if (!hasData(data)) { - return []; - } - return await getAllSuggestions(data); - }, [data]); + const { value: result, loading, error, retry } = useSuggestions(data); + + const suggestions = result?.suggestions; + const hasLoadingErrors = result?.hasErrors ?? false; const [suggestionHash, setSuggestionHash] = useState(null); const [firstCardRef, { width }] = useMeasure(); const [firstCardHash, setFirstCardHash] = useState(null); @@ -131,80 +135,97 @@ export function VisualizationSuggestions({ onChange, data, panel }: Props) { } return ( -
- {isNewVizSuggestionsEnabled - ? suggestionsByVizType.map(([vizType, vizTypeSuggestions], groupIndex) => ( - -
- - {vizType?.info && } - {vizType?.name || t('panel.visualization-suggestions.unknown-viz-type', 'Unknown visualization type')} - -
- {vizTypeSuggestions?.map((suggestion, index) => { - const isCardSelected = suggestionHash === suggestion.hash; - return ( -
{ - if (ev.key === 'Enter' || ev.key === ' ') { - ev.preventDefault(); - applySuggestion(suggestion, isNewVizSuggestionsEnabled && !isCardSelected); - } - }} - ref={index === 0 ? firstCardRef : undefined} - > - {isCardSelected && ( - +
+ + )} +
+ {isNewVizSuggestionsEnabled + ? suggestionsByVizType.map(([vizType, vizTypeSuggestions], groupIndex) => ( + +
+ + {vizType?.info && } + {vizType?.name || + t('panel.visualization-suggestions.unknown-viz-type', 'Unknown visualization type')} + +
+ {vizTypeSuggestions?.map((suggestion, index) => { + const isCardSelected = suggestionHash === suggestion.hash; + return ( +
{ + if (ev.key === 'Enter' || ev.key === ' ') { + ev.preventDefault(); + applySuggestion(suggestion, isNewVizSuggestionsEnabled && !isCardSelected); } - > - {t('panel.visualization-suggestions.use-this-suggestion', 'Use this suggestion')} - - )} - applySuggestion(suggestion, true)} - /> -
- ); - })} -
- )) - : suggestions?.map((suggestion, index) => ( -
- applySuggestion(suggestion)} - /> -
- ))} -
+ }} + ref={index === 0 ? firstCardRef : undefined} + > + {isCardSelected && ( + + )} + applySuggestion(suggestion, true)} + /> +
+ ); + })} + + )) + : suggestions?.map((suggestion, index) => ( +
+ applySuggestion(suggestion)} + /> +
+ ))} + + ); } @@ -217,6 +238,11 @@ const getStyles = (theme: GrafanaTheme2) => { width: '100%', marginTop: theme.spacing(6), }), + alertContent: css({ + display: 'flex', + alignItems: 'center', + justifyContent: 'space-between', + }), filterRow: css({ display: 'flex', flexDirection: 'row', diff --git a/public/app/features/panel/suggestions/consts.ts b/public/app/features/panel/suggestions/consts.ts index 76e012a7425..decdf8ac7b4 100644 --- a/public/app/features/panel/suggestions/consts.ts +++ b/public/app/features/panel/suggestions/consts.ts @@ -16,4 +16,5 @@ export const panelsToCheckFirst = [ 'heatmap', 'histogram', 'geomap', + 'text', ]; diff --git a/public/app/features/panel/suggestions/getAllSuggestions.test.ts b/public/app/features/panel/suggestions/getAllSuggestions.test.ts index e76a7df15e3..8657824cc27 100644 --- a/public/app/features/panel/suggestions/getAllSuggestions.test.ts +++ b/public/app/features/panel/suggestions/getAllSuggestions.test.ts @@ -1,4 +1,5 @@ import { + AppEvents, DataFrame, FieldType, getDefaultTimeRange, @@ -18,10 +19,20 @@ import { StackingMode, VizOrientation, } from '@grafana/schema'; +import { appEvents } from 'app/core/app_events'; import { config } from 'app/core/config'; +import { clearPanelPluginCache } from 'app/features/plugins/importPanelPlugin'; +import { pluginImporter } from 'app/features/plugins/importer/pluginImporter'; import { panelsToCheckFirst } from './consts'; -import { getAllSuggestions, sortSuggestions } from './getAllSuggestions'; +import { getAllSuggestions, loadPlugins, sortSuggestions } from './getAllSuggestions'; + +jest.mock('app/core/app_events', () => ({ + appEvents: { + subscribe: jest.fn(() => ({ unsubscribe: jest.fn() })), + publish: jest.fn(), + }, +})); config.featureToggles.externalVizSuggestions = true; @@ -52,28 +63,6 @@ for (const pluginId of panelsToCheckFirst) { }; } -config.panels.text = { - id: 'text', - module: 'core:plugin/text', - sort: idx++, - name: 'Text', - type: PluginType.panel, - baseUrl: 'public/app/plugins/panel', - skipDataQuery: true, - suggestions: false, - info: { - version: '1.0.0', - updated: '2025-01-01', - links: [], - screenshots: [], - author: { - name: 'Grafana Labs', - }, - description: 'Text panel', - logos: { small: 'small/logo', large: 'large/logo' }, - }, -}; - jest.mock('../state/util', () => { const originalModule = jest.requireActual('../state/util'); return { @@ -103,7 +92,8 @@ class ScenarioContext { timeRange: getDefaultTimeRange(), }; - this.suggestions = await getAllSuggestions(panelData); + const result = await getAllSuggestions(panelData); + this.suggestions = result.suggestions; } names() { @@ -554,6 +544,81 @@ describe('sortSuggestions', () => { }); }); +describe('Visualization suggestions error handling', () => { + it('returns result with hasErrors flag', async () => { + const result = await getAllSuggestions({ + series: [ + toDataFrame({ + fields: [ + { name: 'Time', type: FieldType.time, values: [1, 2] }, + { name: 'Max', type: FieldType.number, values: [1, 10] }, + ], + }), + ], + state: LoadingState.Done, + timeRange: getDefaultTimeRange(), + }); + + expect(result).toHaveProperty('suggestions'); + expect(result).toHaveProperty('hasErrors'); + expect(result.hasErrors).toBe(false); + }); +}); + +// this needs to happen before any +describe('loadPlugins', () => { + beforeEach(() => { + clearPanelPluginCache(); + }); + + afterEach(() => { + if (jest.isMockFunction(pluginImporter.importPanel)) { + jest.mocked(pluginImporter.importPanel).mockRestore(); + } + }); + + it('should swallow errors when failing to load core plugins', async () => { + jest.spyOn(console, 'error').mockImplementation(); + + const _importPanel = pluginImporter.importPanel; + jest.spyOn(pluginImporter, 'importPanel').mockImplementation(async (meta) => { + if (meta.id === 'timeseries') { + throw new Error('Failed to load core panel plugin'); + } + return await _importPanel(meta); + }); + + const panelIds = ['timeseries', 'table']; + const { plugins, hasErrors } = await loadPlugins(panelIds); + + expect(plugins).toEqual([expect.objectContaining({ meta: expect.objectContaining({ id: 'table' }) })]); + expect(hasErrors).toBe(true); + expect(appEvents.publish).not.toHaveBeenCalled(); + }); + + it('should swallow errors when failing to load external plugins', async () => { + jest.spyOn(console, 'error').mockImplementation(); + + const panelIds = ['non-existent-panel']; + const { plugins, hasErrors } = await loadPlugins(panelIds); + + expect(plugins).toEqual([]); + expect(hasErrors).toBe(false); + expect(appEvents.publish).toHaveBeenCalledWith({ + type: AppEvents.alertError.name, + payload: [expect.stringContaining('Failed to load panel plugin: non-existent-panel.')], + }); + }); + + it('should load panel plugins with suggestions', async () => { + const panelIds = ['timeseries', 'table']; + const { plugins, hasErrors } = await loadPlugins(panelIds); + + expect(plugins.map((p) => p.meta.id)).toEqual(expect.arrayContaining(['timeseries', 'table'])); + expect(hasErrors).toBe(false); + }); +}); + function repeatFrame(count: number, frame: DataFrame): DataFrame[] { const frames: DataFrame[] = []; for (let i = 0; i < count; i++) { diff --git a/public/app/features/panel/suggestions/getAllSuggestions.ts b/public/app/features/panel/suggestions/getAllSuggestions.ts index ea94add39ab..d0bb73dfb83 100644 --- a/public/app/features/panel/suggestions/getAllSuggestions.ts +++ b/public/app/features/panel/suggestions/getAllSuggestions.ts @@ -1,4 +1,5 @@ import { + AppEvents, getPanelDataSummary, PanelData, PanelDataSummary, @@ -7,41 +8,67 @@ import { PreferredVisualisationType, VisualizationSuggestionScore, } from '@grafana/data'; +import { t } from '@grafana/i18n'; import { config } from '@grafana/runtime'; +import { appEvents } from 'app/core/app_events'; import { importPanelPlugin, isBuiltInPlugin } from 'app/features/plugins/importPanelPlugin'; import { getAllPanelPluginMeta } from '../state/util'; import { panelsToCheckFirst } from './consts'; -/** - * gather and cache the plugins which provide visualization suggestions so they can be invoked to build suggestions - */ -async function getPanelsWithSuggestions(): Promise { - // list of plugins to load is determined by the feature flag - const pluginIds: string[] = config.featureToggles.externalVizSuggestions +interface PluginLoadResult { + plugins: PanelPlugin[]; + hasErrors: boolean; +} + +function getPanelPluginIds(): string[] { + return config.featureToggles.externalVizSuggestions ? getAllPanelPluginMeta() .filter((panel) => panel.suggestions) .map((m) => m.id) : panelsToCheckFirst; +} +/** + * gather and cache the plugins which provide visualization suggestions so they can be invoked to build suggestions + */ +export async function loadPlugins(pluginIds: string[]): Promise { // import the plugins in parallel using Promise.allSettled const plugins: PanelPlugin[] = []; - const settledPromises = await Promise.allSettled(pluginIds.map((id) => importPanelPlugin(id))); + let hasErrors = false; + const settledPromises = await Promise.allSettled( + pluginIds.map(async (pluginId) => { + return await importPanelPlugin(pluginId); + }) + ); + for (let i = 0; i < settledPromises.length; i++) { const settled = settledPromises[i]; - if (settled.status === 'fulfilled') { plugins.push(settled.value); + } else { + const pluginId = pluginIds[i]; + console.error(`Failed to load ${pluginId} for visualization suggestions:`, settled.reason); + + if (isBuiltInPlugin(pluginId)) { + hasErrors = true; + } else { + appEvents.publish({ + type: AppEvents.alertError.name, + payload: [ + t( + 'panel.visualization-suggestions.error-loading-suggestions.plugin-failed', + 'Failed to load panel plugin: {{ pluginId }}.', + { pluginId } + ), + ], + }); + } } - // TODO: do we want to somehow log if there were errors loading some of the plugins? } - if (plugins.length === 0) { - throw new Error('No panel plugins with visualization suggestions found'); - } - - return plugins; + return { plugins, hasErrors }; } /** @@ -89,41 +116,37 @@ export function sortSuggestions(suggestions: PanelPluginVisualizationSuggestion[ }); } +export interface SuggestionsResult { + suggestions: PanelPluginVisualizationSuggestion[]; + hasErrors: boolean; +} + /** * given PanelData, return a sorted list of Suggestions from all plugins which support it. * @param {PanelData} data queried and transformed data for the panel - * @returns {PanelPluginVisualizationSuggestion[]} sorted list of suggestions + * @returns {SuggestionsResult} sorted list of suggestions and error status */ -export async function getAllSuggestions(data?: PanelData): Promise { +export async function getAllSuggestions(data?: PanelData): Promise { const dataSummary = getPanelDataSummary(data?.series); const list: PanelPluginVisualizationSuggestion[] = []; - for (const plugin of await getPanelsWithSuggestions()) { - const suggestions = plugin.getSuggestions(dataSummary); - if (suggestions) { - list.push(...suggestions); - } - } + const pluginIds: string[] = getPanelPluginIds(); + const { plugins, hasErrors: pluginLoadErrors } = await loadPlugins(pluginIds); - if (dataSummary.fieldCount === 0) { - for (const plugin of Object.values(config.panels)) { - if (!plugin.skipDataQuery || plugin.hideFromList) { - continue; + let pluginSuggestionsError = false; + for (const plugin of plugins) { + try { + const suggestions = plugin.getSuggestions(dataSummary); + if (suggestions) { + list.push(...suggestions); } - - list.push({ - name: plugin.name, - pluginId: plugin.id, - description: plugin.info.description, - hash: 'plugin-empty-' + plugin.id, - cardOptions: { - imgSrc: plugin.info.logos.small, - }, - }); + } catch (e) { + console.warn(`error when loading suggestions from plugin "${plugin.meta.id}"`, e); + pluginSuggestionsError = true; } } sortSuggestions(list, dataSummary); - return list; + return { suggestions: list, hasErrors: pluginLoadErrors || pluginSuggestionsError }; } diff --git a/public/app/features/plugins/admin/components/PluginDetailsPage.tsx b/public/app/features/plugins/admin/components/PluginDetailsPage.tsx index b135321e558..2a7342e6be8 100644 --- a/public/app/features/plugins/admin/components/PluginDetailsPage.tsx +++ b/public/app/features/plugins/admin/components/PluginDetailsPage.tsx @@ -17,18 +17,9 @@ import { PluginDetailsSignature } from '../components/PluginDetailsSignature'; import { usePluginDetailsTabs } from '../hooks/usePluginDetailsTabs'; import { usePluginPageExtensions } from '../hooks/usePluginPageExtensions'; import { useGetSingle, useFetchStatus, useFetchDetailsStatus, useGetPluginInsights } from '../state/hooks'; -import { PluginTabIds } from '../types'; import { PluginDetailsDeprecatedWarning } from './PluginDetailsDeprecatedWarning'; -function isPluginTabId(value: string | null): value is PluginTabIds { - if (!value) { - return false; - } - const validIds: string[] = Object.values(PluginTabIds); - return validIds.includes(value); -} - export type Props = { // The ID of the plugin pluginId: string; @@ -60,10 +51,7 @@ export function PluginDetailsPage({ useGetPluginInsights(pluginId, plugin?.isInstalled ? plugin?.installedVersion : plugin?.latestVersion); const isNarrowScreen = useMedia('(max-width: 600px)'); - const pageParam = queryParams.get('page'); - const pageId = pageParam && isPluginTabId(pageParam) ? pageParam : undefined; - const { navModel, activePageId } = usePluginDetailsTabs(plugin, pageId, isNarrowScreen); - + const { navModel, activePageId } = usePluginDetailsTabs(plugin, queryParams.get('page'), isNarrowScreen); const { actions, info, subtitle } = usePluginPageExtensions(plugin); const { isLoading: isFetchLoading } = useFetchStatus(); const { isLoading: isFetchDetailsLoading } = useFetchDetailsStatus(); diff --git a/public/app/features/plugins/admin/hooks/usePluginDetailsTabs.tsx b/public/app/features/plugins/admin/hooks/usePluginDetailsTabs.tsx index ab616988e3f..6cb8ec39af4 100644 --- a/public/app/features/plugins/admin/hooks/usePluginDetailsTabs.tsx +++ b/public/app/features/plugins/admin/hooks/usePluginDetailsTabs.tsx @@ -18,9 +18,9 @@ type ReturnType = { }; function getCurrentPageId( - pageId: PluginTabIds | undefined, isNarrowScreen: boolean | undefined, - defaultTab: string + defaultTab: string, + pageId?: PluginTabIds | string | null ): PluginTabIds | string { if (!isNarrowScreen && pageId === PluginTabIds.PLUGINDETAILS) { return defaultTab; @@ -30,7 +30,7 @@ function getCurrentPageId( export const usePluginDetailsTabs = ( plugin?: CatalogPlugin, - pageId?: PluginTabIds, + pageId?: PluginTabIds | string | null, isNarrowScreen?: boolean ): ReturnType => { const { loading, error, value: pluginConfig } = usePluginConfig(plugin); @@ -38,7 +38,7 @@ export const usePluginDetailsTabs = ( const defaultTab = useDefaultPage(plugin, pluginConfig); const isPublished = Boolean(plugin?.isPublished); - const currentPageId = getCurrentPageId(pageId, isNarrowScreen, defaultTab); + const currentPageId = getCurrentPageId(isNarrowScreen, defaultTab, pageId); const navModelChildren = useMemo(() => { const canConfigurePlugins = plugin && contextSrv.hasPermissionInMetadata(AccessControlAction.PluginsWrite, plugin); diff --git a/public/app/features/plugins/extensions/usePluginComponents.tsx b/public/app/features/plugins/extensions/usePluginComponents.tsx index c800bf08a31..c7f5b40815f 100644 --- a/public/app/features/plugins/extensions/usePluginComponents.tsx +++ b/public/app/features/plugins/extensions/usePluginComponents.tsx @@ -67,21 +67,15 @@ export function createComponentWithMeta( ): ComponentTypeWithExtensionMeta { const { component: Component, ...config } = registryItem; - function ComponentWithMeta(props: Props) { - return ; - } - - ComponentWithMeta.displayName = Component.displayName; - ComponentWithMeta.defaultProps = Component.defaultProps; - ComponentWithMeta.propTypes = Component.propTypes; - ComponentWithMeta.contextTypes = Component.contextTypes; - ComponentWithMeta.meta = { - pluginId: config.pluginId, - title: config.title ?? '', - description: config.description ?? '', - id: generateExtensionId(config.pluginId, extensionPointId, config.title), - type: PluginExtensionTypes.component, - } satisfies PluginExtensionComponentMeta; + const ComponentWithMeta: ComponentTypeWithExtensionMeta = Object.assign(Component, { + meta: { + pluginId: config.pluginId, + title: config.title ?? '', + description: config.description ?? '', + id: generateExtensionId(config.pluginId, extensionPointId, config.title), + type: PluginExtensionTypes.component, + } satisfies PluginExtensionComponentMeta, + }); return ComponentWithMeta; } diff --git a/public/app/features/plugins/importPanelPlugin.ts b/public/app/features/plugins/importPanelPlugin.ts index e541b8f7893..ef8d955f562 100644 --- a/public/app/features/plugins/importPanelPlugin.ts +++ b/public/app/features/plugins/importPanelPlugin.ts @@ -62,3 +62,9 @@ export function syncGetPanelPlugin(id: string): PanelPlugin | undefined { function getPanelPlugin(meta: PanelPluginMeta): Promise { return pluginImporter.importPanel(meta); } + +export function clearPanelPluginCache(): void { + for (const key of Object.keys(promiseCache)) { + delete promiseCache[key]; + } +} diff --git a/public/app/features/provisioning/Config/ConfigForm.tsx b/public/app/features/provisioning/Config/ConfigForm.tsx index a29bc68329e..3b1aebc1911 100644 --- a/public/app/features/provisioning/Config/ConfigForm.tsx +++ b/public/app/features/provisioning/Config/ConfigForm.tsx @@ -28,7 +28,6 @@ import { FormPrompt } from 'app/core/components/FormPrompt/FormPrompt'; import { DeleteRepositoryButton } from '../Repository/DeleteRepositoryButton'; import { TokenPermissionsInfo } from '../Shared/TokenPermissionsInfo'; import { getGitProviderFields, getLocalProviderFields } from '../Wizard/fields'; -import { InlineSecureValueWarning } from '../components/InlineSecureValueWarning'; import { PROVISIONING_URL } from '../constants'; import { useCreateOrUpdateRepository } from '../hooks/useCreateOrUpdateRepository'; import { RepositoryFormData } from '../types'; @@ -80,10 +79,7 @@ export function ConfigForm({ data }: ConfigFormProps) { const [isLoading, setIsLoading] = useState(false); const navigate = useNavigate(); const [type, readOnly] = watch(['type', 'readOnly']); - const targetOptions = useMemo( - () => getTargetOptions(settings.data?.allowedTargets || ['instance', 'folder']), - [settings.data] - ); + const targetOptions = useMemo(() => getTargetOptions(settings.data?.allowedTargets || ['folder']), [settings.data]); const isGitBased = isGitProvider(type); const { @@ -181,7 +177,6 @@ export function ConfigForm({ data }: ConfigFormProps) {
{gitFields && ( <> - - {legacyStorage && ( - - - When you connect your whole instance, dashboards will be unavailable while running the migration. We - recommend warning your users before starting the process. - - - )}
diff --git a/public/app/features/provisioning/HomePage.tsx b/public/app/features/provisioning/HomePage.tsx index 465a294fa61..fb7508df700 100644 --- a/public/app/features/provisioning/HomePage.tsx +++ b/public/app/features/provisioning/HomePage.tsx @@ -1,18 +1,14 @@ import { useMemo, useState } from 'react'; -import { Trans, t } from '@grafana/i18n'; -import { Alert, ConfirmModal, Stack, Tab, TabContent, TabsBar } from '@grafana/ui'; -import { - useDeletecollectionRepositoryMutation, - useGetFrontendSettingsQuery, -} from 'app/api/clients/provisioning/v0alpha1'; +import { t } from '@grafana/i18n'; +import { ConfirmModal, Stack, Tab, TabContent, TabsBar } from '@grafana/ui'; +import { useDeletecollectionRepositoryMutation } from 'app/api/clients/provisioning/v0alpha1'; import { Page } from 'app/core/components/Page/Page'; import GettingStarted from './GettingStarted/GettingStarted'; import GettingStartedPage from './GettingStarted/GettingStartedPage'; import { ConnectRepositoryButton } from './Shared/ConnectRepositoryButton'; import { RepositoryList } from './Shared/RepositoryList'; -import { InlineSecureValueWarning } from './components/InlineSecureValueWarning'; import { useRepositoryList } from './hooks/useRepositoryList'; enum TabSelection { @@ -22,7 +18,6 @@ enum TabSelection { export default function HomePage() { const [items, isLoading] = useRepositoryList({ watch: true }); - const settings = useGetFrontendSettingsQuery(); const [deleteAll] = useDeletecollectionRepositoryMutation(); const [showDeleteModal, setShowDeleteModal] = useState(false); const [activeTab, setActiveTab] = useState(TabSelection.Repositories); @@ -71,25 +66,6 @@ export default function HomePage() { actions={activeTab === TabSelection.Repositories && } > - {settings.data?.legacyStorage && ( - - Remove all configured repositories - - } - onRemove={() => { - setShowDeleteModal(true); - }} - > - - Configured repositories will not work while running legacy storage. - - - )} - diff --git a/public/app/features/provisioning/Job/JobStatus.tsx b/public/app/features/provisioning/Job/JobStatus.tsx index 02e0b733bbb..7aec776f8aa 100644 --- a/public/app/features/provisioning/Job/JobStatus.tsx +++ b/public/app/features/provisioning/Job/JobStatus.tsx @@ -1,8 +1,11 @@ +import { useEffect } from 'react'; + import { Trans, t } from '@grafana/i18n'; import { Spinner, Stack, Text } from '@grafana/ui'; import { Job, useListJobQuery } from 'app/api/clients/provisioning/v0alpha1'; import { StepStatusInfo } from '../Wizard/types'; +import { getErrorMessage } from '../utils/httpUtils'; import { FinishedJobStatus } from './FinishedJobStatus'; import { JobContent } from './JobContent'; @@ -25,6 +28,18 @@ export function JobStatus({ jobType, watch, onStatusChange }: JobStatusProps) { const activeQueryCompleted = !activeQuery.isUninitialized && !activeQuery.isLoading; const shouldCheckFinishedJobs = activeQueryCompleted && !activeJob && !!repoLabel; + useEffect(() => { + if (activeQuery.isError) { + onStatusChange?.({ + status: 'error', + error: { + title: t('provisioning.job-status.title.error-fetching-active-job', 'Error fetching active job'), + message: getErrorMessage(activeQuery.error), + }, + }); + } + }, [activeQuery.isError, activeQuery.error, onStatusChange]); + if (activeQuery.isLoading) { return ( @@ -37,12 +52,6 @@ export function JobStatus({ jobType, watch, onStatusChange }: JobStatusProps) { } if (activeQuery.isError) { - onStatusChange?.({ - status: 'error', - error: { - title: t('provisioning.job-status.title.error-fetching-active-job', 'Error fetching active job'), - }, - }); return null; } diff --git a/public/app/features/provisioning/Repository/RepositoryStatusPage.tsx b/public/app/features/provisioning/Repository/RepositoryStatusPage.tsx index b41bcc3260f..e18e47500da 100644 --- a/public/app/features/provisioning/Repository/RepositoryStatusPage.tsx +++ b/public/app/features/provisioning/Repository/RepositoryStatusPage.tsx @@ -5,13 +5,13 @@ import { useParams } from 'react-router-dom-v5-compat'; import { SelectableValue, urlUtil } from '@grafana/data'; import { Trans, t } from '@grafana/i18n'; import { Alert, EmptyState, Spinner, Stack, Tab, TabContent, TabsBar, Text, TextLink } from '@grafana/ui'; -import { useGetFrontendSettingsQuery, useListRepositoryQuery } from 'app/api/clients/provisioning/v0alpha1'; +import { useListRepositoryQuery } from 'app/api/clients/provisioning/v0alpha1'; import { Page } from 'app/core/components/Page/Page'; import { useQueryParams } from 'app/core/hooks/useQueryParams'; import { isNotFoundError } from 'app/features/alerting/unified/api/util'; -import { InlineSecureValueWarning } from '../components/InlineSecureValueWarning'; import { PROVISIONING_URL } from '../constants'; +import { getErrorMessage } from '../utils/httpUtils'; import { RepositoryActions } from './RepositoryActions'; import { RepositoryOverview } from './RepositoryOverview'; @@ -32,11 +32,11 @@ export default function RepositoryStatusPage() { const data = query.data?.items?.[0]; const location = useLocation(); const [queryParams] = useQueryParams(); - const settings = useGetFrontendSettingsQuery(); const tab = queryParams['tab'] ?? TabSelection.Overview; const notFound = query.isError && isNotFoundError(query.error); + const hasError = query.isError && !notFound; const tabInfo = useMemo>( () => [ @@ -64,17 +64,11 @@ export default function RepositoryStatusPage() { actions={data && } > - {settings.data?.legacyStorage && ( - - - Instance is not yet running unified storage -- requires migration wizard - + {hasError && ( + + {getErrorMessage(query.error)} )} - {notFound ? ( item.metadata?.name?.includes(query)); const { instanceConnected } = checkSyncSettings(items); + const hasInstanceSyncRepo = items.some((item) => item.spec?.sync?.target === 'instance'); const getResourceCountSection = () => { if (isProvisionedInstance) { @@ -77,6 +78,17 @@ export function RepositoryList({ items }: Props) { return ( <> {getResourceCountSection()} + {hasInstanceSyncRepo && ( + + + Instance sync is currently not fully supported and breaks library panels and alerts. To use library panels + and alerts, disconnect your repository and reconnect it using folder sync instead. + + + )} {!instanceConnected && ( diff --git a/public/app/features/provisioning/Wizard/BootstrapStep.test.tsx b/public/app/features/provisioning/Wizard/BootstrapStep.test.tsx index ef16124895c..24d7e322ac3 100644 --- a/public/app/features/provisioning/Wizard/BootstrapStep.test.tsx +++ b/public/app/features/provisioning/Wizard/BootstrapStep.test.tsx @@ -32,7 +32,7 @@ function FormWrapper({ children, defaultValues }: { children: ReactNode; default url: 'https://github.com/test/repo', title: '', sync: { - target: 'instance', + target: 'folder', enabled: true, }, branch: 'main', @@ -101,12 +101,6 @@ describe('BootstrapStep', () => { (useModeOptions as jest.Mock).mockReturnValue({ enabledOptions: [ - { - target: 'instance', - label: 'Sync all resources with external storage', - description: 'Resources will be synced with external storage', - subtitle: 'Use this option if you want to sync your entire instance', - }, { target: 'folder', label: 'Sync external storage to a new Grafana folder', @@ -142,8 +136,8 @@ describe('BootstrapStep', () => { it('should render correct info for GitHub repository type', async () => { setup(); - expect(screen.getAllByText('External storage')).toHaveLength(2); - expect(screen.getAllByText('Empty')).toHaveLength(3); // Three elements should have the role "Empty" (2 external + 1 unmanaged) + expect(screen.getAllByText('External storage')).toHaveLength(1); // Only folder sync is shown by default + expect(screen.getAllByText('Empty')).toHaveLength(2); // Two elements should have the role "Empty" (1 external + 1 unmanaged) }); it('should render correct info for local file repository type', async () => { @@ -171,10 +165,12 @@ describe('BootstrapStep', () => { setup(); - expect(await screen.getAllByText('2 files')).toHaveLength(2); + expect(await screen.getAllByText('2 files')).toHaveLength(1); // Only folder sync is shown by default }); it('should display resource counts when resources exist', async () => { + // Note: Resource counts are only shown for instance sync, but instance sync is not available by default + // This test is kept for when instance sync is explicitly enabled via settings (useGetResourceStatsQuery as jest.Mock).mockReturnValue({ data: { instance: [ @@ -196,7 +192,27 @@ describe('BootstrapStep', () => { shouldSkipSync: false, }); - setup(); + // Mock settings to allow instance sync for this test + (useModeOptions as jest.Mock).mockReturnValue({ + enabledOptions: [ + { + target: 'instance', + label: 'Sync all resources with external storage', + description: 'Resources will be synced with external storage', + subtitle: 'Use this option if you want to sync your entire instance', + }, + ], + disabledOptions: [], + }); + + setup({ + settingsData: { + allowedTargets: ['instance', 'folder'], + allowImageRendering: true, + items: [], + availableRepositoryTypes: [], + }, + }); expect(await screen.findByText('7 resources')).toBeInTheDocument(); }); @@ -207,13 +223,13 @@ describe('BootstrapStep', () => { setup(); const mockUseResourceStats = require('./hooks/useResourceStats').useResourceStats; - expect(mockUseResourceStats).toHaveBeenCalledWith('test-repo', undefined); + expect(mockUseResourceStats).toHaveBeenCalledWith('test-repo', 'folder'); }); - it('should use useResourceStats hook with legacy storage flag', async () => { + it('should use useResourceStats hook with settings data', async () => { setup({ settingsData: { - legacyStorage: true, + allowedTargets: ['folder'], allowImageRendering: true, items: [], availableRepositoryTypes: [], @@ -221,16 +237,16 @@ describe('BootstrapStep', () => { }); const mockUseResourceStats = require('./hooks/useResourceStats').useResourceStats; - expect(mockUseResourceStats).toHaveBeenCalledWith('test-repo', true); + expect(mockUseResourceStats).toHaveBeenCalledWith('test-repo', 'folder'); }); }); describe('sync target options', () => { - it('should display both instance and folder options by default', async () => { + it('should display only folder option by default', async () => { setup(); - expect(await screen.findByText('Sync all resources with external storage')).toBeInTheDocument(); expect(await screen.findByText('Sync external storage to a new Grafana folder')).toBeInTheDocument(); + expect(screen.queryByText('Sync all resources with external storage')).not.toBeInTheDocument(); }); it('should only display instance option when legacy storage exists', async () => { @@ -255,7 +271,7 @@ describe('BootstrapStep', () => { setup({ settingsData: { - legacyStorage: true, + allowedTargets: ['instance', 'folder'], allowImageRendering: true, items: [], availableRepositoryTypes: [], @@ -278,15 +294,10 @@ describe('BootstrapStep', () => { }); describe('title field visibility', () => { - it('should show title field only for folder sync target', async () => { - const { user } = setup(); - - // Initially should not show title field (default is instance) - expect(screen.queryByRole('textbox', { name: /display name/i })).not.toBeInTheDocument(); - - const folderOption = await screen.findByText('Sync external storage to a new Grafana folder'); - await user.click(folderOption); + it('should show title field for folder sync target', async () => { + setup(); + // Default is folder, so title field should be visible expect(await screen.findByRole('textbox', { name: /display name/i })).toBeInTheDocument(); }); }); diff --git a/public/app/features/provisioning/Wizard/BootstrapStep.tsx b/public/app/features/provisioning/Wizard/BootstrapStep.tsx index 1dafe14c709..90a21ce5a7b 100644 --- a/public/app/features/provisioning/Wizard/BootstrapStep.tsx +++ b/public/app/features/provisioning/Wizard/BootstrapStep.tsx @@ -37,7 +37,7 @@ export const BootstrapStep = memo(function BootstrapStep({ settingsData, repoNam const repositoryType = watch('repository.type'); const { enabledOptions, disabledOptions } = useModeOptions(repoName, settingsData); const { target } = enabledOptions?.[0]; - const { resourceCountString, fileCountString, isLoading } = useResourceStats(repoName, settingsData?.legacyStorage); + const { resourceCountString, fileCountString, isLoading } = useResourceStats(repoName, selectedTarget); const styles = useStyles2(getStyles); useEffect(() => { @@ -103,7 +103,6 @@ export const BootstrapStep = memo(function BootstrapStep({ settingsData, repoNam
diff --git a/public/app/features/provisioning/Wizard/BootstrapStepResourceCounting.tsx b/public/app/features/provisioning/Wizard/BootstrapStepResourceCounting.tsx index 1c5f0f16d4f..ade52354935 100644 --- a/public/app/features/provisioning/Wizard/BootstrapStepResourceCounting.tsx +++ b/public/app/features/provisioning/Wizard/BootstrapStepResourceCounting.tsx @@ -1,40 +1,23 @@ import { Trans } from '@grafana/i18n'; import { Stack, Text } from '@grafana/ui'; -import { Target } from './types'; - export function BootstrapStepResourceCounting({ - target, fileCountString, resourceCountString, }: { - target: Target; fileCountString: string; resourceCountString: string; }) { - if (target === 'instance') { - return ( - - - External storage - {fileCountString} - - - Unmanaged resources{' '} - {resourceCountString} - - - ); - } - - if (target === 'folder') { - return ( + return ( + - External storage{' '} + External storage {fileCountString} - ); - } - - return null; + + Unmanaged resources{' '} + {resourceCountString} + + + ); } diff --git a/public/app/features/provisioning/Wizard/ProvisioningWizard.test.tsx b/public/app/features/provisioning/Wizard/ProvisioningWizard.test.tsx index 922d8609673..db49c3bb86e 100644 --- a/public/app/features/provisioning/Wizard/ProvisioningWizard.test.tsx +++ b/public/app/features/provisioning/Wizard/ProvisioningWizard.test.tsx @@ -121,7 +121,6 @@ describe('ProvisioningWizard', () => { mockUseGetFrontendSettingsQuery.mockReturnValue({ data: { items: [], - legacyStorage: false, allowImageRendering: true, availableRepositoryTypes: ['github', 'gitlab', 'bitbucket', 'git', 'local'], }, @@ -228,6 +227,15 @@ describe('ProvisioningWizard', () => { error: null, refetch: jest.fn(), }); + // Mock files to ensure sync step is not skipped for folder sync + mockUseGetRepositoryFilesQuery.mockReturnValue({ + data: { + items: [{ name: 'test.json', path: 'test.json' }], + }, + isLoading: false, + error: null, + refetch: jest.fn(), + }); const { user } = setup(); await fillConnectionForm(user, 'github', { @@ -501,10 +509,10 @@ describe('ProvisioningWizard', () => { }); it('should show button text changes based on current step', async () => { - // Mock resources to ensure sync step is not skipped - mockUseGetResourceStatsQuery.mockReturnValue({ + // Mock files to ensure sync step is not skipped for folder sync + mockUseGetRepositoryFilesQuery.mockReturnValue({ data: { - instance: [{ group: 'dashboard.grafana.app', count: 1 }], + items: [{ name: 'test.json', path: 'test.json' }], }, isLoading: false, error: null, diff --git a/public/app/features/provisioning/Wizard/ProvisioningWizard.tsx b/public/app/features/provisioning/Wizard/ProvisioningWizard.tsx index 01b8c5436c3..0950500a378 100644 --- a/public/app/features/provisioning/Wizard/ProvisioningWizard.tsx +++ b/public/app/features/provisioning/Wizard/ProvisioningWizard.tsx @@ -89,7 +89,6 @@ export const ProvisioningWizard = memo(function ProvisioningWizard({ activeStep === 'finish' && (isStepSuccess || completedSteps.includes('synchronize')); const shouldUseCancelBehavior = activeStep === 'connection' || isSyncCompleted || isFinishWithSyncCompleted; - const isLegacyStorage = Boolean(settingsData?.legacyStorage); const navigate = useNavigate(); const steps = getSteps(); @@ -118,16 +117,9 @@ export const ProvisioningWizard = memo(function ProvisioningWizard({ const [repoName = '', repoType, syncTarget] = watch(['repositoryName', 'repository.type', 'repository.sync.target']); const [submitData] = useCreateOrUpdateRepository(repoName); const [deleteRepository] = useDeleteRepositoryMutation(); - const { - shouldSkipSync, - requiresMigration, - isLoading: isResourceStatsLoading, - } = useResourceStats(repoName, isLegacyStorage, syncTarget); + const { shouldSkipSync, isLoading: isResourceStatsLoading } = useResourceStats(repoName, syncTarget); const { createSyncJob, isLoading: isCreatingSkipJob } = useCreateSyncJob({ repoName: repoName, - requiresMigration, - repoType, - isLegacyStorage, setStepStatusInfo, }); @@ -277,8 +269,8 @@ export const ProvisioningWizard = memo(function ProvisioningWizard({ if (activeStep === 'bootstrap' && canSkipSync) { nextStepIndex = currentStepIndex + 2; // Skip to finish step - // Create a pull job to initialize the repository - const job = await createSyncJob(); + // No migration needed when skipping sync + const job = await createSyncJob(false); if (!job) { return; // Don't proceed if job creation fails } @@ -412,11 +404,7 @@ export const ProvisioningWizard = memo(function ProvisioningWizard({ {activeStep === 'connection' && } {activeStep === 'bootstrap' && } {activeStep === 'synchronize' && ( - + )} {activeStep === 'finish' && }
diff --git a/public/app/features/provisioning/Wizard/SynchronizeStep.tsx b/public/app/features/provisioning/Wizard/SynchronizeStep.tsx index ba03c07f630..299fe775a0e 100644 --- a/public/app/features/provisioning/Wizard/SynchronizeStep.tsx +++ b/public/app/features/provisioning/Wizard/SynchronizeStep.tsx @@ -15,25 +15,22 @@ import { useResourceStats } from './hooks/useResourceStats'; import { WizardFormData } from './types'; export interface SynchronizeStepProps { - isLegacyStorage?: boolean; onCancel?: (repoName: string) => void; isCancelling?: boolean; } -export const SynchronizeStep = memo(function SynchronizeStep({ - isLegacyStorage, - onCancel, - isCancelling, -}: SynchronizeStepProps) { - const { getValues, register, watch } = useFormContext(); +export const SynchronizeStep = memo(function SynchronizeStep({ onCancel, isCancelling }: SynchronizeStepProps) { + const { watch, register } = useFormContext(); const { setStepStatusInfo } = useStepStatus(); - const [repoName = '', repoType] = watch(['repositoryName', 'repository.type']); - const { requiresMigration } = useResourceStats(repoName, isLegacyStorage); - const { createSyncJob, supportsHistory } = useCreateSyncJob({ + const [repoName = '', syncTarget, migrateResources] = watch([ + 'repositoryName', + 'repository.sync.target', + 'migrate.migrateResources', + ]); + const { requiresMigration } = useResourceStats(repoName, syncTarget, migrateResources); + + const { createSyncJob } = useCreateSyncJob({ repoName, - requiresMigration, - repoType, - isLegacyStorage, setStepStatusInfo, }); const [job, setJob] = useState(); @@ -70,8 +67,7 @@ export const SynchronizeStep = memo(function SynchronizeStep({ const isButtonDisabled = hasError || (checked !== undefined && isRepositoryHealthy === false) || healthStatusNotReady; const startSynchronization = async () => { - const [history] = getValues(['migrate.history']); - const response = await createSyncJob({ history }); + const response = await createSyncJob(requiresMigration); if (response) { setJob(response); } @@ -116,61 +112,108 @@ export const SynchronizeStep = memo(function SynchronizeStep({ )} {isRepositoryHealthy && ( -
    -
  • - - Resources won't be able to be created, edited, or deleted during this process. In the last step, - they will disappear. + + + + Please be aware of the following limitations. For more details, see the{' '} + + Git Sync documentation + + . -
  • -
  • - - Once provisioning is complete, resources will reappear and be managed through external storage. - -
  • -
  • - - The duration of this process depends on the number of resources involved. - -
  • -
  • + +
      +
    • + + Resources can still be created, edited, or deleted during this process, but changes may not be + exported. + +
    • +
    • + + Alerts and library panels are not supported in provisioned folders. + +
    • +
    • + + Fine-grained permissions are not supported. Default permissions apply: Admin, Editor, and Viewer roles + are preserved with their standard access levels. + +
    • +
    • + + The duration of this process depends on the number of resources involved. + +
    • + {syncTarget === 'instance' && ( +
    • + + Existing alerts and library panels will be lost and will not be usable after migration. + +
    • + )} + {syncTarget === 'folder' && ( + <> +
    • + + When migrating existing dashboards, the folder structure will be replicated in the repository. + Original folders will be emptied of dashboards but may still contain alerts or library panels. + +
    • +
    • + + You may need to manually remove or manage original folders after migration. + +
    • + + )} +
    + - Enterprise instance administrators can display an announcement banner to users. See{' '} - + Enterprise instance administrators can display an announcement banner to notify users that migration is + in progress. See{' '} + this guide {' '} for step-by-step instructions. -
  • -
+ +
)} - {supportsHistory && ( - <> - - Synchronization options - - - - Include commits for each historical value - - } - /> - - - )} - + + Options + + + + Instance sync requires all resources to be managed. Existing resources will be migrated automatically. + + ) : ( + + Import existing dashboards from all folders into the new provisioned folder + + ) + } + /> + {healthStatusNotReady ? ( <> diff --git a/public/app/features/provisioning/Wizard/hooks/useCreateSyncJob.ts b/public/app/features/provisioning/Wizard/hooks/useCreateSyncJob.ts index 94b457bf97e..1aaa7a250f0 100644 --- a/public/app/features/provisioning/Wizard/hooks/useCreateSyncJob.ts +++ b/public/app/features/provisioning/Wizard/hooks/useCreateSyncJob.ts @@ -1,28 +1,17 @@ import { t } from '@grafana/i18n'; import { useCreateRepositoryJobsMutation } from 'app/api/clients/provisioning/v0alpha1'; -import { isGitProvider } from '../../utils/repositoryTypes'; -import { RepoType, StepStatusInfo } from '../types'; +import { StepStatusInfo } from '../types'; export interface UseCreateSyncJobParams { repoName: string; - requiresMigration: boolean; - repoType: RepoType; - isLegacyStorage?: boolean; setStepStatusInfo?: (info: StepStatusInfo) => void; } -export function useCreateSyncJob({ - repoName, - requiresMigration, - repoType, - isLegacyStorage, - setStepStatusInfo, -}: UseCreateSyncJobParams) { +export function useCreateSyncJob({ repoName, setStepStatusInfo }: UseCreateSyncJobParams) { const [createJob, { isLoading }] = useCreateRepositoryJobsMutation(); - const supportsHistory = isGitProvider(repoType) && isLegacyStorage; - const createSyncJob = async (options?: { history?: boolean }) => { + const createSyncJob = async (requiresMigration: boolean) => { if (!repoName) { setStepStatusInfo?.({ status: 'error', @@ -36,9 +25,7 @@ export function useCreateSyncJob({ const jobSpec = requiresMigration ? { - migrate: { - history: (options?.history || false) && supportsHistory, - }, + migrate: {}, } : { pull: { @@ -59,7 +46,7 @@ export function useCreateSyncJob({ return null; } - setStepStatusInfo?.({ status: 'success' }); + // Job status will be tracked by JobStatus component, keep status as 'running' return response; } catch (error) { setStepStatusInfo?.({ @@ -73,6 +60,5 @@ export function useCreateSyncJob({ return { createSyncJob, isLoading, - supportsHistory, }; } diff --git a/public/app/features/provisioning/Wizard/hooks/useModeOptions.ts b/public/app/features/provisioning/Wizard/hooks/useModeOptions.ts index b642c1ad41b..3d288ab487d 100644 --- a/public/app/features/provisioning/Wizard/hooks/useModeOptions.ts +++ b/public/app/features/provisioning/Wizard/hooks/useModeOptions.ts @@ -10,15 +10,14 @@ import { ModeOption } from '../types'; */ function filterModeOptions(modeOptions: ModeOption[], repoName: string, settings?: RepositoryViewList): ModeOption[] { const folderConnected = settings?.items?.some((item) => item.target === 'folder' && item.name !== repoName); - const allowedTargets = settings?.allowedTargets || ['instance', 'folder']; - const legacyStorageEnabled = settings?.legacyStorage; + const allowedTargets = settings?.allowedTargets || ['folder']; return modeOptions.map((option) => { if (option.disabled) { return option; } - const disabledReason = resolveDisabledReason(option, { allowedTargets, folderConnected, legacyStorageEnabled }); + const disabledReason = resolveDisabledReason(option, { allowedTargets, folderConnected }); if (!disabledReason) { return option; @@ -35,7 +34,6 @@ function filterModeOptions(modeOptions: ModeOption[], repoName: string, settings type DisableContext = { allowedTargets: string[]; folderConnected?: boolean; - legacyStorageEnabled?: boolean; }; // Returns a translated reason why the given mode option should be disabled. @@ -47,13 +45,6 @@ function resolveDisabledReason(option: ModeOption, context: DisableContext) { ); } - if (context.legacyStorageEnabled && option.target !== 'instance') { - return t( - 'provisioning.mode-options.disabled.legacy-storage', - 'Legacy storage mode only supports syncing the entire Grafana instance.' - ); - } - if (option.target === 'instance' && context.folderConnected) { return t( 'provisioning.mode-options.disabled.folder-connected', diff --git a/public/app/features/provisioning/Wizard/hooks/useResourceStats.ts b/public/app/features/provisioning/Wizard/hooks/useResourceStats.ts index 49573b4e793..5daaed87f95 100644 --- a/public/app/features/provisioning/Wizard/hooks/useResourceStats.ts +++ b/public/app/features/provisioning/Wizard/hooks/useResourceStats.ts @@ -100,7 +100,7 @@ function getResourceStats(files?: GetRepositoryFilesApiResponse, stats?: GetReso /** * Hook that provides resource statistics and sync logic */ -export function useResourceStats(repoName?: string, isLegacyStorage?: boolean, syncTarget?: RepositoryView['target']) { +export function useResourceStats(repoName?: string, syncTarget?: RepositoryView['target'], migrateResources?: boolean) { const resourceStatsQuery = useGetResourceStatsQuery(repoName ? undefined : skipToken); const filesQuery = useGetRepositoryFilesQuery(repoName ? { name: repoName } : skipToken); @@ -121,8 +121,11 @@ export function useResourceStats(repoName?: string, isLegacyStorage?: boolean, s }; }, [resourceStatsQuery.data]); - const requiresMigration = isLegacyStorage || resourceCount > 0; - const shouldSkipSync = !isLegacyStorage && (resourceCount === 0 || syncTarget === 'folder') && fileCount === 0; + // Calculate requiresMigration based on sync target and user selection + // For instance sync: migrate if there are resources (checkbox is disabled and always true) + // For folder sync: only migrate if user explicitly opts in via checkbox + const requiresMigration = syncTarget === 'instance' ? resourceCount > 0 : (migrateResources ?? false); + const shouldSkipSync = (resourceCount === 0 || syncTarget === 'folder') && fileCount === 0; // Format display strings const resourceCountDisplay = diff --git a/public/app/features/provisioning/Wizard/types.ts b/public/app/features/provisioning/Wizard/types.ts index 0dc2f001a43..34ee246da04 100644 --- a/public/app/features/provisioning/Wizard/types.ts +++ b/public/app/features/provisioning/Wizard/types.ts @@ -9,6 +9,7 @@ export type RepoType = RepositorySpec['type']; export interface MigrateFormData { history: boolean; identifier: boolean; + migrateResources?: boolean; } export interface WizardFormData { diff --git a/public/app/features/provisioning/components/Dashboards/SaveProvisionedDashboardForm.test.tsx b/public/app/features/provisioning/components/Dashboards/SaveProvisionedDashboardForm.test.tsx index bca9ca1939c..69a94c5e9ae 100644 --- a/public/app/features/provisioning/components/Dashboards/SaveProvisionedDashboardForm.test.tsx +++ b/public/app/features/provisioning/components/Dashboards/SaveProvisionedDashboardForm.test.tsx @@ -9,7 +9,7 @@ import { DashboardScene } from 'app/features/dashboard-scene/scene/DashboardScen import { validationSrv } from 'app/features/manage-dashboards/services/ValidationSrv'; import { useCreateOrUpdateRepositoryFile } from 'app/features/provisioning/hooks/useCreateOrUpdateRepositoryFile'; -import { SaveProvisionedDashboardForm, Props } from './SaveProvisionedDashboardForm'; +import { Props, SaveProvisionedDashboardForm } from './SaveProvisionedDashboardForm'; jest.mock('@grafana/runtime', () => { const actual = jest.requireActual('@grafana/runtime'); @@ -118,6 +118,7 @@ function setup(props: Partial = {}) { closeModal: jest.fn(), getSaveAsModel: jest.fn().mockReturnValue(mockDashboard), setManager: jest.fn(), + getRawJsonFromEditor: jest.fn().mockReturnValue(undefined), } as unknown as DashboardScene, drawer: { onClose: jest.fn(), @@ -291,6 +292,7 @@ describe('SaveProvisionedDashboardForm', () => { closeModal: jest.fn(), getSaveResource: jest.fn().mockReturnValue(updatedDashboard), setManager: jest.fn(), + getRawJsonFromEditor: jest.fn().mockReturnValue(undefined), } as unknown as DashboardScene, }); @@ -385,6 +387,7 @@ describe('SaveProvisionedDashboardForm', () => { closeModal: jest.fn(), getSaveAsModel: jest.fn().mockReturnValue({}), setManager: jest.fn(), + getRawJsonFromEditor: jest.fn().mockReturnValue(undefined), } as unknown as DashboardScene, }); @@ -431,6 +434,7 @@ describe('SaveProvisionedDashboardForm', () => { closeModal: jest.fn(), getSaveAsModel: jest.fn().mockReturnValue({}), setManager: jest.fn(), + getRawJsonFromEditor: jest.fn().mockReturnValue(undefined), } as unknown as DashboardScene, }); @@ -445,4 +449,70 @@ describe('SaveProvisionedDashboardForm', () => { expect(saveButton).toBeEnabled(); }); }); + + it('should save dashboard with raw JSON from editor', async () => { + const mockAction = jest.fn(); + const mockRequest = { ...mockRequestBase, isSuccess: true }; + (useCreateOrUpdateRepositoryFile as jest.Mock).mockReturnValue([mockAction, mockRequest]); + + const rawJson = JSON.stringify({ + title: 'Raw JSON Dashboard', + panels: [], + schemaVersion: 36, + }); + + const dashboardFromRawJson = { + apiVersion: 'dashboard.grafana.app/v1alpha1', + kind: 'Dashboard', + metadata: { + generateName: 'p', + name: undefined, + }, + spec: { + title: 'Raw JSON Dashboard', + panels: [], + schemaVersion: 36, + }, + }; + + const { user } = setup({ + dashboard: { + useState: () => ({ + meta: { + folderUid: 'folder-uid', + slug: 'test-dashboard', + }, + title: 'Test Dashboard', + description: 'Test Description', + isDirty: false, + }), + setState: jest.fn(), + closeModal: jest.fn(), + getSaveAsModel: jest.fn().mockReturnValue({}), + getSaveResource: jest.fn().mockReturnValue(dashboardFromRawJson), + getSaveResourceFromSpec: jest.fn().mockReturnValue(dashboardFromRawJson), + setManager: jest.fn(), + getRawJsonFromEditor: jest.fn().mockReturnValue(rawJson), + } as unknown as DashboardScene, + }); + + const saveButton = screen.getByRole('button', { name: /save/i }); + expect(saveButton).toBeEnabled(); + + const commentInput = screen.getByRole('textbox', { name: /comment/i }); + await user.clear(commentInput); + await user.type(commentInput, 'Save with raw JSON'); + + await user.click(saveButton); + + await waitFor(() => { + expect(mockAction).toHaveBeenCalledWith({ + ref: 'dashboard/2023-01-01-abcde', + name: 'test-repo', + path: 'test-dashboard.json', + message: 'Save with raw JSON', + body: dashboardFromRawJson, + }); + }); + }); }); diff --git a/public/app/features/provisioning/components/Dashboards/SaveProvisionedDashboardForm.tsx b/public/app/features/provisioning/components/Dashboards/SaveProvisionedDashboardForm.tsx index 219bb521111..3fee476b189 100644 --- a/public/app/features/provisioning/components/Dashboards/SaveProvisionedDashboardForm.tsx +++ b/public/app/features/provisioning/components/Dashboards/SaveProvisionedDashboardForm.tsx @@ -12,6 +12,7 @@ import kbn from 'app/core/utils/kbn'; import { Resource } from 'app/features/apiserver/types'; import { SaveDashboardFormCommonOptions } from 'app/features/dashboard-scene/saving/SaveDashboardForm'; import { getDashboardUrl } from 'app/features/dashboard-scene/utils/getDashboardUrl'; +import { dashboardWatcher } from 'app/features/live/dashboard/dashboardWatcher'; import { validationSrv } from 'app/features/manage-dashboards/services/ValidationSrv'; import { PROVISIONING_URL } from 'app/features/provisioning/constants'; import { useCreateOrUpdateRepositoryFile } from 'app/features/provisioning/hooks/useCreateOrUpdateRepositoryFile'; @@ -64,8 +65,9 @@ export function SaveProvisionedDashboardForm({ register, formState: { dirtyFields }, } = methods; - // button enabled if form comment is dirty or dashboard state is dirty - const isDirtyState = Boolean(dirtyFields.comment) || isDirty; + // button enabled if form comment is dirty or dashboard state is dirty or raw JSON was provided from editor + const rawDashboardJSON = dashboard.getRawJsonFromEditor(); + const isDirtyState = Boolean(dirtyFields.comment) || isDirty || Boolean(rawDashboardJSON); const [workflow, ref, path] = watch(['workflow', 'ref', 'path']); // Update the form if default values change @@ -190,13 +192,15 @@ export function SaveProvisionedDashboardForm({ const message = comment || `Save dashboard: ${dashboard.state.title}`; - const body = dashboard.getSaveResource({ - isNew, - title, - description, - copyTags, - saveAsCopy, - }); + const body = rawDashboardJSON + ? dashboard.getSaveResourceFromSpec(rawDashboardJSON) + : dashboard.getSaveResource({ + isNew, + title, + description, + copyTags, + saveAsCopy, + }); reportInteraction('grafana_provisioning_dashboard_save_submitted', { workflow, @@ -204,6 +208,9 @@ export function SaveProvisionedDashboardForm({ repositoryType: repository?.type ?? 'unknown', }); + // ignore incoming save events + dashboardWatcher.ignoreNextSave(); + createOrUpdateFile({ // Skip adding ref to the default branch request ref: ref === repository?.branch ? undefined : ref, diff --git a/public/app/features/provisioning/components/InlineSecureValueWarning.tsx b/public/app/features/provisioning/components/InlineSecureValueWarning.tsx deleted file mode 100644 index 9ed4a23b7b1..00000000000 --- a/public/app/features/provisioning/components/InlineSecureValueWarning.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import { t } from '@grafana/i18n'; -import { Alert } from '@grafana/ui'; -import { Repository } from 'app/api/clients/provisioning/v0alpha1'; - -interface Props { - repo?: Repository; - items?: Repository[]; -} - -// TODO: remove this after 12.2 -export function InlineSecureValueWarning({ repo, items }: Props) { - const isRepoValid = (r?: Repository) => r?.spec?.type === 'local' || !!r?.secure?.token?.name; - - if (isRepoValid(repo)) { - return null; - } - - // When a list is passed in, show an error if anything is missing - if (items?.every(isRepoValid)) { - return null; - } - - return ( - - ); -} diff --git a/public/app/features/provisioning/utils/httpUtils.ts b/public/app/features/provisioning/utils/httpUtils.ts index 6e9cbc4e933..3fb6bd7704f 100644 --- a/public/app/features/provisioning/utils/httpUtils.ts +++ b/public/app/features/provisioning/utils/httpUtils.ts @@ -1,4 +1,5 @@ import { t } from '@grafana/i18n'; +import { isFetchError } from '@grafana/runtime'; import { HttpError, isHttpError } from '../guards'; @@ -187,6 +188,8 @@ export function getErrorMessage(err: unknown) { } else if (err.message) { errorMessage = err.message; } + } else if (isFetchError(err)) { + errorMessage = err.data.message; } return errorMessage; diff --git a/public/app/features/query/components/QueryEditorRow.test.tsx b/public/app/features/query/components/QueryEditorRow.test.tsx index f839e570819..13be75a8fcb 100644 --- a/public/app/features/query/components/QueryEditorRow.test.tsx +++ b/public/app/features/query/components/QueryEditorRow.test.tsx @@ -461,8 +461,7 @@ describe('QueryEditorRow', () => { render(); await waitFor(() => { - expect(screen.queryByText('Save query')).not.toBeInTheDocument(); - expect(screen.queryByText('Replace with saved query')).not.toBeInTheDocument(); + expect(screen.queryByText('Saved queries')).not.toBeInTheDocument(); }); }); diff --git a/public/app/features/query/components/QueryEditorRow.tsx b/public/app/features/query/components/QueryEditorRow.tsx index b474d0293f9..5cc7f3467d3 100644 --- a/public/app/features/query/components/QueryEditorRow.tsx +++ b/public/app/features/query/components/QueryEditorRow.tsx @@ -1,7 +1,7 @@ import classNames from 'classnames'; import { cloneDeep, filter, uniqBy, uniqueId } from 'lodash'; import pluralize from 'pluralize'; -import { PureComponent, ReactNode, type JSX } from 'react'; +import { PureComponent, ReactNode, type JSX, createRef } from 'react'; import { CoreApp, @@ -88,6 +88,7 @@ interface State { export class QueryEditorRow extends PureComponent, State> { dataSourceSrv = getDataSourceSrv(); id = ''; + editorRef = createRef(); state: State = { datasource: null, @@ -419,6 +420,7 @@ export class QueryEditorRow extends PureComponent )} @@ -542,7 +544,7 @@ export class QueryEditorRow extends PureComponent +
{queryLibraryRef && ( void; onSelectQuery: (query: DataQuery) => void; datasourceFilters: string[]; + parentRef: React.RefObject; }) { const { renderSavedQueryButtons } = useQueryLibraryContext(); - return renderSavedQueryButtons(props.query, props.app, props.onUpdateSuccess, props.onSelectQuery); + return renderSavedQueryButtons( + props.query, + props.app, + props.onUpdateSuccess, + props.onSelectQuery, + undefined, + props.parentRef + ); } // Will render editing header only if query library is enabled diff --git a/public/app/features/scopes/selector/ScopesTree.test.tsx b/public/app/features/scopes/selector/ScopesTree.test.tsx new file mode 100644 index 00000000000..2ac4b647a5c --- /dev/null +++ b/public/app/features/scopes/selector/ScopesTree.test.tsx @@ -0,0 +1,248 @@ +import { render, screen } from '@testing-library/react'; + +import { ScopeNode } from '@grafana/data'; + +import { ScopesTree } from './ScopesTree'; +import { NodesMap, SelectedScope, TreeNode } from './types'; + +// Mock the ScopesContextProvider hook since it requires a full context setup +jest.mock('../ScopesContextProvider', () => ({ + useScopesServices: () => ({ + scopesSelectorService: { + closeAndApply: jest.fn(), + }, + }), +})); + +describe('ScopesTree', () => { + const mockFilterNode = jest.fn(); + const mockSelectScope = jest.fn(); + const mockDeselectScope = jest.fn(); + const mockToggleExpandedNode = jest.fn(); + + const createMockScopeNode = (name: string, parentName?: string): ScopeNode => ({ + metadata: { name }, + spec: { + title: `Title ${name}`, + nodeType: 'leaf', + linkType: 'scope', + linkId: `scope-${name}`, + parentName: parentName ?? '', + }, + }); + + const defaultScopeNodes: NodesMap = { + 'parent-container': { + metadata: { name: 'parent-container' }, + spec: { + title: 'Parent Container', + nodeType: 'container', + parentName: '', + }, + }, + 'child-1': createMockScopeNode('child-1', 'parent-container'), + 'child-2': createMockScopeNode('child-2', 'parent-container'), + }; + + const defaultTree: TreeNode = { + scopeNodeId: 'parent-container', + expanded: true, + query: '', + children: { + 'child-1': { scopeNodeId: 'child-1', expanded: false, query: '' }, + 'child-2': { scopeNodeId: 'child-2', expanded: false, query: '' }, + }, + childrenLoaded: true, + }; + + const defaultProps = { + tree: defaultTree, + loadingNodeName: undefined, + selectedScopes: [] as SelectedScope[], + scopeNodes: defaultScopeNodes, + filterNode: mockFilterNode, + selectScope: mockSelectScope, + deselectScope: mockDeselectScope, + toggleExpandedNode: mockToggleExpandedNode, + }; + + beforeEach(() => { + jest.clearAllMocks(); + }); + + describe('selectedNodesToShow logic', () => { + it('should not show selectedNodesToShow when no scopes are selected', () => { + render(); + + // Both child-1 and child-2 should be visible in the regular children list + expect(screen.getByText('Title child-1')).toBeInTheDocument(); + expect(screen.getByText('Title child-2')).toBeInTheDocument(); + }); + + it('should only consider first selected scope for selectedNodesToShow', () => { + const selectedScopes: SelectedScope[] = [ + { scopeId: 'scope-1', scopeNodeId: 'child-1' }, + { scopeId: 'scope-2', scopeNodeId: 'child-2' }, + ]; + + // Use a tree where child-1 is NOT in the children (to trigger selectedNodesToShow) + const tree: TreeNode = { + scopeNodeId: 'parent-container', + expanded: true, + query: '', + children: { + // child-1 is NOT here, so it should appear in selectedNodesToShow + 'child-2': { scopeNodeId: 'child-2', expanded: false, query: '' }, + }, + childrenLoaded: true, + }; + + render(); + + // child-1 should be shown (from selectedNodesToShow - only first scope is considered) + expect(screen.getByText('Title child-1')).toBeInTheDocument(); + // child-2 should also be shown (from regular children) + expect(screen.getByText('Title child-2')).toBeInTheDocument(); + }); + + it('should not show selectedNodesToShow when first scope has no scopeNodeId', () => { + const selectedScopes: SelectedScope[] = [ + { scopeId: 'scope-1', scopeNodeId: undefined }, // No scopeNodeId + { scopeId: 'scope-2', scopeNodeId: 'child-2' }, + ]; + + // Tree with no children to make it obvious if selectedNodesToShow is populated + const tree: TreeNode = { + scopeNodeId: 'parent-container', + expanded: true, + query: '', + children: {}, + childrenLoaded: true, + }; + + render(); + + // child-2 should NOT appear because only first scope is considered and it has no scopeNodeId + expect(screen.queryByText('Title child-2')).not.toBeInTheDocument(); + }); + + it('should not show selectedNodesToShow when first scope node is not in scopeNodes cache', () => { + const selectedScopes: SelectedScope[] = [ + { scopeId: 'scope-1', scopeNodeId: 'missing-node' }, // Node not in scopeNodes + { scopeId: 'scope-2', scopeNodeId: 'child-2' }, + ]; + + // Tree with no children + const tree: TreeNode = { + scopeNodeId: 'parent-container', + expanded: true, + query: '', + children: {}, + childrenLoaded: true, + }; + + render(); + + // Neither should appear since first scope's node is missing from cache + expect(screen.queryByText('Title missing-node')).not.toBeInTheDocument(); + expect(screen.queryByText('Title child-2')).not.toBeInTheDocument(); + }); + + it('should not show selectedNodesToShow when tree scopeNodeId does not match first scope parent', () => { + const selectedScopes: SelectedScope[] = [ + { scopeId: 'scope-1', scopeNodeId: 'child-1' }, // child-1's parent is 'parent-container' + ]; + + // Tree with different scopeNodeId + const tree: TreeNode = { + scopeNodeId: 'different-container', // Different from child-1's parent + expanded: true, + query: '', + children: {}, + childrenLoaded: true, + }; + + const scopeNodes: NodesMap = { + ...defaultScopeNodes, + 'different-container': { + metadata: { name: 'different-container' }, + spec: { title: 'Different', nodeType: 'container', parentName: '' }, + }, + }; + + render(); + + // child-1 should NOT appear since tree's scopeNodeId doesn't match child-1's parent + expect(screen.queryByText('Title child-1')).not.toBeInTheDocument(); + }); + + it('should not duplicate scope in selectedNodesToShow if already in children', () => { + const selectedScopes: SelectedScope[] = [{ scopeId: 'scope-1', scopeNodeId: 'child-1' }]; + + // Tree already has child-1 in children + const tree: TreeNode = { + scopeNodeId: 'parent-container', + expanded: true, + query: '', + children: { + 'child-1': { scopeNodeId: 'child-1', expanded: false, query: '' }, + 'child-2': { scopeNodeId: 'child-2', expanded: false, query: '' }, + }, + childrenLoaded: true, + }; + + render(); + + // child-1 should appear exactly once (in regular children, not duplicated) + const child1Elements = screen.getAllByText('Title child-1'); + expect(child1Elements).toHaveLength(1); + }); + }); + + describe('graceful handling of missing data', () => { + it('should not crash when scopeNodes is empty', () => { + const tree: TreeNode = { + scopeNodeId: '', + expanded: true, + query: '', + children: {}, + childrenLoaded: true, + }; + + render(); + + // Should render without crashing - search input should be present + expect(screen.getByRole('combobox')).toBeInTheDocument(); + }); + + it('should handle tree with children referencing missing nodes', () => { + const tree: TreeNode = { + scopeNodeId: 'parent-container', + expanded: true, + query: '', + children: { + 'existing-node': { scopeNodeId: 'existing-node', expanded: false, query: '' }, + 'missing-node': { scopeNodeId: 'missing-node', expanded: false, query: '' }, + }, + childrenLoaded: true, + }; + + const scopeNodes: NodesMap = { + 'parent-container': { + metadata: { name: 'parent-container' }, + spec: { title: 'Parent', nodeType: 'container', parentName: '' }, + }, + 'existing-node': createMockScopeNode('existing-node', 'parent-container'), + // 'missing-node' intentionally not included + }; + + // Should render without crashing + render(); + + // Existing node should be rendered + expect(screen.getByText('Title existing-node')).toBeInTheDocument(); + // Missing node should be gracefully skipped + expect(screen.queryByText('Title missing-node')).not.toBeInTheDocument(); + }); + }); +}); diff --git a/public/app/features/scopes/selector/ScopesTree.tsx b/public/app/features/scopes/selector/ScopesTree.tsx index dd2fd61184c..8178acd3368 100644 --- a/public/app/features/scopes/selector/ScopesTree.tsx +++ b/public/app/features/scopes/selector/ScopesTree.tsx @@ -55,21 +55,22 @@ export function ScopesTree({ const anyChildExpanded = childrenArray.some(({ expanded }) => expanded); // Nodes that are already selected (not applied) are always shown if we are in their category, even if they are - // filtered out by query filter + // filtered out by query filter. Only consider the first selected scope for this display logic. let selectedNodesToShow: TreeNode[] = []; - if (selectedScopes.length > 0 && selectedScopes[0].scopeNodeId) { - if (tree.scopeNodeId === scopeNodes[selectedScopes[0].scopeNodeId]?.spec.parentName) { - selectedNodesToShow = selectedScopes - // We filter out those which are still shown in the normal list of results - .filter((s) => !childrenArray.map((c) => c.scopeNodeId).includes(s.scopeNodeId!)) - .map((s) => ({ - // Because we had to check the parent with the use of scopeNodeId we know we have it. (we may not have it - // if the selected scopes are from url persistence, in which case we don't show them) - scopeNodeId: s.scopeNodeId!, - query: '', - expanded: false, - })); - } + const firstSelectedScope = selectedScopes[0]; + if ( + firstSelectedScope?.scopeNodeId && + scopeNodes[firstSelectedScope.scopeNodeId] && + tree.scopeNodeId === scopeNodes[firstSelectedScope.scopeNodeId]?.spec.parentName && + !childrenArray.map((c) => c.scopeNodeId).includes(firstSelectedScope.scopeNodeId) + ) { + selectedNodesToShow = [ + { + scopeNodeId: firstSelectedScope.scopeNodeId, + query: '', + expanded: false, + }, + ]; } const { highlightedId, ariaActiveDescendant, enableHighlighting, disableHighlighting } = useScopesHighlighting({ diff --git a/public/app/features/scopes/selector/ScopesTreeHeadline.tsx b/public/app/features/scopes/selector/ScopesTreeHeadline.tsx index 755fadf64b5..44ed80ce1bf 100644 --- a/public/app/features/scopes/selector/ScopesTreeHeadline.tsx +++ b/public/app/features/scopes/selector/ScopesTreeHeadline.tsx @@ -18,7 +18,7 @@ export function ScopesTreeHeadline({ anyChildExpanded, query, resultsNodes, scop if ( anyChildExpanded || - (resultsNodes.some((n) => scopeNodes[n.scopeNodeId].spec.nodeType === 'container') && !query) + (resultsNodes.some((n) => scopeNodes[n.scopeNodeId]?.spec.nodeType === 'container') && !query) ) { return null; } diff --git a/public/app/features/scopes/selector/ScopesTreeItemList.test.tsx b/public/app/features/scopes/selector/ScopesTreeItemList.test.tsx new file mode 100644 index 00000000000..a93bb456a83 --- /dev/null +++ b/public/app/features/scopes/selector/ScopesTreeItemList.test.tsx @@ -0,0 +1,136 @@ +import { render, screen } from '@testing-library/react'; + +import { ScopeNode } from '@grafana/data'; + +import { ScopesTreeItemList } from './ScopesTreeItemList'; +import { NodesMap, SelectedScope, TreeNode } from './types'; + +// Mock the ScopesContextProvider hook since it requires a full context setup +jest.mock('../ScopesContextProvider', () => ({ + useScopesServices: () => ({ + scopesSelectorService: { + closeAndApply: jest.fn(), + }, + }), +})); + +describe('ScopesTreeItemList', () => { + const mockFilterNode = jest.fn(); + const mockSelectScope = jest.fn(); + const mockDeselectScope = jest.fn(); + const mockToggleExpandedNode = jest.fn(); + + const defaultProps = { + anyChildExpanded: false, + lastExpandedNode: false, + loadingNodeName: undefined, + maxHeight: '100%', + selectedScopes: [] as SelectedScope[], + filterNode: mockFilterNode, + selectScope: mockSelectScope, + deselectScope: mockDeselectScope, + highlightedId: undefined, + id: 'test-tree', + toggleExpandedNode: mockToggleExpandedNode, + }; + + const createMockScopeNode = (name: string, parentName = 'parent'): ScopeNode => ({ + metadata: { name }, + spec: { + title: `Title ${name}`, + nodeType: 'leaf', + linkType: 'scope', + linkId: `scope-${name}`, + parentName, + }, + }); + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('should render nothing when items array is empty', () => { + const { container } = render(); + + expect(container.firstChild).toBeNull(); + }); + + it('should render tree items when nodes are available', () => { + const items: TreeNode[] = [ + { scopeNodeId: 'node-1', expanded: false, query: '' }, + { scopeNodeId: 'node-2', expanded: false, query: '' }, + ]; + + const scopeNodes: NodesMap = { + 'node-1': createMockScopeNode('node-1'), + 'node-2': createMockScopeNode('node-2'), + parent: { + metadata: { name: 'parent' }, + spec: { title: 'Parent', nodeType: 'container', parentName: '' }, + }, + }; + + render(); + + expect(screen.getByText('Title node-1')).toBeInTheDocument(); + expect(screen.getByText('Title node-2')).toBeInTheDocument(); + }); + + it('should skip rendering items when node data is not available in scopeNodes', () => { + const items: TreeNode[] = [ + { scopeNodeId: 'node-1', expanded: false, query: '' }, + { scopeNodeId: 'missing-node', expanded: false, query: '' }, // This node doesn't exist in scopeNodes + { scopeNodeId: 'node-2', expanded: false, query: '' }, + ]; + + const scopeNodes: NodesMap = { + 'node-1': createMockScopeNode('node-1'), + 'node-2': createMockScopeNode('node-2'), + parent: { + metadata: { name: 'parent' }, + spec: { title: 'Parent', nodeType: 'container', parentName: '' }, + }, + // 'missing-node' is intentionally not included + }; + + render(); + + // Should render the available nodes + expect(screen.getByText('Title node-1')).toBeInTheDocument(); + expect(screen.getByText('Title node-2')).toBeInTheDocument(); + + // Should NOT crash and should skip the missing node + expect(screen.queryByText('Title missing-node')).not.toBeInTheDocument(); + }); + + it('should handle all items having missing node data gracefully', () => { + const items: TreeNode[] = [ + { scopeNodeId: 'missing-1', expanded: false, query: '' }, + { scopeNodeId: 'missing-2', expanded: false, query: '' }, + ]; + + const scopeNodes: NodesMap = {}; + + // Should not crash + const { container } = render(); + + // Container should have the tree div but no visible items rendered inside + expect(container.querySelector('[role="tree"]')).toBeInTheDocument(); + expect(screen.queryByRole('treeitem')).not.toBeInTheDocument(); + }); + + it('should handle empty string scopeNodeId gracefully', () => { + const items: TreeNode[] = [ + { scopeNodeId: '', expanded: false, query: '' }, // Empty string scopeNodeId + ]; + + const scopeNodes: NodesMap = {}; + + // Should not crash + const { container } = render(); + + // Should have tree container but no items + expect(container.querySelector('[role="tree"]')).toBeInTheDocument(); + expect(screen.queryByRole('treeitem')).not.toBeInTheDocument(); + }); +}); diff --git a/public/app/features/scopes/selector/ScopesTreeItemList.tsx b/public/app/features/scopes/selector/ScopesTreeItemList.tsx index 33d3a4e2b53..e28a8cda214 100644 --- a/public/app/features/scopes/selector/ScopesTreeItemList.tsx +++ b/public/app/features/scopes/selector/ScopesTreeItemList.tsx @@ -47,15 +47,20 @@ export function ScopesTreeItemList({ const children = (
{items.map((childNode) => { + const node = scopeNodes[childNode.scopeNodeId]; + // Skip rendering if node data isn't available + if (!node) { + return null; + } const selected = - isNodeSelectable(scopeNodes[childNode.scopeNodeId]) && + isNodeSelectable(node) && selectedScopes.some((s) => { if (s.scopeNodeId) { // If we have scopeNodeId we only match based on that so even if the actual scope is the same we don't // mark different scopeNode as selected. return s.scopeNodeId === childNode.scopeNodeId; } else { - return s.scopeId === scopeNodes[childNode.scopeNodeId]?.spec.linkId; + return s.scopeId === node.spec.linkId; } }); return ( diff --git a/public/app/features/search/hooks/useDashboardLocationInfo.tsx b/public/app/features/search/hooks/useDashboardLocationInfo.tsx new file mode 100644 index 00000000000..10c4f80c62e --- /dev/null +++ b/public/app/features/search/hooks/useDashboardLocationInfo.tsx @@ -0,0 +1,29 @@ +import { useAsync } from 'react-use'; + +import { getGrafanaSearcher } from 'app/features/search/service/searcher'; +import { LocationInfo } from 'app/features/search/service/types'; + +/** + * + * @description Hook to fetch dashboard location info (folders). + * @returns An object containing a mapping of folder UIDs to LocationInfo, loading state, and error state. + */ +export function useDashboardLocationInfo(enabled: boolean) { + const searcher = getGrafanaSearcher(); + const { + value: foldersByUid, + loading, + error, + } = useAsync(async (): Promise> => { + if (!enabled) { + return {}; + } + return searcher.getLocationInfo(); + }, [enabled, searcher]); + + return { + foldersByUid: foldersByUid ?? {}, + loading, + error, + }; +} diff --git a/public/app/features/serviceaccounts/components/ServiceAccountTokensTable.tsx b/public/app/features/serviceaccounts/components/ServiceAccountTokensTable.tsx index c0e6c8ccd0b..064fa504946 100644 --- a/public/app/features/serviceaccounts/components/ServiceAccountTokensTable.tsx +++ b/public/app/features/serviceaccounts/components/ServiceAccountTokensTable.tsx @@ -1,7 +1,7 @@ import { css, cx } from '@emotion/css'; import type { JSX } from 'react'; -import { dateTimeFormat, GrafanaTheme2, TimeZone } from '@grafana/data'; +import { dateTimeFormat, GrafanaTheme2, TimeZone, dateTimeFormatTimeAgo } from '@grafana/data'; import { Trans, t } from '@grafana/i18n'; import { DeleteButton, Icon, Tooltip, useStyles2, useTheme2 } from '@grafana/ui'; import { ApiKey } from 'app/types/apiKeys'; @@ -84,9 +84,9 @@ function formatDate(timeZone: TimeZone, expiration?: string): string { } function formatSecondsLeftUntilExpiration(secondsUntilExpiration: number): string { - const days = Math.ceil(secondsUntilExpiration / (3600 * 24)); - const daysFormat = days > 1 ? `${days} days` : `${days} day`; - return `Expires in ${daysFormat}`; + const expirationTime = Date.now() + secondsUntilExpiration * 1000; + const daysFormat = dateTimeFormatTimeAgo(expirationTime, { timeZone: 'browser' }); + return `Expires ${daysFormat}`; } const TokenRevoked = () => { @@ -126,14 +126,14 @@ const TokenExpiration = ({ timeZone, token }: TokenExpirationProps) => { } if (token.secondsUntilExpiration) { return ( - + {formatSecondsLeftUntilExpiration(token.secondsUntilExpiration)} ); } if (token.hasExpired) { return ( - + Expired ) => { - return render(, { - preloadedState: { - team: { - groups: [], - ...preloadedTeamState, - }, - }, - }); +const setup = () => { + return render(); }; describe('TeamGroupSync', () => { @@ -29,28 +20,37 @@ describe('TeamGroupSync', () => { expect(screen.getByRole('heading', { name: /External group sync/i })).toBeInTheDocument(); }); - it('should render groups table', () => { - setup({ groups: getMockTeamGroups(3) }); - expect(screen.getAllByRole('row')).toHaveLength(4); // 3 items plus table header + it('should render groups table', async () => { + setup(); + expect(await screen.findAllByRole('row')).toHaveLength(MOCK_TEAM_GROUPS.length + 1); // items plus table header }); it('should call add group', async () => { const { user } = setup(); - // Empty List CTA "Add group" button is second in the DOM order - await user.click(screen.getAllByRole('button', { name: /add group/i })[1]); + // Wait for the groups to load so the "Add group" button appears + await screen.findAllByRole('row'); + + await user.click(screen.getAllByRole('button', { name: /add group/i })[0]); expect(screen.getByRole('textbox', { name: /add external group/i })).toBeVisible(); await user.type(screen.getByRole('textbox', { name: /add external group/i }), 'test/group'); - await user.click(screen.getAllByRole('button', { name: /add group/i })[0]); + await user.click(screen.getAllByRole('button', { name: /add group/i })[1]); - expect(screen.getByRole('row', { name: /test\/group/i })).toBeInTheDocument(); + expect(await screen.findByRole('row', { name: /test\/group/i })).toBeInTheDocument(); }); it('should remove group', async () => { - const mockGroup: TeamGroup = { teamId: 1, groupId: 'someGroup' }; - const { user } = setup({ groups: [mockGroup] }); - await user.click(screen.getByRole('button', { name: 'Remove group someGroup' })); + const { user } = setup(); + const groupToRemove = MOCK_TEAM_GROUPS[0].groupId; - expect(screen.queryByRole('row', { name: /test\/group/i })).not.toBeInTheDocument(); + // Wait for group to be rendered + await screen.findByRole('row', { name: new RegExp(groupToRemove, 'i') }); + + // Remove group + await user.click(screen.getByRole('button', { name: `Remove group ${groupToRemove}` })); + + await waitFor(() => + expect(screen.queryByRole('row', { name: new RegExp(groupToRemove, 'i') })).not.toBeInTheDocument() + ); }); }); diff --git a/public/app/features/teams/TeamGroupSync.tsx b/public/app/features/teams/TeamGroupSync.tsx index 37887ee8d6a..66a227527dc 100644 --- a/public/app/features/teams/TeamGroupSync.tsx +++ b/public/app/features/teams/TeamGroupSync.tsx @@ -1,85 +1,63 @@ import { css, cx } from '@emotion/css'; -import { FormEventHandler, PureComponent } from 'react'; -import { connect, ConnectedProps } from 'react-redux'; +import { FormEventHandler, useState } from 'react'; +import { + TeamGroupDto, + useAddTeamGroupApiMutation, + useGetTeamGroupsApiQuery, + useRemoveTeamGroupApiQueryMutation, +} from '@grafana/api-clients/rtkq/legacy'; import { Trans, t } from '@grafana/i18n'; -import { Input, Tooltip, Icon, Button, useTheme2, InlineField, InlineFieldRow } from '@grafana/ui'; +import { Input, Tooltip, Icon, Button, useTheme2, InlineField, InlineFieldRow, useStyles2 } from '@grafana/ui'; import { SlideDown } from 'app/core/components/Animations/SlideDown'; import { CloseButton } from 'app/core/components/CloseButton/CloseButton'; import EmptyListCTA from 'app/core/components/EmptyListCTA/EmptyListCTA'; import { UpgradeBox, UpgradeContent, UpgradeContentProps } from 'app/core/components/Upgrade/UpgradeBox'; import { highlightTrial } from 'app/features/admin/utils'; -import { StoreState } from 'app/types/store'; -import { TeamGroup } from 'app/types/teams'; -import { addTeamGroup, loadTeamGroups, removeTeamGroup } from './state/actions'; -import { getTeamGroups } from './state/selectors'; - -function mapStateToProps(state: StoreState) { - return { - groups: getTeamGroups(state.team), - }; -} - -const mapDispatchToProps = { - loadTeamGroups, - addTeamGroup, - removeTeamGroup, -}; - -interface OwnProps { +interface Props { isReadOnly: boolean; teamUid: string; } -interface State { - isAdding: boolean; - newGroupId: string; -} - -const connector = connect(mapStateToProps, mapDispatchToProps); -export type Props = OwnProps & ConnectedProps; - const headerTooltip = `Sync LDAP, OAuth or SAML groups with your Grafana teams.`; -export class TeamGroupSync extends PureComponent { - constructor(props: Props) { - super(props); - this.state = { isAdding: false, newGroupId: '' }; - } +export const TeamGroupSync = ({ isReadOnly, teamUid }: Props) => { + const [isAddBoxVisible, setIsAddBoxVisible] = useState(false); + const [newGroupId, setNewGroupId] = useState(''); + const styles = useStyles2(getStyles); - componentDidMount() { - this.fetchTeamGroups(); - } + const { data: groups = [] } = useGetTeamGroupsApiQuery({ teamId: teamUid }); + const [addTeamGroup] = useAddTeamGroupApiMutation(); + const [removeTeamGroup] = useRemoveTeamGroupApiQueryMutation(); - async fetchTeamGroups() { - this.props.loadTeamGroups(this.props.teamUid); - } - - onToggleAdding = () => { - this.setState({ isAdding: !this.state.isAdding }); + const onToggleAdding = () => { + setIsAddBoxVisible(!isAddBoxVisible); }; - onNewGroupIdChanged: FormEventHandler = (event) => { - this.setState({ newGroupId: event.currentTarget.value }); + const onNewGroupIdChanged: FormEventHandler = (event) => { + setNewGroupId(event.currentTarget.value); }; - onAddGroup: FormEventHandler = (event) => { + const onAddGroup: FormEventHandler = async (event) => { event.preventDefault(); - this.props.addTeamGroup(this.props.teamUid, this.state.newGroupId); - this.setState({ isAdding: false, newGroupId: '' }); + await addTeamGroup({ teamId: teamUid, teamGroupMapping: { groupId: newGroupId } }); + setIsAddBoxVisible(false); + setNewGroupId(''); }; - onRemoveGroup = (group: TeamGroup) => { - this.props.removeTeamGroup(this.props.teamUid, group.groupId); + const onRemoveGroup = async (groupId: string | undefined) => { + if (!groupId) { + return; + } + await removeTeamGroup({ teamId: teamUid, groupId }); }; - isNewGroupValid() { - return this.state.newGroupId.length > 1; - } + const isNewGroupValid = () => { + return newGroupId.length > 1; + }; - renderGroup(group: TeamGroup) { - const { isReadOnly } = this.props; + const renderGroup = (group: TeamGroupDto) => { return ( {group.groupId} @@ -87,7 +65,7 @@ export class TeamGroupSync extends PureComponent { - )} -
- - -
- -
- - - - - - -
-
-
- - {groups.length === 0 && - !isAdding && - (highlightTrial() ? ( - - ) : ( - - ))} - +
{groups.length > 0 && ( -
- - - - - - - {groups.map((group) => this.renderGroup(group))} -
- External Group ID - -
-
+ )}
- ); - } -} + + +
+ +
+ + + + + + +
+
+
+ + {groups.length === 0 && + !isAddBoxVisible && + (highlightTrial() ? ( + + ) : ( + + ))} + + {groups.length > 0 && ( +
+ + + + + + + {groups.map((group) => renderGroup(group))} +
+ External Group ID + +
+
+ )} +
+ ); +}; export const TeamSyncUpgradeContent = ({ action }: { action?: UpgradeContentProps['action'] }) => { const theme = useTheme2(); @@ -226,7 +196,7 @@ export const TeamSyncUpgradeContent = ({ action }: { action?: UpgradeContentProp /> ); }; -export default connect(mapStateToProps, mapDispatchToProps)(TeamGroupSync); +export default TeamGroupSync; const getStyles = () => ({ icon: css({ diff --git a/public/app/features/teams/mocks/teamMocks.ts b/public/app/features/teams/mocks/teamMocks.ts index d6472499cb2..d43f1c454b2 100644 --- a/public/app/features/teams/mocks/teamMocks.ts +++ b/public/app/features/teams/mocks/teamMocks.ts @@ -1,7 +1,7 @@ import { randomBytes } from 'crypto'; import { TeamPermissionLevel } from 'app/types/acl'; -import { Team, TeamMember, TeamGroup } from 'app/types/teams'; +import { Team, TeamMember } from 'app/types/teams'; function generateShortUid(): string { return randomBytes(3).toString('hex'); // Generate a short UID @@ -44,16 +44,3 @@ export const getMockTeamMember = (): TeamMember => { permission: TeamPermissionLevel.Member, }; }; - -export const getMockTeamGroups = (amount: number): TeamGroup[] => { - const groups: TeamGroup[] = []; - - for (let i = 1; i <= amount; i++) { - groups.push({ - groupId: `group-${i}`, - teamId: 1, - }); - } - - return groups; -}; diff --git a/public/app/features/teams/state/actions.ts b/public/app/features/teams/state/actions.ts deleted file mode 100644 index d0d05e0946c..00000000000 --- a/public/app/features/teams/state/actions.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { getBackendSrv } from '@grafana/runtime'; -import { ThunkResult } from 'app/types/store'; - -import { teamGroupsLoaded } from './reducers'; - -export function loadTeamGroups(teamUid: string): ThunkResult { - return async (dispatch) => { - const response = await getBackendSrv().get(`/api/teams/${teamUid}/groups`); - dispatch(teamGroupsLoaded(response)); - }; -} - -export function addTeamGroup(teamUid: string, groupId: string): ThunkResult { - return async (dispatch) => { - await getBackendSrv().post(`/api/teams/${teamUid}/groups`, { groupId: groupId }); - dispatch(loadTeamGroups(teamUid)); - }; -} - -export function removeTeamGroup(teamUid: string, groupId: string): ThunkResult { - return async (dispatch) => { - // need to use query parameter due to escaped characters in the request - await getBackendSrv().delete(`/api/teams/${teamUid}/groups?groupId=${encodeURIComponent(groupId)}`); - dispatch(loadTeamGroups(teamUid)); - }; -} diff --git a/public/app/features/teams/state/reducers.ts b/public/app/features/teams/state/reducers.ts deleted file mode 100644 index 50011316a72..00000000000 --- a/public/app/features/teams/state/reducers.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { createSlice, PayloadAction } from '@reduxjs/toolkit'; - -import { TeamState, TeamGroup } from 'app/types/teams'; - -export const initialTeamState: TeamState = { - groups: [], -}; - -const teamSlice = createSlice({ - name: 'team', - initialState: initialTeamState, - reducers: { - teamGroupsLoaded: (state, action: PayloadAction): TeamState => { - return { ...state, groups: action.payload }; - }, - }, -}); - -export const { teamGroupsLoaded } = teamSlice.actions; - -export const teamReducer = teamSlice.reducer; - -export default { - team: teamReducer, -}; diff --git a/public/app/features/teams/state/selectors.ts b/public/app/features/teams/state/selectors.ts deleted file mode 100644 index 4ada9ee8d46..00000000000 --- a/public/app/features/teams/state/selectors.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { TeamState } from 'app/types/teams'; - -export const getTeamGroups = (state: TeamState) => state.groups; diff --git a/public/app/features/transformers/calculateHeatmap/heatmap.test.ts b/public/app/features/transformers/calculateHeatmap/heatmap.test.ts index 4155a763d4d..d0a963ee9f7 100644 --- a/public/app/features/transformers/calculateHeatmap/heatmap.test.ts +++ b/public/app/features/transformers/calculateHeatmap/heatmap.test.ts @@ -1,7 +1,7 @@ import { FieldType, toDataFrame } from '@grafana/data'; -import { HeatmapCalculationOptions } from '@grafana/schema'; +import { HeatmapCalculationOptions, HeatmapCellLayout, ScaleDistribution } from '@grafana/schema'; -import { rowsToCellsHeatmap, calculateHeatmapFromData } from './heatmap'; +import { rowsToCellsHeatmap, calculateHeatmapFromData, calculateBucketFactor } from './heatmap'; describe('Heatmap transformer', () => { it('calculate heatmap from input data', async () => { @@ -121,4 +121,327 @@ describe('Heatmap transformer', () => { }) ).toThrowErrorMatchingInlineSnapshot(`"No numeric fields found for heatmap"`); }); + + describe('calculateBucketFactor', () => { + it('calculates ratio from last two buckets for log2 spacing', () => { + const buckets = [1, 2, 4, 8]; + expect(calculateBucketFactor(buckets)).toBe(2); + }); + + it('calculates ratio from last two buckets for log10 spacing', () => { + const buckets = [1, 10, 100, 1000]; + expect(calculateBucketFactor(buckets)).toBe(10); + }); + + it('calculates ratio for non-uniform spacing', () => { + const buckets = [1, 2.5, 6.25]; + expect(calculateBucketFactor(buckets)).toBe(2.5); + }); + + it('returns default factor for single value array', () => { + expect(calculateBucketFactor([5])).toBe(1.5); + }); + + it('returns default factor for empty array', () => { + expect(calculateBucketFactor([])).toBe(1.5); + }); + + it('returns default factor when ratio is not valid expansion (<=1)', () => { + const buckets = [10, 5]; // Descending + expect(calculateBucketFactor(buckets)).toBe(1.5); + }); + + it('returns default factor when ratio contains zero', () => { + const buckets = [0, 5]; + expect(calculateBucketFactor(buckets)).toBe(1.5); + }); + + it('returns default factor when ratio is infinite', () => { + const buckets = [5, Infinity]; + expect(calculateBucketFactor(buckets)).toBe(1.5); + }); + + it('accepts custom default factor', () => { + expect(calculateBucketFactor([5], 3)).toBe(3); + }); + }); + + describe('rowsToCellsHeatmap with linear scale', () => { + it('converts prometheus-style le labels to numeric buckets with linear scale', () => { + const frame = toDataFrame({ + fields: [ + { name: 'time', type: FieldType.time, values: [1000, 2000] }, + { + name: '1', + type: FieldType.number, + labels: { le: '1' }, + values: [10, 15], + }, + { + name: '10', + type: FieldType.number, + labels: { le: '10' }, + values: [20, 25], + }, + { + name: '100', + type: FieldType.number, + labels: { le: '100' }, + values: [30, 35], + }, + ], + }); + + const heatmap = rowsToCellsHeatmap({ + frame, + yBucketScale: { type: ScaleDistribution.Linear }, + }); + + expect(heatmap.fields[1].name).toBe('yMin'); + expect(heatmap.fields[1].values).toEqual([1, 10, 100, 1, 10, 100]); + }); + + it('converts ge labels to numeric buckets with linear scale', () => { + const frame = toDataFrame({ + fields: [ + { name: 'time', type: FieldType.time, values: [1000, 2000] }, + { + name: '1', + type: FieldType.number, + labels: { ge: '1' }, + values: [10, 15], + }, + { + name: '10', + type: FieldType.number, + labels: { ge: '10' }, + values: [20, 25], + }, + ], + }); + + const heatmap = rowsToCellsHeatmap({ + frame, + yBucketScale: { type: ScaleDistribution.Linear }, + layout: HeatmapCellLayout.ge, + }); + + expect(heatmap.fields[1].values).toEqual([1, 10, 1, 10]); + expect(heatmap.fields[1].name).toBe('yMin'); // ge layout + }); + + it('generates yMax field for linear scale', () => { + const frame = toDataFrame({ + fields: [ + { name: 'time', type: FieldType.time, values: [1000] }, + { name: '1', type: FieldType.number, values: [10] }, + { name: '2', type: FieldType.number, values: [20] }, + { name: '4', type: FieldType.number, values: [30] }, + ], + }); + + const heatmap = rowsToCellsHeatmap({ + frame, + yBucketScale: { type: ScaleDistribution.Linear }, + }); + + // Should have yMin, yMax, and count fields + expect(heatmap.fields.length).toBe(4); + expect(heatmap.fields[2].name).toBe('yMax'); + expect(heatmap.fields[2].type).toBe('number'); + + // yMax should be [2, 4, 8] (shifted buckets + calculated last bucket) + // Last bucket uses factor 2 (from 2→4) to estimate 4→8 + expect(heatmap.fields[2].values).toEqual([2, 4, 8]); + }); + + it('clears yOrdinalDisplay for linear scale', () => { + const frame = toDataFrame({ + fields: [ + { name: 'time', type: FieldType.time, values: [1000] }, + { name: '1', type: FieldType.number, values: [10] }, + { name: '10', type: FieldType.number, values: [20] }, + ], + }); + + const heatmap = rowsToCellsHeatmap({ + frame, + yBucketScale: { type: ScaleDistribution.Linear }, + }); + + expect(heatmap.meta?.custom?.yOrdinalDisplay).toBeUndefined(); + }); + + it('clears yOrdinalDisplay for log scale', () => { + const frame = toDataFrame({ + fields: [ + { name: 'time', type: FieldType.time, values: [1000] }, + { name: '1', type: FieldType.number, values: [10] }, + { name: '10', type: FieldType.number, values: [20] }, + ], + }); + + const heatmap = rowsToCellsHeatmap({ + frame, + yBucketScale: { type: ScaleDistribution.Log, log: 10 }, + }); + + expect(heatmap.meta?.custom?.yOrdinalDisplay).toBeUndefined(); + }); + + it('clears yOrdinalDisplay for symlog scale', () => { + const frame = toDataFrame({ + fields: [ + { name: 'time', type: FieldType.time, values: [1000] }, + { name: '1', type: FieldType.number, values: [10] }, + { name: '10', type: FieldType.number, values: [20] }, + ], + }); + + const heatmap = rowsToCellsHeatmap({ + frame, + yBucketScale: { type: ScaleDistribution.Symlog, log: 10, linearThreshold: 1 }, + }); + + expect(heatmap.meta?.custom?.yOrdinalDisplay).toBeUndefined(); + }); + + it('preserves yOrdinalDisplay for non-numeric scale (auto/ordinal)', () => { + const frame = toDataFrame({ + fields: [ + { name: 'time', type: FieldType.time, values: [1000] }, + { name: 'low', type: FieldType.number, values: [10] }, + { name: 'high', type: FieldType.number, values: [20] }, + ], + }); + + const heatmap = rowsToCellsHeatmap({ frame }); + + expect(heatmap.meta?.custom?.yOrdinalDisplay).toEqual(['low', 'high']); + }); + + it('sets unit to undefined for linear scale when no unit exists', () => { + const frame = toDataFrame({ + fields: [ + { name: 'time', type: FieldType.time, values: [1000] }, + { name: '1', type: FieldType.number, values: [10] }, + { name: '10', type: FieldType.number, values: [20] }, + ], + }); + + const heatmap = rowsToCellsHeatmap({ + frame, + yBucketScale: { type: ScaleDistribution.Linear }, + }); + + // No unit → expect undefined (not 'short') + expect(heatmap.fields[1].config.unit).toBeUndefined(); + }); + + it('passes through existing unit for linear scale', () => { + const frame = toDataFrame({ + fields: [ + { name: 'time', type: FieldType.time, values: [1000] }, + { name: '1', type: FieldType.number, values: [10], config: { unit: 'ms' } }, + { name: '10', type: FieldType.number, values: [20], config: { unit: 'ms' } }, + ], + }); + + const heatmap = rowsToCellsHeatmap({ + frame, + yBucketScale: { type: ScaleDistribution.Linear }, + }); + + // Existing unit → pass through unchanged + expect(heatmap.fields[1].config.unit).toBe('ms'); + }); + + it('sets unit to short for ordinal scale', () => { + const frame = toDataFrame({ + fields: [ + { name: 'time', type: FieldType.time, values: [1000] }, + { name: 'low', type: FieldType.number, values: [10] }, + { name: 'high', type: FieldType.number, values: [20] }, + ], + }); + + const heatmap = rowsToCellsHeatmap({ frame }); + + expect(heatmap.fields[1].config.unit).toBe('short'); + }); + + it('uses "count" as value field name for linear scale', () => { + const frame = toDataFrame({ + fields: [ + { name: 'time', type: FieldType.time, values: [1000] }, + { name: '1', type: FieldType.number, values: [10] }, + { name: '10', type: FieldType.number, values: [20] }, + ], + }); + + const heatmap = rowsToCellsHeatmap({ + frame, + yBucketScale: { type: ScaleDistribution.Linear }, + }); + + // Without yMax, should be 3 fields: xMax, y/yMin/yMax, yMax, count + const valueField = heatmap.fields.find((f) => f.name === 'count'); + expect(valueField).toBeDefined(); + }); + + it('uses "Value" as field name for ordinal scale', () => { + const frame = toDataFrame({ + fields: [ + { name: 'time', type: FieldType.time, values: [1000] }, + { name: 'low', type: FieldType.number, values: [10] }, + { name: 'high', type: FieldType.number, values: [20] }, + ], + }); + + const heatmap = rowsToCellsHeatmap({ frame }); + + const valueField = heatmap.fields.find((f) => f.name === 'Value'); + expect(valueField).toBeDefined(); + }); + + it('respects custom value field name for linear scale', () => { + const frame = toDataFrame({ + fields: [ + { name: 'time', type: FieldType.time, values: [1000] }, + { name: '1', type: FieldType.number, values: [10] }, + { name: '10', type: FieldType.number, values: [20] }, + ], + }); + + const heatmap = rowsToCellsHeatmap({ + frame, + yBucketScale: { type: ScaleDistribution.Linear }, + value: 'Temperature', + }); + + const valueField = heatmap.fields.find((f) => f.name === 'Temperature'); + expect(valueField).toBeDefined(); + }); + + it('calculates yMax upper bound using bucket factor', () => { + const frame = toDataFrame({ + fields: [ + { name: 'time', type: FieldType.time, values: [1000] }, + { name: '1', type: FieldType.number, values: [10] }, + { name: '10', type: FieldType.number, values: [20] }, + { name: '100', type: FieldType.number, values: [30] }, + ], + }); + + const heatmap = rowsToCellsHeatmap({ + frame, + yBucketScale: { type: ScaleDistribution.Linear }, + }); + + // buckets: [1, 10, 100] + // yMax: [10, 100, 1000] - last one calculated as 100 * 10 + const yMaxField = heatmap.fields.find((f) => f.name === 'yMax'); + expect(yMaxField?.values).toEqual([10, 100, 1000]); + }); + }); }); diff --git a/public/app/features/transformers/calculateHeatmap/heatmap.ts b/public/app/features/transformers/calculateHeatmap/heatmap.ts index 49a54bb43f1..43640708eae 100644 --- a/public/app/features/transformers/calculateHeatmap/heatmap.ts +++ b/public/app/features/transformers/calculateHeatmap/heatmap.ts @@ -19,6 +19,7 @@ import { isLikelyAscendingVector } from '@grafana/data/internal'; import { t } from '@grafana/i18n'; import { ScaleDistribution, + ScaleDistributionConfig, HeatmapCellLayout, HeatmapCalculationMode, HeatmapCalculationOptions, @@ -72,13 +73,36 @@ function parseNumeric(v?: string | null) { return v === '+Inf' ? Infinity : v === '-Inf' ? -Infinity : +(v ?? 0); } +/** + * Calculate the expansion factor from adjacent bucket values. + * This is used to estimate the size/bound of the next bucket based on the spacing of existing buckets. + * + * @param bucketValues - Array of bucket boundary values + * @param defaultFactor - Factor to use if ratio cannot be determined (default: 1.5 for 50% expansion) + * @returns The calculated or default expansion factor + */ +export function calculateBucketFactor(bucketValues: number[], defaultFactor = 1.5): number { + if (bucketValues.length >= 2) { + const last = bucketValues.at(-1)!; + const prev = bucketValues.at(-2)!; + const ratio = last / prev; + + // Only use ratio if it represents expansion (>1) and is valid + if (ratio > 1 && Number.isFinite(ratio)) { + return ratio; + } + } + + return defaultFactor; +} + export function sortAscStrInf(aName?: string | null, bName?: string | null) { return parseNumeric(aName) - parseNumeric(bName); } export interface HeatmapRowsCustomMeta { /** This provides the lookup values */ - yOrdinalDisplay: string[]; + yOrdinalDisplay?: string[]; yOrdinalLabel?: string[]; yMatchWithLabel?: string; yMinDisplay?: string; @@ -115,6 +139,7 @@ export interface RowsHeatmapOptions { unit?: string; decimals?: number; layout?: HeatmapCellLayout; + yBucketScale?: ScaleDistributionConfig; } /** Given existing buckets, create a values style frame */ @@ -129,10 +154,19 @@ export function rowsToCellsHeatmap(opts: RowsHeatmapOptions): DataFrame { throw new Error(t('heatmap.error.no-y-fields', 'No numeric fields found for heatmap')); } + // Determine if we should use numeric scaling based on yBucketScale option + // Default to 'auto' behavior (ordinal) if not specified + const scaleType = opts.yBucketScale?.type; + const useNumericScale = + scaleType === ScaleDistribution.Linear || + scaleType === ScaleDistribution.Log || + scaleType === ScaleDistribution.Symlog; + // similar to initBins() below const len = xValues.length * yFields.length; const xs = new Array(len); const ys = new Array(len); + const ys2 = useNumericScale ? new Array(len) : undefined; const counts2 = new Array(len); const counts = yFields.map((field) => field.values.slice()); @@ -144,21 +178,8 @@ export function rowsToCellsHeatmap(opts: RowsHeatmapOptions): DataFrame { } }); - const bucketBounds = Array.from({ length: yFields.length }, (v, i) => i); - - // fill flat/repeating array - for (let i = 0, yi = 0, xi = 0; i < len; yi = ++i % bucketBounds.length) { - ys[i] = bucketBounds[yi]; - - if (yi === 0 && i >= bucketBounds.length) { - xi++; - } - - xs[i] = xValues[xi]; - } - // this name determines whether cells are drawn above, below, or centered on the values - let ordinalFieldName = yFields[0].labels?.le != null ? 'yMax' : 'y'; + let ordinalFieldName = yFields[0].labels?.le != null ? 'yMax' : yFields[0].labels?.ge != null ? 'yMin' : 'y'; switch (opts.layout) { case HeatmapCellLayout.le: ordinalFieldName = 'yMax'; @@ -175,6 +196,45 @@ export function rowsToCellsHeatmap(opts: RowsHeatmapOptions): DataFrame { yOrdinalDisplay: yFields.map((f) => getFieldDisplayName(f, opts.frame)), yMatchWithLabel: Object.keys(yFields[0].labels ?? {})[0], }; + + let bucketBounds: number[]; + let bucketBoundsMax: number[] | undefined; + + if (useNumericScale) { + // Numeric mode: use numeric bucket values + bucketBounds = yFields.map((field) => { + const labelKey = custom.yMatchWithLabel; + const labelValue = labelKey ? field.labels?.[labelKey] : undefined; + const valueStr = labelValue ?? field.name; + return Number(valueStr); + }); + + // Generate upper bounds: shift values + calculate last bucket + bucketBoundsMax = bucketBounds.slice(); + bucketBoundsMax.shift(); + const factor = calculateBucketFactor(bucketBounds); + bucketBoundsMax.push(bucketBounds[bucketBounds.length - 1] * factor); + + custom.yMatchWithLabel = undefined; + } else { + // Auto mode: use ordinal indices like the original main branch behavior + bucketBounds = Array.from({ length: yFields.length }, (v, i) => i); + } + + // fill flat/repeating array + for (let i = 0, yi = 0, xi = 0; i < len; yi = ++i % bucketBounds.length) { + ys[i] = bucketBounds[yi]; + if (useNumericScale && ys2 && bucketBoundsMax) { + ys2[i] = bucketBoundsMax[yi]; + } + + if (yi === 0 && i >= bucketBounds.length) { + xi++; + } + + xs[i] = xValues[xi]; + } + if (custom.yMatchWithLabel) { custom.yOrdinalLabel = yFields.map((f) => f.labels?.[custom.yMatchWithLabel!] ?? ''); if (custom.yMatchWithLabel === 'le') { @@ -189,7 +249,7 @@ export function rowsToCellsHeatmap(opts: RowsHeatmapOptions): DataFrame { if (custom.yMinDisplay) { custom.yMinDisplay = formattedValueToString(fmt(0, opts.decimals)); } - custom.yOrdinalDisplay = custom.yOrdinalDisplay.map((name) => { + custom.yOrdinalDisplay = custom.yOrdinalDisplay?.map((name) => { let num = +name; if (!Number.isNaN(num)) { @@ -200,6 +260,11 @@ export function rowsToCellsHeatmap(opts: RowsHeatmapOptions): DataFrame { }); } + // Clear yOrdinalDisplay when using numeric scales (linear, log, symlog) + if (useNumericScale) { + custom.yOrdinalDisplay = undefined; + } + const valueCfg = { ...yFields[0].config, }; @@ -208,6 +273,43 @@ export function rowsToCellsHeatmap(opts: RowsHeatmapOptions): DataFrame { delete valueCfg.displayNameFromDS; } + // Build fields array - only include yMax in linear scale mode + const fields: Field[] = [ + { + name: xField.type === FieldType.time ? 'xMax' : 'x', + type: xField.type, + values: xs, + config: xField.config, + }, + { + name: useNumericScale ? 'yMin' : ordinalFieldName, + type: FieldType.number, + values: ys, + config: { + unit: useNumericScale ? yFields[0]?.config?.unit : 'short', // preserve original unit for numeric, use 'short' for ordinal + }, + }, + ]; + + // yMax provides explicit upper bounds for proper rendering, critical for ge layout + if (useNumericScale && ys2) { + fields.push({ + name: 'yMax', + type: FieldType.number, + values: ys2, + config: {}, + }); + } + + // Add value/count field + fields.push({ + name: opts.value?.length ? opts.value : useNumericScale ? 'count' : 'Value', + type: FieldType.number, + values: counts2, + config: valueCfg, + display: yFields[0].display, + }); + return { length: xs.length, refId: opts.frame.refId, @@ -215,29 +317,7 @@ export function rowsToCellsHeatmap(opts: RowsHeatmapOptions): DataFrame { type: DataFrameType.HeatmapCells, custom, }, - fields: [ - { - name: xField.type === FieldType.time ? 'xMax' : 'x', - type: xField.type, - values: xs, - config: xField.config, - }, - { - name: ordinalFieldName, - type: FieldType.number, - values: ys, - config: { - unit: 'short', // ordinal lookup - }, - }, - { - name: opts.value?.length ? opts.value : 'Value', - type: FieldType.number, - values: counts2, - config: valueCfg, - display: yFields[0].display, - }, - ], + fields, }; } diff --git a/public/app/plugins/datasource/elasticsearch/datasource.test.ts b/public/app/plugins/datasource/elasticsearch/datasource.test.ts index 33c3486bd31..6e3c7b2c2ce 100644 --- a/public/app/plugins/datasource/elasticsearch/datasource.test.ts +++ b/public/app/plugins/datasource/elasticsearch/datasource.test.ts @@ -1000,7 +1000,7 @@ describe('ElasticDatasource', () => { }); expect(postResourceRequestMock).toHaveBeenCalledWith( '_msearch', - '{"search_type":"query_then_fetch","ignore_unavailable":true,"index":"[test-]YYYY.MM.DD"}\n{"query":{"bool":{"filter":[{"bool":{"should":[{"range":{"@test_time":{"from":1683291160012,"to":1683291460012,"format":"epoch_millis"}}},{"range":{"@time_end_field":{"from":1683291160012,"to":1683291460012,"format":"epoch_millis"}}}],"minimum_should_match":1}},{"query_string":{"query":"abc"}}]}},"size":10000}\n' + '{"search_type":"query_then_fetch","ignore_unavailable":true,"index":"[test-]YYYY.MM.DD"}\n{"query":{"bool":{"filter":[{"bool":{"should":[{"range":{"@test_time":{"gte":1683291160012,"lte":1683291460012,"format":"epoch_millis"}}},{"range":{"@time_end_field":{"gte":1683291160012,"lte":1683291460012,"format":"epoch_millis"}}}],"minimum_should_match":1}},{"query_string":{"query":"abc"}}]}},"size":10000}\n' ); }); @@ -1030,7 +1030,7 @@ describe('ElasticDatasource', () => { }); expect(postResourceRequestMock).toHaveBeenCalledWith( '_msearch', - '{"search_type":"query_then_fetch","ignore_unavailable":true,"index":"[test-]YYYY.MM.DD"}\n{"query":{"bool":{"filter":[{"bool":{"should":[{"range":{"@timestamp":{"from":1683291160012,"to":1683291460012,"format":"epoch_millis"}}}],"minimum_should_match":1}}]}},"size":10000}\n' + '{"search_type":"query_then_fetch","ignore_unavailable":true,"index":"[test-]YYYY.MM.DD"}\n{"query":{"bool":{"filter":[{"bool":{"should":[{"range":{"@timestamp":{"gte":1683291160012,"lte":1683291460012,"format":"epoch_millis"}}}],"minimum_should_match":1}}]}},"size":10000}\n' ); }); @@ -1087,7 +1087,7 @@ describe('ElasticDatasource', () => { }); expect(postResourceRequestMock).toHaveBeenCalledWith( '_msearch', - '{"search_type":"query_then_fetch","ignore_unavailable":true,"index":"[test-]YYYY.MM.DD"}\n{"query":{"bool":{"filter":[{"bool":{"should":[{"range":{"@test_time":{"from":1683291160012,"to":1683291460012,"format":"epoch_millis"}}},{"range":{"@time_end_field":{"from":1683291160012,"to":1683291460012,"format":"epoch_millis"}}}],"minimum_should_match":1}},{"query_string":{"query":"abc AND abc_key:\\"abc_value\\""}}]}},"size":10000}\n' + '{"search_type":"query_then_fetch","ignore_unavailable":true,"index":"[test-]YYYY.MM.DD"}\n{"query":{"bool":{"filter":[{"bool":{"should":[{"range":{"@test_time":{"gte":1683291160012,"lte":1683291460012,"format":"epoch_millis"}}},{"range":{"@time_end_field":{"gte":1683291160012,"lte":1683291460012,"format":"epoch_millis"}}}],"minimum_should_match":1}},{"query_string":{"query":"abc AND abc_key:\\"abc_value\\""}}]}},"size":10000}\n' ); }); }); diff --git a/public/app/plugins/datasource/elasticsearch/datasource.ts b/public/app/plugins/datasource/elasticsearch/datasource.ts index d9294e5e62e..95e329e03ea 100644 --- a/public/app/plugins/datasource/elasticsearch/datasource.ts +++ b/public/app/plugins/datasource/elasticsearch/datasource.ts @@ -294,8 +294,8 @@ export class ElasticDatasource const dateRanges = []; const rangeStart: RangeMap = {}; rangeStart[timeField] = { - from: options.range.from.valueOf(), - to: options.range.to.valueOf(), + gte: options.range.from.valueOf(), + lte: options.range.to.valueOf(), format: 'epoch_millis', }; dateRanges.push({ range: rangeStart }); @@ -303,8 +303,8 @@ export class ElasticDatasource if (timeEndField) { const rangeEnd: RangeMap = {}; rangeEnd[timeEndField] = { - from: options.range.from.valueOf(), - to: options.range.to.valueOf(), + gte: options.range.from.valueOf(), + lte: options.range.to.valueOf(), format: 'epoch_millis', }; dateRanges.push({ range: rangeEnd }); diff --git a/public/app/plugins/datasource/elasticsearch/types.ts b/public/app/plugins/datasource/elasticsearch/types.ts index c3a7c5f9da2..4645a2a824f 100644 --- a/public/app/plugins/datasource/elasticsearch/types.ts +++ b/public/app/plugins/datasource/elasticsearch/types.ts @@ -137,7 +137,7 @@ export interface ElasticsearchAnnotationQuery { index?: string; } -export type RangeMap = Record; +export type RangeMap = Record; export type ElasticsearchResponse = ElasticsearchResponseWithHits | ElasticsearchResponseWithAggregations; diff --git a/public/app/plugins/panel/dashlist/DashList.tsx b/public/app/plugins/panel/dashlist/DashList.tsx index dab66730379..ff62a9ffd0a 100644 --- a/public/app/plugins/panel/dashlist/DashList.tsx +++ b/public/app/plugins/panel/dashlist/DashList.tsx @@ -4,18 +4,18 @@ import { useThrottle } from 'react-use'; import { InterpolateFunction, PanelProps, textUtil } from '@grafana/data'; import { t } from '@grafana/i18n'; -import { useStyles2, ScrollContainer, Box, Text, EmptyState, Link } from '@grafana/ui'; +import { ScrollContainer, Box, Text, EmptyState } from '@grafana/ui'; import { getConfig } from 'app/core/config'; import impressionSrv from 'app/core/services/impression_srv'; +import { useDashboardLocationInfo } from 'app/features/search/hooks/useDashboardLocationInfo'; import { getGrafanaSearcher } from 'app/features/search/service/searcher'; -import { DashboardQueryResult, LocationInfo, QueryResponse, SearchQuery } from 'app/features/search/service/types'; -import { StarToolbarButton } from 'app/features/stars/StarToolbarButton'; +import { DashboardQueryResult, QueryResponse, SearchQuery } from 'app/features/search/service/types'; +import { DashListItem } from './DashListItem'; import { Options } from './panelcfg.gen'; -import { getStyles } from './styles'; import { useDashListUrlParams } from './utils'; -type Dashboard = DashboardQueryResult & { +export type Dashboard = DashboardQueryResult & { isSearchResult?: boolean; isRecent?: boolean; isStarred?: boolean; @@ -107,15 +107,10 @@ async function fetchDashboards(options: Options, replaceVars: InterpolateFunctio return dashMap; } -async function fetchDashboardFolders() { - return getGrafanaSearcher().getLocationInfo(); -} - const collator = new Intl.Collator(); export function DashList(props: PanelProps) { const [dashboards, setDashboards] = useState(new Map()); - const [foldersTitleMap, setFoldersTitleMap] = useState>({}); const throttledRenderCount = useThrottle(props.renderCounter, 5000); @@ -125,13 +120,7 @@ export function DashList(props: PanelProps) { }); }, [props.options, props.replaceVariables, throttledRenderCount]); - useEffect(() => { - if (props.options.showFolderNames && dashboards.size > 0) { - fetchDashboardFolders().then((locationInfo) => { - setFoldersTitleMap(locationInfo); - }); - } - }, [props.options.showFolderNames, dashboards]); + const { foldersByUid } = useDashboardLocationInfo(props.options.showFolderNames && dashboards.size > 0); const [starredDashboards, recentDashboards, searchedDashboards] = useMemo(() => { const dashboardList = [...dashboards.values()]; @@ -185,7 +174,6 @@ export function DashList(props: PanelProps) { setDashboards(updatedDashboards); }; - const css = useStyles2(getStyles); const urlParams = useDashListUrlParams(props); const renderList = (dashboards: Dashboard[]) => ( @@ -194,26 +182,17 @@ export function DashList(props: PanelProps) { let url = dash.url + urlParams; url = getConfig().disableSanitizeHtml ? url : textUtil.sanitizeUrl(url); - const locationInfo = showFolderNames && dash.location ? foldersTitleMap[dash.location] : undefined; + const locationInfo = showFolderNames && dash.location ? foldersByUid[dash.location] : undefined; return (
  • -
    - - {dash.name} - {showFolderNames && locationInfo && ( - - {locationInfo?.name} - - )} - - -
    +
  • ); })} diff --git a/public/app/plugins/panel/dashlist/DashListItem.tsx b/public/app/plugins/panel/dashlist/DashListItem.tsx new file mode 100644 index 00000000000..9ef0ca64c3d --- /dev/null +++ b/public/app/plugins/panel/dashlist/DashListItem.tsx @@ -0,0 +1,64 @@ +import { Box, Card, Icon, Link, Stack, Text, useStyles2 } from '@grafana/ui'; +import { LocationInfo } from 'app/features/search/service/types'; +import { StarToolbarButton } from 'app/features/stars/StarToolbarButton'; + +import { Dashboard } from './DashList'; +import { getStyles } from './styles'; + +interface Props { + dashboard: Dashboard; + url: string; + showFolderNames: boolean; + locationInfo?: LocationInfo; + layoutMode: 'list' | 'card'; + onStarChange?: (id: string, isStarred: boolean) => void; +} +export function DashListItem({ dashboard, url, showFolderNames, locationInfo, layoutMode, onStarChange }: Props) { + const css = useStyles2(getStyles); + + return ( + <> + {layoutMode === 'list' ? ( +
    + + {dashboard.name} + {showFolderNames && locationInfo && ( + + {locationInfo?.name} + + )} + + +
    + ) : ( + + + {dashboard.name} + + + + {showFolderNames && locationInfo && ( + + + )} + + )} + + ); +} diff --git a/public/app/plugins/panel/dashlist/styles.ts b/public/app/plugins/panel/dashlist/styles.ts index 56becdd0684..c6346480c22 100644 --- a/public/app/plugins/panel/dashlist/styles.ts +++ b/public/app/plugins/panel/dashlist/styles.ts @@ -1,8 +1,13 @@ import { css } from '@emotion/css'; -import { GrafanaTheme2 } from '@grafana/data'; +import { GrafanaTheme2, colorManipulator } from '@grafana/data'; export const getStyles = (theme: GrafanaTheme2) => { + const gradient = `linear-gradient( + 90deg, + ${colorManipulator.alpha(theme.colors.primary.text, 0.1)} 0%, + ${colorManipulator.alpha(theme.colors.secondary.main, 0.1)} 100% + )`; return { dashlistLink: css({ display: 'flex', @@ -19,5 +24,22 @@ export const getStyles = (theme: GrafanaTheme2) => { }, }, }), + dashlistCard: css({ + display: 'flex', + flexDirection: 'column', + '&:hover a': { + color: theme.colors.text.link, + textDecoration: 'underline', + }, + height: '100%', + + '&:hover': { + backgroundImage: gradient, + color: theme.colors.text.primary, + }, + }), + dashlistCardIcon: css({ + marginRight: theme.spacing(0.5), + }), }; }; diff --git a/public/app/plugins/panel/geomap/GeomapPanel.tsx b/public/app/plugins/panel/geomap/GeomapPanel.tsx index eb7d7c7dad4..cb532f0ed95 100644 --- a/public/app/plugins/panel/geomap/GeomapPanel.tsx +++ b/public/app/plugins/panel/geomap/GeomapPanel.tsx @@ -79,7 +79,7 @@ export class GeomapPanel extends Component { this.subs.add( this.props.eventBus.subscribe(PanelEditExitedEvent, (evt) => { if (this.mapDiv && this.props.id === evt.payload) { - this.initMapRef(this.mapDiv); + this.initMapAsync(this.mapDiv); } }) ); @@ -97,7 +97,7 @@ export class GeomapPanel extends Component { }); if (hasDependencies) { - this.initMapRef(this.mapDiv); + this.initMapAsync(this.mapDiv); } } }) @@ -182,7 +182,7 @@ export class GeomapPanel extends Component { if (noRepeatChanged) { if (this.mapDiv) { - this.initMapRef(this.mapDiv); + this.initMapAsync(this.mapDiv); } // Skip other options processing return; @@ -227,7 +227,7 @@ export class GeomapPanel extends Component { this.setState({ legends: this.getLegends() }); } - initMapRef = async (div: HTMLDivElement) => { + initMapAsync = async (div: HTMLDivElement | null) => { if (!div) { // Do not initialize new map or dispose old map return; @@ -437,6 +437,10 @@ export class GeomapPanel extends Component { return legends; } + initMapRef = (div: HTMLDivElement | null) => { + this.initMapAsync(div); + }; + render() { let { ttip, ttipOpen, topRight1, legends, topRight2 } = this.state; const { options } = this.props; diff --git a/public/app/plugins/panel/geomap/components/DebugOverlay.tsx b/public/app/plugins/panel/geomap/components/DebugOverlay.tsx index de267de908f..d08d2042f05 100644 --- a/public/app/plugins/panel/geomap/components/DebugOverlay.tsx +++ b/public/app/plugins/panel/geomap/components/DebugOverlay.tsx @@ -6,7 +6,7 @@ import { PureComponent } from 'react'; import tinycolor from 'tinycolor2'; import { GrafanaTheme2 } from '@grafana/data'; -import { selectors } from '@grafana/e2e-selectors/src'; +import { selectors } from '@grafana/e2e-selectors'; import { Trans } from '@grafana/i18n'; import { config } from 'app/core/config'; @@ -44,7 +44,7 @@ export class DebugOverlay extends PureComponent { const { zoom, center } = this.state; return ( -
    +
    diff --git a/public/app/plugins/panel/heatmap/HeatmapPanel.tsx b/public/app/plugins/panel/heatmap/HeatmapPanel.tsx index 4d2762a9be3..64efef6c5aa 100644 --- a/public/app/plugins/panel/heatmap/HeatmapPanel.tsx +++ b/public/app/plugins/panel/heatmap/HeatmapPanel.tsx @@ -5,7 +5,6 @@ import { DashboardCursorSync, PanelProps, TimeRange } from '@grafana/data'; import { PanelDataErrorView } from '@grafana/runtime'; import { ScaleDistributionConfig } from '@grafana/schema'; import { - ScaleDistribution, TooltipPlugin2, TooltipDisplayMode, UPlotChart, @@ -29,7 +28,7 @@ import { HeatmapTooltip } from './HeatmapTooltip'; import { HeatmapData, prepareHeatmapData } from './fields'; import { quantizeScheme } from './palettes'; import { Options } from './types'; -import { prepConfig } from './utils'; +import { calculateYSizeDivisor, prepConfig } from './utils'; interface HeatmapPanelProps extends PanelProps {} @@ -141,6 +140,16 @@ const HeatmapPanelViz = ({ const builder = useMemo(() => { const scaleConfig: ScaleDistributionConfig = dataRef.current?.heatmap?.fields[1].config?.custom?.scaleDistribution; + const activeScaleConfig = options.rowsFrame?.yBucketScale ?? scaleConfig; + + // For log/symlog scales: use 1 for pre-bucketed data with explicit scale, otherwise use split value + const hasExplicitScale = options.rowsFrame?.yBucketScale !== undefined; + const ySizeDivisor = calculateYSizeDivisor( + activeScaleConfig?.type, + hasExplicitScale, + options.calculation?.yBuckets?.value + ); + return prepConfig({ dataRef, theme, @@ -151,9 +160,10 @@ const HeatmapPanelViz = ({ hideGE: options.filterValues?.ge, exemplarColor: options.exemplars?.color ?? 'rgba(255,0,255,0.7)', yAxisConfig: options.yAxis, - ySizeDivisor: scaleConfig?.type === ScaleDistribution.Log ? +(options.calculation?.yBuckets?.value || 1) : 1, + ySizeDivisor, selectionMode: options.selectionMode, xAxisConfig: getXAxisConfig(annotationsLength), + rowsFrame: options.rowsFrame, }); // eslint-disable-next-line react-hooks/exhaustive-deps diff --git a/public/app/plugins/panel/heatmap/HeatmapTooltip.tsx b/public/app/plugins/panel/heatmap/HeatmapTooltip.tsx index 480d36a5a6a..269243f1ad8 100644 --- a/public/app/plugins/panel/heatmap/HeatmapTooltip.tsx +++ b/public/app/plugins/panel/heatmap/HeatmapTooltip.tsx @@ -4,7 +4,6 @@ import uPlot from 'uplot'; import { ActionModel, - DataFrameType, Field, FieldType, formattedValueToString, @@ -26,7 +25,7 @@ import { } from '@grafana/ui/internal'; import { ColorScale } from 'app/core/components/ColorScale/ColorScale'; import { getDashboardSrv } from 'app/features/dashboard/services/DashboardSrv'; -import { isHeatmapCellsDense, readHeatmapRowsCustomMeta } from 'app/features/transformers/calculateHeatmap/heatmap'; +import { readHeatmapRowsCustomMeta } from 'app/features/transformers/calculateHeatmap/heatmap'; import { getDisplayValuesAndLinks } from 'app/features/visualization/data-hover/DataHoverView'; import { ExemplarTooltip } from 'app/features/visualization/data-hover/ExemplarTooltip'; @@ -35,7 +34,13 @@ import { isTooltipScrollable } from '../timeseries/utils'; import { HeatmapData } from './fields'; import { renderHistogram } from './renderHistogram'; -import { formatMilliseconds, getFieldFromData, getHoverCellColor, getSparseCellMinMax } from './tooltip/utils'; +import { + formatMilliseconds, + getFieldFromData, + getHoverCellColor, + getSparseCellMinMax, + isHeatmapSparse, +} from './tooltip/utils'; interface HeatmapTooltipProps { mode: TooltipDisplayMode; @@ -99,9 +104,7 @@ const HeatmapHoverCell = ({ const index = dataIdxs[1]!; const data = dataRef.current; - const [isSparse] = useState( - () => data.heatmap?.meta?.type === DataFrameType.HeatmapCells && !isHeatmapCellsDense(data.heatmap) - ); + const [isSparse] = useState(() => isHeatmapSparse(data.heatmap)); const xField = getFieldFromData(data.heatmap!, 'x', isSparse)!; const yField = getFieldFromData(data.heatmap!, 'y', isSparse)!; diff --git a/public/app/plugins/panel/heatmap/YBucketScaleEditor.test.tsx b/public/app/plugins/panel/heatmap/YBucketScaleEditor.test.tsx new file mode 100644 index 00000000000..6c0ff4b804c --- /dev/null +++ b/public/app/plugins/panel/heatmap/YBucketScaleEditor.test.tsx @@ -0,0 +1,277 @@ +import { render, screen, within } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import selectEvent from 'react-select-event'; + +import { StandardEditorContext, StandardEditorsRegistryItem } from '@grafana/data'; +import { ScaleDistribution, ScaleDistributionConfig } from '@grafana/schema'; + +import { YBucketScaleEditor } from './YBucketScaleEditor'; + +const mockContext: StandardEditorContext = { + data: [], +}; + +const mockItem: StandardEditorsRegistryItem = { + id: 'yBucketScale', + name: 'Y Bucket Scale', + editor: YBucketScaleEditor, +}; + +describe('YBucketScaleEditor', () => { + describe('Scale selection', () => { + it('should render with Auto selected when value is undefined', () => { + const onChange = jest.fn(); + render(); + + const autoButton = screen.getByRole('radio', { name: /auto/i }); + expect(autoButton).toBeChecked(); + }); + + it('should render with Linear selected when value is Linear', () => { + const onChange = jest.fn(); + render( + + ); + + const linearButton = screen.getByRole('radio', { name: /linear/i }); + expect(linearButton).toBeChecked(); + }); + + it('should call onChange with undefined when Auto is selected', async () => { + const onChange = jest.fn(); + render( + + ); + + const autoButton = screen.getByRole('radio', { name: /auto/i }); + await userEvent.click(autoButton); + + expect(onChange).toHaveBeenCalledWith(undefined); + }); + + it('should call onChange with Linear config when Linear is selected', async () => { + const onChange = jest.fn(); + render(); + + const linearButton = screen.getByRole('radio', { name: /linear/i }); + await userEvent.click(linearButton); + + expect(onChange).toHaveBeenCalledWith({ type: ScaleDistribution.Linear }); + }); + + it('should call onChange with Log config when Log is selected', async () => { + const onChange = jest.fn(); + render(); + + const logButton = screen.getByRole('radio', { name: /^log$/i }); + await userEvent.click(logButton); + + expect(onChange).toHaveBeenCalledWith({ type: ScaleDistribution.Log, log: 2 }); + }); + + it('should call onChange with Symlog config when Symlog is selected', async () => { + const onChange = jest.fn(); + render(); + + const symlogButton = screen.getByRole('radio', { name: /symlog/i }); + await userEvent.click(symlogButton); + + expect(onChange).toHaveBeenCalledWith({ type: ScaleDistribution.Symlog, log: 2, linearThreshold: 1 }); + }); + }); + + describe('Log base selection', () => { + it('should show log base selector for Log scale', () => { + const onChange = jest.fn(); + render( + + ); + + expect(screen.getByText('Log base')).toBeInTheDocument(); + }); + + it('should show log base selector for Symlog scale', () => { + const onChange = jest.fn(); + render( + + ); + + expect(screen.getByText('Log base')).toBeInTheDocument(); + }); + + it('should not show log base selector for Linear scale', () => { + const onChange = jest.fn(); + render( + + ); + + expect(screen.queryByText('Log base')).not.toBeInTheDocument(); + }); + + it('should not show log base selector for Auto', () => { + const onChange = jest.fn(); + render(); + + expect(screen.queryByText('Log base')).not.toBeInTheDocument(); + }); + + it('should preserve existing log base when switching to Log', async () => { + const onChange = jest.fn(); + render( + + ); + + const logButton = screen.getByRole('radio', { name: /^log$/i }); + await userEvent.click(logButton); + + expect(onChange).toHaveBeenCalledWith({ type: ScaleDistribution.Log, log: 10 }); + }); + + it('should update log base when changed for Log scale', async () => { + const onChange = jest.fn(); + render( + + ); + + // Find the log base field container and query the combobox within it + const logBaseLabel = screen.getByText('Log base'); + const fieldContainer = logBaseLabel.closest('div[style]') as HTMLElement; // The div with style="margin-top: 8px;" + const selectEl = within(fieldContainer).getByRole('combobox'); + + await selectEvent.select(selectEl, '10', { container: document.body }); + + expect(onChange).toHaveBeenCalledWith({ type: ScaleDistribution.Log, log: 10 }); + }); + + it('should update log base when changed for Symlog scale', async () => { + const onChange = jest.fn(); + render( + + ); + + // Find the log base field container and query the combobox within it + const logBaseLabel = screen.getByText('Log base'); + const fieldContainer = logBaseLabel.closest('div[style]') as HTMLElement; // The div with style="margin-top: 8px;" + const selectEl = within(fieldContainer).getByRole('combobox'); + + await selectEvent.select(selectEl, '10', { container: document.body }); + + expect(onChange).toHaveBeenCalledWith({ type: ScaleDistribution.Symlog, log: 10, linearThreshold: 1 }); + }); + }); + + describe('Linear threshold', () => { + it('should show linear threshold input for Symlog scale', () => { + const onChange = jest.fn(); + render( + + ); + + expect(screen.getByText('Linear threshold')).toBeInTheDocument(); + }); + + it('should not show linear threshold input for Log scale', () => { + const onChange = jest.fn(); + render( + + ); + + expect(screen.queryByText('Linear threshold')).not.toBeInTheDocument(); + }); + + it('should not update linear threshold for a 0 value', async () => { + const onChange = jest.fn(); + const origValue = { type: ScaleDistribution.Symlog, log: 10, linearThreshold: 1 }; + + render(); + + const input = screen.getByPlaceholderText('1'); + + await userEvent.clear(input); + await userEvent.type(input, '0'); + expect(onChange).not.toHaveBeenCalled(); + + await userEvent.type(input, '.'); + expect(onChange).not.toHaveBeenCalled(); + + await userEvent.type(input, '5'); + expect(onChange).toHaveBeenCalledWith({ ...origValue, linearThreshold: 0.5 }); + }); + + it('should update linear threshold for valid non-zero values', async () => { + const onChange = jest.fn(); + const origValue = { type: ScaleDistribution.Symlog, log: 2, linearThreshold: 1 }; + + render(); + + const input = screen.getByPlaceholderText('1'); + + await userEvent.clear(input); + await userEvent.type(input, '5'); + expect(onChange).toHaveBeenCalledWith({ ...origValue, linearThreshold: 5 }); + }); + + it('should not dispatch onChange for invalid input', async () => { + const onChange = jest.fn(); + const origValue = { type: ScaleDistribution.Symlog, log: 2, linearThreshold: 1 }; + + render(); + + const input = screen.getByPlaceholderText('1'); + + await userEvent.clear(input); + await userEvent.type(input, 'abc'); + expect(onChange).not.toHaveBeenCalled(); + }); + }); +}); diff --git a/public/app/plugins/panel/heatmap/YBucketScaleEditor.tsx b/public/app/plugins/panel/heatmap/YBucketScaleEditor.tsx new file mode 100644 index 00000000000..fc96101f9bd --- /dev/null +++ b/public/app/plugins/panel/heatmap/YBucketScaleEditor.tsx @@ -0,0 +1,135 @@ +import { useState } from 'react'; + +import { SelectableValue, StandardEditorProps } from '@grafana/data'; +import { t } from '@grafana/i18n'; +import { ScaleDistribution, ScaleDistributionConfig } from '@grafana/schema'; +import { RadioButtonGroup, Field, Select, Input } from '@grafana/ui'; + +type ScaleOptionValue = 'auto' | ScaleDistribution; + +/** + * Simplified scale editor that shows all options in a single line. + * Includes "Auto" option which returns undefined to use default behavior. + */ +export const YBucketScaleEditor = (props: StandardEditorProps) => { + const { value, onChange } = props; + + const type = value?.type; + const log = value?.log ?? 2; + const isAuto = value === undefined; + + const [localLinearThreshold, setLocalLinearThreshold] = useState( + value?.linearThreshold != null ? String(value.linearThreshold) : '' + ); + + const currentOption: ScaleOptionValue = isAuto ? 'auto' : type!; + const showLogBase = type === ScaleDistribution.Log || type === ScaleDistribution.Symlog; + const showLinearThreshold = type === ScaleDistribution.Symlog; + + const SCALE_OPTIONS: Array> = [ + { + label: t('heatmap.y-bucket-scale-editor.scale-options.label-auto', 'Auto'), + value: 'auto', + }, + { + label: t('heatmap.y-bucket-scale-editor.scale-options.label-linear', 'Linear'), + value: ScaleDistribution.Linear, + }, + { + label: t('heatmap.y-bucket-scale-editor.scale-options.label-log', 'Log'), + value: ScaleDistribution.Log, + }, + { + label: t('heatmap.y-bucket-scale-editor.scale-options.label-symlog', 'Symlog'), + value: ScaleDistribution.Symlog, + }, + ]; + + const LOG_BASE_OPTIONS: Array> = [ + { + label: '2', + value: 2, + }, + { + label: '10', + value: 10, + }, + ]; + + const handleScaleChange = (v: ScaleOptionValue) => { + if (v === 'auto') { + onChange(undefined); + return; + } + + if (v === ScaleDistribution.Linear) { + onChange({ type: ScaleDistribution.Linear }); + return; + } + + if (v === ScaleDistribution.Log) { + onChange({ type: ScaleDistribution.Log, log }); + return; + } + + if (v === ScaleDistribution.Symlog) { + onChange({ + type: ScaleDistribution.Symlog, + log, + linearThreshold: value?.linearThreshold ?? 1, + }); + return; + } + }; + + const handleLogBaseChange = (newLog: number) => { + onChange({ + ...value!, + log: newLog, + }); + }; + + const handleLinearThresholdChange = (newValue: string) => { + setLocalLinearThreshold(newValue); + const numValue = parseFloat(newValue); + if (!isNaN(numValue) && numValue !== 0) { + onChange({ + ...value!, + linearThreshold: numValue, + }); + } + }; + + return ( + <> + + {showLogBase && ( + + handleLinearThresholdChange(e.currentTarget.value)} + placeholder={t('heatmap.y-bucket-scale-editor.linear-threshold-placeholder', '1')} + /> + + )} + + ); +}; diff --git a/public/app/plugins/panel/heatmap/module.tsx b/public/app/plugins/panel/heatmap/module.tsx index a7d44726886..99bb66e2c3c 100644 --- a/public/app/plugins/panel/heatmap/module.tsx +++ b/public/app/plugins/panel/heatmap/module.tsx @@ -1,4 +1,11 @@ -import { DataFrame, FieldConfigProperty, FieldType, identityOverrideProcessor, PanelPlugin } from '@grafana/data'; +import { + DataFrame, + DataFrameType, + FieldConfigProperty, + FieldType, + identityOverrideProcessor, + PanelPlugin, +} from '@grafana/data'; import { t } from '@grafana/i18n'; import { config } from '@grafana/runtime'; import { @@ -15,6 +22,7 @@ import { addHeatmapCalculationOptions } from 'app/features/transformers/calculat import { readHeatmapRowsCustomMeta } from 'app/features/transformers/calculateHeatmap/heatmap'; import { HeatmapPanel } from './HeatmapPanel'; +import { YBucketScaleEditor } from './YBucketScaleEditor'; import { prepareHeatmapData } from './fields'; import { heatmapChangedHandler, heatmapMigrationHandler } from './migrations'; import { colorSchemes, quantizeScheme } from './palettes'; @@ -59,6 +67,7 @@ export const plugin = new PanelPlugin(HeatmapPanel) const opts = context.options ?? defaultOptions; let isOrdinalY = false; + const isHeatmapCells = context.data.some((frame) => frame.meta?.type === DataFrameType.HeatmapCells); if (context.data.length > 0) { try { @@ -94,6 +103,17 @@ export const plugin = new PanelPlugin(HeatmapPanel) addHeatmapCalculationOptions('calculation.', builder, opts.calculation, category); } + if (!opts.calculate && !isHeatmapCells && config.featureToggles.heatmapRowsAxisOptions) { + builder.addCustomEditor({ + id: 'rowsFrame-yBucketScale', + path: 'rowsFrame.yBucketScale', + name: t('heatmap.name-y-bucket-scale', 'Y bucket scale'), + category, + editor: YBucketScaleEditor, + defaultValue: undefined, + }); + } + category = [t('heatmap.category-y-axis', 'Y Axis')]; builder @@ -170,7 +190,9 @@ export const plugin = new PanelPlugin(HeatmapPanel) category, }); - if (!opts.calculate) { + // Hide tick alignment for explicit scales - bucket boundaries are fixed by numeric labels + const hasExplicitScale = context.options?.rowsFrame?.yBucketScale !== undefined; + if (!opts.calculate && !hasExplicitScale) { builder.addRadio({ path: 'rowsFrame.layout', name: t('heatmap.name-tick-alignment', 'Tick alignment'), diff --git a/public/app/plugins/panel/heatmap/panelcfg.cue b/public/app/plugins/panel/heatmap/panelcfg.cue index e947aaf9bb6..e07717429d7 100644 --- a/public/app/plugins/panel/heatmap/panelcfg.cue +++ b/public/app/plugins/panel/heatmap/panelcfg.cue @@ -105,6 +105,8 @@ composableKinds: PanelCfg: lineage: { value?: string // Controls tick alignment when not calculating from data layout?: ui.HeatmapCellLayout + // Controls the scale distribution of the y-axis buckets + yBucketScale?: ui.ScaleDistributionConfig } @cuetsy(kind="interface") Options: { annotations?: ui.VizAnnotations diff --git a/public/app/plugins/panel/heatmap/panelcfg.gen.ts b/public/app/plugins/panel/heatmap/panelcfg.gen.ts index ef3ab0c9459..d5b822eb1ab 100644 --- a/public/app/plugins/panel/heatmap/panelcfg.gen.ts +++ b/public/app/plugins/panel/heatmap/panelcfg.gen.ts @@ -183,6 +183,10 @@ export interface RowsHeatmapOptions { * Sets the name of the cell when not calculating from data */ value?: string; + /** + * Controls the scale distribution of the y-axis buckets + */ + yBucketScale?: ui.ScaleDistributionConfig; } export interface Options { diff --git a/public/app/plugins/panel/heatmap/tooltip/utils.test.ts b/public/app/plugins/panel/heatmap/tooltip/utils.test.ts new file mode 100644 index 00000000000..a5da298d75c --- /dev/null +++ b/public/app/plugins/panel/heatmap/tooltip/utils.test.ts @@ -0,0 +1,47 @@ +import { DataFrameType, toDataFrame } from '@grafana/data'; + +import { isHeatmapSparse } from './utils'; + +describe('isHeatmapSparse', () => { + it('should return false when heatmap is undefined', () => { + expect(isHeatmapSparse(undefined)).toBe(false); + }); + + it('should return false for dense HeatmapCells (single Y field)', () => { + const heatmap = toDataFrame({ + fields: [{ name: 'y', values: [] }], + meta: { type: DataFrameType.HeatmapCells }, + }); + + expect(isHeatmapSparse(heatmap)).toBe(false); + }); + + it('should return true for sparse HeatmapCells (yMin and yMax fields)', () => { + const heatmap = toDataFrame({ + fields: [ + { name: 'yMin', values: [] }, + { name: 'yMax', values: [] }, + ], + meta: { type: DataFrameType.HeatmapCells }, + }); + + expect(isHeatmapSparse(heatmap)).toBe(true); + }); + + it('should return false for non-HeatmapCells data frames', () => { + const heatmap = toDataFrame({ + fields: [{ name: 'Value', values: [] }], + meta: { type: DataFrameType.HeatmapRows }, + }); + + expect(isHeatmapSparse(heatmap)).toBe(false); + }); + + it('should return false when meta is undefined', () => { + const heatmap = toDataFrame({ + fields: [{ name: 'value', values: [] }], + }); + + expect(isHeatmapSparse(heatmap)).toBe(false); + }); +}); diff --git a/public/app/plugins/panel/heatmap/tooltip/utils.ts b/public/app/plugins/panel/heatmap/tooltip/utils.ts index 58114245d4e..067bf7d2b71 100644 --- a/public/app/plugins/panel/heatmap/tooltip/utils.ts +++ b/public/app/plugins/panel/heatmap/tooltip/utils.ts @@ -1,4 +1,5 @@ -import { DataFrame, Field } from '@grafana/data'; +import { DataFrame, DataFrameType, Field } from '@grafana/data'; +import { isHeatmapCellsDense } from 'app/features/transformers/calculateHeatmap/heatmap'; import { HeatmapData } from '../fields'; @@ -91,3 +92,14 @@ export const getSparseCellMinMax = (data: HeatmapData, index: number): BucketsMi yBucketMax: yMax.values[index], }; }; + +/** + * Determines if a heatmap DataFrame is sparse (has explicit yMin/yMax bounds). + * Sparse heatmaps have HeatmapCells type and are not dense. + */ +export function isHeatmapSparse(heatmap: DataFrame | undefined): boolean { + if (!heatmap) { + return false; + } + return heatmap.meta?.type === DataFrameType.HeatmapCells && !isHeatmapCellsDense(heatmap); +} diff --git a/public/app/plugins/panel/heatmap/utils.test.ts b/public/app/plugins/panel/heatmap/utils.test.ts index 26fecaad53b..abb10812469 100644 --- a/public/app/plugins/panel/heatmap/utils.test.ts +++ b/public/app/plugins/panel/heatmap/utils.test.ts @@ -1,5 +1,374 @@ -describe('a test', () => { - it('has to have at least one test', () => { - expect(true).toBeTruthy(); +import { ScaleDistribution } from '@grafana/schema'; + +import { applyExplicitMinMax, boundedMinMax, calculateYSizeDivisor, toLogBase, valuesToFills } from './utils'; + +describe('toLogBase', () => { + it('returns 10 when value is 10', () => { + expect(toLogBase(10)).toBe(10); + }); + + it('returns 2 when value is 2', () => { + expect(toLogBase(2)).toBe(2); + }); + + it('returns 2 (default) when value is undefined', () => { + expect(toLogBase(undefined)).toBe(2); + }); + + it('returns 2 (default) for invalid values', () => { + expect(toLogBase(5)).toBe(2); + expect(toLogBase(0)).toBe(2); + expect(toLogBase(-1)).toBe(2); + expect(toLogBase(100)).toBe(2); + }); +}); + +describe('applyExplicitMinMax', () => { + it('returns original values when no explicit values provided', () => { + const [min, max] = applyExplicitMinMax(0, 100, undefined, undefined); + expect(min).toBe(0); + expect(max).toBe(100); + }); + + it('applies explicit min only', () => { + const [min, max] = applyExplicitMinMax(0, 100, 10, undefined); + expect(min).toBe(10); + expect(max).toBe(100); + }); + + it('applies explicit max only', () => { + const [min, max] = applyExplicitMinMax(0, 100, undefined, 90); + expect(min).toBe(0); + expect(max).toBe(90); + }); + + it('applies both explicit min and max', () => { + const [min, max] = applyExplicitMinMax(0, 100, 20, 80); + expect(min).toBe(20); + expect(max).toBe(80); + }); + + it('handles negative values', () => { + const [min, max] = applyExplicitMinMax(-50, 50, -10, 10); + expect(min).toBe(-10); + expect(max).toBe(10); + }); + + it('handles explicit min = 0', () => { + const [min, max] = applyExplicitMinMax(10, 100, 0, undefined); + expect(min).toBe(0); + expect(max).toBe(100); + }); + + it('handles explicit max = 0', () => { + const [min, max] = applyExplicitMinMax(-100, -10, undefined, 0); + expect(min).toBe(-100); + expect(max).toBe(0); + }); + + it('handles null scaleMin', () => { + const [min, max] = applyExplicitMinMax(null, 100, 10, undefined); + expect(min).toBe(10); + expect(max).toBe(100); + }); + + it('handles null scaleMax', () => { + const [min, max] = applyExplicitMinMax(0, null, undefined, 90); + expect(min).toBe(0); + expect(max).toBe(90); + }); + + it('preserves null when no explicit value provided', () => { + const [min, max] = applyExplicitMinMax(null, null, undefined, undefined); + expect(min).toBe(null); + expect(max).toBe(null); + }); +}); + +describe('calculateYSizeDivisor', () => { + it('returns 1 for linear scale', () => { + expect(calculateYSizeDivisor(ScaleDistribution.Linear, false, 2)).toBe(1); + }); + + it('returns 1 for log scale with explicit scale', () => { + expect(calculateYSizeDivisor(ScaleDistribution.Log, true, 2)).toBe(1); + }); + + it('returns 1 for symlog scale with explicit scale', () => { + expect(calculateYSizeDivisor(ScaleDistribution.Symlog, true, 2)).toBe(1); + }); + + it('returns split value for log scale without explicit scale', () => { + expect(calculateYSizeDivisor(ScaleDistribution.Log, false, 2)).toBe(2); + expect(calculateYSizeDivisor(ScaleDistribution.Log, false, 4)).toBe(4); + }); + + it('returns split value for symlog scale without explicit scale', () => { + expect(calculateYSizeDivisor(ScaleDistribution.Symlog, false, 2)).toBe(2); + expect(calculateYSizeDivisor(ScaleDistribution.Symlog, false, 3)).toBe(3); + }); + + it('handles string split values', () => { + expect(calculateYSizeDivisor(ScaleDistribution.Log, false, '2')).toBe(2); + expect(calculateYSizeDivisor(ScaleDistribution.Log, false, '4')).toBe(4); + }); + + it('returns 1 when split value is undefined', () => { + expect(calculateYSizeDivisor(ScaleDistribution.Log, false, undefined)).toBe(1); + }); + + it('returns 1 when scale type is undefined', () => { + expect(calculateYSizeDivisor(undefined, false, 2)).toBe(1); + }); + + it('returns 1 for ordinal scale', () => { + expect(calculateYSizeDivisor(ScaleDistribution.Ordinal, false, 2)).toBe(1); + }); +}); + +describe('boundedMinMax', () => { + describe('when min and max are not provided', () => { + it('calculates min and max from values', () => { + const values = [10, 20, 5, 30, 15]; + const [min, max] = boundedMinMax(values); + expect(min).toBe(5); + expect(max).toBe(30); + }); + + it('handles single value', () => { + const values = [42]; + const [min, max] = boundedMinMax(values); + expect(min).toBe(42); + expect(max).toBe(42); + }); + + it('handles negative values', () => { + const values = [-10, -20, -5, -30]; + const [min, max] = boundedMinMax(values); + expect(min).toBe(-30); + expect(max).toBe(-5); + }); + + it('handles mixed positive and negative values', () => { + const values = [-10, 20, -5, 30]; + const [min, max] = boundedMinMax(values); + expect(min).toBe(-10); + expect(max).toBe(30); + }); + + it('returns Infinity/-Infinity for empty array', () => { + const values: number[] = []; + const [min, max] = boundedMinMax(values); + expect(min).toBe(Infinity); + expect(max).toBe(-Infinity); + }); + }); + + describe('when min is provided', () => { + it('uses provided min value', () => { + const values = [10, 20, 5, 30]; + const [min, max] = boundedMinMax(values, 0); + expect(min).toBe(0); + expect(max).toBe(30); + }); + + it('uses provided min even if higher than data min', () => { + const values = [10, 20, 5, 30]; + const [min, max] = boundedMinMax(values, 15); + expect(min).toBe(15); + expect(max).toBe(30); + }); + }); + + describe('when max is provided', () => { + it('uses provided max value', () => { + const values = [10, 20, 5, 30]; + const [min, max] = boundedMinMax(values, undefined, 50); + expect(min).toBe(5); + expect(max).toBe(50); + }); + + it('uses provided max even if lower than data max', () => { + const values = [10, 20, 5, 30]; + const [min, max] = boundedMinMax(values, undefined, 25); + expect(min).toBe(5); + expect(max).toBe(25); + }); + }); + + describe('when both min and max are provided', () => { + it('uses both provided values', () => { + const values = [10, 20, 5, 30]; + const [min, max] = boundedMinMax(values, 0, 50); + expect(min).toBe(0); + expect(max).toBe(50); + }); + }); + + describe('with hideLE filter', () => { + it('excludes values less than or equal to hideLE', () => { + const values = [5, 10, 15, 20, 25]; + const [min, max] = boundedMinMax(values, undefined, undefined, 10); + expect(min).toBe(15); + expect(max).toBe(25); + }); + + it('excludes all values when hideLE is higher than all values', () => { + const values = [5, 10, 15]; + const [min, max] = boundedMinMax(values, undefined, undefined, 20); + expect(min).toBe(Infinity); + expect(max).toBe(-Infinity); + }); + }); + + describe('with hideGE filter', () => { + it('excludes values greater than or equal to hideGE', () => { + const values = [5, 10, 15, 20, 25]; + const [min, max] = boundedMinMax(values, undefined, undefined, -Infinity, 20); + expect(min).toBe(5); + expect(max).toBe(15); + }); + + it('excludes all values when hideGE is lower than all values', () => { + const values = [15, 20, 25]; + const [min, max] = boundedMinMax(values, undefined, undefined, -Infinity, 10); + expect(min).toBe(Infinity); + expect(max).toBe(-Infinity); + }); + }); + + describe('with both hideLE and hideGE filters', () => { + it('excludes values outside the range', () => { + const values = [5, 10, 15, 20, 25, 30]; + const [min, max] = boundedMinMax(values, undefined, undefined, 10, 25); + expect(min).toBe(15); + expect(max).toBe(20); + }); + + it('works with provided min/max bounds', () => { + const values = [5, 10, 15, 20, 25, 30]; + const [min, max] = boundedMinMax(values, 0, 50, 10, 25); + expect(min).toBe(0); + expect(max).toBe(50); + }); + }); +}); + +describe('valuesToFills', () => { + // Fake color palette for testing index mapping + const palette5 = ['c0', 'c1', 'c2', 'c3', 'c4']; + + describe('basic mapping', () => { + it('maps values to palette indices', () => { + const values = [0, 25, 50, 75, 100]; + const fills = valuesToFills(values, palette5, 0, 100); + + expect(fills).toEqual([0, 1, 2, 3, 4]); + }); + + it('maps min value to first palette index', () => { + const values = [10]; + const fills = valuesToFills(values, palette5, 10, 20); + + expect(fills[0]).toBe(0); + }); + + it('maps max value to last palette index', () => { + const values = [20]; + const fills = valuesToFills(values, palette5, 10, 20); + + expect(fills[0]).toBe(4); + }); + + it('maps mid-range values proportionally', () => { + const values = [15]; + const fills = valuesToFills(values, palette5, 10, 20); + + // 15 is middle of 10-20, should map to index 2 (middle color) + expect(fills[0]).toBe(2); + }); + }); + + describe('edge cases', () => { + it('clamps values below min to first index', () => { + const values = [5, 8, 10]; + const fills = valuesToFills(values, palette5, 10, 20); + + expect(fills[0]).toBe(0); // 5 < 10 + expect(fills[1]).toBe(0); // 8 < 10 + }); + + it('clamps values above max to last index', () => { + const values = [20, 25, 30]; + const fills = valuesToFills(values, palette5, 10, 20); + + expect(fills[0]).toBe(4); // 20 = max + expect(fills[1]).toBe(4); // 25 > max + expect(fills[2]).toBe(4); // 30 > max + }); + + it('handles zero range (min equals max)', () => { + const values = [10, 10, 10]; + const fills = valuesToFills(values, palette5, 10, 10); + + // When range is 0, defaults to 1, so all values map to 0 + expect(fills).toEqual([0, 0, 0]); + }); + + it('handles single color palette', () => { + const values = [0, 50, 100]; + const palette = ['c0']; + const fills = valuesToFills(values, palette, 0, 100); + + expect(fills).toEqual([0, 0, 0]); + }); + + it('handles large palette', () => { + const values = [50]; + const palette = Array.from({ length: 256 }, (_, i) => `c${i}`); + const fills = valuesToFills(values, palette, 0, 100); + + // 50 is 50% of 0-100, should map to 128 (middle of 256) + expect(fills[0]).toBe(128); + }); + }); + + describe('negative values', () => { + it('handles negative min and max', () => { + const values = [-10, -5, 0]; + const palette = ['c0', 'c1', 'c2']; + const fills = valuesToFills(values, palette, -10, 0); + + expect(fills[0]).toBe(0); // -10 is min + expect(fills[1]).toBe(1); // -5 is middle + expect(fills[2]).toBe(2); // 0 is max + }); + + it('handles range crossing zero', () => { + const values = [-10, 0, 10]; + const palette = ['c0', 'c1', 'c2']; + const fills = valuesToFills(values, palette, -10, 10); + + expect(fills[0]).toBe(0); // -10 is min + expect(fills[1]).toBe(1); // 0 is middle + expect(fills[2]).toBe(2); // 10 is max + }); + }); + + describe('preserves array length', () => { + it('returns array with same length as input', () => { + const values = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + const palette = ['c0', 'c1']; + const fills = valuesToFills(values, palette, 1, 10); + + expect(fills.length).toBe(values.length); + }); + + it('handles empty array', () => { + const values: number[] = []; + const fills = valuesToFills(values, palette5, 0, 100); + + expect(fills).toEqual([]); + }); }); }); diff --git a/public/app/plugins/panel/heatmap/utils.ts b/public/app/plugins/panel/heatmap/utils.ts index a51c86f0d1c..6ae058f6261 100644 --- a/public/app/plugins/panel/heatmap/utils.ts +++ b/public/app/plugins/panel/heatmap/utils.ts @@ -14,13 +14,22 @@ import { } from '@grafana/data'; import { AxisPlacement, ScaleDirection, ScaleDistribution, ScaleOrientation, HeatmapCellLayout } from '@grafana/schema'; import { UPlotConfigBuilder, UPlotConfigPrepFn } from '@grafana/ui'; -import { isHeatmapCellsDense, readHeatmapRowsCustomMeta } from 'app/features/transformers/calculateHeatmap/heatmap'; +import { + calculateBucketFactor, + isHeatmapCellsDense, + readHeatmapRowsCustomMeta, +} from 'app/features/transformers/calculateHeatmap/heatmap'; import { pointWithin, Quadtree, Rect } from '../barchart/quadtree'; import { HeatmapData } from './fields'; import { FieldConfig, HeatmapSelectionMode, YAxisConfig } from './types'; +/** Validates and returns a safe log base (2 or 10), defaults to 2 if invalid */ +export function toLogBase(value: number | undefined): 2 | 10 { + return value === 10 ? 10 : 2; +} + interface PathbuilderOpts { each: (u: uPlot, seriesIdx: number, dataIdx: number, lft: number, top: number, wid: number, hgt: number) => void; gap?: number | null; @@ -54,6 +63,7 @@ interface PrepConfigOpts { ySizeDivisor?: number; selectionMode?: HeatmapSelectionMode; xAxisConfig?: Parameters[0]['xAxisConfig']; + rowsFrame?: { yBucketScale?: { type: ScaleDistribution; log?: number; linearThreshold?: number } }; } export function prepConfig(opts: PrepConfigOpts) { @@ -69,8 +79,11 @@ export function prepConfig(opts: PrepConfigOpts) { ySizeDivisor, selectionMode = HeatmapSelectionMode.X, xAxisConfig, + rowsFrame, } = opts; + const yBucketScale = rowsFrame?.yBucketScale; + const xScaleKey = 'x'; let isTime = true; @@ -196,7 +209,20 @@ export function prepConfig(opts: PrepConfigOpts) { const yScale = yFieldConfig?.scaleDistribution ?? { type: ScaleDistribution.Linear }; const yAxisReverse = Boolean(yAxisConfig.reverse); const isSparseHeatmap = heatmapType === DataFrameType.HeatmapCells && !isHeatmapCellsDense(dataRef.current?.heatmap!); - const shouldUseLogScale = yScale.type !== ScaleDistribution.Linear || isSparseHeatmap; + + const scaleDistribution = (() => { + if (yBucketScale) { + return yBucketScale.type; + } + if (yScale.type !== ScaleDistribution.Linear || isSparseHeatmap) { + return ScaleDistribution.Log; + } + return ScaleDistribution.Linear; + })(); + + const scaleLog = toLogBase(yBucketScale?.log ?? yScale.log); + const scaleLinearThreshold = yBucketScale?.linearThreshold; + const isOrdinalY = readHeatmapRowsCustomMeta(dataRef.current?.heatmap).yOrdinalDisplay != null; // random to prevent syncing y in other heatmaps @@ -210,8 +236,9 @@ export function prepConfig(opts: PrepConfigOpts) { orientation: ScaleOrientation.Vertical, direction: yAxisReverse ? ScaleDirection.Down : ScaleDirection.Up, // should be tweakable manually - distribution: shouldUseLogScale ? ScaleDistribution.Log : ScaleDistribution.Linear, - log: yScale.log ?? 2, + distribution: scaleDistribution, + log: scaleLog, + linearThreshold: scaleLinearThreshold, range: // sparse already accounts for le/ge by explicit yMin & yMax cell bounds, so no need to expand y range isSparseHeatmap @@ -224,16 +251,16 @@ export function prepConfig(opts: PrepConfigOpts) { let scaleMin: number | null, scaleMax: number | null; - [scaleMin, scaleMax] = shouldUseLogScale - ? uPlot.rangeLog(dataMin, dataMax, (yScale.log ?? 2) as unknown as uPlot.Scale.LogBase, true) - : [dataMin, dataMax]; + const isLogScale = + scaleDistribution === ScaleDistribution.Log || scaleDistribution === ScaleDistribution.Symlog; + [scaleMin, scaleMax] = isLogScale ? uPlot.rangeLog(dataMin, dataMax, scaleLog, true) : [dataMin, dataMax]; - if (shouldUseLogScale && !isOrdinalY) { + let { min: explicitMin, max: explicitMax } = yAxisConfig; + + if (isLogScale && !isOrdinalY) { let yExp = u.scales[yScaleKey].log!; let log = yExp === 2 ? Math.log2 : Math.log10; - let { min: explicitMin, max: explicitMax } = yAxisConfig; - // guard against <= 0 if (explicitMin != null && explicitMin > 0) { // snap to magnitude @@ -245,6 +272,9 @@ export function prepConfig(opts: PrepConfigOpts) { let maxLog = log(explicitMax); scaleMax = yExp ** incrRoundUp(maxLog, 1); } + } else if (!isOrdinalY) { + // Apply explicit min/max for linear scale + [scaleMin, scaleMax] = applyExplicitMinMax(scaleMin, scaleMax, explicitMin, explicitMax); } return [scaleMin, scaleMax]; @@ -257,7 +287,7 @@ export function prepConfig(opts: PrepConfigOpts) { let { min: explicitMin, max: explicitMax } = yAxisConfig; // logarithmic expansion - if (shouldUseLogScale) { + if (scaleDistribution === ScaleDistribution.Log || scaleDistribution === ScaleDistribution.Symlog) { let yExp = u.scales[yScaleKey].log!; let minExpanded = false; @@ -280,17 +310,31 @@ export function prepConfig(opts: PrepConfigOpts) { } } + // For pre-bucketed data with explicit scale, calculate expansion factor from actual bucket spacing + // For calculated heatmaps, use the full log base + let expansionFactor: number = yExp; + + if (yBucketScale !== undefined) { + // Try to infer the bucket factor from the actual data spacing + const yValues = u.data[1]?.[1]; + if (Array.isArray(yValues) && yValues.length >= 2 && typeof yValues[0] === 'number') { + expansionFactor = calculateBucketFactor(yValues, yExp); + } + } + if (dataRef.current?.yLayout === HeatmapCellLayout.le) { if (!minExpanded) { - scaleMin /= yExp; + scaleMin /= expansionFactor; } } else if (dataRef.current?.yLayout === HeatmapCellLayout.ge) { if (!maxExpanded) { - scaleMax *= yExp; + scaleMax *= expansionFactor; } } else { - scaleMin /= yExp / 2; - scaleMax *= yExp / 2; + // Unknown layout - expand both directions + const factor = Math.sqrt(expansionFactor); // Use sqrt for balanced expansion + scaleMin /= factor; + scaleMax *= factor; } if (!isOrdinalY) { @@ -383,7 +427,7 @@ export function prepConfig(opts: PrepConfigOpts) { return splits.map((v) => v < 0 ? (meta.yMinDisplay ?? '') // Check prometheus style labels - : (meta.yOrdinalDisplay[v] ?? '') + : (meta.yOrdinalDisplay?.[v] ?? '') ); } return splits; @@ -585,15 +629,19 @@ export function heatmapPathsDense(opts: PathbuilderOpts) { let ySize: number; if (scaleX.distr === 3) { - xSize = Math.abs(valToPosX(xs[0] * scaleX.log!, scaleX, xDim, xOff) - valToPosX(xs[0], scaleX, xDim, xOff)); + // For log scales, calculate cell size from actual adjacent bucket positions + const nextXValue = xs[yBinQty] ?? xs[0] * scaleX.log!; + xSize = Math.abs(valToPosX(nextXValue, scaleX, xDim, xOff) - valToPosX(xs[0], scaleX, xDim, xOff)); } else { xSize = Math.abs(valToPosX(xBinIncr, scaleX, xDim, xOff) - valToPosX(0, scaleX, xDim, xOff)); } if (scaleY.distr === 3) { - ySize = - Math.abs(valToPosY(ys[0] * scaleY.log!, scaleY, yDim, yOff) - valToPosY(ys[0], scaleY, yDim, yOff)) / - ySizeDivisor; + // Use actual data spacing for pre-bucketed data, or full magnitude for calculated heatmaps with splits + const nextYValue = ySizeDivisor === 1 ? (ys[1] ?? ys[0] * scaleY.log!) : ys[0] * scaleY.log!; + + const baseYSize = Math.abs(valToPosY(nextYValue, scaleY, yDim, yOff) - valToPosY(ys[0], scaleY, yDim, yOff)); + ySize = baseYSize / ySizeDivisor; } else { ySize = Math.abs(valToPosY(yBinIncr, scaleY, yDim, yOff) - valToPosY(0, scaleY, yDim, yOff)) / ySizeDivisor; } @@ -882,3 +930,30 @@ export const valuesToFills = (values: number[], palette: string[], minValue: num return indexedFills; }; + +/** + * Calculates the Y-axis size divisor for heatmap cell rendering. + * For log/symlog scales with calculated data (no explicit scale), divides cells by the split value. + * Otherwise returns 1 (no division). + */ +export function calculateYSizeDivisor( + scaleType: ScaleDistribution | undefined, + hasExplicitScale: boolean, + splitValue: number | string | undefined +): number { + const isLogScale = scaleType === ScaleDistribution.Log || scaleType === ScaleDistribution.Symlog; + return isLogScale && !hasExplicitScale ? +(splitValue || 1) : 1; +} + +/** + * Applies explicit min/max values to scale range for linear scales. + * Returns the original values if explicitMin/explicitMax are undefined. + */ +export function applyExplicitMinMax( + scaleMin: number | null, + scaleMax: number | null, + explicitMin: number | undefined, + explicitMax: number | undefined +): [number | null, number | null] { + return [explicitMin ?? scaleMin, explicitMax ?? scaleMax]; +} diff --git a/public/app/plugins/panel/table/suggestions.ts b/public/app/plugins/panel/table/suggestions.ts index 8e0d6e44953..260e73b43eb 100644 --- a/public/app/plugins/panel/table/suggestions.ts +++ b/public/app/plugins/panel/table/suggestions.ts @@ -1,4 +1,5 @@ import { PanelDataSummary, VisualizationSuggestionScore, VisualizationSuggestionsSupplier } from '@grafana/data'; +import { config } from 'app/core/config'; import icnTablePanelSvg from 'app/plugins/panel/table/img/icn-table-panel.svg'; import { Options, FieldConfig } from './panelcfg.gen'; @@ -29,7 +30,7 @@ export const tableSuggestionsSupplier: VisualizationSuggestionsSupplier(TextPanel) defaultValue: defaultOptions.content, }); }) - .setMigrationHandler(textPanelMigrationHandler); + .setMigrationHandler(textPanelMigrationHandler) + .setSuggestionsSupplier((ds) => + ds.fieldCount === 0 && !config.featureToggles.newVizSuggestions + ? [{ cardOptions: { imgSrc: icnTextPanelSvg } }] + : [] + ); diff --git a/public/app/plugins/panel/text/plugin.json b/public/app/plugins/panel/text/plugin.json index ce437e97bf5..a1acce42c6e 100644 --- a/public/app/plugins/panel/text/plugin.json +++ b/public/app/plugins/panel/text/plugin.json @@ -2,7 +2,7 @@ "type": "panel", "name": "Text", "id": "text", - + "suggestions": true, "skipDataQuery": true, "info": { diff --git a/public/app/types/accessControl.ts b/public/app/types/accessControl.ts index b759bc32d6f..c53bdb9389e 100644 --- a/public/app/types/accessControl.ts +++ b/public/app/types/accessControl.ts @@ -143,6 +143,7 @@ export enum AccessControlAction { AlertingReceiversCreate = 'alert.notifications.receivers:create', AlertingReceiversWrite = 'alert.notifications.receivers:write', AlertingReceiversRead = 'alert.notifications.receivers:read', + AlertingReceiversUpdateProtected = 'alert.notifications.receivers.protected:write', // Alerting routes actions AlertingRoutesRead = 'alert.notifications.routes:read', diff --git a/public/app/types/teams.ts b/public/app/types/teams.ts index 72202a21295..e78a74a3bda 100644 --- a/public/app/types/teams.ts +++ b/public/app/types/teams.ts @@ -37,7 +37,3 @@ export interface TeamGroup { groupId: string; teamId: number; } - -export interface TeamState { - groups: TeamGroup[]; -} diff --git a/public/img/DO_NOT_MODIFY.md b/public/img/DO_NOT_MODIFY.md new file mode 100644 index 00000000000..0cb524cd4b4 --- /dev/null +++ b/public/img/DO_NOT_MODIFY.md @@ -0,0 +1,7 @@ +# WARNING: Do NOT modify the contents of this directory! + +User modifications in this directory to change the runtime behavior or appearance of Grafana are NOT supported. Doing so could result in undefined behaviour including: bugs, security vulnerabilities, or critical failures. + +Grafana is an open source project. Please feel free to contribute changes for review if you have specific bug fix or feature that you think might be useful to the rest of the community. + +- SEE: https://github.com/grafana/plugin-tools/blob/main/CONTRIBUTING.md diff --git a/public/locales/cs-CZ/grafana.json b/public/locales/cs-CZ/grafana.json index c64175c4d1f..575bba19ca1 100644 --- a/public/locales/cs-CZ/grafana.json +++ b/public/locales/cs-CZ/grafana.json @@ -2248,6 +2248,13 @@ "receiver-metadata-badge": { "aria-label-open-external-link": "Otevřít externí odkaz" }, + "receivers": { + "protected": { + "field": { + "description": "" + } + } + }, "receivers-section": { "button-more": "Další", "new-menu": { @@ -3344,6 +3351,7 @@ "login-attribute-path-label": "Cesta atributu přihlášení", "login-prompt-consent": "Souhlas", "login-prompt-description": "Označuje typ interakce uživatele při přihlášení pomocí IdP.", + "login-prompt-description-google": "", "login-prompt-label": "Výzva k přihlášení", "login-prompt-login": "Přihlášení", "login-prompt-select-account": "Vyberte účet", @@ -3401,6 +3409,7 @@ "use-pkce-description": "Pokud je povoleno, Grafana použije <2>ověřovací klíč pro výměnu kódů (PKCE) s udělením autorizačního kódu OAuth2.", "use-pkce-label": "Použít PKCE", "use-refresh-token-description": "Pokud je povoleno, Grafana načte nový přístupový token pomocí obnovovacího tokenu poskytnutého poskytovatelem OAuth2.", + "use-refresh-token-description-google": "", "use-refresh-token-label": "Použít token pro obnovení", "validate-hosted-domain-description": "Pokud je povoleno, Grafana porovná hostovanou doménu načtenou z tokenu Google ID se seznamem „{{ allowedDomainsLabel }}“ zadaným uživatelem.", "validate-hosted-domain-label": "Ověřit hostovanou doménu", @@ -4859,8 +4868,7 @@ "apply": "", "change-value": "", "discard": "", - "modal-title": "", - "values": "Hodnoty oddělené čárkou" + "modal-title": "" }, "datasource-options": { "name-filter": "Filtr názvu", @@ -10261,7 +10269,8 @@ "copy": "Kopírovat výběr", "disable-menu": "Zakázat nabídku", "line-contains": "Přidat jako řádek obsahuje filtr", - "line-contains-not": "Přidat jako řádek neobsahuje filtr" + "line-contains-not": "Přidat jako řádek neobsahuje filtr", + "search-text": "" }, "show-log-attributes": "", "timestamp-format": "Rozlišení časového razítka", @@ -11505,6 +11514,12 @@ "latestReleaseDate": "Nejnovější datum vydání:", "latestVersion": "Poslední verze", "license": "Licence", + "moreDetails": "", + "pluginInsights": { + "header": "" + }, + "pluginInsightsSuccessTooltip": "", + "pluginInsightsWarningTooltip": "", "raiseAnIssue": "Nahlásit problém", "reportAbuse": "", "reportAbuseTooltip": "Nahlaste problémy související se škodlivými pluginy přímo společnosti Grafana Labs.", @@ -11961,7 +11976,6 @@ } }, "getting-started": { - "alert-temporary-outage": "Když připojíte celou instanci, nástěnky nebudou během migrace k dispozici. Doporučujeme uživatele před zahájením procesu varovat.", "modal-description-public-access": "Nastavte veřejný přístup k vaší instanci Grafana pro povolení integrace GitHubu", "modal-description-required-features": "Povolit požadované funkce Grafany pro zajištění", "modal-title-set-up-public-access": "Nastavit veřejný přístup", @@ -11973,8 +11987,7 @@ "step-title-copy-url": "Kopírovat veřejnou adresu URL", "step-title-enable-feature-toggles": "Povolit požadované přepínače funkcí", "step-title-start-ngrok": "Spustit „ngrok“ pro dočasný veřejný přístup", - "step-title-update-grafana-config": "Aktualizujte konfiguraci Grafany", - "title-setting-connection-could-cause-temporary-outage": "Nastavení tohoto připojení může způsobit dočasný výpadek" + "step-title-update-grafana-config": "Aktualizujte konfiguraci Grafany" }, "getting-started-page": { "subtitle-provisioning-feature": "Zobrazujte a spravujte vazby zajištění" @@ -12043,18 +12056,15 @@ }, "home-page": { "button-delete-repositories": "Odstranit úložiště", - "configured-repositories-while-running-legacy-storage": "Konfigurovaná úložiště nebudou fungovat při spuštění starší verze úložiště.", "confirm-delete-repositories": "Opravdu chcete odstranit všechna nakonfigurovaná úložiště? Tato akce je nevratná.", "error-delete-all-repositories": "Nepodařilo se odstranit všechna úložiště", - "remove-all-configured-repositories": "Odebrat všechna nakonfigurovaná úložiště", "subtitle": "Zobrazujte a spravujte nakonfigurovaná úložiště", "success-all-repositories-deleted": "Všechna nakonfigurovaná úložiště byla odstraněna", "tab-getting-started": "Začínáme", "tab-getting-started-title": "Začínáme", "tab-repositories": "Úložiště", "tab-repositories-title": "Seznam úložišť", - "title-delete-all-configured-repositories": "Odstranit všechna nakonfigurovaná úložiště", - "title-legacy-storage-detected": "Bylo zjištěno starší úložiště" + "title-delete-all-configured-repositories": "Odstranit všechna nakonfigurovaná úložiště" }, "http-utils": { "access-denied": "", @@ -12094,7 +12104,6 @@ "mode-options": { "disabled": { "folder-connected": "", - "legacy-storage": "", "not-allowed": "", "not-supported": "" }, @@ -12174,7 +12183,6 @@ "repository-status-page": { "back-to-repositories": "Zpět na úložiště", "cleaning-up-resources": "Čištění zdrojů úložiště", - "legacy-storage-message": "Instance nespustila sjednocené úložiště – vyžaduje průvodce migrací", "not-found": "nenalezeno", "not-found-message": "Úložiště nebylo nalezeno", "repository-config-exists-configuration": "Ujistěte se, že konfigurace úložiště existuje v konfiguračním souboru.", @@ -12183,7 +12191,6 @@ "tab-resources": "Zdroje", "tab-resources-title": "", "title": "Stav úložiště", - "title-legacy-storage": "Starší verze úložiště", "title-queued-for-deletion": "Zařazeno do fronty k odstranění" }, "repository-type-cards": { @@ -12279,9 +12286,7 @@ "synchronize-step": { "repository-error": "", "repository-error-message": "", - "repository-unhealthy": "", - "synchronization-description": "Zahrnout předložení pro každou historickou hodnotu", - "synchronization-options": "Možnosti synchronizace" + "repository-unhealthy": "" }, "token-permissions-info": { "and-click": "a klikněte", @@ -12298,11 +12303,11 @@ }, "warning-title-default": "Varování", "wizard": { - "alert-point-1": "Během tohoto procesu nebude možné vytvářet, upravovat ani odstraňovat zdroje. V posledním kroku zmizí.", - "alert-point-2": "Po zajištění se zdroje znovu zobrazí a budou spravovány prostřednictvím externího úložiště.", + "alert-point-1": "", + "alert-point-2": "", "alert-point-3": "Doba trvání tohoto procesu závisí na počtu zapojených zdrojů.", - "alert-point-4": "Správci podnikových instancí mohou uživatelům zobrazit banner oznámení. Podrobné pokyny najdete v <2>této příručce.", - "alert-title": "Důležité: Nebudou ztracena žádná data ani konfigurace, ale nástěnky budou na několik minut dočasně nedostupné.", + "alert-point-4": "", + "alert-title": "", "button-cancel": "", "button-cancelling": "", "button-next": "Dokončit", @@ -12320,7 +12325,6 @@ "step-finish": "Vybrat další nastavení", "step-synchronize": "Synchronizovat s externím úložištěm", "sync-description": "Synchronizujte zdroje s externím úložištěm. Po tomto jednorázovém kroku budou všechny budoucí aktualizace automaticky uloženy do úložiště a zajištěny zpět do instance.", - "sync-option-history": "Historie", "title-bootstrap": "Vyberte, co chcete synchronizovat", "title-connect": "Připojit k externímu úložišti", "title-finish": "Vybrat další nastavení", diff --git a/public/locales/de-DE/grafana.json b/public/locales/de-DE/grafana.json index 0da32e80f94..9df0dd8a2da 100644 --- a/public/locales/de-DE/grafana.json +++ b/public/locales/de-DE/grafana.json @@ -2232,6 +2232,13 @@ "receiver-metadata-badge": { "aria-label-open-external-link": "Externen Link öffnen" }, + "receivers": { + "protected": { + "field": { + "description": "" + } + } + }, "receivers-section": { "button-more": "Mehr", "new-menu": { @@ -3322,6 +3329,7 @@ "login-attribute-path-label": "Anmeldeattributpfad", "login-prompt-consent": "Einverständnis", "login-prompt-description": "Gibt die Art der Nutzerinteraktion an, wenn sich der Nutzer mit dem IdP anmeldet.", + "login-prompt-description-google": "", "login-prompt-label": "Anmeldeaufforderung", "login-prompt-login": "Anmelden", "login-prompt-select-account": "Account auswählen", @@ -3379,6 +3387,7 @@ "use-pkce-description": "Wenn dies aktiviert ist, nutzt Grafana <2>Proof Key for Code Exchange (PKCE) mit OAuth2 Authorization Code Grant.", "use-pkce-label": "PKCE verwenden", "use-refresh-token-description": "Wenn dies aktiviert ist, ruft Grafana einen neuen Zugriffstoken mit dem vom OAuth2-Anbieter bereitgestellten Aktualisierungstoken ab.", + "use-refresh-token-description-google": "", "use-refresh-token-label": "Aktualisierungstoken nutzen", "validate-hosted-domain-description": "Wenn dies aktiviert ist, wird Grafana die vom Google-ID-Token abgerufene gehostete Domain mit der vom Nutzer spezifizierten Liste „{{ allowedDomainsLabel }}“ abgleichen.", "validate-hosted-domain-label": "Gehostete Domain validieren", @@ -4821,8 +4830,7 @@ "apply": "", "change-value": "", "discard": "", - "modal-title": "", - "values": "Werte werden durch Komma getrennt" + "modal-title": "" }, "datasource-options": { "name-filter": "Namensfilter", @@ -10175,7 +10183,8 @@ "copy": "Auswahl kopieren", "disable-menu": "Menü deaktivieren", "line-contains": "„Als Zeile hinzufügen“ enthält Filter", - "line-contains-not": "„Als Zeile hinzufügen“ enthält keinen Filter" + "line-contains-not": "„Als Zeile hinzufügen“ enthält keinen Filter", + "search-text": "" }, "show-log-attributes": "", "timestamp-format": "Zeitstempelauflösung", @@ -11413,6 +11422,12 @@ "latestReleaseDate": "Neuestes Release-Datum:", "latestVersion": "Aktuelle Version", "license": "Lizenz", + "moreDetails": "", + "pluginInsights": { + "header": "" + }, + "pluginInsightsSuccessTooltip": "", + "pluginInsightsWarningTooltip": "", "raiseAnIssue": "Ein Problem melden", "reportAbuse": "", "reportAbuseTooltip": "Melden Sie Probleme im Zusammenhang mit bösartigen oder schädlichen Plugins direkt an Grafana Labs.", @@ -11859,7 +11874,6 @@ } }, "getting-started": { - "alert-temporary-outage": "Wenn Sie Ihre gesamte Instanz verbinden, sind während der Ausführung der Migration keine Dashboards verfügbar. Wir empfehlen Ihnen, Ihre Nutzer vor Beginn des Prozesses zu benachrichtigen.", "modal-description-public-access": "Richten Sie zur Aktivierung der GitHub-Integration den öffentlichen Zugriff auf Ihre Grafana-Instanz ein", "modal-description-required-features": "Benötigte Grafana-Funktionen für die Bereitstellung aktivieren", "modal-title-set-up-public-access": "Öffentlichen Zugriff einrichten", @@ -11871,8 +11885,7 @@ "step-title-copy-url": "Kopieren Sie Ihre öffentliche URL", "step-title-enable-feature-toggles": "Benötigte Funktionsschalter aktivieren", "step-title-start-ngrok": "ngrok für temporären öffentlichen Zugriff starten", - "step-title-update-grafana-config": "Aktualisieren Sie Ihre Grafana-Konfiguration", - "title-setting-connection-could-cause-temporary-outage": "Das Einrichten dieser Verbindung kann zu einem vorübergehenden Ausfall führen" + "step-title-update-grafana-config": "Aktualisieren Sie Ihre Grafana-Konfiguration" }, "getting-started-page": { "subtitle-provisioning-feature": "Sehen und verwalten Sie Ihre Bereitstellungsverbindungen" @@ -11941,18 +11954,15 @@ }, "home-page": { "button-delete-repositories": "Repositorys löschen", - "configured-repositories-while-running-legacy-storage": "Konfigurierte Repositorys funktionieren nicht, wenn veralteter Speicher ausgeführt wird.", "confirm-delete-repositories": "Sind Sie sicher, dass Sie alle konfigurierten Repositorys löschen möchten? Diese Aktion kann nicht rückgängig gemacht werden.", "error-delete-all-repositories": "Es konnten nicht alle Repositorys gelöscht werden", - "remove-all-configured-repositories": "Alle konfigurierten Repositorys entfernen", "subtitle": "Sehen und verwalten Sie Ihre konfigurierten Repositorys", "success-all-repositories-deleted": "Alle konfigurierten Repositorys gelöscht", "tab-getting-started": "Erste Schritte", "tab-getting-started-title": "Erste Schritte", "tab-repositories": "Repositorys", "tab-repositories-title": "Liste der Repositorys", - "title-delete-all-configured-repositories": "Alle konfigurierten Repositorys löschen", - "title-legacy-storage-detected": "Veralteter Speicher erkannt" + "title-delete-all-configured-repositories": "Alle konfigurierten Repositorys löschen" }, "http-utils": { "access-denied": "", @@ -11992,7 +12002,6 @@ "mode-options": { "disabled": { "folder-connected": "", - "legacy-storage": "", "not-allowed": "", "not-supported": "" }, @@ -12072,7 +12081,6 @@ "repository-status-page": { "back-to-repositories": "Zurück zu den Repositorys", "cleaning-up-resources": "Bereinigen von Repository-Ressourcen", - "legacy-storage-message": "Die Instanz führt noch keinen Unified Storage aus – Migrationsassistent erforderlich", "not-found": "nicht gefunden", "not-found-message": "Repository nicht gefunden", "repository-config-exists-configuration": "Achten Sie darauf, dass die Repository-config in der Konfigurationsdatei vorhanden ist.", @@ -12081,7 +12089,6 @@ "tab-resources": "Ressourcen", "tab-resources-title": "", "title": "Repository-Status", - "title-legacy-storage": "Veralteter Speicher", "title-queued-for-deletion": "Zum Löschen in die Warteschlange gestellt" }, "repository-type-cards": { @@ -12177,9 +12184,7 @@ "synchronize-step": { "repository-error": "", "repository-error-message": "", - "repository-unhealthy": "", - "synchronization-description": "Commits für jeden historischen Wert erfassen", - "synchronization-options": "Synchronisierungsoptionen" + "repository-unhealthy": "" }, "token-permissions-info": { "and-click": "und klicken", @@ -12196,11 +12201,11 @@ }, "warning-title-default": "Warnung", "wizard": { - "alert-point-1": "Während dieses Vorgangs können keine Ressourcen erstellt, bearbeitet oder gelöscht werden. Im letzten Schritt werden sie entfernt.", - "alert-point-2": "Sobald die Bereitstellung abgeschlossen ist, werden die Ressourcen wieder angezeigt und über einen externen Speicher verwaltet.", + "alert-point-1": "", + "alert-point-2": "", "alert-point-3": "Die Dauer dieses Prozesses hängt von der Anzahl der betroffenen Ressourcen ab.", - "alert-point-4": "Administratoren von Enterprise-Instanzen können Nutzern gegenüber ein Ankündigungsbanner anzeigen. Schritt-für-Schritt-Anweisungen finden Sie in <2>dieser Anleitung.", - "alert-title": "Wichtig: Es gehen keine Daten oder Konfigurationen verloren, aber die Dashboards sind für einige Minuten vorübergehend nicht verfügbar.", + "alert-point-4": "", + "alert-title": "", "button-cancel": "", "button-cancelling": "", "button-next": "Fertigstellen", @@ -12218,7 +12223,6 @@ "step-finish": "Zusätzliche Einstellungen auswählen", "step-synchronize": "Mit externem Speicher synchronisieren", "sync-description": "Synchronisieren Sie Ressourcen mit externem Speicher. Nach diesem einmaligen Schritt werden alle zukünftigen Updates automatisch im Repository gespeichert und wieder in der Instanz bereitgestellt.", - "sync-option-history": "Verlauf", "title-bootstrap": "Wählen Sie aus, was synchronisiert wird", "title-connect": "Mit externem Speicher verbinden", "title-finish": "Zusätzliche Einstellungen auswählen", diff --git a/public/locales/en-US/grafana.json b/public/locales/en-US/grafana.json index b3b6ce2c8db..a4e39d534a3 100644 --- a/public/locales/en-US/grafana.json +++ b/public/locales/en-US/grafana.json @@ -2232,6 +2232,13 @@ "receiver-metadata-badge": { "aria-label-open-external-link": "Open external link" }, + "receivers": { + "protected": { + "field": { + "description": "This field is protected and can only be edited by users with elevated permissions" + } + } + }, "receivers-section": { "button-more": "More", "new-menu": { @@ -2659,6 +2666,35 @@ "text-federated": "Federated", "text-provisioned": "Provisioned" }, + "saved-searches": { + "actions-aria-label": "Actions", + "apply-aria-label": "Apply search \"{{name}}\"", + "apply-tooltip": "Apply this search", + "button-label": "Saved searches", + "cancel": "Cancel", + "default-indicator": "Default search", + "delete": "Delete", + "delete-button": "Delete", + "dropdown-aria-label": "Saved searches", + "empty-state": "No saved searches yet", + "error-load-description": "Your saved searches could not be loaded. Please try refreshing the page.", + "error-load-title": "Failed to load saved searches", + "error-name-duplicate": "A saved search with this name already exists", + "error-name-required": "Name is required", + "error-rename-description": "Your changes could not be saved. Please try again.", + "error-rename-title": "Failed to rename", + "error-save-description": "Your changes could not be saved. Please try again.", + "error-save-title": "Failed to save", + "list-aria-label": "Saved searches list", + "name-placeholder": "Enter a name...", + "remove-default": "Remove default", + "rename": "Rename", + "rename-button": "Rename", + "save-button": "Save", + "save-current-search": "Save current search", + "save-disabled-tooltip": "Enter a search query first", + "set-default": "Set as default" + }, "search": { "property": { "data-source": "Data source", @@ -3322,6 +3358,7 @@ "login-attribute-path-label": "Login attribute path", "login-prompt-consent": "Consent", "login-prompt-description": "Indicates the type of user interaction when the user logs in with the IdP.", + "login-prompt-description-google": "Indicates the type of user interaction when the user logs in with Google. This is forced to \"Consent\" when \"Use refresh token\" is enabled.", "login-prompt-label": "Login prompt", "login-prompt-login": "Login", "login-prompt-select-account": "Select account", @@ -3379,6 +3416,7 @@ "use-pkce-description": "If enabled, Grafana will use <2>Proof Key for Code Exchange (PKCE) with the OAuth2 Authorization Code Grant.", "use-pkce-label": "Use PKCE", "use-refresh-token-description": "If enabled, Grafana will fetch a new access token using the refresh token provided by the OAuth2 provider.", + "use-refresh-token-description-google": "If enabled, Grafana will fetch a new access token using the refresh token provided by Google. This forces the login prompt to \"Consent\" to ensure Google returns a refresh token.", "use-refresh-token-label": "Use refresh token", "validate-hosted-domain-description": "If enabled, Grafana will match the Hosted Domain retrieved from the Google ID Token against the \"{{ allowedDomainsLabel }}\" list specified by the user.", "validate-hosted-domain-label": "Validate hosted domain", @@ -3708,6 +3746,7 @@ "text": "No results found for your query" }, "recently-viewed": { + "clear": "Clear history", "empty": "Nothing viewed yet", "title": "Recently viewed" }, @@ -4821,8 +4860,7 @@ "apply": "Apply", "change-value": "Change variable value", "discard": "Discard", - "modal-title": "Custom Variable", - "values": "Values separated by comma" + "modal-title": "Custom Variable" }, "datasource-options": { "name-filter": "Name filter", @@ -6172,7 +6210,7 @@ "title-someone-else-has-updated-this-dashboard": "Someone else has updated this dashboard", "would-still-dashboard": "Would you still like to save this dashboard?" }, - "save-and-overwrite": "'Save and overwrite'" + "save-and-overwrite": "Save and overwrite" }, "library-viz-panel-info": { "last-edited": "{{timeAgo}} by ", @@ -7157,6 +7195,9 @@ "time-range-label": "Lock time range" } }, + "embedded-panel": { + "powered-by": "Powered by" + }, "empty-list-cta": { "pro-tip": "ProTip: {{proTip}}" }, @@ -7633,39 +7674,6 @@ }, "share-span": "Share" }, - "span-filters": { - "aria-label-select-max-span-operator": "Select max span operator", - "aria-label-select-min-span-operator": "Select min span operator", - "aria-label-select-service-name": "Select service name", - "aria-label-select-service-name-operator": "Select service name operator", - "aria-label-select-span-name": "Select span name", - "aria-label-select-span-name-operator": "Select span name operator", - "ariaLabel-select-max-span-duration": "Select max span duration", - "ariaLabel-select-min-span-duration": "Select min span duration", - "label-collapse": "Span Filters", - "label-duration": "Duration", - "label-service-name": "Service name", - "label-span-name": "Span name", - "label-tags": "Tags", - "placeholder-all-service-names": "All service names", - "placeholder-all-span-names": "All span names", - "tooltip-collapse": "Filter your spans below. You can continue to apply filters until you have narrowed down your resulting spans to the select few you are most interested in.", - "tooltip-duration": "Filter by duration. Accepted units are {{units}}", - "tooltip-tags": "Filter by tags, process tags or log fields in your spans." - }, - "span-filters-tags": { - "aria-label-add-tag": "Add tag", - "aria-label-input-tag-value": "Input tag value", - "aria-label-remove-tag": "Remove tag", - "aria-label-select-tag-key": "Select tag key", - "aria-label-select-tag-operator": "Select tag operator", - "aria-label-select-tag-value": "Select tag value", - "placeholder-select-tag": "Select tag", - "placeholder-select-value": "Select value", - "placeholder-tag-value": "Tag value", - "tooltip-add-tag": "Add tag", - "tooltip-remove-tag": "Remove tag" - }, "span-flame-graph": { "flame-graph": "Flame graph" }, @@ -9385,6 +9393,7 @@ "name-unit": "Unit", "name-value-name": "Value name", "name-y-axis-scale": "Y axis scale", + "name-y-bucket-scale": "Y bucket scale", "placeholder-axis-label": "Auto", "placeholder-axis-width": "Auto", "placeholder-decimals": "Auto", @@ -9414,6 +9423,18 @@ "label-all": "All", "label-hidden": "Hidden", "label-single": "Single" + }, + "y-bucket-scale-editor": { + "linear-threshold-description": "Range within which the scale is linear", + "linear-threshold-label": "Linear threshold", + "linear-threshold-placeholder": "1", + "log-base-label": "Log base", + "scale-options": { + "label-auto": "Auto", + "label-linear": "Linear", + "label-log": "Log", + "label-symlog": "Symlog" + } } }, "help-modal": { @@ -10175,7 +10196,8 @@ "copy": "Copy selection", "disable-menu": "Disable menu", "line-contains": "Add as line contains filter", - "line-contains-not": "Add as line does not contain filter" + "line-contains-not": "Add as line does not contain filter", + "search-text": "Search in results" }, "show-log-attributes": "Display log attributes for OTel logs", "timestamp-format": "Timestamp resolution", @@ -11194,9 +11216,14 @@ }, "visualization-suggestions": { "apply-suggestion-aria-label": "Apply {{suggestionName}} visualization", + "error-loading-some-suggestions": { + "message": "Some suggestions could not be loaded" + }, "error-loading-suggestions": { "message": "An error occurred when loading visualization suggestions.", - "title": "Error" + "plugin-failed": "Failed to load panel plugin: {{ pluginId }}.", + "title": "Error", + "try-again-button": "Try again" }, "unknown-viz-type": "Unknown visualization type", "use-this-suggestion": "Use this suggestion" @@ -11865,7 +11892,6 @@ } }, "getting-started": { - "alert-temporary-outage": "When you connect your whole instance, dashboards will be unavailable while running the migration. We recommend warning your users before starting the process.", "modal-description-public-access": "Set up public access to your Grafana instance to enable GitHub integration", "modal-description-required-features": "Enable required Grafana features for provisioning", "modal-title-set-up-public-access": "Set up public access", @@ -11877,8 +11903,7 @@ "step-title-copy-url": "Copy your public URL", "step-title-enable-feature-toggles": "Enable Required Feature Toggles", "step-title-start-ngrok": "Start ngrok for temporary public access", - "step-title-update-grafana-config": "Update your Grafana configuration", - "title-setting-connection-could-cause-temporary-outage": "Setting up this connection could cause a temporary outage" + "step-title-update-grafana-config": "Update your Grafana configuration" }, "getting-started-page": { "subtitle-provisioning-feature": "View and manage your provisioning connections" @@ -11947,18 +11972,15 @@ }, "home-page": { "button-delete-repositories": "Delete repositories", - "configured-repositories-while-running-legacy-storage": "Configured repositories will not work while running legacy storage.", "confirm-delete-repositories": "Are you sure you want to delete all configured repositories? This action cannot be undone.", "error-delete-all-repositories": "Failed to delete all repositories", - "remove-all-configured-repositories": "Remove all configured repositories", "subtitle": "View and manage your configured repositories", "success-all-repositories-deleted": "All configured repositories deleted", "tab-getting-started": "Getting started", "tab-getting-started-title": "Getting started", "tab-repositories": "Repositories", "tab-repositories-title": "List of repositories", - "title-delete-all-configured-repositories": "Delete all configured repositories", - "title-legacy-storage-detected": "Legacy storage detected" + "title-delete-all-configured-repositories": "Delete all configured repositories" }, "http-utils": { "access-denied": "Access denied. Please check your token permissions.", @@ -11968,7 +11990,10 @@ "resource-not-found": "Resource not found. Please check the URL or repository.", "unsupported-repository-type": "Unsupported repository type: {{repositoryType}}" }, - "inline-secure-values-warning": "You need to save your access tokens again due to a system update", + "instance-sync-deprecation": { + "message": "Instance sync is currently not fully supported and breaks library panels and alerts. To use library panels and alerts, disconnect your repository and reconnect it using folder sync instead.", + "title": "Instance sync is not fully supported" + }, "job-status": { "label-view-details": "View details", "loading-finished-job": "Loading finished job...", @@ -11998,7 +12023,6 @@ "mode-options": { "disabled": { "folder-connected": "Full instance synchronization is disabled because another folder is already synced with a repository.", - "legacy-storage": "Legacy storage mode only supports syncing the entire Grafana instance.", "not-allowed": "Provisioning settings for this repository restrict syncing to specific targets. Update the repository configuration to enable this option.", "not-supported": "This option is not supported yet." }, @@ -12075,10 +12099,12 @@ "webhook-last-event": "Last Event:", "webhook-url": "View Webhook" }, + "repository-status": { + "error": "Failed to load repository" + }, "repository-status-page": { "back-to-repositories": "Back to repositories", "cleaning-up-resources": "Cleaning up repository resources", - "legacy-storage-message": "Instance is not yet running unified storage -- requires migration wizard", "not-found": "not found", "not-found-message": "Repository not found", "repository-config-exists-configuration": "Make sure the repository config exists in the configuration file.", @@ -12087,7 +12113,6 @@ "tab-resources": "Resources", "tab-resources-title": "Repository files and resources", "title": "Repository Status", - "title-legacy-storage": "Legacy Storage", "title-queued-for-deletion": "Queued for deletion" }, "repository-type-cards": { @@ -12181,11 +12206,12 @@ "tooltip-unhealthy-repository": "Unable to pull an unhealthy repository" }, "synchronize-step": { + "instance-migrate-resources-description": "Instance sync requires all resources to be managed. Existing resources will be migrated automatically.", + "migrate-resources-description": "Import existing dashboards from all folders into the new provisioned folder", + "options": "Options", "repository-error": "Repository error", "repository-error-message": "Unable to check repository status. Please verify the repository configuration and try again.", - "repository-unhealthy": "The repository cannot be synchronized. Cancel provisioning and try again once the issue has been resolved. See details below.", - "synchronization-description": "Include commits for each historical value", - "synchronization-options": "Synchronization options" + "repository-unhealthy": "The repository cannot be synchronized. Cancel provisioning and try again once the issue has been resolved. See details below." }, "token-permissions-info": { "and-click": "and click", @@ -12202,11 +12228,16 @@ }, "warning-title-default": "Warning", "wizard": { - "alert-point-1": "Resources won't be able to be created, edited, or deleted during this process. In the last step, they will disappear.", - "alert-point-2": "Once provisioning is complete, resources will reappear and be managed through external storage.", + "alert-intro": "Please be aware of the following limitations. For more details, see the <2>Git Sync documentation.", + "alert-point-1": "Resources can still be created, edited, or deleted during this process, but changes may not be exported.", "alert-point-3": "The duration of this process depends on the number of resources involved.", - "alert-point-4": "Enterprise instance administrators can display an announcement banner to users. See <2>this guide for step-by-step instructions.", - "alert-title": "Important: No data or configuration will be lost, but dashboards will be temporarily unavailable for a few minutes.", + "alert-point-4": "Enterprise instance administrators can display an announcement banner to notify users that migration is in progress. See <2>this guide for step-by-step instructions.", + "alert-point-folder-cleanup": "You may need to manually remove or manage original folders after migration.", + "alert-point-folder-structure": "When migrating existing dashboards, the folder structure will be replicated in the repository. Original folders will be emptied of dashboards but may still contain alerts or library panels.", + "alert-point-instance-alerts": "Existing alerts and library panels will be lost and will not be usable after migration.", + "alert-point-permissions": "Fine-grained permissions are not supported. Default permissions apply: Admin, Editor, and Viewer roles are preserved with their standard access levels.", + "alert-point-unsupported": "Alerts and library panels are not supported in provisioned folders.", + "alert-title": "Important: Review Git Sync limitations before proceeding", "button-cancel": "Cancel", "button-cancelling": "Cancelling...", "button-next": "Finish", @@ -12224,7 +12255,7 @@ "step-finish": "Choose additional settings", "step-synchronize": "Synchronize with external storage", "sync-description": "Sync resources with external storage. After this one-time step, all future updates will be automatically saved to the repository and provisioned back into the instance.", - "sync-option-history": "History", + "sync-option-migrate-resources": "Migrate existing resources", "title-bootstrap": "Choose what to synchronize", "title-connect": "Connect to external storage", "title-finish": "Choose additional settings", diff --git a/public/locales/es-ES/grafana.json b/public/locales/es-ES/grafana.json index c44e8c8ff3b..1c8c641cfad 100644 --- a/public/locales/es-ES/grafana.json +++ b/public/locales/es-ES/grafana.json @@ -2232,6 +2232,13 @@ "receiver-metadata-badge": { "aria-label-open-external-link": "Abrir enlace externo" }, + "receivers": { + "protected": { + "field": { + "description": "" + } + } + }, "receivers-section": { "button-more": "Más", "new-menu": { @@ -3322,6 +3329,7 @@ "login-attribute-path-label": "Ruta del atributo de inicio de sesión", "login-prompt-consent": "Aceptar", "login-prompt-description": "Indica el tipo de interacción del usuario cuando este inicia sesión con el IdP.", + "login-prompt-description-google": "", "login-prompt-label": "Aviso de inicio de sesión", "login-prompt-login": "Iniciar sesión", "login-prompt-select-account": "Seleccionar cuenta", @@ -3379,6 +3387,7 @@ "use-pkce-description": "Si está habilitado, Grafana utilizará la <2>clave de prueba para el intercambio de código (PKCE) con la concesión de código de autorización OAuth2.", "use-pkce-label": "Utilizar PKCE", "use-refresh-token-description": "Si se ha habilitado, Grafana obtendrá un nuevo token de acceso a través del token de actualización que proporcione el proveedor de OAuth2.", + "use-refresh-token-description-google": "", "use-refresh-token-label": "Usar token de actualización", "validate-hosted-domain-description": "Si se ha habilitado, Grafana comparará el dominio alojado recuperado del token de ID de Google con la lista «{{ allowedDomainsLabel }}» que especifique el usuario.", "validate-hosted-domain-label": "Validar dominio alojado", @@ -4821,8 +4830,7 @@ "apply": "", "change-value": "", "discard": "", - "modal-title": "", - "values": "Valores separados por coma" + "modal-title": "" }, "datasource-options": { "name-filter": "Nombrar filtro", @@ -10175,7 +10183,8 @@ "copy": "Copiar selección", "disable-menu": "Desactivar menú", "line-contains": "Añadir como filtro «la línea contiene»", - "line-contains-not": "Añadir como filtro «la línea no contiene»" + "line-contains-not": "Añadir como filtro «la línea no contiene»", + "search-text": "" }, "show-log-attributes": "", "timestamp-format": "Resolución de marca de tiempo", @@ -11413,6 +11422,12 @@ "latestReleaseDate": "Fecha último lanzamiento:", "latestVersion": "Versión más reciente", "license": "Licencia", + "moreDetails": "", + "pluginInsights": { + "header": "" + }, + "pluginInsightsSuccessTooltip": "", + "pluginInsightsWarningTooltip": "", "raiseAnIssue": "Comunicar un problema", "reportAbuse": "", "reportAbuseTooltip": "Informa de problemas relacionados con complementos maliciosos o dañinos directamente a Grafana Labs.", @@ -11859,7 +11874,6 @@ } }, "getting-started": { - "alert-temporary-outage": "Cuando conectes toda tu instancia, los paneles no estarán disponibles mientras se ejecuta la migración. Recomendamos advertir a tus usuarios antes de iniciar el proceso.", "modal-description-public-access": "Configura el acceso público a tu instancia de Grafana para habilitar la integración de GitHub", "modal-description-required-features": "Habilitar las funciones de Grafana necesarias para el aprovisionamiento", "modal-title-set-up-public-access": "Configurar el acceso público", @@ -11871,8 +11885,7 @@ "step-title-copy-url": "Copia tu URL pública", "step-title-enable-feature-toggles": "Habilitar las opciones de las funciones necesarias", "step-title-start-ngrok": "Iniciar ngrok para el acceso público temporal", - "step-title-update-grafana-config": "Actualiza tu configuración de Grafana", - "title-setting-connection-could-cause-temporary-outage": "Configurar esta conexión podría causar una interrupción temporal" + "step-title-update-grafana-config": "Actualiza tu configuración de Grafana" }, "getting-started-page": { "subtitle-provisioning-feature": "Ver y gestionar tus conexiones de aprovisionamiento" @@ -11941,18 +11954,15 @@ }, "home-page": { "button-delete-repositories": "Eliminar repositorios", - "configured-repositories-while-running-legacy-storage": "Los repositorios configurados no funcionarán mientras se ejecuta el almacenamiento heredado.", "confirm-delete-repositories": "¿Seguro que quieres eliminar todos los repositorios configurados? Esta acción no se puede deshacer.", "error-delete-all-repositories": "Error al eliminar todos los repositorios", - "remove-all-configured-repositories": "Eliminar todos los repositorios configurados", "subtitle": "Ver y gestionar tus repositorios configurados", "success-all-repositories-deleted": "Se han eliminado todos los repositorios configurados", "tab-getting-started": "Cómo empezar", "tab-getting-started-title": "Cómo empezar", "tab-repositories": "Repositorios", "tab-repositories-title": "Lista de repositorios", - "title-delete-all-configured-repositories": "Eliminar todos los repositorios configurados", - "title-legacy-storage-detected": "Almacenamiento heredado detectado" + "title-delete-all-configured-repositories": "Eliminar todos los repositorios configurados" }, "http-utils": { "access-denied": "", @@ -11992,7 +12002,6 @@ "mode-options": { "disabled": { "folder-connected": "", - "legacy-storage": "", "not-allowed": "", "not-supported": "" }, @@ -12072,7 +12081,6 @@ "repository-status-page": { "back-to-repositories": "Volver a los repositorios", "cleaning-up-resources": "Limpiando los recursos del repositorio", - "legacy-storage-message": "La instancia aún no está ejecutando almacenamiento unificado, requiere un asistente de migración", "not-found": "no ha sido encontrado", "not-found-message": "Repositorio no encontrado", "repository-config-exists-configuration": "Asegúrate de que la configuración del repositorio exista en el archivo de configuración.", @@ -12081,7 +12089,6 @@ "tab-resources": "Recursos", "tab-resources-title": "", "title": "Estado del repositorio", - "title-legacy-storage": "Almacenamiento heredado", "title-queued-for-deletion": "En cola para su eliminación" }, "repository-type-cards": { @@ -12177,9 +12184,7 @@ "synchronize-step": { "repository-error": "", "repository-error-message": "", - "repository-unhealthy": "", - "synchronization-description": "Incluir confirmaciones para cada valor histórico", - "synchronization-options": "Opciones de sincronización" + "repository-unhealthy": "" }, "token-permissions-info": { "and-click": "y haz clic en", @@ -12196,11 +12201,11 @@ }, "warning-title-default": "Advertencia", "wizard": { - "alert-point-1": "Los recursos no se podrán crear, editar ni eliminar durante este proceso. En el último paso, desaparecerán.", - "alert-point-2": "Una vez que se complete el aprovisionamiento, los recursos volverán a aparecer y se gestionarán a través de un almacenamiento externo.", + "alert-point-1": "", + "alert-point-2": "", "alert-point-3": "La duración de este proceso depende del número de recursos involucrados.", - "alert-point-4": "Los administradores de instancias empresariales pueden mostrar un báner de anuncio a los usuarios. Consulta <2>esta guía para obtener instrucciones paso a paso.", - "alert-title": "Importante: No se perderán datos ni configuraciones, pero los dashboards no estarán disponibles temporalmente durante unos minutos.", + "alert-point-4": "", + "alert-title": "", "button-cancel": "", "button-cancelling": "", "button-next": "Terminar", @@ -12218,7 +12223,6 @@ "step-finish": "Elegir ajustes adicionales", "step-synchronize": "Sincronizar con un almacenamiento externo", "sync-description": "Sincroniza los recursos con un almacenamiento externo. Después de este paso único, todas las actualizaciones futuras se guardarán automáticamente en el repositorio y se aprovisionarán de nuevo en la instancia.", - "sync-option-history": "Historial", "title-bootstrap": "Elegir qué sincronizar", "title-connect": "Conectar a un almacenamiento externo", "title-finish": "Elegir ajustes adicionales", diff --git a/public/locales/fr-FR/grafana.json b/public/locales/fr-FR/grafana.json index aecae73acab..d2faa93f8e5 100644 --- a/public/locales/fr-FR/grafana.json +++ b/public/locales/fr-FR/grafana.json @@ -2232,6 +2232,13 @@ "receiver-metadata-badge": { "aria-label-open-external-link": "Ouvrir le lien externe" }, + "receivers": { + "protected": { + "field": { + "description": "" + } + } + }, "receivers-section": { "button-more": "Plus", "new-menu": { @@ -3322,6 +3329,7 @@ "login-attribute-path-label": "Chemin d’attribut de connexion", "login-prompt-consent": "Consentement", "login-prompt-description": "Indique le type d’interaction utilisateur lors de la connexion via le fournisseur d’identité (IdP).", + "login-prompt-description-google": "", "login-prompt-label": "Invite de connexion", "login-prompt-login": "Connexion", "login-prompt-select-account": "Sélectionner un compte", @@ -3379,6 +3387,7 @@ "use-pkce-description": "Si cette option est activée, Grafana utilisera la <2>clé de preuve pour l’échange de code (PKCE) avec l’octroi de code d’autorisation OAuth2.", "use-pkce-label": "Utiliser PKCE", "use-refresh-token-description": "Si cette option est activée, Grafana récupérera un nouveau jeton d’accès à l’aide du jeton d’actualisation fourni par le fournisseur OAuth2.", + "use-refresh-token-description-google": "", "use-refresh-token-label": "Utiliser le jeton d’actualisation", "validate-hosted-domain-description": "Si cette option est activée, Grafana fera correspondre le domaine hébergé récupéré à partir du jeton d’identification Google à la liste « {{ allowedDomainsLabel }} » spécifiée par l’utilisateur.", "validate-hosted-domain-label": "Valider le domaine hébergé", @@ -4821,8 +4830,7 @@ "apply": "", "change-value": "", "discard": "", - "modal-title": "", - "values": "Valeurs séparées par une virgule" + "modal-title": "" }, "datasource-options": { "name-filter": "Nom du filtre", @@ -10175,7 +10183,8 @@ "copy": "Copier la sélection", "disable-menu": "Désactiver le menu", "line-contains": "Ajouter car la ligne contient un filtre", - "line-contains-not": "Ajouter car la ligne ne contient pas de filtre" + "line-contains-not": "Ajouter car la ligne ne contient pas de filtre", + "search-text": "" }, "show-log-attributes": "", "timestamp-format": "Résolution des horodatages", @@ -11413,6 +11422,12 @@ "latestReleaseDate": "Dernière date de sortie :", "latestVersion": "Dernière version", "license": "Licence", + "moreDetails": "", + "pluginInsights": { + "header": "" + }, + "pluginInsightsSuccessTooltip": "", + "pluginInsightsWarningTooltip": "", "raiseAnIssue": "Signaler un problème", "reportAbuse": "", "reportAbuseTooltip": "Signalez les problèmes liés à des plugins malveillants ou nuisibles directement à Grafana Labs.", @@ -11859,7 +11874,6 @@ } }, "getting-started": { - "alert-temporary-outage": "Lorsque vous connectez l’ensemble de votre instance, les tableaux de bord ne seront pas disponibles pendant l’exécution de la migration. Nous vous recommandons d’avertir vos utilisateurs avant de commencer le processus.", "modal-description-public-access": "Configurez l’accès public à votre instance Grafana pour activer l’intégration GitHub", "modal-description-required-features": "Activez les fonctionnalités Grafana requises pour la mise en service", "modal-title-set-up-public-access": "Configurer l’accès public", @@ -11871,8 +11885,7 @@ "step-title-copy-url": "Copier l’URL publique", "step-title-enable-feature-toggles": "Activer les bascules de fonctionnalité requises", "step-title-start-ngrok": "Démarrer ngrok pour un accès public temporaire", - "step-title-update-grafana-config": "Mettre à jour la configuration Grafana", - "title-setting-connection-could-cause-temporary-outage": "La configuration de cette connexion peut entraîner une interruption temporaire" + "step-title-update-grafana-config": "Mettre à jour la configuration Grafana" }, "getting-started-page": { "subtitle-provisioning-feature": "Afficher et gérer vos connexions de mise en service" @@ -11941,18 +11954,15 @@ }, "home-page": { "button-delete-repositories": "Supprimer les référentiels", - "configured-repositories-while-running-legacy-storage": "Les référentiels configurés ne fonctionneront pas lors de l’exécution du stockage hérité.", "confirm-delete-repositories": "Voulez-vous vraiment supprimer tous les référentiels configurés ? Cette action ne peut pas être annulée.", "error-delete-all-repositories": "Échec de la suppression de tous les référentiels", - "remove-all-configured-repositories": "Supprimer tous les référentiels configurés", "subtitle": "Afficher et gérer vos référentiels configurés", "success-all-repositories-deleted": "Tous les référentiels configurés ont été supprimés", "tab-getting-started": "Pour commencer", "tab-getting-started-title": "Pour commencer", "tab-repositories": "Référentiels", "tab-repositories-title": "Liste des référentiels", - "title-delete-all-configured-repositories": "Supprimer tous les référentiels configurés", - "title-legacy-storage-detected": "Stockage hérité détecté" + "title-delete-all-configured-repositories": "Supprimer tous les référentiels configurés" }, "http-utils": { "access-denied": "", @@ -11992,7 +12002,6 @@ "mode-options": { "disabled": { "folder-connected": "", - "legacy-storage": "", "not-allowed": "", "not-supported": "" }, @@ -12072,7 +12081,6 @@ "repository-status-page": { "back-to-repositories": "Retour aux référentiels", "cleaning-up-resources": "Nettoyage des ressources du référentiel", - "legacy-storage-message": "L’instance n’exécute pas encore de stockage unifié ; l’assistant de migration est requis", "not-found": "introuvable", "not-found-message": "Référentiel introuvable", "repository-config-exists-configuration": "Assurez-vous que la configuration du référentiel existe dans le fichier de configuration.", @@ -12081,7 +12089,6 @@ "tab-resources": "Ressources", "tab-resources-title": "", "title": "Statut du référentiel", - "title-legacy-storage": "Stockage hérité", "title-queued-for-deletion": "Mis en attente pour suppression" }, "repository-type-cards": { @@ -12177,9 +12184,7 @@ "synchronize-step": { "repository-error": "", "repository-error-message": "", - "repository-unhealthy": "", - "synchronization-description": "Inclure les commits pour chaque valeur historique", - "synchronization-options": "Options de synchronisation" + "repository-unhealthy": "" }, "token-permissions-info": { "and-click": "et cliquez", @@ -12196,11 +12201,11 @@ }, "warning-title-default": "Avertissement", "wizard": { - "alert-point-1": "Les ressources ne pourront pas être créées, modifiées ou supprimées pendant ce processus. Lors de la dernière étape, elles disparaîtront.", - "alert-point-2": "Une fois la mise en service terminée, les ressources réapparaîtront et seront gérées via un stockage externe.", + "alert-point-1": "", + "alert-point-2": "", "alert-point-3": "La durée de ce processus dépend du nombre de ressources impliquées.", - "alert-point-4": "Les administrateurs d’instances d’entreprise peuvent afficher une bannière d’annonce aux utilisateurs. Consultez <2>ce guide pour obtenir des instructions étape par étape.", - "alert-title": "Important : aucune donnée ou configuration ne sera perdue, mais les tableaux de bord seront temporairement indisponibles pendant quelques minutes.", + "alert-point-4": "", + "alert-title": "", "button-cancel": "", "button-cancelling": "", "button-next": "Terminer", @@ -12218,7 +12223,6 @@ "step-finish": "Choisir des paramètres supplémentaires", "step-synchronize": "Synchroniser avec un stockage externe", "sync-description": "Synchronisez les ressources avec un stockage externe. Après cette étape unique, toutes les futures mises à jour seront automatiquement enregistrées dans le référentiel et mises en service dans l’instance.", - "sync-option-history": "Historique", "title-bootstrap": "Choisir ce qui doit être synchronisé", "title-connect": "Se connecter à un stockage externe", "title-finish": "Choisir des paramètres supplémentaires", diff --git a/public/locales/hu-HU/grafana.json b/public/locales/hu-HU/grafana.json index 7f049004022..0c8c164742b 100644 --- a/public/locales/hu-HU/grafana.json +++ b/public/locales/hu-HU/grafana.json @@ -2232,6 +2232,13 @@ "receiver-metadata-badge": { "aria-label-open-external-link": "Külső hivatkozás megnyitása" }, + "receivers": { + "protected": { + "field": { + "description": "" + } + } + }, "receivers-section": { "button-more": "Továbbiak", "new-menu": { @@ -3322,6 +3329,7 @@ "login-attribute-path-label": "Bejelentkezési attribútum útvonala", "login-prompt-consent": "Hozzájárulás", "login-prompt-description": "Jelzi a felhasználói interakció típusát, amikor a felhasználó az IdP-vel jelentkezik be.", + "login-prompt-description-google": "", "login-prompt-label": "Bejelentkezési felszólítás", "login-prompt-login": "Bejelentkezés", "login-prompt-select-account": "Számla kiválasztása", @@ -3379,6 +3387,7 @@ "use-pkce-description": "Ha engedélyezve van, a Grafana a <2>Proof Key for Code Exchange (PKCE) lehetőséget használja az OAuth2 engedélyezési kód megadásával.", "use-pkce-label": "PKCE használata", "use-refresh-token-description": "Ha engedélyezett, a Grafana új hozzáférési tokent fog lekérni az OAuth2-szolgáltató által biztosított frissítési token használatával.", + "use-refresh-token-description-google": "", "use-refresh-token-label": "Frissítési token használata", "validate-hosted-domain-description": "Ha engedélyezett, a Grafana a Google ID-tokennel lekérdezett üzemeltetett tartományt a felhasználó által megadott „{{ allowedDomainsLabel }}” listával próbálja meg egyeztetni.", "validate-hosted-domain-label": "Üzemeltetett tartomány validálása", @@ -4821,8 +4830,7 @@ "apply": "", "change-value": "", "discard": "", - "modal-title": "", - "values": "Értékek vesszővel elválasztva" + "modal-title": "" }, "datasource-options": { "name-filter": "Névszűrő", @@ -10175,7 +10183,8 @@ "copy": "Kijelölés másolása", "disable-menu": "Menü letiltása", "line-contains": "A hozzáadás sorként szűrőt tartalmaz", - "line-contains-not": "A hozzáadás sorként nem tartalmaz szűrőt" + "line-contains-not": "A hozzáadás sorként nem tartalmaz szűrőt", + "search-text": "" }, "show-log-attributes": "", "timestamp-format": "Időbélyeg felbontása", @@ -11413,6 +11422,12 @@ "latestReleaseDate": "Legújabb kiadás dátuma:", "latestVersion": "Legújabb verzió", "license": "Licenc", + "moreDetails": "", + "pluginInsights": { + "header": "" + }, + "pluginInsightsSuccessTooltip": "", + "pluginInsightsWarningTooltip": "", "raiseAnIssue": "Probléma felveté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.", @@ -11859,7 +11874,6 @@ } }, "getting-started": { - "alert-temporary-outage": "Ha az egész példányt csatlakoztatja, az áttelepítés futtatása során az irányítópultok nem lesznek elérhetők. Javasoljuk, hogy a folyamat megkezdése előtt figyelmeztesse a felhasználókat.", "modal-description-public-access": "Nyilvános hozzáférés beállítása a Grafana-példányhoz a GitHub-integráció engedélyezéséhez", "modal-description-required-features": "Szükséges Grafana-funkciók engedélyezése a kiépítéshez", "modal-title-set-up-public-access": "Nyilvános hozzáférés beállítása", @@ -11871,8 +11885,7 @@ "step-title-copy-url": "A nyilvános URL-cím kimásolása", "step-title-enable-feature-toggles": "Szükséges funkciókapcsolók engedélyezése", "step-title-start-ngrok": "Az ngrok elindítása az ideiglenes nyilvános hozzáféréshez", - "step-title-update-grafana-config": "Saját Grafana-konfiguráció frissítése", - "title-setting-connection-could-cause-temporary-outage": "A kapcsolat létrehozása ideiglenes üzemszünetet okozhat" + "step-title-update-grafana-config": "Saját Grafana-konfiguráció frissítése" }, "getting-started-page": { "subtitle-provisioning-feature": "Kiépítési kapcsolatok megtekintése és kezelése" @@ -11941,18 +11954,15 @@ }, "home-page": { "button-delete-repositories": "Adattárak törlése", - "configured-repositories-while-running-legacy-storage": "A konfigurált adattárak nem fognak működni az örökölt tárolás futtatása közben.", "confirm-delete-repositories": "Biztosan törli az összes konfigurált adattárat? A művelet nem vonható vissza.", "error-delete-all-repositories": "Az összes adattár törlése nem sikerült", - "remove-all-configured-repositories": "Az összes konfigurált adattár eltávolítása", "subtitle": "Konfigurált adattárak megtekintése és kezelése", "success-all-repositories-deleted": "Az összes konfigurált adattár törölve", "tab-getting-started": "Kezdés", "tab-getting-started-title": "Kezdés", "tab-repositories": "Adattárak", "tab-repositories-title": "Adattárak listája", - "title-delete-all-configured-repositories": "Az összes konfigurált adattár törlése", - "title-legacy-storage-detected": "Örökölt tárolás észlelve" + "title-delete-all-configured-repositories": "Az összes konfigurált adattár törlése" }, "http-utils": { "access-denied": "", @@ -11992,7 +12002,6 @@ "mode-options": { "disabled": { "folder-connected": "", - "legacy-storage": "", "not-allowed": "", "not-supported": "" }, @@ -12072,7 +12081,6 @@ "repository-status-page": { "back-to-repositories": "Vissza az adattárakhoz", "cleaning-up-resources": "Adattári erőforrások tisztítása", - "legacy-storage-message": "A példány még nem fut egyesített tárhellyel – áttelepítési varázslót igényel", "not-found": "nem található", "not-found-message": "Nem található adattár", "repository-config-exists-configuration": "Győződjön meg arról, hogy a tároló konfigurációja létezik a konfigurációs fájlban.", @@ -12081,7 +12089,6 @@ "tab-resources": "Erőforrások", "tab-resources-title": "", "title": "Adattár állapota", - "title-legacy-storage": "Örökölt tárolás", "title-queued-for-deletion": "Törlésre vár" }, "repository-type-cards": { @@ -12177,9 +12184,7 @@ "synchronize-step": { "repository-error": "", "repository-error-message": "", - "repository-unhealthy": "", - "synchronization-description": "Változtatások belefoglalása minden előzményértékhez", - "synchronization-options": "Szinkronizálási beállítások" + "repository-unhealthy": "" }, "token-permissions-info": { "and-click": "és kattintson erre:", @@ -12196,11 +12201,11 @@ }, "warning-title-default": "Figyelmeztetés", "wizard": { - "alert-point-1": "A folyamat során nem lehet erőforrásokat létrehozni, szerkeszteni vagy törölni. Az utolsó lépésben el fognak tűnni.", - "alert-point-2": "A kiépítés befejezése után az erőforrások újra megjelennek, és külső tárolóeszközön keresztül kezelhetők.", + "alert-point-1": "", + "alert-point-2": "", "alert-point-3": "A folyamat időtartama az érintett erőforrások számától függ.", - "alert-point-4": "A vállalati példányok adminisztrátorai megjeleníthetnek egy értesítési szalagot a felhasználóknak. A lépésenkénti utasításokat lásd az <2>útmutatóban.", - "alert-title": "Fontos: Egyetlen adat vagy konfiguráció sem fog elveszni, de az irányítópultok néhány percig átmenetileg nem lesznek elérhetők.", + "alert-point-4": "", + "alert-title": "", "button-cancel": "", "button-cancelling": "", "button-next": "Befejezés", @@ -12218,7 +12223,6 @@ "step-finish": "Válassza ki a további beállításokat", "step-synchronize": "Szinkronizálás külső tárolóval", "sync-description": "Erőforrások szinkronizálása külső tárolóval. Ezután az egyszeri lépés után az összes jövőbeli frissítés automatikusan mentve lesz az adattárba, és vissza lesz építve a példányba.", - "sync-option-history": "Előzmények", "title-bootstrap": "Válassza ki, mit szeretne szinkronizálni", "title-connect": "Csatlakozás külső tárolóhoz", "title-finish": "Válassza ki a további beállításokat", diff --git a/public/locales/id-ID/grafana.json b/public/locales/id-ID/grafana.json index 1676500a4b3..66ad5574fb6 100644 --- a/public/locales/id-ID/grafana.json +++ b/public/locales/id-ID/grafana.json @@ -2224,6 +2224,13 @@ "receiver-metadata-badge": { "aria-label-open-external-link": "Buka tautan eksternal" }, + "receivers": { + "protected": { + "field": { + "description": "" + } + } + }, "receivers-section": { "button-more": "Lebih banyak", "new-menu": { @@ -3311,6 +3318,7 @@ "login-attribute-path-label": "Jalur atribut login", "login-prompt-consent": "Persetujuan", "login-prompt-description": "Menunjukkan jenis interaksi pengguna saat pengguna masuk dengan IdP.", + "login-prompt-description-google": "", "login-prompt-label": "Permintaan masuk", "login-prompt-login": "Masuk", "login-prompt-select-account": "Pilih akun", @@ -3368,6 +3376,7 @@ "use-pkce-description": "Jika diaktifkan, Grafana akan menggunakan <2>Proof Key for Code Exchange (PKCE) dengan Pemberian Kode Otorisasi OAuth2.", "use-pkce-label": "Gunakan PKCE", "use-refresh-token-description": "Jika diaktifkan, Grafana akan mengambil token akses baru menggunakan token muat ulang yang disediakan oleh penyedia OAuth2.", + "use-refresh-token-description-google": "", "use-refresh-token-label": "Gunakan token muat ulang", "validate-hosted-domain-description": "Jika diaktifkan, Grafana akan mencocokkan Domain yang Di-hosting yang diambil dari Token ID Google dengan daftar \"{{ allowedDomainsLabel }}\" yang ditentukan oleh pengguna.", "validate-hosted-domain-label": "Validasi domain yang di-hosting", @@ -4802,8 +4811,7 @@ "apply": "", "change-value": "", "discard": "", - "modal-title": "", - "values": "Nilai dipisahkan dengan koma" + "modal-title": "" }, "datasource-options": { "name-filter": "Filter nama", @@ -10132,7 +10140,8 @@ "copy": "Salin pilihan", "disable-menu": "Nonaktifkan menu", "line-contains": "Tambahkan sebagai baris berisi filter", - "line-contains-not": "Tambahkan sebagai baris tidak berisi filter" + "line-contains-not": "Tambahkan sebagai baris tidak berisi filter", + "search-text": "" }, "show-log-attributes": "", "timestamp-format": "Resolusi stempel waktu", @@ -11367,6 +11376,12 @@ "latestReleaseDate": "Tanggal rilis terbaru:", "latestVersion": "Versi Terbaru", "license": "Lisensi", + "moreDetails": "", + "pluginInsights": { + "header": "" + }, + "pluginInsightsSuccessTooltip": "", + "pluginInsightsWarningTooltip": "", "raiseAnIssue": "Kemukakan masalah", "reportAbuse": "", "reportAbuseTooltip": "Laporkan masalah yang terkait dengan plugin jahat atau berbahaya langsung ke Grafana Labs.", @@ -11808,7 +11823,6 @@ } }, "getting-started": { - "alert-temporary-outage": "Saat Anda menghubungkan seluruh instans, dasbor tidak akan tersedia saat menjalankan migrasi. Sebaiknya peringatkan pengguna Anda sebelum memulai proses.", "modal-description-public-access": "Siapkan akses publik ke instans Grafana Anda untuk mengaktifkan integrasi GitHub", "modal-description-required-features": "Aktifkan fitur Grafana yang diperlukan untuk penyediaan", "modal-title-set-up-public-access": "Atur akses publik", @@ -11820,8 +11834,7 @@ "step-title-copy-url": "Salin URL publik Anda", "step-title-enable-feature-toggles": "Aktifkan Tombol Fitur yang Diperlukan", "step-title-start-ngrok": "Mulai ngrok untuk akses publik sementara", - "step-title-update-grafana-config": "Perbarui konfigurasi Grafana Anda", - "title-setting-connection-could-cause-temporary-outage": "Mengatur koneksi ini dapat menyebabkan pemadaman sementara" + "step-title-update-grafana-config": "Perbarui konfigurasi Grafana Anda" }, "getting-started-page": { "subtitle-provisioning-feature": "Lihat dan kelola koneksi penyediaan Anda" @@ -11890,18 +11903,15 @@ }, "home-page": { "button-delete-repositories": "Hapus repositori", - "configured-repositories-while-running-legacy-storage": "Repositori yang dikonfigurasi tidak akan berfungsi saat menjalankan penyimpanan lama.", "confirm-delete-repositories": "Anda yakin ingin menghapus semua repositori yang dikonfigurasi? Tindakan ini tidak dapat dibatalkan.", "error-delete-all-repositories": "Gagal menghapus semua repositori", - "remove-all-configured-repositories": "Hapus semua repositori yang dikonfigurasi", "subtitle": "Lihat dan kelola repositori yang dikonfigurasi", "success-all-repositories-deleted": "Semua repositori yang dikonfigurasi dihapus", "tab-getting-started": "Memulai", "tab-getting-started-title": "Memulai", "tab-repositories": "Repositori", "tab-repositories-title": "Daftar repositori", - "title-delete-all-configured-repositories": "Hapus semua repositori yang dikonfigurasi", - "title-legacy-storage-detected": "Penyimpanan lama terdeteksi" + "title-delete-all-configured-repositories": "Hapus semua repositori yang dikonfigurasi" }, "http-utils": { "access-denied": "", @@ -11941,7 +11951,6 @@ "mode-options": { "disabled": { "folder-connected": "", - "legacy-storage": "", "not-allowed": "", "not-supported": "" }, @@ -12021,7 +12030,6 @@ "repository-status-page": { "back-to-repositories": "Kembali ke repositori", "cleaning-up-resources": "Membersihkan sumber daya repositori", - "legacy-storage-message": "Instans belum menjalankan penyimpanan terpadu -- memerlukan wizard migrasi", "not-found": "tidak ditemukan", "not-found-message": "Repositori tidak ditemukan", "repository-config-exists-configuration": "Pastikan konfigurasi repositori ada dalam file konfigurasi.", @@ -12030,7 +12038,6 @@ "tab-resources": "Sumber Daya", "tab-resources-title": "", "title": "Status Repositori", - "title-legacy-storage": "Penyimpanan Lama", "title-queued-for-deletion": "Diantrekan untuk dihapus" }, "repository-type-cards": { @@ -12126,9 +12133,7 @@ "synchronize-step": { "repository-error": "", "repository-error-message": "", - "repository-unhealthy": "", - "synchronization-description": "Sertakan commit untuk setiap nilai historis", - "synchronization-options": "Opsi sinkronisasi" + "repository-unhealthy": "" }, "token-permissions-info": { "and-click": "dan klik", @@ -12145,11 +12150,11 @@ }, "warning-title-default": "Peringatan", "wizard": { - "alert-point-1": "Sumber daya tidak akan dapat dibuat, diedit, atau dihapus selama proses ini. Pada langkah terakhir, sumber daya akan menghilang.", - "alert-point-2": "Setelah penyediaan selesai, sumber daya akan muncul kembali dan dikelola melalui penyimpanan eksternal.", + "alert-point-1": "", + "alert-point-2": "", "alert-point-3": "Durasi proses ini bergantung pada jumlah sumber daya yang terlibat.", - "alert-point-4": "Administrator instans Enterprise dapat menampilkan banner pengumuman kepada pengguna. Lihat <2>panduan ini untuk petunjuk langkah demi langkah.", - "alert-title": "Penting: Tidak ada data atau konfigurasi yang akan hilang, tetapi dasbor tidak akan tersedia sementara selama beberapa menit.", + "alert-point-4": "", + "alert-title": "", "button-cancel": "", "button-cancelling": "", "button-next": "Selesai", @@ -12167,7 +12172,6 @@ "step-finish": "Pilih pengaturan tambahan", "step-synchronize": "Sinkronkan dengan penyimpanan eksternal", "sync-description": "Sinkronkan sumber daya dengan penyimpanan eksternal. Setelah langkah satu kali ini, semua pembaruan mendatang akan disimpan secara otomatis ke repositori dan disediakan kembali ke instans.", - "sync-option-history": "Sejarah", "title-bootstrap": "Pilih item yang akan disinkronkan", "title-connect": "Hubungkan ke penyimpanan eksternal", "title-finish": "Pilih pengaturan tambahan", diff --git a/public/locales/it-IT/grafana.json b/public/locales/it-IT/grafana.json index ef4e977fca8..76898afd674 100644 --- a/public/locales/it-IT/grafana.json +++ b/public/locales/it-IT/grafana.json @@ -2232,6 +2232,13 @@ "receiver-metadata-badge": { "aria-label-open-external-link": "Apri collegamento esterno" }, + "receivers": { + "protected": { + "field": { + "description": "" + } + } + }, "receivers-section": { "button-more": "Altro", "new-menu": { @@ -3322,6 +3329,7 @@ "login-attribute-path-label": "Percorso attributo di accesso", "login-prompt-consent": "Consenso", "login-prompt-description": "Indica il tipo di interazione dell'utente quando accede con l'IdP.", + "login-prompt-description-google": "", "login-prompt-label": "Richiesta di accesso", "login-prompt-login": "Accedi", "login-prompt-select-account": "Seleziona account", @@ -3379,6 +3387,7 @@ "use-pkce-description": "Se abilitato, Grafana utilizzerà <2>Proof Key for Code Exchange (PKCE) con il codice di autorizzazione OAuth2.", "use-pkce-label": "Usa PKCE", "use-refresh-token-description": "Se abilitata, Grafana recupererà un nuovo token di accesso utilizzando il token di aggiornamento fornito dal provider OAuth2.", + "use-refresh-token-description-google": "", "use-refresh-token-label": "Usa token di aggiornamento", "validate-hosted-domain-description": "Se abilitata, Grafana abbinerà il dominio ospitato recuperato dal token ID Google all'elenco \"{{ allowedDomainsLabel }}\" specificato dall'utente.", "validate-hosted-domain-label": "Convalida dominio ospitato", @@ -4821,8 +4830,7 @@ "apply": "", "change-value": "", "discard": "", - "modal-title": "", - "values": "Valori separati da virgola" + "modal-title": "" }, "datasource-options": { "name-filter": "Filtro nome", @@ -10175,7 +10183,8 @@ "copy": "Copia la selezione", "disable-menu": "Disabilita menu", "line-contains": "Aggiungi come riga contenente filtro", - "line-contains-not": "Aggiungi come riga non contenente filtro" + "line-contains-not": "Aggiungi come riga non contenente filtro", + "search-text": "" }, "show-log-attributes": "", "timestamp-format": "Risoluzione marca temporale", @@ -11413,6 +11422,12 @@ "latestReleaseDate": "Data dell'ultima versione:", "latestVersion": "Versione più recente", "license": "Licenza", + "moreDetails": "", + "pluginInsights": { + "header": "" + }, + "pluginInsightsSuccessTooltip": "", + "pluginInsightsWarningTooltip": "", "raiseAnIssue": "Segnala un problema", "reportAbuse": "", "reportAbuseTooltip": "Segnala i problemi relativi a plug-in dannosi o pericolosi direttamente a Grafana Labs.", @@ -11859,7 +11874,6 @@ } }, "getting-started": { - "alert-temporary-outage": "Quando colleghi l'intera istanza, le dashboard non saranno disponibili durante l'esecuzione della migrazione. Ti consigliamo di avvisare gli utenti prima di avviare il processo.", "modal-description-public-access": "Configura l'accesso pubblico alla tua istanza Grafana per abilitare l'integrazione con GitHub", "modal-description-required-features": "Abilita le funzionalità Grafana necessarie per il provisioning", "modal-title-set-up-public-access": "Configura l'accesso pubblico", @@ -11871,8 +11885,7 @@ "step-title-copy-url": "Copia il tuo URL pubblico", "step-title-enable-feature-toggles": "Abilita i toggle della funzionalità richieste", "step-title-start-ngrok": "Avvia ngrok per l'accesso pubblico temporaneo", - "step-title-update-grafana-config": "Aggiorna la configurazione di Grafana", - "title-setting-connection-could-cause-temporary-outage": "La configurazione di questa connessione potrebbe causare un'interruzione temporanea" + "step-title-update-grafana-config": "Aggiorna la configurazione di Grafana" }, "getting-started-page": { "subtitle-provisioning-feature": "Visualizza e gestisci le connessioni di provisioning" @@ -11941,18 +11954,15 @@ }, "home-page": { "button-delete-repositories": "Elimina repository", - "configured-repositories-while-running-legacy-storage": "I repository configurati non funzioneranno durante l'esecuzione della memoria esistente.", "confirm-delete-repositories": "Desideri davvero eliminare tutti i repository configurati? Quest'azione non può essere annullata.", "error-delete-all-repositories": "Impossibile eliminare tutti i repository", - "remove-all-configured-repositories": "Rimuovi tutti i repository configurati", "subtitle": "Visualizza e gestisci i repository configurati", "success-all-repositories-deleted": "Tutti i repository configurati sono stati eliminati", "tab-getting-started": "Come iniziare", "tab-getting-started-title": "Come iniziare", "tab-repositories": "Repository", "tab-repositories-title": "Elenco dei repository", - "title-delete-all-configured-repositories": "Elimina tutti i repository configurati", - "title-legacy-storage-detected": "Rilevata memoria esistente" + "title-delete-all-configured-repositories": "Elimina tutti i repository configurati" }, "http-utils": { "access-denied": "", @@ -11992,7 +12002,6 @@ "mode-options": { "disabled": { "folder-connected": "", - "legacy-storage": "", "not-allowed": "", "not-supported": "" }, @@ -12072,7 +12081,6 @@ "repository-status-page": { "back-to-repositories": "Torna ai repository", "cleaning-up-resources": "Pulizia delle risorse del repository", - "legacy-storage-message": "L'istanza non esegue ancora l'archiviazione unificata: richiede la procedura guidata di migrazione", "not-found": "non trovato", "not-found-message": "Repository non trovato", "repository-config-exists-configuration": "Assicurati che la configurazione del repository esista nel file di configurazione.", @@ -12081,7 +12089,6 @@ "tab-resources": "Risorse", "tab-resources-title": "", "title": "Stato del repository", - "title-legacy-storage": "Memoria esistente", "title-queued-for-deletion": "In coda per l'eliminazione" }, "repository-type-cards": { @@ -12177,9 +12184,7 @@ "synchronize-step": { "repository-error": "", "repository-error-message": "", - "repository-unhealthy": "", - "synchronization-description": "Includi commit per ogni valore storico", - "synchronization-options": "Opzioni di sincronizzazione" + "repository-unhealthy": "" }, "token-permissions-info": { "and-click": "e fare clic", @@ -12196,11 +12201,11 @@ }, "warning-title-default": "Attenzione", "wizard": { - "alert-point-1": "Le risorse non potranno essere create, modificate o eliminate durante questo processo. Nell'ultimo passaggio, scompariranno.", - "alert-point-2": "Una volta completato il provisioning, le risorse riappariranno e verranno gestite tramite la memoria esterna.", + "alert-point-1": "", + "alert-point-2": "", "alert-point-3": "La durata di questo processo dipende dal numero di risorse coinvolte.", - "alert-point-4": "Gli amministratori dell'istanza aziendale possono mostrare un banner di annuncio agli utenti. Consulta <2>questa guida per istruzioni dettagliate.", - "alert-title": "Importante: nessun dato o configurazione andrà perso, ma le dashboard non saranno disponibili per alcuni minuti.", + "alert-point-4": "", + "alert-title": "", "button-cancel": "", "button-cancelling": "", "button-next": "Fine", @@ -12218,7 +12223,6 @@ "step-finish": "Scegli impostazioni aggiuntive", "step-synchronize": "Sincronizza con la memoria esterna", "sync-description": "Sincronizza le risorse con la memoria esterna. Dopo questo passaggio una tantum, tutti gli aggiornamenti futuri verranno salvati automaticamente nel repository e ripristinati nell'istanza.", - "sync-option-history": "Cronologia", "title-bootstrap": "Scegli cosa sincronizzare", "title-connect": "Connetti a una memoria esterna", "title-finish": "Scegli impostazioni aggiuntive", diff --git a/public/locales/ja-JP/grafana.json b/public/locales/ja-JP/grafana.json index feb94f34766..cebb4cd6bad 100644 --- a/public/locales/ja-JP/grafana.json +++ b/public/locales/ja-JP/grafana.json @@ -2224,6 +2224,13 @@ "receiver-metadata-badge": { "aria-label-open-external-link": "外部リンクを開く" }, + "receivers": { + "protected": { + "field": { + "description": "" + } + } + }, "receivers-section": { "button-more": "その他", "new-menu": { @@ -3311,6 +3318,7 @@ "login-attribute-path-label": "ログイン属性パス", "login-prompt-consent": "同意", "login-prompt-description": "ユーザーがアイデンティティプロバイダー (IdP) でログインするときのユーザーインタラクションのタイプを示します。", + "login-prompt-description-google": "", "login-prompt-label": "ログインプロンプト", "login-prompt-login": "ログイン", "login-prompt-select-account": "アカウントの選択", @@ -3368,6 +3376,7 @@ "use-pkce-description": "有効にすると、Grafanaは<2>OAuth2認証コード付与でコード交換用証明キー(PKCE)を使用します。", "use-pkce-label": "PKCEを使用", "use-refresh-token-description": "有効にすると、GrafanaはOAuth2プロバイダーから提供されたリフレッシュトークンを使用して新しいアクセストークンを取得します。", + "use-refresh-token-description-google": "", "use-refresh-token-label": "リフレッシュトークンを使用", "validate-hosted-domain-description": "有効にすると、GrafanaはGoogle IDトークンから取得したホストドメインをユーザーが指定した「{{ allowedDomainsLabel }}」リストと照合します。", "validate-hosted-domain-label": "ホストドメインを検証", @@ -4802,8 +4811,7 @@ "apply": "", "change-value": "", "discard": "", - "modal-title": "", - "values": "カンマで区切った値" + "modal-title": "" }, "datasource-options": { "name-filter": "名前フィルター", @@ -10132,7 +10140,8 @@ "copy": "選択した部分をコピー", "disable-menu": "メニューを無効にする", "line-contains": "行にフィルタが含まれている場合はフィルタとして追加", - "line-contains-not": "フィルタが含まれていない行として追加" + "line-contains-not": "フィルタが含まれていない行として追加", + "search-text": "" }, "show-log-attributes": "", "timestamp-format": "タイムスタンプの表示形式", @@ -11367,6 +11376,12 @@ "latestReleaseDate": "最新リリース日:", "latestVersion": "最新のバージョン", "license": "ライセンス", + "moreDetails": "", + "pluginInsights": { + "header": "" + }, + "pluginInsightsSuccessTooltip": "", + "pluginInsightsWarningTooltip": "", "raiseAnIssue": "問題を提起する", "reportAbuse": "", "reportAbuseTooltip": "悪意のあるプラグインや有害なプラグインに関連する問題は、Grafana Labsに直接報告してください。", @@ -11808,7 +11823,6 @@ } }, "getting-started": { - "alert-temporary-outage": "インスタンス全体を接続すると、移行実行中はダッシュボードが利用できなくなります。このプロセスを開始する前に、ユーザーに警告することをお勧めします。", "modal-description-public-access": "GitHub連携を有効にするために、Grafanaインスタンスへの公開アクセスを設定", "modal-description-required-features": "プロビジョニングに必要なGrafana機能を有効化", "modal-title-set-up-public-access": "公開アクセスを設定", @@ -11820,8 +11834,7 @@ "step-title-copy-url": "公開URLをコピー", "step-title-enable-feature-toggles": "必要な機能トグルを有効化", "step-title-start-ngrok": "一時的な公開アクセス用にngrokを起動", - "step-title-update-grafana-config": "Grafana設定を更新", - "title-setting-connection-could-cause-temporary-outage": "この接続設定を行うことで、一時的に停止する可能性があります" + "step-title-update-grafana-config": "Grafana設定を更新" }, "getting-started-page": { "subtitle-provisioning-feature": "プロビジョニング接続を表示・管理" @@ -11890,18 +11903,15 @@ }, "home-page": { "button-delete-repositories": "リポジトリを削除", - "configured-repositories-while-running-legacy-storage": "レガシーストレージの実行中は、設定したリポジトリは機能しません。", "confirm-delete-repositories": "設定済みのリポジトリをすべて削除してもよろしいですか?この操作は元に戻せません。", "error-delete-all-repositories": "すべてのリポジトリの削除に失敗しました", - "remove-all-configured-repositories": "設定済みのリポジトリをすべて削除", "subtitle": "設定済みのリポジトリを表示・管理", "success-all-repositories-deleted": "設定済みのリポジトリがすべて削除されました", "tab-getting-started": "はじめに", "tab-getting-started-title": "はじめに", "tab-repositories": "リポジトリ", "tab-repositories-title": "リポジトリ一覧", - "title-delete-all-configured-repositories": "設定済みのリポジトリをすべて削除", - "title-legacy-storage-detected": "レガシーストレージが検出されました" + "title-delete-all-configured-repositories": "設定済みのリポジトリをすべて削除" }, "http-utils": { "access-denied": "", @@ -11941,7 +11951,6 @@ "mode-options": { "disabled": { "folder-connected": "", - "legacy-storage": "", "not-allowed": "", "not-supported": "" }, @@ -12021,7 +12030,6 @@ "repository-status-page": { "back-to-repositories": "リポジトリに戻る", "cleaning-up-resources": "リポジトリリソースのクリーンアップ中", - "legacy-storage-message": "インスタンスはまだ統合ストレージを実行していません - 移行ウィザードが必要です", "not-found": "見つかりません", "not-found-message": "リポジトリが見つかりません", "repository-config-exists-configuration": "リポジトリ設定が設定ファイルに含まれていることを確認してください。", @@ -12030,7 +12038,6 @@ "tab-resources": "リソース", "tab-resources-title": "", "title": "リポジトリの状態", - "title-legacy-storage": "レガシーストレージ", "title-queued-for-deletion": "削除待ちリストに追加されました" }, "repository-type-cards": { @@ -12126,9 +12133,7 @@ "synchronize-step": { "repository-error": "", "repository-error-message": "", - "repository-unhealthy": "", - "synchronization-description": "各履歴値のコミットを含める", - "synchronization-options": "同期オプション" + "repository-unhealthy": "" }, "token-permissions-info": { "and-click": "そしてクリック", @@ -12145,11 +12150,11 @@ }, "warning-title-default": "警告", "wizard": { - "alert-point-1": "このプロセス中はリソースの作成、編集、削除を行えません。最後のステップになると、リソースが消えます。", - "alert-point-2": "プロビジョニングが完了すると、リソースが再表示され、外部ストレージを通じて管理されます。", + "alert-point-1": "", + "alert-point-2": "", "alert-point-3": "このプロセスの所要時間は、関連するリソースの数によって異なります。", - "alert-point-4": "エンタープライズインスタンス管理者は、ユーザーにお知らせバナーを表示できます。詳しい手順については<2>このガイドをご覧ください。", - "alert-title": "重要:データや設定は失われませんが、ダッシュボードは数分間一時的に利用できなくなります。", + "alert-point-4": "", + "alert-title": "", "button-cancel": "", "button-cancelling": "", "button-next": "完了", @@ -12167,7 +12172,6 @@ "step-finish": "追加設定を選択", "step-synchronize": "外部ストレージと同期", "sync-description": "リソースを外部ストレージと同期します。この一度限りの手順が完了すると、その後のすべての更新は自動的にリポジトリに保存され、インスタンスにプロビジョニングされます。", - "sync-option-history": "履歴", "title-bootstrap": "同期する内容を選択", "title-connect": "外部ストレージに接続", "title-finish": "追加設定を選択", diff --git a/public/locales/ko-KR/grafana.json b/public/locales/ko-KR/grafana.json index 24ea525fbb6..07e410e67e1 100644 --- a/public/locales/ko-KR/grafana.json +++ b/public/locales/ko-KR/grafana.json @@ -2224,6 +2224,13 @@ "receiver-metadata-badge": { "aria-label-open-external-link": "외부 링크 열기" }, + "receivers": { + "protected": { + "field": { + "description": "" + } + } + }, "receivers-section": { "button-more": "더 보기", "new-menu": { @@ -3311,6 +3318,7 @@ "login-attribute-path-label": "로그인 속성 경로", "login-prompt-consent": "동의", "login-prompt-description": "사용자가 IdP로 로그인할 때 어떤 유형의 사용자 상호 작용이 있었는지 보여줍니다.", + "login-prompt-description-google": "", "login-prompt-label": "로그인 프롬프트", "login-prompt-login": "로그인", "login-prompt-select-account": "계정 선택", @@ -3368,6 +3376,7 @@ "use-pkce-description": "활성화되면 Grafana는 OAuth2 인증 코드 부여와 함께 <2>코드 교환을 위한 증명 키(PKCE)를 사용합니다.", "use-pkce-label": "PKCE 사용", "use-refresh-token-description": "활성화되면 Grafana는 OAuth2 제공자가 제공한 새로 고침 토큰을 사용하여 새 액세스 토큰을 가져옵니다.", + "use-refresh-token-description-google": "", "use-refresh-token-label": "새로 고침 토큰 사용", "validate-hosted-domain-description": "활성화되면 Grafana는 Google ID 토큰에서 검색한 호스팅된 도메인을 사용자가 지정한 \"{{ allowedDomainsLabel }}\" 목록과 일치시킵니다.", "validate-hosted-domain-label": "호스팅된 도메인 검증", @@ -4802,8 +4811,7 @@ "apply": "", "change-value": "", "discard": "", - "modal-title": "", - "values": "쉼표로 구분된 값" + "modal-title": "" }, "datasource-options": { "name-filter": "이름 필터", @@ -10132,7 +10140,8 @@ "copy": "선택 항목 복사", "disable-menu": "메뉴 비활성화", "line-contains": "라인에 포함 필터로 추가", - "line-contains-not": "라인에 미포함 필터로 추가" + "line-contains-not": "라인에 미포함 필터로 추가", + "search-text": "" }, "show-log-attributes": "", "timestamp-format": "타임스탬프 해상도", @@ -11367,6 +11376,12 @@ "latestReleaseDate": "최신 릴리스 날짜:", "latestVersion": "최신 버전", "license": "라이선스", + "moreDetails": "", + "pluginInsights": { + "header": "" + }, + "pluginInsightsSuccessTooltip": "", + "pluginInsightsWarningTooltip": "", "raiseAnIssue": "문제 제기", "reportAbuse": "", "reportAbuseTooltip": "악성 또는 유해한 플러그인과 관련된 문제는 바로 Grafana Labs에 신고해 주세요.", @@ -11808,7 +11823,6 @@ } }, "getting-started": { - "alert-temporary-outage": "전체 인스턴스를 연결하면 마이그레이션를 실행하는 동안 대시보드를 사용할 수 없습니다. 프로세스를 시작하기 전에 사용자에게 경고하는 것이 좋습니다.", "modal-description-public-access": "Grafana 인스턴스에 대한 공개 액세스를 설정하여 GitHub 통합을 활성화합니다", "modal-description-required-features": "프로비저닝에 필요한 Grafana 기능 활성화", "modal-title-set-up-public-access": "공개 액세스 설정", @@ -11820,8 +11834,7 @@ "step-title-copy-url": "공개 URL 복사", "step-title-enable-feature-toggles": "필요한 기능 토글 활성화", "step-title-start-ngrok": "임시 공용 액세스를 위해 ngrok 시작", - "step-title-update-grafana-config": "Grafana 구성 업데이트", - "title-setting-connection-could-cause-temporary-outage": "이 연결을 설정하면 일시적인 중단이 발생할 수 있습니다" + "step-title-update-grafana-config": "Grafana 구성 업데이트" }, "getting-started-page": { "subtitle-provisioning-feature": "프로비저닝 연결 보기 및 관리" @@ -11890,18 +11903,15 @@ }, "home-page": { "button-delete-repositories": "리포지토리 삭제", - "configured-repositories-while-running-legacy-storage": "레거시 스토리지를 실행하는 동안에는 구성된 리포지토리가 작동하지 않습니다.", "confirm-delete-repositories": "정말 구성된 모든 리포지토리를 삭제하시겠어요? 처리 후에는 되돌릴 수 없습니다.", "error-delete-all-repositories": "모든 리포지토리 삭제 실패", - "remove-all-configured-repositories": "구성된 모든 리포지토리 제거", "subtitle": "구성된 리포지토리 보기 및 관리", "success-all-repositories-deleted": "구성된 모든 리포지토리가 삭제되었습니다", "tab-getting-started": "시작하기", "tab-getting-started-title": "시작하기", "tab-repositories": "리포지토리", "tab-repositories-title": "리포지토리 목록", - "title-delete-all-configured-repositories": "구성된 모든 리포지토리 삭제", - "title-legacy-storage-detected": "레거시 스토리지 감지됨" + "title-delete-all-configured-repositories": "구성된 모든 리포지토리 삭제" }, "http-utils": { "access-denied": "", @@ -11941,7 +11951,6 @@ "mode-options": { "disabled": { "folder-connected": "", - "legacy-storage": "", "not-allowed": "", "not-supported": "" }, @@ -12021,7 +12030,6 @@ "repository-status-page": { "back-to-repositories": "리포지토리로 돌아가기", "cleaning-up-resources": "리포지토리 리소스 정리 및 삭제 중", - "legacy-storage-message": "인스턴스가 아직 통합 스토리지를 실행하고 있지 않습니다. 마이그레이션 마법사가 필요합니다", "not-found": "찾을 수 없음", "not-found-message": "리포지토리를 찾을 수 없습니다", "repository-config-exists-configuration": "리포지토리 구성이 구성 파일에 있는지 확인하세요.", @@ -12030,7 +12038,6 @@ "tab-resources": "리소스", "tab-resources-title": "", "title": "리포지토리 상태", - "title-legacy-storage": "레거시 스토리지", "title-queued-for-deletion": "삭제 대기열에 추가됨" }, "repository-type-cards": { @@ -12126,9 +12133,7 @@ "synchronize-step": { "repository-error": "", "repository-error-message": "", - "repository-unhealthy": "", - "synchronization-description": "각 과거 값에 대한 커밋을 포함합니다", - "synchronization-options": "동기화 옵션" + "repository-unhealthy": "" }, "token-permissions-info": { "and-click": "및 클릭", @@ -12145,11 +12150,11 @@ }, "warning-title-default": "경고", "wizard": { - "alert-point-1": "이 프로세스 중에는 리소스를 생성, 편집 또는 삭제할 수 없습니다. 마지막 단계에서는 리소스가 표시되지 않습니다.", - "alert-point-2": "프로비저닝이 완료되면 리소스가 다시 표시되고 외부 스토리지를 통해 관리됩니다.", + "alert-point-1": "", + "alert-point-2": "", "alert-point-3": "이 프로세스의 지속 시간은 관련된 리소스 수에 따라 달라집니다.", - "alert-point-4": "Enterprise 인스턴스 관리자는 사용자에게 공지 배너를 표시할 수 있습니다. 단계별 지침은 <2>이 가이드를 확인하세요.", - "alert-title": "중요: 데이터나 구성은 손실되지 않지만 대시보드를 몇 분 동안 일시적으로 사용할 수 없습니다.", + "alert-point-4": "", + "alert-title": "", "button-cancel": "", "button-cancelling": "", "button-next": "완료", @@ -12167,7 +12172,6 @@ "step-finish": "추가 설정 선택", "step-synchronize": "외부 스토리지와 동기화", "sync-description": "외부 스토리지와 리소스를 동기화합니다. 이 일회성 단계 후에는 향후 모든 업데이트가 자동으로 리포지토리에 저장되고 인스턴스에 다시 프로비저닝됩니다.", - "sync-option-history": "이력", "title-bootstrap": "동기화할 항목 선택", "title-connect": "외부 스토리지에 연결", "title-finish": "추가 설정 선택", diff --git a/public/locales/nl-NL/grafana.json b/public/locales/nl-NL/grafana.json index facfe8cee8e..237fbb74953 100644 --- a/public/locales/nl-NL/grafana.json +++ b/public/locales/nl-NL/grafana.json @@ -2232,6 +2232,13 @@ "receiver-metadata-badge": { "aria-label-open-external-link": "Externe link openen" }, + "receivers": { + "protected": { + "field": { + "description": "" + } + } + }, "receivers-section": { "button-more": "Meer", "new-menu": { @@ -3322,6 +3329,7 @@ "login-attribute-path-label": "Pad inlogattribuut", "login-prompt-consent": "Toestemming ", "login-prompt-description": "Geeft het type gebruikersinteractie aan wanneer de gebruiker inlogt met de IdP.", + "login-prompt-description-google": "", "login-prompt-label": "Login prompt", "login-prompt-login": "Inloggen", "login-prompt-select-account": "Selecteer account", @@ -3379,6 +3387,7 @@ "use-pkce-description": "Indien ingeschakeld, gebruikt Grafana <2>Proof Key for Code Exchange (PKCE) met de OAuth2-autorisatiecodetoewijzing.", "use-pkce-label": "PKCE gebruiken", "use-refresh-token-description": "Indien ingeschakeld, haalt Grafana een nieuw toegangstoken op met behulp van het vernieuwingstoken dat is verstrekt door de OAuth2-provider.", + "use-refresh-token-description-google": "", "use-refresh-token-label": "Vernieuwingstoken gebruiken", "validate-hosted-domain-description": "Indien ingeschakeld, zal Grafana het gehoste domein dat is opgehaald uit het Google id-token vergelijken met de '{{ allowedDomainsLabel }}' lijst die is opgegeven door de gebruiker.", "validate-hosted-domain-label": "Gehost domein valideren", @@ -4821,8 +4830,7 @@ "apply": "", "change-value": "", "discard": "", - "modal-title": "", - "values": "Waarden gescheiden door komma" + "modal-title": "" }, "datasource-options": { "name-filter": "Filter een naam geven", @@ -10175,7 +10183,8 @@ "copy": "Selectie kopiëren", "disable-menu": "Menu uitschakelen", "line-contains": "Toevoegen als regel filter bevat", - "line-contains-not": "Toevoegen als regel geen filter bevat" + "line-contains-not": "Toevoegen als regel geen filter bevat", + "search-text": "" }, "show-log-attributes": "", "timestamp-format": "Tijdstempelresolutie", @@ -11413,6 +11422,12 @@ "latestReleaseDate": "Uiterste releasedatum:", "latestVersion": "Nieuwste versie", "license": "Licentie", + "moreDetails": "", + "pluginInsights": { + "header": "" + }, + "pluginInsightsSuccessTooltip": "", + "pluginInsightsWarningTooltip": "", "raiseAnIssue": "Een probleem melden", "reportAbuse": "", "reportAbuseTooltip": "Meld problemen met kwaadaardige of schadelijke plug-ins rechtstreeks aan Grafana Labs.", @@ -11859,7 +11874,6 @@ } }, "getting-started": { - "alert-temporary-outage": "Wanneer je je hele instantie koppelt, zijn er geen dashboards beschikbaar tijdens het uitvoeren van de migratie. We raden je aan je gebruikers te waarschuwen voordat je het proces start.", "modal-description-public-access": "Stel openbare toeging tot je Grafana-instantie in om GitHub-integratie in te schakelen", "modal-description-required-features": "Vereiste Grafana-functies inschakelen voor provisioning", "modal-title-set-up-public-access": "Openbare toegang instellen", @@ -11871,8 +11885,7 @@ "step-title-copy-url": "Kopieer je openbare URL", "step-title-enable-feature-toggles": "Schakel de vereiste functieschakelaars in", "step-title-start-ngrok": "Start ngrok voor tijdelijke openbare toegang", - "step-title-update-grafana-config": "Werk je Grafana-configuratie bij", - "title-setting-connection-could-cause-temporary-outage": "Het opzetten van deze verbinding kan een tijdelijke storing veroorzaken" + "step-title-update-grafana-config": "Werk je Grafana-configuratie bij" }, "getting-started-page": { "subtitle-provisioning-feature": "Je provisioningverbindingen bekijken en beheren" @@ -11941,18 +11954,15 @@ }, "home-page": { "button-delete-repositories": "Repositories verwijderen", - "configured-repositories-while-running-legacy-storage": "Geconfigureerde repositories werken niet tijdens het uitvoeren van legacy-opslag.", "confirm-delete-repositories": "Weet je zeker dat je alle geconfigureerde repositories wilt verwijderen? Deze actie kan niet ongedaan worden gemaakt.", "error-delete-all-repositories": "Kan niet alle repositories verwijderen", - "remove-all-configured-repositories": "Alle geconfigureerde repositories verwijderen", "subtitle": "Je geconfigureerde repositories bekijken en beheren", "success-all-repositories-deleted": "Alle geconfigureerde repositories zijn verwijderd", "tab-getting-started": "Aan de slag", "tab-getting-started-title": "Aan de slag", "tab-repositories": "Repositories", "tab-repositories-title": "Lijst van repositories", - "title-delete-all-configured-repositories": "Alle geconfigureerde repositories verwijderen", - "title-legacy-storage-detected": "Verouderde opslag gedetecteerd" + "title-delete-all-configured-repositories": "Alle geconfigureerde repositories verwijderen" }, "http-utils": { "access-denied": "", @@ -11992,7 +12002,6 @@ "mode-options": { "disabled": { "folder-connected": "", - "legacy-storage": "", "not-allowed": "", "not-supported": "" }, @@ -12072,7 +12081,6 @@ "repository-status-page": { "back-to-repositories": "Terug naar repositories", "cleaning-up-resources": "Bronnen van repository opschonen", - "legacy-storage-message": "Instantie draait nog geen geïntegreerde opslag -- migratiewizard vereist", "not-found": "niet gevonden", "not-found-message": "Repository niet gevonden", "repository-config-exists-configuration": "Zorg ervoor dat de repository-configuratie in het configuratiebestand bestaat.", @@ -12081,7 +12089,6 @@ "tab-resources": "Bronnen", "tab-resources-title": "", "title": "Repository-status", - "title-legacy-storage": "Legacy-opslag", "title-queued-for-deletion": "In de wachtrij voor verwijdering" }, "repository-type-cards": { @@ -12177,9 +12184,7 @@ "synchronize-step": { "repository-error": "", "repository-error-message": "", - "repository-unhealthy": "", - "synchronization-description": "Commits opnemen voor elke historische waarde", - "synchronization-options": "Synchronisatie-opties" + "repository-unhealthy": "" }, "token-permissions-info": { "and-click": "en klik", @@ -12196,11 +12201,11 @@ }, "warning-title-default": "Waarschuwing", "wizard": { - "alert-point-1": "Bronnen kunnen tijdens dit proces niet worden gemaakt, bewerkt of verwijderd. In de laatste stap verdwijnen ze.", - "alert-point-2": "Zodra de provisioning is voltooid, verschijnen bronnen weer en worden ze beheerd via externe opslag.", + "alert-point-1": "", + "alert-point-2": "", "alert-point-3": "De duur van dit proces is afhankelijk van het aantal betrokken bronnen.", - "alert-point-4": "Enterprise-instantiebeheerders kunnen een aankondigingsbanner weergeven aan gebruikers. Zie <2>deze handleiding voor stapsgewijze instructies.", - "alert-title": "Belangrijk: er zullen geen gegevens of configuratie verloren gaan, maar dashboards zullen tijdelijk een paar minuten niet beschikbaar zijn.", + "alert-point-4": "", + "alert-title": "", "button-cancel": "", "button-cancelling": "", "button-next": "Voltooien", @@ -12218,7 +12223,6 @@ "step-finish": "Kies aanvullende instellingen", "step-synchronize": "Synchroniseren met externe opslag", "sync-description": "Bronnen synchroniseren met externe opslag. Na deze eenmalige stap worden alle toekomstige updates automatisch opgeslagen in de repository en opnieuw ingericht in de instantie.", - "sync-option-history": "Geschiedenis", "title-bootstrap": "Kies wat je wilt synchroniseren", "title-connect": "Verbinden met externe opslag", "title-finish": "Kies aanvullende instellingen", diff --git a/public/locales/pl-PL/grafana.json b/public/locales/pl-PL/grafana.json index 98cfa899c2e..6ff40c3ab1f 100644 --- a/public/locales/pl-PL/grafana.json +++ b/public/locales/pl-PL/grafana.json @@ -2248,6 +2248,13 @@ "receiver-metadata-badge": { "aria-label-open-external-link": "Otwórz link zewnętrzny" }, + "receivers": { + "protected": { + "field": { + "description": "" + } + } + }, "receivers-section": { "button-more": "Więcej", "new-menu": { @@ -3344,6 +3351,7 @@ "login-attribute-path-label": "Ścieżka atrybutu loginu", "login-prompt-consent": "Zgoda", "login-prompt-description": "Wskazuje rodzaj interakcji użytkownika, gdy użytkownik loguje się za pomocą IdP.", + "login-prompt-description-google": "", "login-prompt-label": "Monit o zalogowanie", "login-prompt-login": "Logowanie", "login-prompt-select-account": "Wybierz konto", @@ -3401,6 +3409,7 @@ "use-pkce-description": "Jeśli ta opcja jest włączona, Grafana będzie używać <2>klucza próbnego do wymiany kodów (PKCE) z nadawaniem kodu autoryzacyjnego OAuth2.", "use-pkce-label": "Użyj PKCE", "use-refresh-token-description": "Jeśli ta opcja jest włączona, Grafana pobiera nowy token dostępu za pomocą tokena odświeżania dostarczonego przez dostawcę OAuth2.", + "use-refresh-token-description-google": "", "use-refresh-token-label": "Użyj tokena odświeżania", "validate-hosted-domain-description": "Jeśli ta opcja jest włączona, Grafana dopasowuje hostowaną domenę pobraną z tokena Google ID do listy „{{ allowedDomainsLabel }}” określonej przez użytkownika.", "validate-hosted-domain-label": "Zweryfikuj hostowaną domenę", @@ -4859,8 +4868,7 @@ "apply": "", "change-value": "", "discard": "", - "modal-title": "", - "values": "Wartości rozdzielone przecinkami" + "modal-title": "" }, "datasource-options": { "name-filter": "Filtr nazwy", @@ -10261,7 +10269,8 @@ "copy": "Kopiuj zaznaczenie", "disable-menu": "Wyłącz menu", "line-contains": "Dodaj jako wiersz zawierający filtr", - "line-contains-not": "Dodaj jako wiersz nie zawierający filtra" + "line-contains-not": "Dodaj jako wiersz nie zawierający filtra", + "search-text": "" }, "show-log-attributes": "", "timestamp-format": "Rozdzielczość znacznika czasu", @@ -11505,6 +11514,12 @@ "latestReleaseDate": "Data wydania najnowszej wersji:", "latestVersion": "Najnowsza wersja", "license": "Licencja", + "moreDetails": "", + "pluginInsights": { + "header": "" + }, + "pluginInsightsSuccessTooltip": "", + "pluginInsightsWarningTooltip": "", "raiseAnIssue": "Zgłoś sprawę", "reportAbuse": "", "reportAbuseTooltip": "Zgłaszaj sprawy związane ze złośliwymi lub szkodliwymi wtyczkami bezpośrednio do Grafana Labs.", @@ -11961,7 +11976,6 @@ } }, "getting-started": { - "alert-temporary-outage": "Po połączeniu całej instancji pulpity będą niedostępne podczas uruchamiania migracji. Zalecamy ostrzeżenie użytkowników przed rozpoczęciem tego procesu.", "modal-description-public-access": "Skonfiguruj publiczny dostęp do instancji Grafany, aby włączyć integrację z GitHubem", "modal-description-required-features": "Włącz funkcje Grafany wymagane do aprowizacji", "modal-title-set-up-public-access": "Skonfiguruj dostęp publiczny", @@ -11973,8 +11987,7 @@ "step-title-copy-url": "Skopiuj swój publiczny URL", "step-title-enable-feature-toggles": "Włącz wymagane przełączniki funkcji", "step-title-start-ngrok": "Uruchom narzędzie ngrok, aby uzyskać tymczasowy dostęp publiczny", - "step-title-update-grafana-config": "Zaktualizuj konfigurację usługi Grafana", - "title-setting-connection-could-cause-temporary-outage": "Skonfigurowanie tego połączenia może spowodować tymczasową niedostępność" + "step-title-update-grafana-config": "Zaktualizuj konfigurację usługi Grafana" }, "getting-started-page": { "subtitle-provisioning-feature": "Wyświetlaj połączenia aprowizacyjne i nimi zarządzaj" @@ -12043,18 +12056,15 @@ }, "home-page": { "button-delete-repositories": "Usuń repozytoria", - "configured-repositories-while-running-legacy-storage": "Skonfigurowane repozytoria nie będą działać podczas uruchamiania starszej pamięci masowej.", "confirm-delete-repositories": "Czy na pewno chcesz usunąć wszystkie skonfigurowane repozytoria? To działanie jest nieodwracalne.", "error-delete-all-repositories": "Nie udało się usunąć wszystkich repozytoriów", - "remove-all-configured-repositories": "Usuń wszystkie skonfigurowane repozytoria", "subtitle": "Wyświetl skonfigurowane repozytoria i nimi zarządzaj", "success-all-repositories-deleted": "Wszystkie skonfigurowane repozytoria zostały usunięte", "tab-getting-started": "Pierwsze kroki", "tab-getting-started-title": "Pierwsze kroki", "tab-repositories": "Repozytoria", "tab-repositories-title": "Lista repozytoriów", - "title-delete-all-configured-repositories": "Usuń wszystkie skonfigurowane repozytoria", - "title-legacy-storage-detected": "Wykryto starszą pamięć masową" + "title-delete-all-configured-repositories": "Usuń wszystkie skonfigurowane repozytoria" }, "http-utils": { "access-denied": "", @@ -12094,7 +12104,6 @@ "mode-options": { "disabled": { "folder-connected": "", - "legacy-storage": "", "not-allowed": "", "not-supported": "" }, @@ -12174,7 +12183,6 @@ "repository-status-page": { "back-to-repositories": "Wróć do repozytoriów", "cleaning-up-resources": "Sprzątanie zasobów repozytorium", - "legacy-storage-message": "Instancja nie używa jeszcze ujednoliconej pamięci masowej – wymaga to kreatora migracji", "not-found": "nie znaleziono", "not-found-message": "Nie znaleziono repozytorium", "repository-config-exists-configuration": "Upewnij się, że konfiguracja repozytorium istnieje w pliku konfiguracyjnym.", @@ -12183,7 +12191,6 @@ "tab-resources": "Zasoby", "tab-resources-title": "", "title": "Status repozytorium", - "title-legacy-storage": "Starsza pamięć masowa", "title-queued-for-deletion": "Dodano do kolejki do usunięcia" }, "repository-type-cards": { @@ -12279,9 +12286,7 @@ "synchronize-step": { "repository-error": "", "repository-error-message": "", - "repository-unhealthy": "", - "synchronization-description": "Uwzględnij zatwierdzenia dla każdej wartości historycznej", - "synchronization-options": "Opcje synchronizacji" + "repository-unhealthy": "" }, "token-permissions-info": { "and-click": "i kliknij", @@ -12298,11 +12303,11 @@ }, "warning-title-default": "Ostrzeżenie", "wizard": { - "alert-point-1": "Podczas tego procesu nie będzie można tworzyć, edytować ani usuwać zasobów. W ostatnim kroku zasoby znikną.", - "alert-point-2": "Po zakończeniu aprowizacji zasoby pojawią się ponownie i będą zarządzane za pośrednictwem zewnętrznej pamięci masowej.", + "alert-point-1": "", + "alert-point-2": "", "alert-point-3": "Czas trwania tego procesu zależy od liczby zasobów.", - "alert-point-4": "Administratorzy instancji Enterprise mogą włączyć wyświetlanie użytkownikom banera z ogłoszeniem. Szczegółowe instrukcje znajdziesz w <2>tym przewodniku.", - "alert-title": "Ważne: dane ani konfiguracja nie zostaną utracone, ale pulpity będą niedostępne przez kilka minut.", + "alert-point-4": "", + "alert-title": "", "button-cancel": "", "button-cancelling": "", "button-next": "Zakończ", @@ -12320,7 +12325,6 @@ "step-finish": "Wybierz dodatkowe ustawienia", "step-synchronize": "Synchronizuj z zewnętrzną pamięcią masową", "sync-description": "Zsynchronizuj zasoby z zewnętrzną pamięcią masową. Po tym jednorazowym kroku wszystkie przyszłe aktualizacje zostaną automatycznie zapisane w repozytorium i ponownie aprowizowane w instancji.", - "sync-option-history": "Historia", "title-bootstrap": "Wybierz, co chcesz zsynchronizować", "title-connect": "Połączenie z zewnętrzną pamięcią masową", "title-finish": "Wybierz dodatkowe ustawienia", diff --git a/public/locales/pt-BR/grafana.json b/public/locales/pt-BR/grafana.json index 542bd14c8a1..cbaee920be0 100644 --- a/public/locales/pt-BR/grafana.json +++ b/public/locales/pt-BR/grafana.json @@ -2232,6 +2232,13 @@ "receiver-metadata-badge": { "aria-label-open-external-link": "Abrir link externo" }, + "receivers": { + "protected": { + "field": { + "description": "" + } + } + }, "receivers-section": { "button-more": "Mais", "new-menu": { @@ -3322,6 +3329,7 @@ "login-attribute-path-label": "Caminho do atributo de login", "login-prompt-consent": "Consentimento ", "login-prompt-description": "Indica o tipo de interação do usuário quando o usuário faz login com o IdP.", + "login-prompt-description-google": "", "login-prompt-label": "Solicitação de login", "login-prompt-login": "Login", "login-prompt-select-account": "Selecionar conta", @@ -3379,6 +3387,7 @@ "use-pkce-description": "Se estiver habilitada, a Grafana usará a <2>Chave de prova para troca de código (PKCE) com a concessão de código de autorização OAuth2.", "use-pkce-label": "Usar PKCE", "use-refresh-token-description": "Se estiver habilitado, o Grafana buscará um novo token de acesso usando o token de atualização fornecido pelo provedor OAuth2.", + "use-refresh-token-description-google": "", "use-refresh-token-label": "Usar token de atualização", "validate-hosted-domain-description": "Se estiver habilitado, o Grafana realizará a comparação entre o Domínio Hospedado obtido a partir do token de ID do Google e a lista \"{{ allowedDomainsLabel }}\" especificada pelo usuário.", "validate-hosted-domain-label": "Validar domínio hospedado", @@ -4821,8 +4830,7 @@ "apply": "", "change-value": "", "discard": "", - "modal-title": "", - "values": "Valores separados por vírgula" + "modal-title": "" }, "datasource-options": { "name-filter": "Filtro de nome", @@ -10175,7 +10183,8 @@ "copy": "Copiar seleção", "disable-menu": "Desativar menu", "line-contains": "Adicionar como linha contém filtro", - "line-contains-not": "Adicionar como linha não contém filtro" + "line-contains-not": "Adicionar como linha não contém filtro", + "search-text": "" }, "show-log-attributes": "", "timestamp-format": "Resolução de data e hora", @@ -11413,6 +11422,12 @@ "latestReleaseDate": "Data de lançamento mais recente:", "latestVersion": "Última versão", "license": "Licença", + "moreDetails": "", + "pluginInsights": { + "header": "" + }, + "pluginInsightsSuccessTooltip": "", + "pluginInsightsWarningTooltip": "", "raiseAnIssue": "Comunicar um problema", "reportAbuse": "", "reportAbuseTooltip": "Comunique problemas relacionados a plug-ins mal-intencionados ou prejudiciais diretamente à Grafana Labs.", @@ -11859,7 +11874,6 @@ } }, "getting-started": { - "alert-temporary-outage": "Quando você conectar toda a sua instância, os painéis ficarão indisponíveis durante a execução da migração. Recomendamos que você avise a seus usuários antes de iniciar o processo.", "modal-description-public-access": "Configure o acesso público à sua instância da Grafana para ativar a integração do GitHub", "modal-description-required-features": "Ativar os recursos necessários da Grafana para provisionamento", "modal-title-set-up-public-access": "Configurar acesso público", @@ -11871,8 +11885,7 @@ "step-title-copy-url": "Copie sua URL pública", "step-title-enable-feature-toggles": "Ativar as opções dos recursos necessários", "step-title-start-ngrok": "Inicie o ngrok para acesso público temporário", - "step-title-update-grafana-config": "Atualize sua configuração da Grafana", - "title-setting-connection-could-cause-temporary-outage": "Estabelecer esta conexão pode causar uma interrupção temporária" + "step-title-update-grafana-config": "Atualize sua configuração da Grafana" }, "getting-started-page": { "subtitle-provisioning-feature": "Visualize e gerencie suas conexões de provisionamento" @@ -11941,18 +11954,15 @@ }, "home-page": { "button-delete-repositories": "Excluir repositórios", - "configured-repositories-while-running-legacy-storage": "Os repositórios configurados não funcionarão durante a execução do armazenamento legado.", "confirm-delete-repositories": "Tem certeza de que deseja excluir todos os repositórios configurados? Esta ação não poderá ser desfeita. ", "error-delete-all-repositories": "Falha ao excluir todos os repositórios", - "remove-all-configured-repositories": "Remover todos os repositórios configurados", "subtitle": "Visualize e gerencie seus repositórios configurados", "success-all-repositories-deleted": "Todos os repositórios configurados foram excluídos", "tab-getting-started": "Como começar", "tab-getting-started-title": "Como começar", "tab-repositories": "Repositórios", "tab-repositories-title": "Lista de repositórios", - "title-delete-all-configured-repositories": "Excluir todos os repositórios configurados", - "title-legacy-storage-detected": "Armazenamento legado detectado" + "title-delete-all-configured-repositories": "Excluir todos os repositórios configurados" }, "http-utils": { "access-denied": "", @@ -11992,7 +12002,6 @@ "mode-options": { "disabled": { "folder-connected": "", - "legacy-storage": "", "not-allowed": "", "not-supported": "" }, @@ -12072,7 +12081,6 @@ "repository-status-page": { "back-to-repositories": "Voltar para os repositórios", "cleaning-up-resources": "Limpando recursos do repositório", - "legacy-storage-message": "A instância ainda não está executando o armazenamento unificado: requer um assistente de migração", "not-found": "não encontrado", "not-found-message": "Repositório não encontrado", "repository-config-exists-configuration": "Verifique se a configuração do repositório existe no arquivo de configuração.", @@ -12081,7 +12089,6 @@ "tab-resources": "Fontes", "tab-resources-title": "", "title": "Status do repositório", - "title-legacy-storage": "Armazenamento legado", "title-queued-for-deletion": "Na fila para exclusão" }, "repository-type-cards": { @@ -12177,9 +12184,7 @@ "synchronize-step": { "repository-error": "", "repository-error-message": "", - "repository-unhealthy": "", - "synchronization-description": "Incluir confirmações para cada valor histórico", - "synchronization-options": "Opções de sincronização" + "repository-unhealthy": "" }, "token-permissions-info": { "and-click": "e clique", @@ -12196,11 +12201,11 @@ }, "warning-title-default": "Aviso", "wizard": { - "alert-point-1": "Os recursos não poderão ser criados, editados ou excluídos durante este processo. Na última etapa, eles desaparecerão.", - "alert-point-2": "Assim que o provisionamento for concluído, os recursos reaparecerão e serão gerenciados por meio de armazenamento externo.", + "alert-point-1": "", + "alert-point-2": "", "alert-point-3": "A duração deste processo depende da quantidade de recursos envolvidos.", - "alert-point-4": "Os administradores de instâncias corporativas podem exibir um banner de anúncio para os usuários. Consulte <2>este guia para conferir instruções passo a passo.", - "alert-title": "Importante: nenhum dado ou configuração será perdido, mas os painéis ficarão indisponíveis por alguns minutos.", + "alert-point-4": "", + "alert-title": "", "button-cancel": "", "button-cancelling": "", "button-next": "Finalizar", @@ -12218,7 +12223,6 @@ "step-finish": "Escolha configurações adicionais", "step-synchronize": "Sincronizar com armazenamento externo", "sync-description": "Sincronize recursos com armazenamento externo. Após esta única etapa, todas as atualizações futuras serão salvas automaticamente no repositório e provisionadas de volta para a instância.", - "sync-option-history": "Histórico", "title-bootstrap": "Escolha o que será sincronizado", "title-connect": "Conectar ao armazenamento externo", "title-finish": "Escolha configurações adicionais", diff --git a/public/locales/pt-PT/grafana.json b/public/locales/pt-PT/grafana.json index 30c132e560d..4e99ebc24f7 100644 --- a/public/locales/pt-PT/grafana.json +++ b/public/locales/pt-PT/grafana.json @@ -2232,6 +2232,13 @@ "receiver-metadata-badge": { "aria-label-open-external-link": "Abrir link externo" }, + "receivers": { + "protected": { + "field": { + "description": "" + } + } + }, "receivers-section": { "button-more": "Mais", "new-menu": { @@ -3322,6 +3329,7 @@ "login-attribute-path-label": "Caminho do atributo de início de sessão", "login-prompt-consent": "Consentimento", "login-prompt-description": "Indica o tipo de interação do utilizador quando o utilizador inicia sessão com o IdP.", + "login-prompt-description-google": "", "login-prompt-label": "Instrução de início de sessão", "login-prompt-login": "Entrar", "login-prompt-select-account": "Selecione a conta", @@ -3379,6 +3387,7 @@ "use-pkce-description": "Se estiver ativado, a Grafana utilizará a <2>Chave de prova para troca de código (PKCE) com a concessão do código de autorização OAuth2.", "use-pkce-label": "Utilizar PKCE", "use-refresh-token-description": "Se estiver ativado, o Grafana irá obter um novo token de acesso ao utilizar o token de atualização fornecido pelo fornecedor OAuth2.", + "use-refresh-token-description-google": "", "use-refresh-token-label": "Utilizar token de atualização", "validate-hosted-domain-description": "Se estiver ativado, o Grafana irá comparar o domínio alojado obtido do token de ID do Google com a lista \"{{ allowedDomainsLabel }}\" especificada pelo utilizador.", "validate-hosted-domain-label": "Validar domínio alojado", @@ -4821,8 +4830,7 @@ "apply": "", "change-value": "", "discard": "", - "modal-title": "", - "values": "Valores separados por vírgulas" + "modal-title": "" }, "datasource-options": { "name-filter": "Filtro de nome", @@ -10175,7 +10183,8 @@ "copy": "Copiar seleção", "disable-menu": "Desativar menu", "line-contains": "Adicionar, pois a linha contém filtro", - "line-contains-not": "Adicionar, pois a linha não contém filtro" + "line-contains-not": "Adicionar, pois a linha não contém filtro", + "search-text": "" }, "show-log-attributes": "", "timestamp-format": "Resolução do carimbo de data e hora", @@ -11413,6 +11422,12 @@ "latestReleaseDate": "Data de lançamento mais recente:", "latestVersion": "Versão mais recente", "license": "Licença", + "moreDetails": "", + "pluginInsights": { + "header": "" + }, + "pluginInsightsSuccessTooltip": "", + "pluginInsightsWarningTooltip": "", "raiseAnIssue": "Comunicar um problema", "reportAbuse": "", "reportAbuseTooltip": "Comunique problemas relacionados com plugins maliciosos ou prejudiciais diretamente à Grafana Labs.", @@ -11859,7 +11874,6 @@ } }, "getting-started": { - "alert-temporary-outage": "Quando liga toda a sua instância, os painéis de controlo ficarão indisponíveis durante a execução da migração. Recomendamos que avise os seus utilizadores antes de iniciar o processo.", "modal-description-public-access": "Configure o acesso público à sua instância Grafana para ativar a integração do GitHub", "modal-description-required-features": "Ativar as funcionalidades necessárias da Grafana para aprovisionamento", "modal-title-set-up-public-access": "Configurar acesso público", @@ -11871,8 +11885,7 @@ "step-title-copy-url": "Copie o seu URL público", "step-title-enable-feature-toggles": "Ativar alternâncias de funcionalidades necessárias", "step-title-start-ngrok": "Inicie a ngrok para um acesso público temporário", - "step-title-update-grafana-config": "Atualizar a sua configuração da Grafana", - "title-setting-connection-could-cause-temporary-outage": "Configurar esta ligação pode causar uma interrupção temporária" + "step-title-update-grafana-config": "Atualizar a sua configuração da Grafana" }, "getting-started-page": { "subtitle-provisioning-feature": "Ver e gerir as suas ligações de provisionamento" @@ -11941,18 +11954,15 @@ }, "home-page": { "button-delete-repositories": "Eliminar repositórios", - "configured-repositories-while-running-legacy-storage": "Os repositórios configurados não funcionarão durante a execução do armazenamento herdado.", "confirm-delete-repositories": "Tem a certeza de que pretende eliminar todos os repositórios configurados? Esta ação não pode ser anulada. ", "error-delete-all-repositories": "Não foi possível eliminar todos os repositórios", - "remove-all-configured-repositories": "Remover todos os repositórios configurados", "subtitle": "Ver e gerir os seus repositórios configurados", "success-all-repositories-deleted": "Todos os repositórios configurados eliminados", "tab-getting-started": "Introdução", "tab-getting-started-title": "Introdução", "tab-repositories": "Repositórios", "tab-repositories-title": "Lista de repositórios", - "title-delete-all-configured-repositories": "Eliminar todos os repositórios configurados", - "title-legacy-storage-detected": "Armazenamento herdado detetado" + "title-delete-all-configured-repositories": "Eliminar todos os repositórios configurados" }, "http-utils": { "access-denied": "", @@ -11992,7 +12002,6 @@ "mode-options": { "disabled": { "folder-connected": "", - "legacy-storage": "", "not-allowed": "", "not-supported": "" }, @@ -12072,7 +12081,6 @@ "repository-status-page": { "back-to-repositories": "Voltar aos repositórios", "cleaning-up-resources": "A limpar recursos do repositório", - "legacy-storage-message": "A instância ainda não está a executar o armazenamento unificado; requer o assistente de migração", "not-found": "não encontrado", "not-found-message": "Repositório não encontrado", "repository-config-exists-configuration": "Certifique-se de que a configuração do repositório existe no ficheiro de configuração.", @@ -12081,7 +12089,6 @@ "tab-resources": "Recursos", "tab-resources-title": "", "title": "Estado do repositório", - "title-legacy-storage": "Armazenamento herdado", "title-queued-for-deletion": "Em fila para eliminação" }, "repository-type-cards": { @@ -12177,9 +12184,7 @@ "synchronize-step": { "repository-error": "", "repository-error-message": "", - "repository-unhealthy": "", - "synchronization-description": "Incluir commits para cada valor histórico", - "synchronization-options": "Opções de sincronização" + "repository-unhealthy": "" }, "token-permissions-info": { "and-click": "e clique em", @@ -12196,11 +12201,11 @@ }, "warning-title-default": "Aviso", "wizard": { - "alert-point-1": "Os recursos não poderão ser criados, editados ou eliminados durante este processo. No último passo, irão desaparecer.", - "alert-point-2": "Assim que o provisionamento estiver concluído, os recursos reaparecerão e serão geridos através de um armazenamento externo.", + "alert-point-1": "", + "alert-point-2": "", "alert-point-3": "A duração deste processo depende do número de recursos envolvidos.", - "alert-point-4": "Os administradores de instâncias empresariais podem exibir um banner de anúncio aos utilizadores. Consulte <2>este guia para obter instruções passo a passo.", - "alert-title": "Importante: não serão perdidos dados ou configurações, mas os painéis de controlo ficarão temporariamente indisponíveis durante alguns minutos.", + "alert-point-4": "", + "alert-title": "", "button-cancel": "", "button-cancelling": "", "button-next": "Concluir", @@ -12218,7 +12223,6 @@ "step-finish": "Escolha as definições adicionais", "step-synchronize": "Sincronizar com armazenamento externo", "sync-description": "Sincronize recursos com um armazenamento externo. Após este passo único, todas as atualizações futuras serão guardadas automaticamente no repositório e aprovisionadas novamente para a instância.", - "sync-option-history": "Histórico", "title-bootstrap": "Escolha o que sincronizar", "title-connect": "Ligar a um armazenamento externo", "title-finish": "Escolha as definições adicionais", diff --git a/public/locales/ru-RU/grafana.json b/public/locales/ru-RU/grafana.json index ade7a64fe21..3d29410a1bf 100644 --- a/public/locales/ru-RU/grafana.json +++ b/public/locales/ru-RU/grafana.json @@ -2248,6 +2248,13 @@ "receiver-metadata-badge": { "aria-label-open-external-link": "Открыть внешнюю ссылку" }, + "receivers": { + "protected": { + "field": { + "description": "" + } + } + }, "receivers-section": { "button-more": "Еще", "new-menu": { @@ -3344,6 +3351,7 @@ "login-attribute-path-label": "Путь атрибута логина", "login-prompt-consent": "Согласие", "login-prompt-description": "Указывает тип взаимодействия с пользователем при входе с помощью IdP.", + "login-prompt-description-google": "", "login-prompt-label": "Приглашение на вход в систему", "login-prompt-login": "Вход", "login-prompt-select-account": "Выберите учетную запись", @@ -3401,6 +3409,7 @@ "use-pkce-description": "Если этот параметр включен, Grafana будет использовать <2>ключ подтверждения для обмена кодом (PKCE) с грантом кода авторизации OAuth2.", "use-pkce-label": "Использовать PKCE", "use-refresh-token-description": "Если этот параметр включен, Grafana будет получать новый токен доступа с помощью токена обновления, предоставленного поставщиком OAuth2.", + "use-refresh-token-description-google": "", "use-refresh-token-label": "Использовать токен обновления", "validate-hosted-domain-description": "Если этот параметр включен, Grafana будет сопоставлять домен размещения, полученный из токена Google ID, с заданным пользователем списком «{{ allowedDomainsLabel }}».", "validate-hosted-domain-label": "Проверять домен размещения", @@ -4859,8 +4868,7 @@ "apply": "", "change-value": "", "discard": "", - "modal-title": "", - "values": "Значения, разделенные запятыми" + "modal-title": "" }, "datasource-options": { "name-filter": "Фильтр по названию", @@ -10261,7 +10269,8 @@ "copy": "Копировать выделение", "disable-menu": "Отключить меню", "line-contains": "Добавить, поскольку строка содержит фильтр", - "line-contains-not": "Добавить, поскольку строка не содержит фильтр" + "line-contains-not": "Добавить, поскольку строка не содержит фильтр", + "search-text": "" }, "show-log-attributes": "", "timestamp-format": "Разрешение метки времени", @@ -11505,6 +11514,12 @@ "latestReleaseDate": "Дата последнего выпуска:", "latestVersion": "Новейшая версия", "license": "Лицензия", + "moreDetails": "", + "pluginInsights": { + "header": "" + }, + "pluginInsightsSuccessTooltip": "", + "pluginInsightsWarningTooltip": "", "raiseAnIssue": "Сообщить о проблеме", "reportAbuse": "", "reportAbuseTooltip": "Сообщайте о проблемах, связанных с вредоносными или опасными плагинами, непосредственно в Grafana Labs.", @@ -11961,7 +11976,6 @@ } }, "getting-started": { - "alert-temporary-outage": "Если подключается весь экземпляр, дашборды будут недоступны во время выполнения переноса. Рекомендуем предупредить пользователей перед запуском процесса.", "modal-description-public-access": "Настройте общий доступ к своему экземпляру Grafana, чтобы включить интеграцию с GitHub.", "modal-description-required-features": "Включите необходимые функции Grafana для подготовки.", "modal-title-set-up-public-access": "Настройка общего доступа", @@ -11973,8 +11987,7 @@ "step-title-copy-url": "Копирование общедоступного URL-адреса", "step-title-enable-feature-toggles": "Включение необходимых переключателей функциональности", "step-title-start-ngrok": "Запуск ngrok для временного общего доступа", - "step-title-update-grafana-config": "Обновление конфигурации Grafana", - "title-setting-connection-could-cause-temporary-outage": "Настройка этого подключения может привести к временному сбою" + "step-title-update-grafana-config": "Обновление конфигурации Grafana" }, "getting-started-page": { "subtitle-provisioning-feature": "Просмотр подключений для подготовки и управлением ими" @@ -12043,18 +12056,15 @@ }, "home-page": { "button-delete-repositories": "Удалить репозитории", - "configured-repositories-while-running-legacy-storage": "Настроенные репозитории не будут работать при использовании устаревшего хранилища.", "confirm-delete-repositories": "Действительно удалить все настроенные репозитории? Это действие невозможно отменить.", "error-delete-all-repositories": "Не удалось удалить все репозитории", - "remove-all-configured-repositories": "Удалить все настроенные репозитории", "subtitle": "Просмотр настроенных репозиториев и управление ими", "success-all-repositories-deleted": "Все настроенные репозитории удалены", "tab-getting-started": "Начало работы", "tab-getting-started-title": "Начало работы", "tab-repositories": "Репозитории", "tab-repositories-title": "Список репозиториев", - "title-delete-all-configured-repositories": "Удаление всех настроенных репозиториев", - "title-legacy-storage-detected": "Обнаружено устаревшее хранилище" + "title-delete-all-configured-repositories": "Удаление всех настроенных репозиториев" }, "http-utils": { "access-denied": "", @@ -12094,7 +12104,6 @@ "mode-options": { "disabled": { "folder-connected": "", - "legacy-storage": "", "not-allowed": "", "not-supported": "" }, @@ -12174,7 +12183,6 @@ "repository-status-page": { "back-to-repositories": "Назад к репозиториям", "cleaning-up-resources": "Очистка ресурсов репозитория", - "legacy-storage-message": "Экземпляр пока не использует унифицированное хранилище — требуется мастер переноса", "not-found": "не найдено", "not-found-message": "Репозиторий не найден", "repository-config-exists-configuration": "Убедитесь, что конфигурация репозитория существует в файле конфигурации.", @@ -12183,7 +12191,6 @@ "tab-resources": "Ресурсы", "tab-resources-title": "", "title": "Состояние репозитория", - "title-legacy-storage": "Устаревшее хранилище", "title-queued-for-deletion": "В очереди на удаление" }, "repository-type-cards": { @@ -12279,9 +12286,7 @@ "synchronize-step": { "repository-error": "", "repository-error-message": "", - "repository-unhealthy": "", - "synchronization-description": "Включить фиксации для каждого ранее зафиксированного значения", - "synchronization-options": "Параметры синхронизации" + "repository-unhealthy": "" }, "token-permissions-info": { "and-click": "и нажать", @@ -12298,11 +12303,11 @@ }, "warning-title-default": "Предупреждение", "wizard": { - "alert-point-1": "Во время этого процесса невозможно создавать, редактировать или удалять ресурсы. На последнем шаге они исчезнут.", - "alert-point-2": "После завершения подготовки ресурсы снова появятся и будут управляться через внешнее хранилище.", + "alert-point-1": "", + "alert-point-2": "", "alert-point-3": "Длительность процесса зависит от количества задействованных ресурсов.", - "alert-point-4": "Администраторы экземпляров Enterprise могут показывать пользователям баннер с объявлением. Пошаговые инструкции см. в <2>руководстве.", - "alert-title": "Важно. Данные и конфигурация не будут потеряны, однако дашборды будут недоступны в течение нескольких минут.", + "alert-point-4": "", + "alert-title": "", "button-cancel": "", "button-cancelling": "", "button-next": "Готово", @@ -12320,7 +12325,6 @@ "step-finish": "Выберите дополнительные параметры", "step-synchronize": "Синхронизировать с внешним хранилищем", "sync-description": "Синхронизируйте ресурсы с внешним хранилищем. После этого разового шага все будущие обновления будут автоматически сохраняться в репозитории и загружаться обратно в экземпляр.", - "sync-option-history": "История", "title-bootstrap": "Выберите, что синхронизировать", "title-connect": "Подключение к внешнему хранилищу", "title-finish": "Выбор дополнительных параметров", diff --git a/public/locales/sv-SE/grafana.json b/public/locales/sv-SE/grafana.json index 45669bf75c5..38943db06ed 100644 --- a/public/locales/sv-SE/grafana.json +++ b/public/locales/sv-SE/grafana.json @@ -2232,6 +2232,13 @@ "receiver-metadata-badge": { "aria-label-open-external-link": "Öppen extern länk" }, + "receivers": { + "protected": { + "field": { + "description": "" + } + } + }, "receivers-section": { "button-more": "Mer", "new-menu": { @@ -3322,6 +3329,7 @@ "login-attribute-path-label": "Sökväg för inloggningsattribut", "login-prompt-consent": "Samtycke", "login-prompt-description": "Anger typen av användarinteraktion när användaren loggar in med IdP.", + "login-prompt-description-google": "", "login-prompt-label": "Inloggningsprompt", "login-prompt-login": "Logga in", "login-prompt-select-account": "Välj konto", @@ -3379,6 +3387,7 @@ "use-pkce-description": "Om det är aktiverat kommer Grafana att använda <2>Proof Key for Code Exchange (PKCE) med OAuth2 Authorization Code Grant.", "use-pkce-label": "Använd PKCE", "use-refresh-token-description": "Om det är aktiverat hämtar Grafana en ny åtkomsttoken med hjälp av den uppdateringstoken som tillhandahålls av OAuth2-leverantören.", + "use-refresh-token-description-google": "", "use-refresh-token-label": "Använd uppdateringstoken", "validate-hosted-domain-description": "Om det är aktiverat kontrollerar Grafana den värddomän som hämtas från Googles ID-token mot den ”{{ allowedDomainsLabel }}”-lista som användaren har specificerat.", "validate-hosted-domain-label": "Validera värddomänen", @@ -4821,8 +4830,7 @@ "apply": "", "change-value": "", "discard": "", - "modal-title": "", - "values": "Värden åtskilda med kommatecken" + "modal-title": "" }, "datasource-options": { "name-filter": "Namnfilter", @@ -10175,7 +10183,8 @@ "copy": "Kopiera markerat", "disable-menu": "Inaktivera meny", "line-contains": "Lägg till som rad innehåller filter", - "line-contains-not": "Lägg till som rad innehåller inte filter" + "line-contains-not": "Lägg till som rad innehåller inte filter", + "search-text": "" }, "show-log-attributes": "", "timestamp-format": "Tidsstämpelupplösning", @@ -11413,6 +11422,12 @@ "latestReleaseDate": "Senaste utgivningsdatum:", "latestVersion": "Senaste versionen", "license": "Licens", + "moreDetails": "", + "pluginInsights": { + "header": "" + }, + "pluginInsightsSuccessTooltip": "", + "pluginInsightsWarningTooltip": "", "raiseAnIssue": "Ta upp ett problem", "reportAbuse": "", "reportAbuseTooltip": "Rapportera problem relaterade till skadliga eller farliga tilläggsprogram direkt till Grafana Labs.", @@ -11859,7 +11874,6 @@ } }, "getting-started": { - "alert-temporary-outage": "När du ansluter hela din instans kommer instrumentpaneler inte att vara tillgängliga när du kör migreringen. Vi rekommenderar att du varnar dina användare innan du påbörjar processen.", "modal-description-public-access": "Konfigurera offentlig åtkomst till din Grafana-instans för att aktivera GitHub-integrering", "modal-description-required-features": "Aktivera obligatoriska Grafana-funktioner för provisionering", "modal-title-set-up-public-access": "Konfigurera offentlig åtkomst", @@ -11871,8 +11885,7 @@ "step-title-copy-url": "Kopiera din offentliga webbadress", "step-title-enable-feature-toggles": "Aktivera obligatoriska funktionsväxlar", "step-title-start-ngrok": "Starta ngrok för tillfällig offentlig åtkomst", - "step-title-update-grafana-config": "Uppdatera din Grafana-konfiguration", - "title-setting-connection-could-cause-temporary-outage": "Konfiguration av den här anslutningen kan orsaka ett tillfälligt avbrott" + "step-title-update-grafana-config": "Uppdatera din Grafana-konfiguration" }, "getting-started-page": { "subtitle-provisioning-feature": "Visa och hantera dina provisioneringsanslutningar" @@ -11941,18 +11954,15 @@ }, "home-page": { "button-delete-repositories": "Radera databaser", - "configured-repositories-while-running-legacy-storage": "Konfigurerade lagringsplatser fungerar inte när äldre lagring används.", "confirm-delete-repositories": "Är du säker på att du vill radera alla konfigurerade databaser? Den här åtgärden kan inte ångras.", "error-delete-all-repositories": "Det gick inte att radera alla databaser", - "remove-all-configured-repositories": "Ta bort alla konfigurerade databaser", "subtitle": "Visa och hantera dina konfigurerade databaser", "success-all-repositories-deleted": "Alla konfigurerade databaser har raderats", "tab-getting-started": "Kom igång", "tab-getting-started-title": "Kom igång", "tab-repositories": "Lagringsplatser", "tab-repositories-title": "Lista över lagringsplatser", - "title-delete-all-configured-repositories": "Radera alla konfigurerade databaser", - "title-legacy-storage-detected": "Äldre lagring upptäcktes" + "title-delete-all-configured-repositories": "Radera alla konfigurerade databaser" }, "http-utils": { "access-denied": "", @@ -11992,7 +12002,6 @@ "mode-options": { "disabled": { "folder-connected": "", - "legacy-storage": "", "not-allowed": "", "not-supported": "" }, @@ -12072,7 +12081,6 @@ "repository-status-page": { "back-to-repositories": "Tillbaka till lagringsplatserna", "cleaning-up-resources": "Rensa lagringsplatsresurser", - "legacy-storage-message": "Instansen kör ännu inte enhetlig lagring – kräver migreringsguide", "not-found": "hittades inte", "not-found-message": "Lagringsplatsen hittades inte", "repository-config-exists-configuration": "Verifiera att lagringsplatskonfigurationen finns i konfigurationsfilen.", @@ -12081,7 +12089,6 @@ "tab-resources": "Resurser", "tab-resources-title": "", "title": "Status för lagringsplats", - "title-legacy-storage": "Äldre lagring", "title-queued-for-deletion": "Köad för radering" }, "repository-type-cards": { @@ -12177,9 +12184,7 @@ "synchronize-step": { "repository-error": "", "repository-error-message": "", - "repository-unhealthy": "", - "synchronization-description": "Inkludera åtaganden för varje historiskt värde", - "synchronization-options": "Synkroniseringsalternativ" + "repository-unhealthy": "" }, "token-permissions-info": { "and-click": "och klicka på", @@ -12196,11 +12201,11 @@ }, "warning-title-default": "Varning", "wizard": { - "alert-point-1": "Resurser kan inte skapas, redigeras eller raderas under den här processen. I det sista steget kommer de att försvinna.", - "alert-point-2": "När provisionering är klar kommer resurserna att visas igen och kan hanteras via extern lagring.", + "alert-point-1": "", + "alert-point-2": "", "alert-point-3": "Hur lång den här processen är beror på hur många resurser som är inblandade.", - "alert-point-4": "Enterprise-instansadministratörer kan visa en meddelandebanner för användare. Se <2>denna guide för steg för steg-anvisningar.", - "alert-title": "Viktigt: Inga data eller konfigurationer kommer att förloras, men instrumentpaneler kommer att vara tillfälligt otillgängliga under några minuter.", + "alert-point-4": "", + "alert-title": "", "button-cancel": "", "button-cancelling": "", "button-next": "Slutför", @@ -12218,7 +12223,6 @@ "step-finish": "Välj ytterligare inställningar", "step-synchronize": "Synkronisera med extern lagring", "sync-description": "Synkronisera resurser med extern lagring. Efter det här engångssteget sparas alla framtida uppdateringar automatiskt på lagringsplatsen och provisioneras tillbaka till instansen.", - "sync-option-history": "Historik", "title-bootstrap": "Välj vad du vill synkronisera", "title-connect": "Anslut till extern lagring", "title-finish": "Välj ytterligare inställningar", diff --git a/public/locales/tr-TR/grafana.json b/public/locales/tr-TR/grafana.json index 2277af7feb5..07a0b6673ac 100644 --- a/public/locales/tr-TR/grafana.json +++ b/public/locales/tr-TR/grafana.json @@ -2232,6 +2232,13 @@ "receiver-metadata-badge": { "aria-label-open-external-link": "" }, + "receivers": { + "protected": { + "field": { + "description": "" + } + } + }, "receivers-section": { "button-more": "Daha Fazla", "new-menu": { @@ -3322,6 +3329,7 @@ "login-attribute-path-label": "Giriş özniteliği yolu", "login-prompt-consent": "Onay", "login-prompt-description": "Kullanıcı IdP ile oturum açtığında kullanıcı etkileşiminin türünü gösterir.", + "login-prompt-description-google": "", "login-prompt-label": "Oturum açma istemi", "login-prompt-login": "Oturum aç", "login-prompt-select-account": "Hesap seç", @@ -3379,6 +3387,7 @@ "use-pkce-description": "Etkinleştirilirse Grafana OAuth2 Yetkilendirme Kodu Verilmesi ile birlikte <2>Proof Key for Code Exchange (PKCE) kullanacaktır.", "use-pkce-label": "PKCE kullan", "use-refresh-token-description": "Etkinleştirilirse Grafana, OAuth2 sağlayıcısı tarafından sağlanan yenileme belirtecini kullanarak yeni bir erişim belirteci alır.", + "use-refresh-token-description-google": "", "use-refresh-token-label": "Yenileme belirteci kullan", "validate-hosted-domain-description": "Etkinleştirilirse Grafana, Google Kimlik Belirtecinden alınan Barındırılan Alan Adı ile kullanıcı tarafından belirtilen \"{{ allowedDomainsLabel }}\" listesini eşleştirir.", "validate-hosted-domain-label": "Barındırılan alan adını doğrula", @@ -4821,8 +4830,7 @@ "apply": "", "change-value": "", "discard": "", - "modal-title": "", - "values": "Virgülle ayrılmış değerler" + "modal-title": "" }, "datasource-options": { "name-filter": "Ad filtresi", @@ -10175,7 +10183,8 @@ "copy": "Seçimi kopyala", "disable-menu": "Menüyü devre dışı bırak", "line-contains": "Satır içerir filtresi olarak ekle", - "line-contains-not": "Satır içermez filtresi olarak ekle" + "line-contains-not": "Satır içermez filtresi olarak ekle", + "search-text": "" }, "show-log-attributes": "", "timestamp-format": "", @@ -11413,6 +11422,12 @@ "latestReleaseDate": "Son yayın tarihi:", "latestVersion": "En Son Sürüm", "license": "Lisans", + "moreDetails": "", + "pluginInsights": { + "header": "" + }, + "pluginInsightsSuccessTooltip": "", + "pluginInsightsWarningTooltip": "", "raiseAnIssue": "Sorun bildir", "reportAbuse": "", "reportAbuseTooltip": "Zararlı veya kötü amaçlı eklentilere ilişkin sorunları doğrudan Grafana Labs'a bildirin.", @@ -11859,7 +11874,6 @@ } }, "getting-started": { - "alert-temporary-outage": "Tüm örneğinizi bağladığınızda geçiş işlemi sırasında panolar kullanılamaz hale gelir. İşleme başlamadan önce kullanıcılarınızı bilgilendirmenizi öneririz.", "modal-description-public-access": "GitHub entegrasyonu için Grafana örneğinizde genel erişimi ayarlayın", "modal-description-required-features": "Sağlama işlemleri için gerekli Grafana özelliklerini etkinleştir", "modal-title-set-up-public-access": "Herkese açık erişimi ayarla", @@ -11871,8 +11885,7 @@ "step-title-copy-url": "Herkese açık URL'nizi kopyalayın", "step-title-enable-feature-toggles": "Gerekli Özellik Geçişlerini Etkinleştir", "step-title-start-ngrok": "Geçici genel erişim için ngrok'u başlat", - "step-title-update-grafana-config": "Grafana yapılandırmanızı güncelleyin", - "title-setting-connection-could-cause-temporary-outage": "Bu bağlantıyı kurmak geçici bir kesintiye neden olabilir" + "step-title-update-grafana-config": "Grafana yapılandırmanızı güncelleyin" }, "getting-started-page": { "subtitle-provisioning-feature": "Sağlama bağlantılarınızı görüntüleyin ve yönetin" @@ -11941,18 +11954,15 @@ }, "home-page": { "button-delete-repositories": "Depoları sil", - "configured-repositories-while-running-legacy-storage": "Eski depolama kullanılırken yapılandırılmış depolar çalışmaz.", "confirm-delete-repositories": "Yapılandırılmış tüm depoları silmek istediğinizden emin misiniz? Bu işlem geri alınamaz. ", "error-delete-all-repositories": "Tüm depolar silinemedi", - "remove-all-configured-repositories": "Yapılandırılmış tüm depoları kaldır", "subtitle": "Yapılandırılmış depoları görüntüleyin ve yönetin", "success-all-repositories-deleted": "Yapılandırılmış tüm depolar silindi", "tab-getting-started": "Başlarken", "tab-getting-started-title": "Başlarken", "tab-repositories": "Depolar", "tab-repositories-title": "Depo listesi", - "title-delete-all-configured-repositories": "Yapılandırılmış tüm depoları sil", - "title-legacy-storage-detected": "Eski depolama algılandı" + "title-delete-all-configured-repositories": "Yapılandırılmış tüm depoları sil" }, "http-utils": { "access-denied": "", @@ -11992,7 +12002,6 @@ "mode-options": { "disabled": { "folder-connected": "", - "legacy-storage": "", "not-allowed": "", "not-supported": "" }, @@ -12072,7 +12081,6 @@ "repository-status-page": { "back-to-repositories": "Depolara geri dön", "cleaning-up-resources": "Depo kaynakları temizleniyor", - "legacy-storage-message": "Örnek henüz birleşik depolamayı kullanmıyor: Geçiş sihirbazı gerekiyor", "not-found": "bulunamadı", "not-found-message": "Depo bulunamadı", "repository-config-exists-configuration": "Depo yapılandırmasının yapılandırma dosyasında mevcut olduğundan emin olun.", @@ -12081,7 +12089,6 @@ "tab-resources": "Kaynaklar", "tab-resources-title": "", "title": "Depo Durumu", - "title-legacy-storage": "Eski Depolama", "title-queued-for-deletion": "Silinmek üzere kuyruğa alındı" }, "repository-type-cards": { @@ -12177,9 +12184,7 @@ "synchronize-step": { "repository-error": "", "repository-error-message": "", - "repository-unhealthy": "", - "synchronization-description": "Her geçmiş değer için yürütmeyi dahil et", - "synchronization-options": "Senkronizasyon seçenekleri" + "repository-unhealthy": "" }, "token-permissions-info": { "and-click": "ve şuna tıklayın:", @@ -12196,11 +12201,11 @@ }, "warning-title-default": "Uyarı", "wizard": { - "alert-point-1": "Bu işlem sırasında kaynaklar oluşturulamayacak, düzenlenemeyecek veya silinemeyecek. Son adımda kaynaklar kaybolacaktır.", - "alert-point-2": "Sağlama işlemi tamamlandığında kaynaklar tekrar görünecek ve harici depolama üzerinden yönetilecektir.", + "alert-point-1": "", + "alert-point-2": "", "alert-point-3": "Bu işlemin süresi dâhil olan kaynakların sayısına bağlıdır.", - "alert-point-4": "Enterprise örnek yöneticileri, kullanıcılara bir duyuru afişi gösterebilir. Adım adım talimatlar için <2>bu kılavuza bakın.", - "alert-title": "Önemli: Veri veya yapılandırma kaybı yaşanmayacak ancak panolar birkaç dakika boyunca geçici olarak kullanılamayacaktır.", + "alert-point-4": "", + "alert-title": "", "button-cancel": "", "button-cancelling": "", "button-next": "Sonlandır", @@ -12218,7 +12223,6 @@ "step-finish": "Ek ayarlar seçin", "step-synchronize": "Harici depolama ile senkronize et", "sync-description": "Kaynakları harici depolama ile senkronize edin. Bu tek seferlik adımdan sonra tüm gelecekteki güncellemeler otomatik olarak depoya kaydedilecek ve örneğe geri sağlanacaktır.", - "sync-option-history": "Geçmiş", "title-bootstrap": "Nelerin senkronize edileceğini seçin", "title-connect": "Harici depolamaya bağlan", "title-finish": "Ek ayarlar seçin", diff --git a/public/locales/zh-Hans/grafana.json b/public/locales/zh-Hans/grafana.json index c6a34de778b..a1eb5ea1fae 100644 --- a/public/locales/zh-Hans/grafana.json +++ b/public/locales/zh-Hans/grafana.json @@ -2224,6 +2224,13 @@ "receiver-metadata-badge": { "aria-label-open-external-link": "打开外部链接" }, + "receivers": { + "protected": { + "field": { + "description": "" + } + } + }, "receivers-section": { "button-more": "更多", "new-menu": { @@ -3311,6 +3318,7 @@ "login-attribute-path-label": "登录属性路径", "login-prompt-consent": "同意", "login-prompt-description": "指示用户使用 IdP 登录时的用户交互类型。", + "login-prompt-description-google": "", "login-prompt-label": "登录提示", "login-prompt-login": "登录", "login-prompt-select-account": "选择账户", @@ -3368,6 +3376,7 @@ "use-pkce-description": "如果启用,Grafana 将使用<2>代码交换的证明密钥 (PKCE) 与 OAuth2 身份验证代码授予。", "use-pkce-label": "使用 PKCE", "use-refresh-token-description": "如果启用,Grafana 将使用 OAuth2 提供程序提供的刷新令牌获取新的访问令牌。", + "use-refresh-token-description-google": "", "use-refresh-token-label": "使用刷新令牌", "validate-hosted-domain-description": "如果启用,Grafana 将把从 Google ID 令牌检索到的托管域与用户指定的“{{ allowedDomainsLabel }}”列表进行匹配。", "validate-hosted-domain-label": "验证托管域", @@ -4802,8 +4811,7 @@ "apply": "", "change-value": "", "discard": "", - "modal-title": "", - "values": "以逗号分隔的值" + "modal-title": "" }, "datasource-options": { "name-filter": "名称筛选器", @@ -10132,7 +10140,8 @@ "copy": "复制选择", "disable-menu": "禁用菜单", "line-contains": "添加为包含筛选器的行", - "line-contains-not": "添加为不包含筛选器的行" + "line-contains-not": "添加为不包含筛选器的行", + "search-text": "" }, "show-log-attributes": "", "timestamp-format": "时间戳分辨率", @@ -11367,6 +11376,12 @@ "latestReleaseDate": "最新发布日期:", "latestVersion": "最新版本", "license": "许可", + "moreDetails": "", + "pluginInsights": { + "header": "" + }, + "pluginInsightsSuccessTooltip": "", + "pluginInsightsWarningTooltip": "", "raiseAnIssue": "报告问题", "reportAbuse": "", "reportAbuseTooltip": "直接向 Grafana Labs 报告与恶意或有害插件相关的问题。", @@ -11808,7 +11823,6 @@ } }, "getting-started": { - "alert-temporary-outage": "在连接整个实例的情况下,数据面板在运行迁移时将不可用。我们建议您在开始此流程之前提醒您的用户。", "modal-description-public-access": "设置对您 Grafana 实例的公共访问以启用 GitHub 集成", "modal-description-required-features": "启用预配所需的 Grafana 功能", "modal-title-set-up-public-access": "设置公共访问", @@ -11820,8 +11834,7 @@ "step-title-copy-url": "复制您的公共 URL", "step-title-enable-feature-toggles": "启用所需的功能切换", "step-title-start-ngrok": "启动 ngrok 以实现临时公共访问", - "step-title-update-grafana-config": "更新您的 Grafana 配置", - "title-setting-connection-could-cause-temporary-outage": "设置此连接可能会导致暂时中断" + "step-title-update-grafana-config": "更新您的 Grafana 配置" }, "getting-started-page": { "subtitle-provisioning-feature": "查看和管理您的预配连接" @@ -11890,18 +11903,15 @@ }, "home-page": { "button-delete-repositories": "删除存储库", - "configured-repositories-while-running-legacy-storage": "运行传统存储时,已配置的存储库将不起作用。", "confirm-delete-repositories": "您确定要删除所有已配置的存储库吗?此操作无法撤销。", "error-delete-all-repositories": "删除所有存储库失败", - "remove-all-configured-repositories": "移除所有已配置的存储库", "subtitle": "查看和管理已配置的存储库", "success-all-repositories-deleted": "已删除所有已配置的存储库", "tab-getting-started": "开始操作", "tab-getting-started-title": "开始操作", "tab-repositories": "存储库", "tab-repositories-title": "存储库列表", - "title-delete-all-configured-repositories": "删除所有已配置的存储库", - "title-legacy-storage-detected": "检测到传统存储" + "title-delete-all-configured-repositories": "删除所有已配置的存储库" }, "http-utils": { "access-denied": "", @@ -11941,7 +11951,6 @@ "mode-options": { "disabled": { "folder-connected": "", - "legacy-storage": "", "not-allowed": "", "not-supported": "" }, @@ -12021,7 +12030,6 @@ "repository-status-page": { "back-to-repositories": "回到存储库", "cleaning-up-resources": "清理存储库资源", - "legacy-storage-message": "实例尚未运行统一存储 -- 需要迁移向导", "not-found": "找不到", "not-found-message": "找不到存储库", "repository-config-exists-configuration": "确保存储库配置存在于配置文件中。", @@ -12030,7 +12038,6 @@ "tab-resources": "资源", "tab-resources-title": "", "title": "存储库状态", - "title-legacy-storage": "传统存储", "title-queued-for-deletion": "已进入队列等待删除" }, "repository-type-cards": { @@ -12126,9 +12133,7 @@ "synchronize-step": { "repository-error": "", "repository-error-message": "", - "repository-unhealthy": "", - "synchronization-description": "包括每个历史值的提交", - "synchronization-options": "同步选项" + "repository-unhealthy": "" }, "token-permissions-info": { "and-click": "并点击", @@ -12145,11 +12150,11 @@ }, "warning-title-default": "警告", "wizard": { - "alert-point-1": "在此过程中将无法创建、编辑或删除资源。在最后一步中,它们将消失。", - "alert-point-2": "预配完成后,资源将重新出现并通过外部存储进行管理。", + "alert-point-1": "", + "alert-point-2": "", "alert-point-3": "此过程的持续时间取决于所涉及资源的数量。", - "alert-point-4": "企业实例管理员可以向用户显示公告横幅。有关分步说明,请参阅<2>本指南。", - "alert-title": "重要提示:数据或配置不会丢失,但数据面板将在几分钟内暂时不可用。", + "alert-point-4": "", + "alert-title": "", "button-cancel": "", "button-cancelling": "", "button-next": "完成", @@ -12167,7 +12172,6 @@ "step-finish": "选择附加设置", "step-synchronize": "与外部存储同步", "sync-description": "将资源与外部存储同步。完成此一次性步骤后,所有后续更新都将自动保存到存储库中,并预配回实例。", - "sync-option-history": "历史记录", "title-bootstrap": "选择要同步的内容", "title-connect": "连接到外部存储", "title-finish": "选择附加设置", diff --git a/public/locales/zh-Hant/grafana.json b/public/locales/zh-Hant/grafana.json index 4a569b10b0f..df0a64f1c1e 100644 --- a/public/locales/zh-Hant/grafana.json +++ b/public/locales/zh-Hant/grafana.json @@ -2224,6 +2224,13 @@ "receiver-metadata-badge": { "aria-label-open-external-link": "開啟外部連結" }, + "receivers": { + "protected": { + "field": { + "description": "" + } + } + }, "receivers-section": { "button-more": "更多", "new-menu": { @@ -3311,6 +3318,7 @@ "login-attribute-path-label": "登入屬性路徑", "login-prompt-consent": "同意", "login-prompt-description": "表示使用者使用 IdP 登入時的使用者互動類型。", + "login-prompt-description-google": "", "login-prompt-label": "登入提示", "login-prompt-login": "登入", "login-prompt-select-account": "選擇帳戶", @@ -3368,6 +3376,7 @@ "use-pkce-description": "若啟用,Grafana 將使用<2>代碼交換的驗證金鑰 (PKCE) 與 OAuth2 授權碼授權。", "use-pkce-label": "使用 PKCE", "use-refresh-token-description": "若啟用,Grafana 將使用 OAuth2 提供者提供的重新整理權杖來擷取新的存取權杖。", + "use-refresh-token-description-google": "", "use-refresh-token-label": "使用重新整理權杖", "validate-hosted-domain-description": "若啟用,Grafana 將會比對從 Google ID 權杖擷取的託管網域與使用者指定的「{{ allowedDomainsLabel }}」清單。", "validate-hosted-domain-label": "驗證託管網域", @@ -4802,8 +4811,7 @@ "apply": "", "change-value": "", "discard": "", - "modal-title": "", - "values": "以逗號分隔的值" + "modal-title": "" }, "datasource-options": { "name-filter": "名稱篩選", @@ -10132,7 +10140,8 @@ "copy": "複製選取範圍", "disable-menu": "停用功能表", "line-contains": "新增為包含篩選條件的行", - "line-contains-not": "新增為不包含篩選條件的行" + "line-contains-not": "新增為不包含篩選條件的行", + "search-text": "" }, "show-log-attributes": "", "timestamp-format": "時間戳記解決方案", @@ -11367,6 +11376,12 @@ "latestReleaseDate": "最新發佈日期:", "latestVersion": "最新版本", "license": "授權", + "moreDetails": "", + "pluginInsights": { + "header": "" + }, + "pluginInsightsSuccessTooltip": "", + "pluginInsightsWarningTooltip": "", "raiseAnIssue": "提出問題", "reportAbuse": "", "reportAbuseTooltip": "將與惡意或有害外掛程式相關的問題直接報告給 Grafana Labs。", @@ -11808,7 +11823,6 @@ } }, "getting-started": { - "alert-temporary-outage": "連接整個執行個體時,在執行移轉時將無法使用儀表板。建議您在開始此流程前通知使用者。", "modal-description-public-access": "設定 Grafana 執行個體的公共存取權限,以啟用 GitHub 整合", "modal-description-required-features": "啟用所需的 Grafana 功能以進行佈建", "modal-title-set-up-public-access": "設定公共存取", @@ -11820,8 +11834,7 @@ "step-title-copy-url": "複製您的公共網址", "step-title-enable-feature-toggles": "啟用必要的功能切換", "step-title-start-ngrok": "啟動 ngrok 以進行臨時公共存取", - "step-title-update-grafana-config": "更新您的 Grafana 設定", - "title-setting-connection-could-cause-temporary-outage": "設定此連線可能會導致暫時中斷" + "step-title-update-grafana-config": "更新您的 Grafana 設定" }, "getting-started-page": { "subtitle-provisioning-feature": "檢視及管理您的佈建連線" @@ -11890,18 +11903,15 @@ }, "home-page": { "button-delete-repositories": "刪除儲存庫", - "configured-repositories-while-running-legacy-storage": "在執行舊的儲存空間時,已設定的儲存庫將不作用。", "confirm-delete-repositories": "確定要刪除所有已設定的儲存庫嗎?此動作無法還原。", "error-delete-all-repositories": "無法刪除所有儲存庫", - "remove-all-configured-repositories": "移除所有已設定的儲存庫", "subtitle": "檢視及管理您設定的儲存庫", "success-all-repositories-deleted": "已刪除所有已設定的儲存庫", "tab-getting-started": "立即開始", "tab-getting-started-title": "立即開始", "tab-repositories": "儲存庫", "tab-repositories-title": "儲存庫清單", - "title-delete-all-configured-repositories": "刪除所有已設定的儲存庫", - "title-legacy-storage-detected": "偵測到舊的儲存空間" + "title-delete-all-configured-repositories": "刪除所有已設定的儲存庫" }, "http-utils": { "access-denied": "", @@ -11941,7 +11951,6 @@ "mode-options": { "disabled": { "folder-connected": "", - "legacy-storage": "", "not-allowed": "", "not-supported": "" }, @@ -12021,7 +12030,6 @@ "repository-status-page": { "back-to-repositories": "返回至儲存庫", "cleaning-up-resources": "清理儲存庫資源", - "legacy-storage-message": "執行個體尚未執行統一儲存空間 -- 需要移轉小工具", "not-found": "找不到", "not-found-message": "找不到儲存庫", "repository-config-exists-configuration": "請確認儲存庫設定存在於設定檔案中。", @@ -12030,7 +12038,6 @@ "tab-resources": "資源", "tab-resources-title": "", "title": "儲存庫狀態", - "title-legacy-storage": "舊版儲存空間", "title-queued-for-deletion": "已排入刪除佇列" }, "repository-type-cards": { @@ -12126,9 +12133,7 @@ "synchronize-step": { "repository-error": "", "repository-error-message": "", - "repository-unhealthy": "", - "synchronization-description": "包含每個歷史數值的提交", - "synchronization-options": "同步選項" + "repository-unhealthy": "" }, "token-permissions-info": { "and-click": "然後按一下", @@ -12145,11 +12150,11 @@ }, "warning-title-default": "警告", "wizard": { - "alert-point-1": "在此過程中,將無法建立、編輯或刪除資源。在最後一步中,它們將會消失。", - "alert-point-2": "佈建完成後,資源將重新出現,並透過外部儲存空間進行管理。", + "alert-point-1": "", + "alert-point-2": "", "alert-point-3": "此流程的持續時間取決於所涉及的資源數量。", - "alert-point-4": "企業執行個體管理員可以向使用者顯示公告橫幅。請參閱<2>本指南,了解逐步說明。", - "alert-title": "重要事項:不會遺失任何資料或設定,但儀表板將在幾分鐘內暫時無法使用。", + "alert-point-4": "", + "alert-title": "", "button-cancel": "", "button-cancelling": "", "button-next": "結束", @@ -12167,7 +12172,6 @@ "step-finish": "選擇附加設定", "step-synchronize": "與外部儲存空間同步", "sync-description": "將資源與外部儲存空間同步。在此一次性步驟之後,未來的所有更新都將自動儲存到儲存庫中,並佈建回執行個體。", - "sync-option-history": "歷史紀錄", "title-bootstrap": "選擇要同步的內容", "title-connect": "連接到外部儲存空間", "title-finish": "選擇附加設定", diff --git a/public/openapi3.json b/public/openapi3.json index 3257a516bb0..9978e3dfa78 100644 --- a/public/openapi3.json +++ b/public/openapi3.json @@ -24691,8 +24691,7 @@ "name": "teamId", "required": true, "schema": { - "format": "int64", - "type": "integer" + "type": "string" } } ], @@ -24730,8 +24729,7 @@ "name": "teamId", "required": true, "schema": { - "format": "int64", - "type": "integer" + "type": "string" } } ], @@ -24769,8 +24767,7 @@ "name": "teamId", "required": true, "schema": { - "format": "int64", - "type": "integer" + "type": "string" } } ], diff --git a/scripts/cli/tsconfig.json b/scripts/cli/tsconfig.json index 468d9938751..057344a363c 100644 --- a/scripts/cli/tsconfig.json +++ b/scripts/cli/tsconfig.json @@ -1,7 +1,7 @@ { "compilerOptions": { - "moduleResolution": "node", - "module": "commonjs" + "moduleResolution": "nodenext", + "module": "NodeNext" }, "extends": "../../tsconfig.json", "ts-node": { diff --git a/scripts/prepare-npm-package.js b/scripts/prepare-npm-package.js index 054b3d12609..7a11a2eca4a 100644 --- a/scripts/prepare-npm-package.js +++ b/scripts/prepare-npm-package.js @@ -1,108 +1,35 @@ +//@ts-check import PackageJson from '@npmcli/package-json'; -import { mkdir } from 'node:fs/promises'; const cwd = process.cwd(); try { const pkgJson = await PackageJson.load(cwd); - const cjsIndex = pkgJson.content.publishConfig?.main ?? pkgJson.content.main; - const esmIndex = pkgJson.content.publishConfig?.module ?? pkgJson.content.module; - const typesIndex = pkgJson.content.publishConfig?.types ?? pkgJson.content.types; + const pkgJsonExports = pkgJson.content.exports; - const exports = { - './package.json': './package.json', - '.': { - import: { - types: typesIndex, - default: esmIndex, - }, - require: { - types: typesIndex, - default: cjsIndex, - }, - }, - }; - // Fix so scenes can access `@grafana/schema` nested dist import paths e.g. - // import {} from '@grafana/schema/dist/esm/raw/composable/bargauge/panelcfg/x/BarGaugePanelCfg_types.gen' - if (pkgJson.content.name === '@grafana/schema') { - exports['./dist/*'] = { - types: './dist/*', - default: './dist/*', - }; - } - - // Fix for @grafana/i18n so eslint-plugin can be imported by consumers - if (pkgJson.content.name === '@grafana/i18n') { - exports['./eslint-plugin'] = { - types: './dist/eslint/index.d.ts', - import: './dist/eslint/index.cjs', - require: './dist/eslint/index.cjs', - }; - } - - pkgJson.update({ - main: cjsIndex, - types: typesIndex, - module: esmIndex, - exports, - }); - - await pkgJson.save(); - - // If an alias package name is provided we add an exports entry for the alias - // then generate an additional "nested" package.json for typescript resolution that - // doesn't use the exports property in package.json. - if (process.env.ALIAS_PACKAGE_NAME) { - const aliasNames = process.env.ALIAS_PACKAGE_NAME.split(','); - - const additionalExports = aliasNames.reduce((acc, alias) => { - acc[`./${alias}`] = { - import: { - types: typesIndex.replace('index', alias), - default: esmIndex.replace('index', alias), - }, - require: { - types: typesIndex.replace('index', alias), - default: cjsIndex.replace('index', alias), - }, - }; - return acc; - }, {}); + // skip packages without exports otherwise consumers cannot import anything from the package + if (pkgJsonExports && typeof pkgJsonExports === 'object') { + // Remove all exports that only contain a single key '@grafana-app/source' + // as these will not resolve when validating packages with attw because the + // source code is not available in the tarball. + for (const [key, val] of Object.entries(pkgJsonExports)) { + if ( + val !== null && + typeof val === 'object' && + Object.keys(val).length === 1 && + Object.keys(val)[0] === '@grafana-app/source' + ) { + delete pkgJsonExports[key]; + } + } pkgJson.update({ - exports: { - ...pkgJson.content.exports, - ...additionalExports, - }, - files: [...pkgJson.content.files, ...aliasNames], + exports: pkgJsonExports, }); - await pkgJson.save(); - for await (const aliasName of aliasNames) { - await createAliasPackageJsonFiles(pkgJson.content, aliasName); - } + await pkgJson.save(); } } catch (e) { console.error(e); process.exit(1); } - -async function createAliasPackageJsonFiles(packageJsonContent, aliasName) { - const pkgName = `${packageJsonContent.name}/${aliasName}`; - try { - console.log(`📦 Writing alias package.json for ${pkgName}.`); - const pkgJsonPath = `${cwd}/${aliasName}`; - await mkdir(pkgJsonPath, { recursive: true }); - const pkgJson = await PackageJson.create(pkgJsonPath, { - data: { - name: pkgName, - types: `../dist/types/${aliasName}.d.ts`, - main: `../dist/cjs/${aliasName}.cjs`, - module: `../dist/esm/${aliasName}.mjs`, - }, - }); - await pkgJson.save(); - } catch (error) { - throw new Error(`Error generating package.json for ${pkgName}`, error); - } -} diff --git a/scripts/tsconfig.base.json b/scripts/tsconfig.base.json index 55eacdf4b61..152674b91e7 100644 --- a/scripts/tsconfig.base.json +++ b/scripts/tsconfig.base.json @@ -4,6 +4,7 @@ "alwaysStrict": true, "strict": true, "allowSyntheticDefaultImports": true, + "customConditions": ["@grafana-app/source"], "downlevelIteration": true, "esModuleInterop": true, "experimentalDecorators": true, diff --git a/scripts/validate-npm-packages.sh b/scripts/validate-npm-packages.sh index 92e871b6899..99474041107 100755 --- a/scripts/validate-npm-packages.sh +++ b/scripts/validate-npm-packages.sh @@ -17,7 +17,7 @@ for file in "$ARTIFACTS_DIR"/*.tgz; do fi # shellcheck disable=SC2086 - if ! yarn attw "$file" --ignore-rules "false-cjs" $ATTW_FLAGS; then + if ! NODE_OPTIONS="-C @grafana-app/source" yarn attw "$file" --ignore-rules "false-cjs" $ATTW_FLAGS; then echo "attw check failed for $file" echo "" failed_checks+=("$file - yarn attw") diff --git a/scripts/webpack/webpack.common.js b/scripts/webpack/webpack.common.js index e694b812100..f81c279d6a3 100644 --- a/scripts/webpack/webpack.common.js +++ b/scripts/webpack/webpack.common.js @@ -22,6 +22,7 @@ module.exports = { publicPath: 'public/build/', }, resolve: { + conditionNames: ['@grafana-app/source', '...'], extensions: ['.ts', '.tsx', '.es6', '.js', '.json', '.svg'], alias: { // some of data source plugins use global Prism object to add the language definition diff --git a/tsconfig.json b/tsconfig.json index 963aa84555c..46f7b630cb2 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -18,9 +18,10 @@ } }, "ts-node": { + "swc": true, "compilerOptions": { "module": "ESNext", - "moduleResolution": "Node" + "moduleResolution": "Bundler" } }, "include": [ diff --git a/yarn.lock b/yarn.lock index 7820f3c3c62..64561ce4dca 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3446,17 +3446,17 @@ __metadata: languageName: unknown linkType: soft -"@grafana/plugin-e2e@npm:^3.0.3": - version: 3.0.3 - resolution: "@grafana/plugin-e2e@npm:3.0.3" +"@grafana/plugin-e2e@npm:^3.1.0": + version: 3.1.0 + resolution: "@grafana/plugin-e2e@npm:3.1.0" dependencies: - "@grafana/e2e-selectors": "npm:^12.4.0-19890644192" + "@grafana/e2e-selectors": "npm:12.4.0-20165274911" semver: "npm:^7.5.4" uuid: "npm:^13.0.0" yaml: "npm:^2.3.4" peerDependencies: "@playwright/test": ^1.52.0 - checksum: 10/d9247d52cc5b65c91983212790610b0c2470d705fa4e37178d04cbf681c4fc80bb08b2c39ea6f0061cb0d78242f108a5c8e6fa1ad2f2209d6f15d34000cb1d00 + checksum: 10/a4003a1c594e8ecd771a8ab7af77357cfe2d942dee821d922e317da2eb7962f86c19bddcc4bdf4d0c793b3ebfec409095b25022b0e3664d66b93163e61cc3fb5 languageName: node linkType: hard @@ -3604,11 +3604,11 @@ __metadata: languageName: unknown linkType: soft -"@grafana/scenes-react@npm:6.49.0": - version: 6.49.0 - resolution: "@grafana/scenes-react@npm:6.49.0" +"@grafana/scenes-react@npm:6.52.0": + version: 6.52.0 + resolution: "@grafana/scenes-react@npm:6.52.0" dependencies: - "@grafana/scenes": "npm:6.49.0" + "@grafana/scenes": "npm:6.52.0" lru-cache: "npm:^10.2.2" react-use: "npm:^17.4.0" peerDependencies: @@ -3620,7 +3620,7 @@ __metadata: react: ^18.0.0 react-dom: ^18.0.0 react-router-dom: ^6.28.0 - checksum: 10/0f9ba2ccaf2c8a703f3c4867320852c07f640aea85491e6c1a35d7fd25b48e69740f7782b52280ab4d423a6e87659de41cf66904acc865c9ea1f934ded6c7e64 + checksum: 10/7f121bcc4fd50f525c7c3457666ad3a32b04783d322d6715aedb6119538f911d0ec265c9c5b49a80478c1deb99286d36d003399a8831f76b6c483f4458b4ce8b languageName: node linkType: hard @@ -3650,9 +3650,9 @@ __metadata: languageName: node linkType: hard -"@grafana/scenes@npm:6.49.0": - version: 6.49.0 - resolution: "@grafana/scenes@npm:6.49.0" +"@grafana/scenes@npm:6.52.0": + version: 6.52.0 + resolution: "@grafana/scenes@npm:6.52.0" dependencies: "@floating-ui/react": "npm:^0.26.16" "@leeoniya/ufuzzy": "npm:^1.0.16" @@ -3672,7 +3672,7 @@ __metadata: react: ^18.0.0 react-dom: ^18.0.0 react-router-dom: ^6.28.0 - checksum: 10/0e873ceac0834879ade41df56ced5a3e8f6a10e5aba15a6f271327aa804729402bcf44845e54614dd0fb1541a28efbb9a5499acceae04cb8be3b11bcdc230347 + checksum: 10/e52e0fb83396776c6cb79f8ac6a8aad0799eb2ccce9d0139f5734a49c3add7a1e3b97f14e0142c95b2bceee3ed8fa97b675b9b94c02382ecd683f470d06ef145 languageName: node linkType: hard @@ -8290,6 +8290,30 @@ __metadata: languageName: node linkType: hard +"@storybook/core@patch:@storybook/core@npm%3A8.6.2#~/.yarn/patches/@storybook-core-npm-8.6.2-8c752112c0.patch": + version: 8.6.2 + resolution: "@storybook/core@patch:@storybook/core@npm%3A8.6.2#~/.yarn/patches/@storybook-core-npm-8.6.2-8c752112c0.patch::version=8.6.2&hash=f4cc1f" + dependencies: + "@storybook/theming": "npm:8.6.2" + better-opn: "npm:^3.0.2" + browser-assert: "npm:^1.2.1" + esbuild: "npm:^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0 || ^0.24.0 || ^0.25.0" + esbuild-register: "npm:^3.5.0" + jsdoc-type-pratt-parser: "npm:^4.0.0" + process: "npm:^0.11.10" + recast: "npm:^0.23.5" + semver: "npm:^7.6.2" + util: "npm:^0.12.5" + ws: "npm:^8.2.3" + peerDependencies: + prettier: ^2 || ^3 + peerDependenciesMeta: + prettier: + optional: true + checksum: 10/cd95a51437135dd3c4333b14acefd528d8064b2cea7789f859ba80783c115c92ed4be51d4a7bd6236888fdd5f46f488a379e0c71bc1a712ffe6dc1353fb4e648 + languageName: node + linkType: hard + "@storybook/csf-plugin@npm:8.6.2": version: 8.6.2 resolution: "@storybook/csf-plugin@npm:8.6.2" @@ -19480,12 +19504,12 @@ __metadata: "@grafana/llm": "npm:1.0.1" "@grafana/monaco-logql": "npm:^0.0.8" "@grafana/o11y-ds-frontend": "workspace:*" - "@grafana/plugin-e2e": "npm:^3.0.3" + "@grafana/plugin-e2e": "npm:^3.1.0" "@grafana/plugin-ui": "npm:^0.11.1" "@grafana/prometheus": "workspace:*" "@grafana/runtime": "workspace:*" - "@grafana/scenes": "npm:6.49.0" - "@grafana/scenes-react": "npm:6.49.0" + "@grafana/scenes": "npm:6.52.0" + "@grafana/scenes-react": "npm:6.52.0" "@grafana/schema": "workspace:*" "@grafana/sql": "workspace:*" "@grafana/test-utils": "workspace:*"